RE: [PATCH v4 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
Hi, >Pawel, > >On 14/02/2019 21:45, Pawel Laszczak wrote: >> This patch introduce new Cadence USBSS DRD driver to linux kernel. >> >> The Cadence USBSS DRD Driver is a highly configurable IP Core whichi >> can be instantiated as Dual-Role Device (DRD), Peripheral Only and >> Host Only (XHCI)configurations. >> >> The current driver has been validated with FPGA burned. We have support >> for PCIe bus, which is used on FPGA prototyping. >> >> The host side of USBSS-DRD controller is compliance with XHCI >> specification, so it works with standard XHCI linux driver. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/Kconfig|2 + >> drivers/usb/Makefile |2 + >> drivers/usb/cdns3/Kconfig | 44 + >> drivers/usb/cdns3/Makefile | 14 + >> drivers/usb/cdns3/cdns3-pci-wrap.c | 155 +++ >> drivers/usb/cdns3/core.c | 403 ++ >> drivers/usb/cdns3/core.h | 116 ++ >> drivers/usb/cdns3/debug.h | 168 +++ >> drivers/usb/cdns3/debugfs.c| 164 +++ >> drivers/usb/cdns3/drd.c| 365 + >> drivers/usb/cdns3/drd.h| 162 +++ >> drivers/usb/cdns3/ep0.c| 907 + >> drivers/usb/cdns3/gadget-export.h | 28 + >> drivers/usb/cdns3/gadget.c | 2003 >> drivers/usb/cdns3/gadget.h | 1207 + >> drivers/usb/cdns3/host-export.h| 28 + >> drivers/usb/cdns3/host.c | 72 + >> drivers/usb/cdns3/trace.c | 23 + >> drivers/usb/cdns3/trace.h | 404 ++ >> 19 files changed, 6267 insertions(+) >> create mode 100644 drivers/usb/cdns3/Kconfig >> create mode 100644 drivers/usb/cdns3/Makefile >> create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c >> create mode 100644 drivers/usb/cdns3/core.c >> create mode 100644 drivers/usb/cdns3/core.h >> create mode 100644 drivers/usb/cdns3/debug.h >> create mode 100644 drivers/usb/cdns3/debugfs.c >> create mode 100644 drivers/usb/cdns3/drd.c >> create mode 100644 drivers/usb/cdns3/drd.h >> create mode 100644 drivers/usb/cdns3/ep0.c >> create mode 100644 drivers/usb/cdns3/gadget-export.h >> create mode 100644 drivers/usb/cdns3/gadget.c >> create mode 100644 drivers/usb/cdns3/gadget.h >> create mode 100644 drivers/usb/cdns3/host-export.h >> create mode 100644 drivers/usb/cdns3/host.c >> create mode 100644 drivers/usb/cdns3/trace.c >> create mode 100644 drivers/usb/cdns3/trace.h >> >> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig >> index 987fc5ba6321..5f9334019d04 100644 >> --- a/drivers/usb/Kconfig >> +++ b/drivers/usb/Kconfig >> @@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig" >> >> endif >> >> +source "drivers/usb/cdns3/Kconfig" >> + >> source "drivers/usb/mtu3/Kconfig" >> >> source "drivers/usb/musb/Kconfig" >> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile >> index 7d1b8c82b208..ab125b966cac 100644 >> --- a/drivers/usb/Makefile >> +++ b/drivers/usb/Makefile >> @@ -12,6 +12,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/ >> obj-$(CONFIG_USB_DWC2) += dwc2/ >> obj-$(CONFIG_USB_ISP1760) += isp1760/ >> >> +obj-$(CONFIG_USB_CDNS3) += cdns3/ >> + >> obj-$(CONFIG_USB_MON) += mon/ >> obj-$(CONFIG_USB_MTU3) += mtu3/ >> >> diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig >> new file mode 100644 >> index ..27cb3d8dbe3d >> --- /dev/null >> +++ b/drivers/usb/cdns3/Kconfig >> @@ -0,0 +1,44 @@ >> +config USB_CDNS3 >> +tristate "Cadence USB3 Dual-Role Controller" >> +depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA >> +help >> + Say Y here if your system has a cadence USB3 dual-role controller. >> + It supports: dual-role switch, Host-only, and Peripheral-only. >> + >> + If you choose to build this driver is a dynamically linked >> + as module, the module will be called cdns3.ko. >> + >> +if USB_CDNS3 >> + >> +config USB_CDNS3_GADGET >> +bool "Cadence USB3 device controller" >> +depends on USB_GADGET >> +help >> + Say Y here to enable device controller functionality of the >> + cadence USBSS-DEV driver. > >"Cadence" ? > >>
RE: [PATCH v4 6/6] usb:cdns3 Fix for stuck packets in on-chip OUT buffer.
Hi, >Hi, > >On 21/02/2019 09:14, Felipe Balbi wrote: >> >> Hi, >> >> (please break your emails at 80-columns) >> >> Pawel Laszczak writes: >>>>> One more thing. Workaround has implemented algorithm that decide for which >>>>> endpoint it should be enabled. e.g for composite device MSC+NCM+ACM it >>>>> should work only for ACM OUT endpoint. >>>>> >>>> >>>> If ACM driver didn't queue the request for ACM OUT endpoint, why does the >>>> controller accept the data at all? >>>> >>>> I didn't understand why we need a workaround for this. It should be >>>> standard >>>> behaviour to NAK data if function driver didn't request for all endpoints. >>> >>> Yes, I agree with you. Controller shouldn’t accept such packet. As I know >>> this >>> behavior will be fixed in RTL. >>> >>> But I assume that some older version of this controller are one the market, >>> and driver should work correct with them. >>> >>> In the feature this workaround can be limited only to selected controllers. >>> >>> Even now I assume that it can be enabled/disabled by module parameter. >> >> no module parameters, please. Use revision detection in runtime. >> > >This is about whether to enable or disable the workaround. >By default we don't want this workaround to be enabled. > >I'm debating whether we should have this workaround at all or not. > >It has the following problems. > >1) It ACKs packets even when gadget end is not ready to accept the transfers. >2) It stores these packets in a temporary buffer and then pushes them to the >gadget driver whenever the gadget driver is ready to process the data. >3) Since the gadget driver can become ready at an indefinite time in the >future, it poses 2 problems: > a) It is sending stale data to the sink. (problematic at next protocol level?) > b) If this temporary buffer runs out we still hit the lock up issue. > >I think the right solution is to make sure that the gadget driver is always >reading all the enabled OUT endpoints *or* (keep the OUT endpoints disabled >if gadget driver is not ready to process OUT transfers). If driver disable endpoint then it not answer for packets from host. It will result that host reset the device, so I can't disable such endpoints. Other good solution is to change ACM driver in a way that it sends requests to controller driver after enabling endpoint. The class driver could decide what should do with such not expected packets. It could delete all or e.g keep only few last packets. This issue will be fixed in RTL but maybe driver should be compatible with previous controller’s version. By default, this workaround will be disabled or will depend on controller version. > >cheers, >-roger >-- >Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. >Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki Cheers, Pawel
RE: [PATCH v9 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
Hi Felipe > >Hi, > >Pawel Laszczak writes: >> +static void cdns3_gadget_config(struct cdns3_device *priv_dev) >> +{ >> +struct cdns3_usb_regs __iomem *regs = priv_dev->regs; >> +u32 reg; >> + >> +cdns3_ep0_config(priv_dev); >> + >> +/* enable interrupts for endpoint 0 (in and out) */ >> +writel(EP_IEN_EP_OUT0 | EP_IEN_EP_IN0, ®s->ep_ien); >> + >> +/* >> + *Driver need modify LFPS minimal U1 Exit time for 0x00024505 revision > >comment style > >> + * of controller >> + */ >> +if (priv_dev->dev_ver == DEV_VER_TI_V1) { > >this version is really only for TI? And there's another only for NXP? Yes, from driver point of view the only difference for this version is LFPS parameter. It's depend on the kind of used PHY and should be set on integration level. Default value is incorrect for DEV_VER_TI_V1 version and it cause some issue for one of the Link Layer test. > >+#define DEV_VER_NXP_V10x00024502 >+#define DEV_VER_TI_V1 0x00024509 >+#define DEV_VER_V20x0002450C >+#define DEV_VER_V30x0002450d > >How do you actually decode this? It's read from register: USB_CAP6 priv_dev->dev_ver = readl(&priv_dev->regs->usb_cap6); But's only 3 less significant bytes are used as version. > >> +static int cdns3_gadget_udc_stop(struct usb_gadget *gadget) >> +{ >> +struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); >> +struct cdns3_endpoint *priv_ep; >> +u32 bEndpointAddress; >> +struct usb_ep *ep; >> +int ret = 0; >> + >> +priv_dev->gadget_driver = NULL; >> + >> +priv_dev->onchip_used_size = 0; >> +priv_dev->out_mem_is_allocated = 0; >> +priv_dev->gadget.speed = USB_SPEED_UNKNOWN; >> + >> +list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { >> +priv_ep = ep_to_cdns3_ep(ep); >> +bEndpointAddress = priv_ep->num | priv_ep->dir; >> +cdns3_select_ep(priv_dev, bEndpointAddress); >> +writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd); >> +ret = cdns3_handshake(&priv_dev->regs->ep_cmd, >> + EP_CMD_EPRST, 0, 100); >> +cdns3_free_trb_pool(priv_ep); > >are you sure you want to free your trb pool when a gadget driver is >unloaded? One can easily fragment memory by constantly loading and >unloading a gadget driver, no? I think that such constantly loading/unloading will occurs only during testing. > >How about you allocate the trb poll during cdns3 load and free it when >cdns3 is unloaded? This allocation is made only in cdns3_gadget_ep_enable, so memory is allocated only for endpoint in use. We save a lot of memory, especially for streams and ISOC endpoint. Streams support is not implemented now but it will be added as separate patch in the feature. It will require allocation multiple Transfer Rings. The second issue are ISOC endpoints. For each ITP we need separate TRB. So, for bInterval > 1 driver must allocate the quite big size of Transfer Ring. During loading cdns3 we don't know which endpoint and how it will be used. If someone from customers will complain about current implementation, Then I will try to implement some improvement. > >> +static int cdns3_gadget_start(struct cdns3 *cdns) >> +{ >> +struct cdns3_device *priv_dev; >> +u32 max_speed; >> +int ret; >> + >> +priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); >> +if (!priv_dev) >> +return -ENOMEM; >> + >> +cdns->gadget_dev = priv_dev; >> +priv_dev->sysdev = cdns->dev; >> +priv_dev->dev = cdns->dev; >> +priv_dev->regs = cdns->dev_regs; >> + >> +device_property_read_u16(priv_dev->dev, "cdns,on-chip-buff-size", >> + &priv_dev->onchip_buffers); >> + >> +if (priv_dev->onchip_buffers <= 0) { >> +u32 reg = readl(&priv_dev->regs->usb_cap2); >> + >> +priv_dev->onchip_buffers = USB_CAP2_ACTUAL_MEM_SIZE(reg); >> +} >> + >> +if (!priv_dev->onchip_buffers) >> +priv_dev->onchip_buffers = 256; >> + >> +max_speed = usb_get_maximum_speed(cdns->dev); >> + >> +/* Check the maximum_speed parameter */ >> +switch (max_speed) { >> +case USB_SPEED_FULL: >> +case USB_SPEED_HIGH: >> +case USB_SPEED_SUPER: >> +
RE: [PATCH 1/3] usb: common: Add usb_get_dr_mode_from_string and usb_dr_mode_to_string.
Hi, >>Pawel Laszczak writes: >>>>> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h >>>>> index 69f1b6328532..c156817672c4 100644 >>>>> --- a/include/linux/usb/otg.h >>>>> +++ b/include/linux/usb/otg.h >>>>> @@ -129,4 +129,20 @@ enum usb_dr_mode { >>>>> */ >>>>> extern enum usb_dr_mode usb_get_dr_mode(struct device *dev); >>>>> >>>>> +/** >>>>> + * usb_get_dr_mode_from_string - Convert string to dual role mode. >>>>> + * @str: Pointer to the given string >>>>> + * >>>>> + * The function gets string and returns the correspondig enum >>>>> usb_dr_mode. >>>>> + */ >>>>> +extern enum usb_dr_mode usb_get_dr_mode_from_string(const char *str); >>>>> + >>>>> +/** >>>>> + * usb_dr_mode_to_string - Convert dual role mode to string. >>>>> + * @dr_mode: Pointer to the given dual role mode >>>>> + * >>>>> + * The function gets enum usb_dr_mode, and returns the correspondig >>>>> string. >>>>> + */ >>>>> +extern const char *usb_dr_mode_to_string(const enum usb_dr_mode dr_mode); >>>>> + >>>>> #endif /* __LINUX_USB_OTG_H */ >>>> >>>>Still missing the stubs I mentioned. Did you try compiling with and >>>>without common enabled? >>>> >>> Sorry, I thought that I send answer yesterday but it's look like I prepared >>> the answer but >>> I forgot to send. >>> >>> In /drivers/usb/Kconfig we have: >>> >>> config USB >>> tristate "Support for Host-side USB" >>> depends on USB_ARCH_HAS_HCD >>> select USB_COMMON >>> >>> and in /drivers/usb/gadget/Kconfig we have: >>> >>> menuconfig USB_GADGET >>> tristate "USB Gadget Support" >>> select USB_COMMON >>> >>> I think that it should cover all cases. >>> >>> Am I right ? >> >>Run a few tens of randconfig builds and see if you ever catch any >>problem. I think randconfig can produce a defconfig where USB=n >>USB_GADGET=n and USB_COMMON=y. > >Ok, I will test it, but I think that it should work. >The same situation we have for example with: usb_otg_state_string or >usb_ep_type_string. > I've been testing it with USB=n USB_GADGET=n and USB_COMMON=y and also only with CONFIG_USB_COMMON=y. Also I've tested this patch with different default configuration together with CDNS3 driver which use these functions. I've test It mainly with x86 and arm architecture. So far I've not found any issue. Cheers, Pawell
[PATCH v10 6/6] usb:cdns3 Fix for stuck packets in on-chip OUT buffer.
Controller for OUT endpoints has shared on-chip buffers for all incoming packets, including ep0out. It's FIFO buffer, so packets must be handled by DMA in correct order. If the first packet in the buffer will not be handled, then the following packets directed for other endpoints and functions will be blocked. Additionally the packets directed to one endpoint can block entire on-chip buffers. In this case transfer to other endpoints also will blocked. To resolve this issue after raising the descriptor missing interrupt driver prepares internal usb_request object and use it to arm DMA transfer. The problematic situation was observed in case when endpoint has been enabled but no usb_request were queued. Driver try detects such endpoints and will use this workaround only for these endpoint. Driver use limited number of buffer. This number can be set by macro CDNS_WA2_NUM_BUFFERS. Such blocking situation was observed on ACM gadget. For this function host send OUT data packet but ACM function is not prepared for this packet. It's cause that buffer placed in on chip memory block transfer to other endpoints. Issue has been fixed for DEV_VER_V2 version of controller. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/gadget.c | 338 - drivers/usb/cdns3/gadget.h | 13 ++ 2 files changed, 349 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 291f08be56fe..a42e832b3c6a 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -28,6 +28,32 @@ * * Issue has been fixed in DEV_VER_V3 version of controller. * + * Work around 2: + * Controller for OUT endpoints has shared on-chip buffers for all incoming + * packets, including ep0out. It's FIFO buffer, so packets must be handle by DMA + * in correct order. If the first packet in the buffer will not be handled, + * then the following packets directed for other endpoints and functions + * will be blocked. + * Additionally the packets directed to one endpoint can block entire on-chip + * buffers. In this case transfer to other endpoints also will blocked. + * + * To resolve this issue after raising the descriptor missing interrupt + * driver prepares internal usb_request object and use it to arm DMA transfer. + * + * The problematic situation was observed in case when endpoint has been enabled + * but no usb_request were queued. Driver try detects such endpoints and will + * use this workaround only for these endpoint. + * + * Driver use limited number of buffer. This number can be set by macro + * CDNS3_WA2_NUM_BUFFERS. + * + * Such blocking situation was observed on ACM gadget. For this function + * host send OUT data packet but ACM function is not prepared for this packet. + * It's cause that buffer placed in on chip memory block transfer to other + * endpoints. + * + * Issue has been fixed in DEV_VER_V2 version of controller. + * */ #include @@ -99,6 +125,17 @@ struct cdns3_aligned_buf *cdns3_next_align_buf(struct list_head *list) return list_first_entry_or_null(list, struct cdns3_aligned_buf, list); } +/** + * cdns3_next_priv_request - returns next request from list + * @list: list containing requests + * + * Returns request or NULL if no requests in list + */ +struct cdns3_request *cdns3_next_priv_request(struct list_head *list) +{ + return list_first_entry_or_null(list, struct cdns3_request, list); +} + /** * select_ep - selects endpoint * @priv_dev: extended gadget object @@ -337,6 +374,254 @@ static int cdns3_start_all_request(struct cdns3_device *priv_dev, return ret; } +/* + * WA2: Set flag for all not ISOC OUT endpoints. If this flag is set + * driver try to detect whether endpoint need additional internal + * buffer for unblocking on-chip FIFO buffer. This flag will be cleared + * if before first DESCMISS interrupt the DMA will be armed. + */ +#define cdns3_wa2_enable_detection(priv_dev, ep_priv, reg) do { \ + if (!priv_ep->dir && priv_ep->type != USB_ENDPOINT_XFER_ISOC) { \ + priv_ep->flags |= EP_QUIRK_EXTRA_BUF_DET; \ + (reg) |= EP_STS_EN_DESCMISEN; \ + } } while (0) + +/** + * cdns3_wa2_descmiss_copy_data copy data from internal requests to + * request queued by class driver. + * @priv_ep: extended endpoint object + * @request: request object + */ +static void cdns3_wa2_descmiss_copy_data(struct cdns3_endpoint *priv_ep, +struct usb_request *request) +{ + struct usb_request *descmiss_req; + struct cdns3_request *descmiss_priv_req; + + while (!list_empty(&priv_ep->wa2_descmiss_req_list)) { + int chunk_end; + int length; + + descmiss_priv_req = + cdns3_next_priv_request(&priv_ep->wa2_descmiss_req_list); + descmiss_req = &descmiss_priv_req->reques
[PATCH v10 3/6] usb:common Patch simplify usb_decode_set_clear_feature function.
Patch adds usb_decode_test_mode and usb_decode_device_feature functions, which allow to make more readable and simplify the usb_decode_set_clear_feature function. Signed-off-by: Pawel Laszczak --- drivers/usb/common/debug.c | 89 ++ 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c index d5a469bc67a3..60a9f70a0904 100644 --- a/drivers/usb/common/debug.c +++ b/drivers/usb/common/debug.c @@ -30,58 +30,55 @@ static void usb_decode_get_status(__u8 bRequestType, __u16 wIndex, } } -static void usb_decode_set_clear_feature(__u8 bRequestType, __u8 bRequest, -__u16 wValue, __u16 wIndex, -char *str, size_t size) +static const char *usb_decode_device_feature(u16 wValue) +{ + switch (wValue) { + case USB_DEVICE_SELF_POWERED: + return "Self Powered"; + case USB_DEVICE_REMOTE_WAKEUP: + return "Remote Wakeup"; + case USB_DEVICE_TEST_MODE: + return "Test Mode"; + case USB_DEVICE_U1_ENABLE: + return "U1 Enable"; + case USB_DEVICE_U2_ENABLE: + return "U2 Enable"; + case USB_DEVICE_LTM_ENABLE: + return "LTM Enable"; + default: + return "UNKNOWN"; + } +} + +static const char *usb_decode_test_mode(u16 wIndex) +{ + switch (wIndex) { + case TEST_J: + return ": TEST_J"; + case TEST_K: + return ": TEST_K"; + case TEST_SE0_NAK: + return ": TEST_SE0_NAK"; + case TEST_PACKET: + return ": TEST_PACKET"; + case TEST_FORCE_EN: + return ": TEST_FORCE_EN"; + default: + return ": UNKNOWN"; + } +} + +static void usb_decode_set_clear_feature(__u8 bRequestType, +__u8 bRequest, __u16 wValue, +__u16 wIndex, char *str, size_t size) { switch (bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: snprintf(str, size, "%s Device Feature(%s%s)", bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", -({char *s; - switch (wValue) { - case USB_DEVICE_SELF_POWERED: - s = "Self Powered"; - break; - case USB_DEVICE_REMOTE_WAKEUP: - s = "Remote Wakeup"; - break; - case USB_DEVICE_TEST_MODE: - s = "Test Mode"; - break; - case USB_DEVICE_U1_ENABLE: - s = "U1 Enable"; - break; - case USB_DEVICE_U2_ENABLE: - s = "U2 Enable"; - break; - case USB_DEVICE_LTM_ENABLE: - s = "LTM Enable"; - break; - default: - s = "UNKNOWN"; - } s; }), +usb_decode_device_feature(wValue), wValue == USB_DEVICE_TEST_MODE ? -({ char *s; - switch (wIndex) { - case TEST_J: - s = ": TEST_J"; - break; - case TEST_K: - s = ": TEST_K"; - break; - case TEST_SE0_NAK: - s = ": TEST_SE0_NAK"; - break; - case TEST_PACKET: - s = ": TEST_PACKET"; - break; - case TEST_FORCE_EN: - s = ": TEST_FORCE_EN"; - break; - default: - s = ": UNKNOWN"; - } s; }) : ""); +usb_decode_test_mode(wIndex) : ""); break; case USB_RECIP_INTERFACE: snprintf(str, size, "%s Interface Feature(%s)", -- 2.17.1
[PATCH v10 4/6] usb:common Simplify usb_decode_get_set_descriptor function.
Patch moves switch responsible for decoding descriptor type outside snprintf. It improves code readability a little. Signed-off-by: Pawel Laszczak --- drivers/usb/common/debug.c | 113 +++-- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c index 60a9f70a0904..92a986aeaa5d 100644 --- a/drivers/usb/common/debug.c +++ b/drivers/usb/common/debug.c @@ -105,62 +105,65 @@ static void usb_decode_get_set_descriptor(__u8 bRequestType, __u8 bRequest, __u16 wValue, __u16 wIndex, __u16 wLength, char *str, size_t size) { + char *s; + + switch (wValue >> 8) { + case USB_DT_DEVICE: + s = "Device"; + break; + case USB_DT_CONFIG: + s = "Configuration"; + break; + case USB_DT_STRING: + s = "String"; + break; + case USB_DT_INTERFACE: + s = "Interface"; + break; + case USB_DT_ENDPOINT: + s = "Endpoint"; + break; + case USB_DT_DEVICE_QUALIFIER: + s = "Device Qualifier"; + break; + case USB_DT_OTHER_SPEED_CONFIG: + s = "Other Speed Config"; + break; + case USB_DT_INTERFACE_POWER: + s = "Interface Power"; + break; + case USB_DT_OTG: + s = "OTG"; + break; + case USB_DT_DEBUG: + s = "Debug"; + break; + case USB_DT_INTERFACE_ASSOCIATION: + s = "Interface Association"; + break; + case USB_DT_BOS: + s = "BOS"; + break; + case USB_DT_DEVICE_CAPABILITY: + s = "Device Capability"; + break; + case USB_DT_PIPE_USAGE: + s = "Pipe Usage"; + break; + case USB_DT_SS_ENDPOINT_COMP: + s = "SS Endpoint Companion"; + break; + case USB_DT_SSP_ISOC_ENDPOINT_COMP: + s = "SSP Isochronous Endpoint Companion"; + break; + default: + s = "UNKNOWN"; + break; + } + snprintf(str, size, "%s %s Descriptor(Index = %d, Length = %d)", -bRequest == USB_REQ_GET_DESCRIPTOR ? "Get" : "Set", -({ char *s; - switch (wValue >> 8) { - case USB_DT_DEVICE: - s = "Device"; - break; - case USB_DT_CONFIG: - s = "Configuration"; - break; - case USB_DT_STRING: - s = "String"; - break; - case USB_DT_INTERFACE: - s = "Interface"; - break; - case USB_DT_ENDPOINT: - s = "Endpoint"; - break; - case USB_DT_DEVICE_QUALIFIER: - s = "Device Qualifier"; - break; - case USB_DT_OTHER_SPEED_CONFIG: - s = "Other Speed Config"; - break; - case USB_DT_INTERFACE_POWER: - s = "Interface Power"; - break; - case USB_DT_OTG: - s = "OTG"; - break; - case USB_DT_DEBUG: - s = "Debug"; - break; - case USB_DT_INTERFACE_ASSOCIATION: - s = "Interface Association"; - break; - case USB_DT_BOS: - s = "BOS"; - break; - case USB_DT_DEVICE_CAPABILITY: - s = "Device Capability"; - break; - case USB_DT_PIPE_USAGE: - s = "Pipe Usage"; - break; - case USB_DT_SS_ENDPOINT_COMP: - s = "SS Endpoint Companion"; -
[PATCH v10 2/6] usb:common Separated decoding functions from dwc3 driver.
Patch moves some decoding functions from driver/usb/dwc3/debug.h driver to driver/usb/common/debug.c file. These moved functions include: dwc3_decode_get_status dwc3_decode_set_clear_feature dwc3_decode_set_address dwc3_decode_get_set_descriptor dwc3_decode_get_configuration dwc3_decode_set_configuration dwc3_decode_get_intf dwc3_decode_set_intf dwc3_decode_synch_frame dwc3_decode_set_sel dwc3_decode_set_isoch_delay dwc3_decode_ctrl These functions are used also in inroduced cdns3 driver. All functions prefixes were changed from dwc3 to usb. Also, function's parameters has been extended according to the name of fields in standard SETUP packet. Additionally, patch adds usb_decode_ctrl function to include/linux/usb/ch9.h file. Signed-off-by: Pawel Laszczak --- drivers/usb/common/Makefile | 1 + drivers/usb/common/debug.c | 268 drivers/usb/dwc3/debug.h| 252 - drivers/usb/dwc3/trace.h| 2 +- include/linux/usb/ch9.h | 27 5 files changed, 297 insertions(+), 253 deletions(-) create mode 100644 drivers/usb/common/debug.c diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile index 0a7c45e85481..76f3e80623db 100644 --- a/drivers/usb/common/Makefile +++ b/drivers/usb/common/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_USB_COMMON) += usb-common.o usb-common-y += common.o +usb-common-$(CONFIG_TRACING) += debug.o usb-common-$(CONFIG_USB_LED_TRIG) += led.o obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c new file mode 100644 index ..d5a469bc67a3 --- /dev/null +++ b/drivers/usb/common/debug.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * Common USB debugging functions + * + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: Felipe Balbi , + * Sebastian Andrzej Siewior + */ + +#include + +static void usb_decode_get_status(__u8 bRequestType, __u16 wIndex, + __u16 wLength, char *str, size_t size) +{ + switch (bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + snprintf(str, size, "Get Device Status(Length = %d)", wLength); + break; + case USB_RECIP_INTERFACE: + snprintf(str, size, +"Get Interface Status(Intf = %d, Length = %d)", +wIndex, wLength); + break; + case USB_RECIP_ENDPOINT: + snprintf(str, size, "Get Endpoint Status(ep%d%s)", +wIndex & ~USB_DIR_IN, +wIndex & USB_DIR_IN ? "in" : "out"); + break; + } +} + +static void usb_decode_set_clear_feature(__u8 bRequestType, __u8 bRequest, +__u16 wValue, __u16 wIndex, +char *str, size_t size) +{ + switch (bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + snprintf(str, size, "%s Device Feature(%s%s)", +bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", +({char *s; + switch (wValue) { + case USB_DEVICE_SELF_POWERED: + s = "Self Powered"; + break; + case USB_DEVICE_REMOTE_WAKEUP: + s = "Remote Wakeup"; + break; + case USB_DEVICE_TEST_MODE: + s = "Test Mode"; + break; + case USB_DEVICE_U1_ENABLE: + s = "U1 Enable"; + break; + case USB_DEVICE_U2_ENABLE: + s = "U2 Enable"; + break; + case USB_DEVICE_LTM_ENABLE: + s = "LTM Enable"; + break; + default: + s = "UNKNOWN"; + } s; }), +wValue == USB_DEVICE_TEST_MODE ? +({ char *s; + switch (wIndex) { + case TEST_J: + s = ": TEST_J"; + break; +
[PATCH v10 0/6] Introduced new Cadence USBSS DRD Driver.
t field during endpoint configuration. - fixed issue in WA1 algorithm. The previous one could not work correct with slow CPU or in case the access to AXI bus would be blocked for some time. - fixed issue with compilation driver occurred when driver was configured as build in. This fix required to move cdns3_handshake function from gadget.c to core.c file. - added missing pci_disable_device in cdns3-pci-wrap.c file. - fixed issue with pm_runtime_get_sync in cdns3_role_switch function. - fixed incorrect condition in cdns3_decode_usb_irq function. - removed cdns3_data_flush function - is no longer used. - fixed issue in cdns3_descmissing_packet function - fixed incorrect condition - added missed callback informing upper layer about reset event. - added resetting endpoint in cdns3_gadget_ep_disable function. - fixed issue: added statement removing request from descmiss_req_list in cdns3_gadget_ep_disable function. - fixed issue in cdns3_ep_onchip_buffer_reserve. - fixed issue with incorrect calculation the number of required on-chip buffer for OUT endpoints cdns3_ep_onchip_buffer_reserve. - fixed issue in __cdns3_gadget_init function: pm_runtime_get_sync was in incorrect place in. - removed some typos and improved comments as suggested by reviewers. - made some other minor changes as suggested by revivers. Changes since v3: - updated dt-binding as suggested by Rob Herring - updated patch 002, 003 and 004 according with patch: https://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git/commit/ ?h=next&id=7790b3556fccc555ae422f1576e97bf34c8ab8b6 posted by Felipe Balbi. - fixed issues related to isochronous transfers. - improved algorithm calculating number of on-chip buffers required by endpoints. - fixed incorrect macro EP_CFG_MULT in gadget.h file. - fixed potential issue with incorrect order of instruction - added wmb(). - made some minor changes suggested by reviewers. *Changes since v2: - made some text correction in Kconfig file as suggested by Randy Dunlap. - simplified Makefile as suggested by Peter Chan. - removed phy-names from dt-binding as suggested Rob Herring. - changed cdns3-usb.txt to cdns3-usb3.txt as suggested by Rob Herring. - added checking error code in some function in drd.c file as suggested by Peter Chan. - added reg-names to dt-binding documentation as suggested by Chunfeng Yun. - replaced platform_get_resource with platform_get_resource_byname. - made other changes suggested by Chunfeng Yun. - fixed bug in cdns3_get_id. Now function return id instead 1. - added trace_cdns3_log trace event. - simplify cdns3_disable_write function. - create separate patch for work around related with blocking endpoint issue. - Fixed issue related with stale data address in TRB. Issue: At some situations, the controller may get stale data address in TRB at below sequences: 1. Controller read TRB includes data address. 2. Software updates TRBs includes data address and Cycle bit. 3. Controller read TRB which includes Cycle bit. 4. DMA run with stale data address. - Fixed issue without transfer. In some cases not all interrupts disabled in Hard IRQ was enabled in Soft Irq. - Modified LFPS minimal U1 Exit time for controller revision 0x00024505. - Fixed issue - in some case selected endpoint was unexpectedly changed. - Fixed issue - after clearing halted endpoint transfer was not started. - Fixed issue - in some case driver send ACK instead STALL in status phase. - Fixed issues related to dequeue request. - Fixed incorrect operator in cdns3_ep_run_transfer function. Changes since v1: - Removed not implemented Suspend/Resume functions. - Fixed some issues in debugging related functions. - Added trace_cdns3_request_handled marker. - Added support for Isochronous transfer. - Added some additional descriptions. - Fixed compilation error in cdns3_gadget_ep_disable. - Added detection of device controller version at runtime. - Upgraded dt-binding documentation. - Deleted ENOSYS from phy initialization section. It should be also removed from generic PHY driver. - added ep0_stage flag used during enumeration process. - Fixed issue with TEST MODE. - Added one common function for finish control transfer. - Separated some decoding function from dwc3 driver to common library file, and removed equivalents function from debug.h file as suggested by Felipe. - replaced function name cdns3_gadget_unconfig with cdns3_hw_reset_eps_config. - Improved algorithm fixing hardware issue related to blocking endpoints. This issue is related to on-chip shared FIFO buffers for OUT packets. Problem was reported by Peter Chan. - Changed organization of endpoint array in cdns3_device object. - added ep0 to common eps array - removed cdns3_free_trb_pool and cdns3_ep_addr_to_bit_pos macros. - removed ep0_trb_dma, ep0_trb fields from cdns3_device. - Removed ep0_request and ep_nums fields from cdns3_device. - Other minor changes according with Felipe sugge
[PATCH v10 1/6] dt-bindings: add binding for USBSS-DRD controller.
This patch aim at documenting USB related dt-bindings for the Cadence USBSS-DRD controller. Signed-off-by: Pawel Laszczak Reviewed-by: Rob Herring --- .../devicetree/bindings/usb/cdns-usb3.txt | 45 +++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/cdns-usb3.txt diff --git a/Documentation/devicetree/bindings/usb/cdns-usb3.txt b/Documentation/devicetree/bindings/usb/cdns-usb3.txt new file mode 100644 index ..b7dc606d37b5 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/cdns-usb3.txt @@ -0,0 +1,45 @@ +Binding for the Cadence USBSS-DRD controller + +Required properties: + - reg: Physical base address and size of the controller's register areas. +Controller has 3 different regions: +- HOST registers area +- DEVICE registers area +- OTG/DRD registers area + - reg-names - register memory area names: + "xhci" - for HOST registers space + "dev" - for DEVICE registers space + "otg" - for OTG/DRD registers space + - compatible: Should contain: "cdns,usb3" + - interrupts: Interrupts used by cdns3 controller: + "host" - interrupt used by XHCI driver. + "peripheral" - interrupt used by device driver + "otg" - interrupt used by DRD/OTG part of driver + +Optional properties: + - maximum-speed : valid arguments are "super-speed", "high-speed" and + "full-speed"; refer to usb/generic.txt + - dr_mode: Should be one of "host", "peripheral" or "otg". + - phys: reference to the USB PHY + - phy-names: from the *Generic PHY* bindings; + Supported names are: + - cdns3,usb2-phy + - cdns3,usb3-phy + + - cdns,on-chip-buff-size : size of memory intended as internal memory for endpoints + buffers expressed in KB + +Example: + usb@f300 { + compatible = "cdns,usb3"; + interrupts = , + , + ; + interrupt-names = "host", "peripheral", "otg"; + reg = <0xf300 0x1>, /* memory area for HOST registers */ + <0xf301 0x1>, /* memory area for DEVICE registers */ + <0xf302 0x1>; /* memory area for OTG/DRD registers */ + reg-names = "xhci", "dev", "otg"; + phys = <&usb2_phy>, <&usb3_phy>; + phy-names = "cdns3,usb2-phy", "cnds3,usb3-phy"; + }; -- 2.17.1
RE: [PATCH v10 0/6] Introduced new Cadence USBSS DRD Driver.
Hi, > >> This patch introduce new Cadence USBSS DRD driver to linux kernel. >> >> The Cadence USBSS DRD Controller is a highly configurable IP Core which >> can be instantiated as Dual-Role Device (DRD), Peripheral Only and >> Host Only (XHCI)configurations. > >I see you are using debugfs to select between DRD, peripheral-onlyh and XHCI... > >Is that good idea? Yes driver allows selecting dr_mode by debugfs. Controller also support such functionality so I don't understand why would it not be a good idea. I personally use this for testing but it can be used to limit controller functionality without recompiling kernel. >This is at least 3rd driver needing that capability, and debugfs does not >sound like a good match. > Pawell
RE: [PATCH v10 2/6] usb:common Separated decoding functions from dwc3 driver.
Hi, > >On Sun, 2019-07-21 at 19:32 +0100, Pawel Laszczak wrote: >> Patch moves some decoding functions from driver/usb/dwc3/debug.h driver >> to driver/usb/common/debug.c file. These moved functions include: >[] >> diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c >[] >> +static void usb_decode_set_clear_feature(__u8 bRequestType, __u8 bRequest, >> + __u16 wValue, __u16 wIndex, >> + char *str, size_t size) > >It's probably not necessary to use Hungarian >when moving these functions into generic code. In my opinion it's ok in this place. It's consistence with USB specification ch9 and with https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/ch9.h. (look at usb_ctrlrequest). > >> +{ >> +switch (bRequestType & USB_RECIP_MASK) { >> +case USB_RECIP_DEVICE: >> +snprintf(str, size, "%s Device Feature(%s%s)", >> + bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", >> + ({char *s; >> +switch (wValue) { >> +case USB_DEVICE_SELF_POWERED: >> +s = "Self Powered"; >> +break; >> +case USB_DEVICE_REMOTE_WAKEUP: >> +s = "Remote Wakeup"; >> +break; >> +case USB_DEVICE_TEST_MODE: >> +s = "Test Mode"; >> +break; >> +case USB_DEVICE_U1_ENABLE: >> +s = "U1 Enable"; >> +break; >> +case USB_DEVICE_U2_ENABLE: >> +s = "U2 Enable"; >> +break; >> +case USB_DEVICE_LTM_ENABLE: >> +s = "LTM Enable"; >> +break; >> +default: >> +s = "UNKNOWN"; >> +} s; }), >> + wValue == USB_DEVICE_TEST_MODE ? >> + ({ char *s; >> +switch (wIndex) { >> +case TEST_J: >> +s = ": TEST_J"; >> +break; >> +case TEST_K: >> +s = ": TEST_K"; >> +break; >> +case TEST_SE0_NAK: >> +s = ": TEST_SE0_NAK"; >> +break; >> +case TEST_PACKET: >> +s = ": TEST_PACKET"; >> +break; >> +case TEST_FORCE_EN: >> +s = ": TEST_FORCE_EN"; >> +break; >> +default: >> +s = ": UNKNOWN"; >> +} s; }) : ""); > >I always find this sort of embedded switch/case char * >statement expressions difficult to read and think it's >better to use separate lookup functions. > It has been changed in next patch in the series. >I would much prefer something like: > >static const char *usb_device_mode_desc(u16 mode) >{ > switch (mode) { > case USB_DEVICE_SELF_POWERED: > return "Self Powered"; > case USB_DEVICE_REMOTE_WAKEUP: > return "Remote Wakeup"; > case USB_DEVICE_TEST_MODE: > return "Test Mode"; > case USB_DEVICE_U1_ENABLE: > return "U1 Enable"; > case USB_DEVICE_U2_ENABLE: > return "U2 Enable"; > case USB_DEVICE_LTM_ENABLE: > return "LTM Enable"; > } > return "UNKNOWN"; >} > > snprintf(str, size, "%s Device Feature(%s%s)", >> bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", >usb_device_mode_desc(wValue), >etc...); > > >etc... > Cheers, Pawell
RE: [PATCH v10 3/6] usb:common Patch simplify usb_decode_set_clear_feature function.
> > >On Sun, 2019-07-21 at 19:32 +0100, Pawel Laszczak wrote: >> Patch adds usb_decode_test_mode and usb_decode_device_feature functions, >> which allow to make more readable and simplify the >> usb_decode_set_clear_feature function. > > I need to read entire patch series before >commenting more I guess... > >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/common/debug.c | 89 ++ >> 1 file changed, 43 insertions(+), 46 deletions(-) >> >> diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c >[] >> +static const char *usb_decode_device_feature(u16 wValue) > >I believe this is still unnecessary hungarian. it's common in usb subsystem if driver refers to descriptors fields. > >> +{ >> +switch (wValue) { >> +case USB_DEVICE_SELF_POWERED: >> +return "Self Powered"; >> +case USB_DEVICE_REMOTE_WAKEUP: >> +return "Remote Wakeup"; >> +case USB_DEVICE_TEST_MODE: >> +return "Test Mode"; >> +case USB_DEVICE_U1_ENABLE: >> +return "U1 Enable"; >> +case USB_DEVICE_U2_ENABLE: >> +return "U2 Enable"; >> +case USB_DEVICE_LTM_ENABLE: >> +return "LTM Enable"; >> +default: >> +return "UNKNOWN"; >> +} >> +} > > But yeah, exactly like this... ;) > Pawell
RE: [PATCH v10 0/6] Introduced new Cadence USBSS DRD Driver.
> >Hi! > >> > >> This patch introduce new Cadence USBSS DRD driver to linux kernel. >> > >> >> > >> The Cadence USBSS DRD Controller is a highly configurable IP Core which >> > >> can be instantiated as Dual-Role Device (DRD), Peripheral Only and >> > >> Host Only (XHCI)configurations. >> > > >> > >I see you are using debugfs to select between DRD, peripheral-onlyh and >> > >XHCI... >> > > >> > >Is that good idea? >> > >> > Yes driver allows selecting dr_mode by debugfs. Controller also support >> > such functionality >> > so I don't understand why would it not be a good idea. >> > >> > I personally use this for testing but it can be used to limit controller >> > functionality without >> > recompiling kernel. >> >> debugfs is ONLY for debugging, never rely on it being enabled, or >> mounted, on a system in order to have any normal operation happen. >> >> So for testing, yes, this is fine. If this is going to be the normal >> api/interface for how to control this driver, no, that is not acceptable >> at all. > >It makes a lot of sense for end-user to toggle this... for example >when he is lacking right cable for proper otg detection. As it is >third driver offering this functionality, I believe we should stop >treating it as debugging. > Exactly I use this for this purpose. Depending on my testing platform I have the adapter with Typ-c plugs or normal Type A plugs. In the second case, by means of this property I can force Device or Host mode from driver without changing adapter. Bu as I wrote I use it only for debugging purpose. I believe that device on the market should not work in this way. Cheers, Pawel.
RE: [PATCH v10 0/6] Introduced new Cadence USBSS DRD Driver.
Hi, >On Mon 2019-07-22 13:56:44, Pavel Machek wrote: >> Hi! >> >> > > >> This patch introduce new Cadence USBSS DRD driver to linux kernel. >> > > >> >> > > >> The Cadence USBSS DRD Controller is a highly configurable IP Core >> > > >> which >> > > >> can be instantiated as Dual-Role Device (DRD), Peripheral Only and >> > > >> Host Only (XHCI)configurations. >> > > > >> > > >I see you are using debugfs to select between DRD, peripheral-onlyh and >> > > >XHCI... >> > > > >> > > >Is that good idea? >> > > >> > > Yes driver allows selecting dr_mode by debugfs. Controller also support >> > > such functionality >> > > so I don't understand why would it not be a good idea. >> > > >> > > I personally use this for testing but it can be used to limit controller >> > > functionality without >> > > recompiling kernel. >> > >> > debugfs is ONLY for debugging, never rely on it being enabled, or >> > mounted, on a system in order to have any normal operation happen. >> > >> > So for testing, yes, this is fine. If this is going to be the normal >> > api/interface for how to control this driver, no, that is not acceptable >> > at all. >> >> It makes a lot of sense for end-user to toggle this... for example >> when he is lacking right cable for proper otg detection. As it is >> third driver offering this functionality, I believe we should stop >> treating it as debugging. > >At least renesas usb controller seems to have variables in sysfs: >drivers/phy/renesas/phy-rcar-gen3-usb2.c : functions role_show and >role_store. See also >Documentation/ABI/testing/sysfs-platform-phy-rcar-gen3-usb2 . > >I believe this driver should do same. > CDNS3 driver use the role framework and also has such variable defined in role switch framework. https://elixir.bootlin.com/linux/latest/source/drivers/usb/roles/class.c Regards, Pawel
RE: [PATCH 1/3] usb: common: Add usb_get_dr_mode_from_string and usb_dr_mode_to_string.
Hi Felipe, What about this patch. I just noticed that prefix is incorrect "1/3". Can it stay or should I send it again ? Cheers, Pawel >>>Pawel Laszczak writes: >>>>>> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h >>>>>> index 69f1b6328532..c156817672c4 100644 >>>>>> --- a/include/linux/usb/otg.h >>>>>> +++ b/include/linux/usb/otg.h >>>>>> @@ -129,4 +129,20 @@ enum usb_dr_mode { >>>>>> */ >>>>>> extern enum usb_dr_mode usb_get_dr_mode(struct device *dev); >>>>>> >>>>>> +/** >>>>>> + * usb_get_dr_mode_from_string - Convert string to dual role mode. >>>>>> + * @str: Pointer to the given string >>>>>> + * >>>>>> + * The function gets string and returns the correspondig enum >>>>>> usb_dr_mode. >>>>>> + */ >>>>>> +extern enum usb_dr_mode usb_get_dr_mode_from_string(const char *str); >>>>>> + >>>>>> +/** >>>>>> + * usb_dr_mode_to_string - Convert dual role mode to string. >>>>>> + * @dr_mode: Pointer to the given dual role mode >>>>>> + * >>>>>> + * The function gets enum usb_dr_mode, and returns the correspondig >>>>>> string. >>>>>> + */ >>>>>> +extern const char *usb_dr_mode_to_string(const enum usb_dr_mode >>>>>> dr_mode); >>>>>> + >>>>>> #endif /* __LINUX_USB_OTG_H */ >>>>> >>>>>Still missing the stubs I mentioned. Did you try compiling with and >>>>>without common enabled? >>>>> >>>> Sorry, I thought that I send answer yesterday but it's look like I >>>> prepared the answer but >>>> I forgot to send. >>>> >>>> In /drivers/usb/Kconfig we have: >>>> >>>> config USB >>>>tristate "Support for Host-side USB" >>>>depends on USB_ARCH_HAS_HCD >>>>select USB_COMMON >>>> >>>> and in /drivers/usb/gadget/Kconfig we have: >>>> >>>> menuconfig USB_GADGET >>>>tristate "USB Gadget Support" >>>>select USB_COMMON >>>> >>>> I think that it should cover all cases. >>>> >>>> Am I right ? >>> >>>Run a few tens of randconfig builds and see if you ever catch any >>>problem. I think randconfig can produce a defconfig where USB=n >>>USB_GADGET=n and USB_COMMON=y. >> >>Ok, I will test it, but I think that it should work. >>The same situation we have for example with: usb_otg_state_string or >>usb_ep_type_string. >> > >I've been testing it with USB=n USB_GADGET=n and USB_COMMON=y and also only >with CONFIG_USB_COMMON=y. >Also I've tested this patch with different default configuration together with >CDNS3 driver which use these functions. >I've test It mainly with x86 and arm architecture. >So far I've not found any issue. >
RE: [PATCH v9 2/6] usb:gadget Separated decoding functions from dwc3 driver.
Hi, > >Roger Quadros writes: > +extern const char *usb_decode_ctrl(char *str, size_t size, __u8 > bRequestType, > +__u8 bRequest, __u16 wValue, __u16 wIndex, > +__u16 wLength); > + where's the stub when !TRACING? >>> >>> Right, I will add >>> #ifdef CONFIG_TRACING >>> . >>> #endif >> >> Can usb_decode_ctrl() be used even when CONFIG_TRACING is not set? >> If yes then above #ifdefe is not sufficient. >> >> You might need to do something like >> >> #if defined(CONFIG_TRACING) >> >> extern const char *usb_decode_ctrl(..) >> >> #else >> >> static inline const char *usb_decode_ctrl(..) { >> return NULL; >> } >> >> #endif > >This is what I mean. They shouldn't be used outside of TRACING, but it's >far safer to have the stubs. usb-common-$(CONFIG_TRACING) += debug.o has been added in Makefile so we don't want to use this if CONFIG_TRACING is not set. I assume that with this approach this part is correct. Thanks Pawell > >-- >balbi
RE: [PATCH v10 0/6] Introduced new Cadence USBSS DRD Driver.
Hi Roger, > > >On 23/07/2019 07:32, Pawel Laszczak wrote: > >> Hi, > >> > >>> On Mon 2019-07-22 13:56:44, Pavel Machek wrote: > >>>> Hi! > >>>> > >>>>>>>> This patch introduce new Cadence USBSS DRD driver to linux kernel. > >>>>>>>> > >>>>>>>> The Cadence USBSS DRD Controller is a highly configurable IP Core which > >>>>>>>> can be instantiated as Dual-Role Device (DRD), Peripheral Only and > >>>>>>>> Host Only (XHCI)configurations. > >>>>>>> > >>>>>>> I see you are using debugfs to select between DRD, peripheral-onlyh and >>>>>>> XHCI... > >>>>>>> > >>>>>>> Is that good idea? > >>>>>> > >>>>>> Yes driver allows selecting dr_mode by debugfs. Controller also support >>>>>> such functionality > >>>>>> so I don't understand why would it not be a good idea. > >>>>>> > >>>>>> I personally use this for testing but it can be used to limit controller >>>>>> functionality without > >>>>>> recompiling kernel. > >>>>> > >>>>> debugfs is ONLY for debugging, never rely on it being enabled, or > >>>>> mounted, on a system in order to have any normal operation happen. > >>>>> > >>>>> So for testing, yes, this is fine. If this is going to be the normal > >>>>> api/interface for how to control this driver, no, that is not acceptable > >>>>> at all. > >>>> > >>>> It makes a lot of sense for end-user to toggle this... for example > >>>> when he is lacking right cable for proper otg detection. As it is > >>>> third driver offering this functionality, I believe we should stop > >>>> treating it as debugging. > >>> > >>> At least renesas usb controller seems to have variables in sysfs: > >>> drivers/phy/renesas/phy-rcar-gen3-usb2.c : functions role_show and > >>> role_store. See also > >>> Documentation/ABI/testing/sysfs-platform-phy-rcar-gen3-usb2 . > >>> > >>> I believe this driver should do same. > >>> > >> > >> CDNS3 driver use the role framework and also has such variable defined > >> in role switch framework. > >> > >> https://urldefense.proofpoint.com/v2/url?u=https- >3A__elixir.bootlin.com_linux_latest_source_drivers_usb_roles_class.c&d=DwICaQ&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ- >_haXqY&r=e1OgxfvkL0qo9XO6fX1gscva-w03uSYC1nIyxl89-rI&m=_jBsEOB3gtoQVvsVk8k2Pz8dp9zhzZbbL4M0tINJLR8&s=mq5ce-d4Td- >lc3OvcvektfSHhXPAL2Go2gWP-q9QwTY&e= > The meaning is little different. Role switch framework allow to changing role [ host -> device, device -> host ] The debugfs.c allows to limit dr_mode. > >Can we get rid of the debugfs interface for user initiated role change and just > >rely on role switch framework via sysfs? > > > >We do need user initiated role changes in production systems. So we can't > >rely on debugfs for this. But I assume that in production systems this will be disabled. cdns3-$(CONFIG_DEBUG_FS)+= debugfs.o I think that I understand your concerns. My idea was not to expand the supported dr_mode. Rather I wanted to have possibility to limit this (only for testing). Eg. If cdns->dr_mode = USB_DR_MODE_OTG then we can limit mode to HOST or DEVICE or DRD if cdns->dr_mode == USB_DR_MODE_HOST || cdns->dr_mode == USB_DR_MODE_PERIPHERAL) then driver can't change anything It allows me for testing some functionality using only single board and even with lacking right cable for proper otg detection. So, removing this can cause that testing some functionality will be limited on my boards. If you rely want to remove this, maybe we could do this after putting this driver to kernel ?. Maintaining this as my internal code before putting this driver to kernel will be problematic. Regards, Pawell
RE: [PATCH v9 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
Hi, > >Pawel Laszczak writes: >>>> +static int cdns3_gadget_start(struct cdns3 *cdns) >>>> +{ >>>> + struct cdns3_device *priv_dev; >>>> + u32 max_speed; >>>> + int ret; >>>> + >>>> + priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); >>>> + if (!priv_dev) >>>> + return -ENOMEM; >>>> + >>>> + cdns->gadget_dev = priv_dev; >>>> + priv_dev->sysdev = cdns->dev; >>>> + priv_dev->dev = cdns->dev; >>>> + priv_dev->regs = cdns->dev_regs; >>>> + >>>> + device_property_read_u16(priv_dev->dev, "cdns,on-chip-buff-size", >>>> + &priv_dev->onchip_buffers); >>>> + >>>> + if (priv_dev->onchip_buffers <= 0) { >>>> + u32 reg = readl(&priv_dev->regs->usb_cap2); >>>> + >>>> + priv_dev->onchip_buffers = USB_CAP2_ACTUAL_MEM_SIZE(reg); >>>> + } >>>> + >>>> + if (!priv_dev->onchip_buffers) >>>> + priv_dev->onchip_buffers = 256; >>>> + >>>> + max_speed = usb_get_maximum_speed(cdns->dev); >>>> + >>>> + /* Check the maximum_speed parameter */ >>>> + switch (max_speed) { >>>> + case USB_SPEED_FULL: >>>> + case USB_SPEED_HIGH: >>>> + case USB_SPEED_SUPER: >>>> + break; >>>> + default: >>>> + dev_err(cdns->dev, "invalid maximum_speed parameter %d\n", >>>> + max_speed); >>>> + /* fall through */ >>>> + case USB_SPEED_UNKNOWN: >>>> + /* default to superspeed */ >>>> + max_speed = USB_SPEED_SUPER; >>>> + break; >>>> + } >>>> + >>>> + /* fill gadget fields */ >>>> + priv_dev->gadget.max_speed = max_speed; >>>> + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; >>>> + priv_dev->gadget.ops = &cdns3_gadget_ops; >>>> + priv_dev->gadget.name = "usb-ss-gadget"; >>>> + priv_dev->gadget.sg_supported = 1; >>>> + >>>> + spin_lock_init(&priv_dev->lock); >>>> + INIT_WORK(&priv_dev->pending_status_wq, >>>> +cdns3_pending_setup_status_handler); >>>> + >>>> + /* initialize endpoint container */ >>>> + INIT_LIST_HEAD(&priv_dev->gadget.ep_list); >>>> + INIT_LIST_HEAD(&priv_dev->aligned_buf_list); >>>> + >>>> + ret = cdns3_init_eps(priv_dev); >>>> + if (ret) { >>>> + dev_err(priv_dev->dev, "Failed to create endpoints\n"); >>>> + goto err1; >>>> + } >>>> + >>>> + /* allocate memory for setup packet buffer */ >>>> + priv_dev->setup_buf = dma_alloc_coherent(priv_dev->sysdev, 8, >>>> + &priv_dev->setup_dma, GFP_DMA); >>>> + if (!priv_dev->setup_buf) { >>>> + ret = -ENOMEM; >>>> + goto err2; >>>> + } >>>> + >>>> + priv_dev->dev_ver = readl(&priv_dev->regs->usb_cap6); >>>> + >>>> + dev_dbg(priv_dev->dev, "Device Controller version: %08x\n", >>>> + readl(&priv_dev->regs->usb_cap6)); >>>> + dev_dbg(priv_dev->dev, "USB Capabilities:: %08x\n", >>>> + readl(&priv_dev->regs->usb_cap1)); >>>> + dev_dbg(priv_dev->dev, "On-Chip memory cnfiguration: %08x\n", >>>> + readl(&priv_dev->regs->usb_cap2)); >>>> + >>>> + priv_dev->dev_ver = GET_DEV_BASE_VERSION(priv_dev->dev_ver); >>>> + >>>> + priv_dev->zlp_buf = kzalloc(CDNS3_EP_ZLP_BUF_SIZE, GFP_KERNEL); >>>> + if (!priv_dev->zlp_buf) { >>>> + ret = -ENOMEM; >>>> + goto err3; >>>> + } >>>> + >>>> + /* add USB gadget device */ >>>> + ret = usb_add_gadget_udc(priv_dev->dev, &priv_dev->gadget); >>>> + if (ret < 0) { >>>> + dev_err(priv_dev->dev, >>>> + "Failed to register USB device controller\n"); >>>> + goto err4; >>>> + } >>>
RE: [PATCH v10 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
Hi, > >On 21/07/2019 21:32, Pawel Laszczak wrote: >> This patch introduce new Cadence USBSS DRD driver to Linux kernel. >> >> The Cadence USBSS DRD Controller is a highly configurable IP Core which >> can be instantiated as Dual-Role Device (DRD), Peripheral Only and >> Host Only (XHCI)configurations. >> >> The current driver has been validated with FPGA platform. We have >> support for PCIe bus, which is used on FPGA prototyping. >> >> The host side of USBSS-DRD controller is compliant with XHCI >> specification, so it works with standard XHCI Linux driver. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/Kconfig|2 + >> drivers/usb/Makefile |2 + >> drivers/usb/cdns3/Kconfig | 46 + >> drivers/usb/cdns3/Makefile | 17 + >> drivers/usb/cdns3/cdns3-pci-wrap.c | 203 +++ >> drivers/usb/cdns3/core.c | 554 +++ >> drivers/usb/cdns3/core.h | 109 ++ >> drivers/usb/cdns3/debug.h | 171 ++ >> drivers/usb/cdns3/debugfs.c| 87 ++ >> drivers/usb/cdns3/drd.c| 390 + >> drivers/usb/cdns3/drd.h| 166 ++ >> drivers/usb/cdns3/ep0.c| 914 +++ >> drivers/usb/cdns3/gadget-export.h | 28 + >> drivers/usb/cdns3/gadget.c | 2338 >> drivers/usb/cdns3/gadget.h | 1321 >> drivers/usb/cdns3/host-export.h| 28 + >> drivers/usb/cdns3/host.c | 71 + >> drivers/usb/cdns3/trace.c | 11 + >> drivers/usb/cdns3/trace.h | 493 ++ >> 19 files changed, 6951 insertions(+) >> create mode 100644 drivers/usb/cdns3/Kconfig >> create mode 100644 drivers/usb/cdns3/Makefile >> create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c >> create mode 100644 drivers/usb/cdns3/core.c >> create mode 100644 drivers/usb/cdns3/core.h >> create mode 100644 drivers/usb/cdns3/debug.h >> create mode 100644 drivers/usb/cdns3/debugfs.c >> create mode 100644 drivers/usb/cdns3/drd.c >> create mode 100644 drivers/usb/cdns3/drd.h >> create mode 100644 drivers/usb/cdns3/ep0.c >> create mode 100644 drivers/usb/cdns3/gadget-export.h >> create mode 100644 drivers/usb/cdns3/gadget.c >> create mode 100644 drivers/usb/cdns3/gadget.h >> create mode 100644 drivers/usb/cdns3/host-export.h >> create mode 100644 drivers/usb/cdns3/host.c >> create mode 100644 drivers/usb/cdns3/trace.c >> create mode 100644 drivers/usb/cdns3/trace.h >> >> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig >> index e4b27413f528..c2e78882f8c2 100644 >> --- a/drivers/usb/Kconfig >> +++ b/drivers/usb/Kconfig >> @@ -113,6 +113,8 @@ source "drivers/usb/usbip/Kconfig" >> >> endif >> >> +source "drivers/usb/cdns3/Kconfig" >> + >> source "drivers/usb/mtu3/Kconfig" >> >> source "drivers/usb/musb/Kconfig" >> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile >> index 7d1b8c82b208..ab125b966cac 100644 >> --- a/drivers/usb/Makefile >> +++ b/drivers/usb/Makefile >> @@ -12,6 +12,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/ >> obj-$(CONFIG_USB_DWC2) += dwc2/ >> obj-$(CONFIG_USB_ISP1760) += isp1760/ >> >> +obj-$(CONFIG_USB_CDNS3) += cdns3/ >> + >> obj-$(CONFIG_USB_MON) += mon/ >> obj-$(CONFIG_USB_MTU3) += mtu3/ >> >> diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig >> new file mode 100644 >> index ..d0331613a355 >> --- /dev/null >> +++ b/drivers/usb/cdns3/Kconfig >> @@ -0,0 +1,46 @@ >> +config USB_CDNS3 >> +tristate "Cadence USB3 Dual-Role Controller" >> +depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA >> +select USB_XHCI_PLATFORM if USB_XHCI_HCD >> +select USB_ROLE_SWITCH >> +help >> + Say Y here if your system has a Cadence USB3 dual-role controller. >> + It supports: dual-role switch, Host-only, and Peripheral-only. >> + >> + If you choose to build this driver is a dynamically linked >> + as module, the module will be called cdns3.ko. >> + >> +if USB_CDNS3 >> + >> +config USB_CDNS3_GADGET >> +bool "Cadence USB3 device controller" >> +depends on USB_GADGET=y || USB_GADGET=USB_CDNS3 >> +help >> + Say Y here to enable device controller functionality of the >> +
RE: [PATCH v9 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
> >> >> Yes, driver frees not used buffers here. >> I think that it's the safest place for this purpose. >> >> > >> + dma_free_coherent(priv_dev->sysdev, buf- >> >size, >> + buf->buf, >> + buf->dma); >> + spin_lock_irqsave(&priv_dev->lock, >> flags); >> + >> + kfree(buf); >> >>> >> >>>why do you even need this "garbage collector"? >> >> >> >> I need to free not used memory. The once allocated buffer will be >> >> associated with request, but if request.length will be increased in >> >> usb_request then driver will must allocate the bigger buffer. As I >> >> remember I couldn't call dma_free_coherent in interrupt context so I >> >> had to move it to thread handled. This flag was used to avoid going >> >> through >> whole aligned_buf_list every time. >> >> In most cases this part will never called int this place >> > >> >Did you try, btw, setting the quirk flag which tells gadget drivers to >> >always allocate buffers aligned to MaxPacketSize? Wouldn't that be enough? >> >> If found only quirk_ep_out_aligned_size flag, but it align only buffer size. >> >> DMA used by this controller must have buffer address aligned to 8. >> I think that on most architecture kmalloc should guarantee such aligned. >> The problem was detected on NXP testing board. >> On my board all buffer address are alignment at least to 8. >> > >This un-aligned request buffer address for 8 occurs for Ethernet Gadget (eg, >NCM), >it allocates socket buffer with NET_IP_ALIGN, so the last byte of buffer >address >is always 2. Although this can be workaround by setting >quirk_avoids_skb_reserve, >but we are not sure if all gadget request buffers can be 8 or Max Packet Size >aligned. > Thanks Peter for explanation. I will add quirk_avoids_skb_reserve to avoid using this extra buffers, but I leave this code for safety. -- Cheers, Pawell
RE: [PATCH v9 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
Hi, > >Hi, > >Pawel Laszczak writes: > >> Hi, >> >>> >>>Pawel Laszczak writes: >>>>>> +static int cdns3_gadget_start(struct cdns3 *cdns) >>>>>> +{ >>>>>> +struct cdns3_device *priv_dev; >>>>>> +u32 max_speed; >>>>>> +int ret; >>>>>> + >>>>>> +priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); >>>>>> +if (!priv_dev) >>>>>> +return -ENOMEM; >>>>>> + >>>>>> +cdns->gadget_dev = priv_dev; >>>>>> +priv_dev->sysdev = cdns->dev; >>>>>> +priv_dev->dev = cdns->dev; >>>>>> +priv_dev->regs = cdns->dev_regs; >>>>>> + >>>>>> +device_property_read_u16(priv_dev->dev, >>>>>> "cdns,on-chip-buff-size", >>>>>> + &priv_dev->onchip_buffers); >>>>>> + >>>>>> +if (priv_dev->onchip_buffers <= 0) { >>>>>> +u32 reg = readl(&priv_dev->regs->usb_cap2); >>>>>> + >>>>>> +priv_dev->onchip_buffers = >>>>>> USB_CAP2_ACTUAL_MEM_SIZE(reg); >>>>>> +} >>>>>> + >>>>>> +if (!priv_dev->onchip_buffers) >>>>>> +priv_dev->onchip_buffers = 256; >>>>>> + >>>>>> +max_speed = usb_get_maximum_speed(cdns->dev); >>>>>> + >>>>>> +/* Check the maximum_speed parameter */ >>>>>> +switch (max_speed) { >>>>>> +case USB_SPEED_FULL: >>>>>> +case USB_SPEED_HIGH: >>>>>> +case USB_SPEED_SUPER: >>>>>> +break; >>>>>> +default: >>>>>> +dev_err(cdns->dev, "invalid maximum_speed parameter >>>>>> %d\n", >>>>>> +max_speed); >>>>>> +/* fall through */ >>>>>> +case USB_SPEED_UNKNOWN: >>>>>> +/* default to superspeed */ >>>>>> +max_speed = USB_SPEED_SUPER; >>>>>> +break; >>>>>> +} >>>>>> + >>>>>> +/* fill gadget fields */ >>>>>> +priv_dev->gadget.max_speed = max_speed; >>>>>> +priv_dev->gadget.speed = USB_SPEED_UNKNOWN; >>>>>> +priv_dev->gadget.ops = &cdns3_gadget_ops; >>>>>> +priv_dev->gadget.name = "usb-ss-gadget"; >>>>>> +priv_dev->gadget.sg_supported = 1; >>>>>> + >>>>>> +spin_lock_init(&priv_dev->lock); >>>>>> +INIT_WORK(&priv_dev->pending_status_wq, >>>>>> + cdns3_pending_setup_status_handler); >>>>>> + >>>>>> +/* initialize endpoint container */ >>>>>> +INIT_LIST_HEAD(&priv_dev->gadget.ep_list); >>>>>> +INIT_LIST_HEAD(&priv_dev->aligned_buf_list); >>>>>> + >>>>>> +ret = cdns3_init_eps(priv_dev); >>>>>> +if (ret) { >>>>>> +dev_err(priv_dev->dev, "Failed to create endpoints\n"); >>>>>> +goto err1; >>>>>> +} >>>>>> + >>>>>> +/* allocate memory for setup packet buffer */ >>>>>> +priv_dev->setup_buf = dma_alloc_coherent(priv_dev->sysdev, 8, >>>>>> + &priv_dev->setup_dma, >>>>>> GFP_DMA); >>>>>> +if (!priv_dev->setup_buf) { >>>>>> +ret = -ENOMEM; >>>>>> +goto err2; >>>>>> +} >>>>>> + >>>>>> +priv_dev->dev_ver = readl(&priv_dev->regs->usb_cap6); >>>>>> + >>>>>> +dev_dbg(priv_dev->dev, "Device Controller version: %08x\n", >&
RE: [PATCH v9 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
Hi, > >Pawel Laszczak writes: >>>> I have such situation in which one interrupt line is shared with ehci and >>>> cdns3 driver. >>>> In such case this function returns error code. >>> >>>which function returns error code? >> >> devm_request_threaded_irq, of course if I set IRQF_SHARED | IRQF_ONESHOT. >> As I remember it was EBUSY error. > >oh, right. That's probably because the handlers must agree on IRQ flags. > >>>> So probably I will need to mask only the reported interrupts. >>> >>>you should mask all interrupts from your device, otherwise you top-halt >>>may still end up reentrant. >>> >>>> I can't mask all interrupt using controller register because I can miss >>>> some of them. >>> >>>why would you miss them? They would be left in the register until you >>>unmask them and the line is raised again. >> >> I consult this with author of controller. >> We have: >> USB_IEN and USB_ISTS for generic interrupts >> EP_IEN and EP_ISTS for endpoint interrupts >> >> Both these group works different. >> For endpoint I can disable all interrupt and I don't miss any of them. >> So it's normal behavior. >> >> But USB_ISTS work little different. If we mask all interrupt in USB_IEN >> then when new event occurs the EP_ISTS will not be updated. > >wait a minute. When you mask USB_ISTS, then EP_ISTS isn't updated? Is >this a quirk on the controller or a design choice? > >> It's not standard and not expected behavior but it works in this way. > >Yeah, sounds rather odd. > Oh no. My mistake. Of course I mean USB_ISTS. If we mask all interrupt in USB_IEN then when new event occurs the USB_ISTS will not be updated. >>>>>>>> + /* check USB device interrupt */ >>>>>>>> + reg = readl(&priv_dev->regs->usb_ists); >>>>>>>> + >>>>>>>> + if (reg) { >>>>>>>> + writel(reg, &priv_dev->regs->usb_ists); >>>>>>>> + cdns3_check_usb_interrupt_proceed(priv_dev, reg); >>>>>>>> + ret = IRQ_HANDLED; >>>>>>> >>>>>>>now, because you _don't_ mask this interrupt, you're gonna have >>>>>>>issues. Say we actually get both device and endpoint interrupts while >>>>>>>the thread is already running with previous endpoint interrupts. Now >>>>>>>we're gonna reenter the top half, because device interrupts are *not* >>>>>>>masked, which will read usb_ists and handle it here. >>>>>> >>>>>> Endpoint interrupts are masked in cdns3_device_irq_handler and stay >>>>>> masked >>>>>> until they are not handled in threaded handler. >>>>> >>>>>Quick question, then: these ISTS registers, are they masked interrupt >>>>>status or raw interrupt status? >>>> >>>> Yes it's masked, but after masking them the new interrupts will not be >>>> reported >>>> In ISTS registers. Form this reason I can mask only reported interrupt. >>> >>>and what happens when you unmask the registers? Do they get reported? >> >> No they are not reported in case of USB_ISTS register. >> They should be reported in case EP_ISTS, but I need to test it. > >okay, please _do_ test and verify the behavior. The description above >sounds really surprising to me. Does it really mean that if you mask all >USB_ISTS and then disconnect the cable while interrupt is masked, you >won't know cable was disconnected? Yes, exactly. Initially I've tested it and it's work correct. I can even simply write 0 to EP_IEN in hard irq and ~0 in thread handler. It's simplest and sufficient way. > >>>>>>>> + struct cdns3_aligned_buf *buf, *tmp; >>>>>>>> + >>>>>>>> + list_for_each_entry_safe(buf, tmp, >>>>>>>> &priv_dev->aligned_buf_list, >>>>>>>> + list) { >>>>>>>> + if (!buf->in_use) { >>>>>>>> + list_del(&buf->list); >>>>>>>> + >>>>>>>> + spin_unlock_irqrestore(&priv_dev->lock, >>>>>>
RE: [PATCH v10 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
Hi, > >On 11/08/2019 14:59, Pawel Laszczak wrote: >> Hi, >> >>> >>> On 21/07/2019 21:32, Pawel Laszczak wrote: >>>> This patch introduce new Cadence USBSS DRD driver to Linux kernel. >>>> >>>> The Cadence USBSS DRD Controller is a highly configurable IP Core which >>>> can be instantiated as Dual-Role Device (DRD), Peripheral Only and >>>> Host Only (XHCI)configurations. >>>> >>>> The current driver has been validated with FPGA platform. We have >>>> support for PCIe bus, which is used on FPGA prototyping. >>>> >>>> The host side of USBSS-DRD controller is compliant with XHCI >>>> specification, so it works with standard XHCI Linux driver. >>>> >>>> Signed-off-by: Pawel Laszczak >>>> --- >>>> drivers/usb/Kconfig|2 + >>>> drivers/usb/Makefile |2 + >>>> drivers/usb/cdns3/Kconfig | 46 + >>>> drivers/usb/cdns3/Makefile | 17 + >>>> drivers/usb/cdns3/cdns3-pci-wrap.c | 203 +++ >>>> drivers/usb/cdns3/core.c | 554 +++ >>>> drivers/usb/cdns3/core.h | 109 ++ >>>> drivers/usb/cdns3/debug.h | 171 ++ >>>> drivers/usb/cdns3/debugfs.c| 87 ++ >>>> drivers/usb/cdns3/drd.c| 390 + >>>> drivers/usb/cdns3/drd.h| 166 ++ >>>> drivers/usb/cdns3/ep0.c| 914 +++ >>>> drivers/usb/cdns3/gadget-export.h | 28 + >>>> drivers/usb/cdns3/gadget.c | 2338 >>>> drivers/usb/cdns3/gadget.h | 1321 >>>> drivers/usb/cdns3/host-export.h| 28 + >>>> drivers/usb/cdns3/host.c | 71 + >>>> drivers/usb/cdns3/trace.c | 11 + >>>> drivers/usb/cdns3/trace.h | 493 ++ >>>> 19 files changed, 6951 insertions(+) >>>> create mode 100644 drivers/usb/cdns3/Kconfig >>>> create mode 100644 drivers/usb/cdns3/Makefile >>>> create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c >>>> create mode 100644 drivers/usb/cdns3/core.c >>>> create mode 100644 drivers/usb/cdns3/core.h >>>> create mode 100644 drivers/usb/cdns3/debug.h >>>> create mode 100644 drivers/usb/cdns3/debugfs.c >>>> create mode 100644 drivers/usb/cdns3/drd.c >>>> create mode 100644 drivers/usb/cdns3/drd.h >>>> create mode 100644 drivers/usb/cdns3/ep0.c >>>> create mode 100644 drivers/usb/cdns3/gadget-export.h >>>> create mode 100644 drivers/usb/cdns3/gadget.c >>>> create mode 100644 drivers/usb/cdns3/gadget.h >>>> create mode 100644 drivers/usb/cdns3/host-export.h >>>> create mode 100644 drivers/usb/cdns3/host.c >>>> create mode 100644 drivers/usb/cdns3/trace.c >>>> create mode 100644 drivers/usb/cdns3/trace.h >>>> >>>> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig >>>> index e4b27413f528..c2e78882f8c2 100644 >>>> --- a/drivers/usb/Kconfig >>>> +++ b/drivers/usb/Kconfig >>>> @@ -113,6 +113,8 @@ source "drivers/usb/usbip/Kconfig" >>>> >>>> endif >>>> >>>> + real_role = cdsn3_real_role_switch_get(cdns->dev); >>>> + >>>> + current_role = role; >>>> + dev_dbg(cdns->dev, "Switching role"); >>>> + >>>> + ret = cdns3_role_start(cdns, real_role); >>>> + if (ret) { >>>> + /* Back to current role */ >>>> + dev_err(cdns->dev, "set %d has failed, back to %d\n", >>>> + role, current_role); >>>> + ret = cdns3_role_start(cdns, current_role); >>>> + if (ret) >>>> + dev_err(cdns->dev, "back to %d failed too\n", >>>> + current_role); >>>> + } >>>> +exit: >>>> + pm_runtime_put_sync(cdns->dev); >>>> + return ret; >>>> +} >>>> + >>>> +static const struct usb_role_switch_desc cdns3_switch_desc = { >>>> + .set = cdns3_role_switch_set, >>>> + .get = cdsn3_real_role_switch_get, >>>> + .allow_userspace_control = true, >>> >>> how does user initiated cdns3_role_switch_set() via sysfs co-exist with role >>> change
RE: [PATCH v9 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
> >Hi, > >Pawel Laszczak writes: >>>>>>>Quick question, then: these ISTS registers, are they masked interrupt >>>>>>>status or raw interrupt status? >>>>>> >>>>>> Yes it's masked, but after masking them the new interrupts will not be >>>>>> reported >>>>>> In ISTS registers. Form this reason I can mask only reported interrupt. >>>>> >>>>>and what happens when you unmask the registers? Do they get reported? >>>> >>>> No they are not reported in case of USB_ISTS register. >>>> They should be reported in case EP_ISTS, but I need to test it. >>> >>>okay, please _do_ test and verify the behavior. The description above >>>sounds really surprising to me. Does it really mean that if you mask all >>>USB_ISTS and then disconnect the cable while interrupt is masked, you >>>won't know cable was disconnected? >> >> Yes, exactly. >> >> Initially I've tested it and it's work correct. >> I can even simply write 0 to EP_IEN in hard irq and ~0 in thread handler. >> It's simplest and sufficient way. > >okay. Just to be sure I understand correctly. If you mask USB_IEN, then >we would miss a cable disconnect event. Right? > >>>>>>>>>> +struct cdns3_aligned_buf *buf, *tmp; >>>>>>>>>> + >>>>>>>>>> +list_for_each_entry_safe(buf, tmp, >>>>>>>>>> &priv_dev->aligned_buf_list, >>>>>>>>>> + list) { >>>>>>>>>> +if (!buf->in_use) { >>>>>>>>>> +list_del(&buf->list); >>>>>>>>>> + >>>>>>>>>> +spin_unlock_irqrestore(&priv_dev->lock, >>>>>>>>>> flags); >>>>>>>>> >>>>>>>>>creates the possibility of a race condition >>>>>>>> Why? In this place the buf can't be used. >>>>>>> >>>>>>>but you're reenabling interrupts, right? >>>>>> >>>>>> Yes, driver frees not used buffers here. >>>>>> I think that it's the safest place for this purpose. >>>>> >>>>>I guess you missed the point a little. Since you reenable interrupts >>>>>just to free the buffer, you end up creating the possibility for a race >>>>>condition. Specially since you don't mask all interrupt events. The >>>>>moment you reenable interrupts, one of your not-unmasked interrupt >>>>>sources could trigger, then top-half gets scheduled which tries to wake >>>>>up the IRQ thread again and things go boom. >>>> >>>> Ok, I think I understand. So I have 3 options: >>>> 1. Mask the USB_IEN and EP_IEN interrupts, but then I can lost some >>>> USB_ISTS >>>> events. It's dangerous options. >>> >>>sure sounds dangerous, but also sounds quite "peculiar" :-) >>> >>>> 2. Remove implementation of handling unaligned buffers and assume that >>>> upper layer will worry about this. What with vendor specific drivers >>>> that >>>> can be used by companies and not upstreamed ? >>>> It could be good to have such safety mechanism even if it is not >>>> currently used. >>> >>>dunno. It may become dead code that's NEVER used :-) >>> >>>> 3. Delegate this part of code for instance to separate thread that will be >>>> called >>>>In free time. >>> >>>Yet another thread? Can't you just run this right before giving back the >>>USB request? So, don't do it from IRQ handler, but from giveback path? >> >> Do you mean in: >> if (request->complete) { >> spin_unlock(&priv_dev->lock); >> if (priv_dev->run_garbage_collector) { >> >> } >> usb_gadget_giveback_request(&priv_ep->endpoint, >> request); >> spin_lock(&priv_dev->lock); >> } >> ?? > >right, you can do it right before giving back the request. Or right >after. > >> I as
RE: [PATCH v10 5/6] usb:cdns3 Add Cadence USB3 DRD Driver
> >On 11/08/2019 14:59, Pawel Laszczak wrote: >> Hi, >> >>> >>> On 21/07/2019 21:32, Pawel Laszczak wrote: >>>> This patch introduce new Cadence USBSS DRD driver to Linux kernel. >>>> >>>> The Cadence USBSS DRD Controller is a highly configurable IP Core which >>>> can be instantiated as Dual-Role Device (DRD), Peripheral Only and >>>> Host Only (XHCI)configurations. >>>> >>>> The current driver has been validated with FPGA platform. We have >>>> support for PCIe bus, which is used on FPGA prototyping. >>>> >>>> The host side of USBSS-DRD controller is compliant with XHCI >>>> specification, so it works with standard XHCI Linux driver. >>>> >>>> Signed-off-by: Pawel Laszczak >>>> --- >>>> drivers/usb/Kconfig|2 + >>>> drivers/usb/Makefile |2 + >>>> drivers/usb/cdns3/Kconfig | 46 + >>>> drivers/usb/cdns3/Makefile | 17 + >>>> drivers/usb/cdns3/cdns3-pci-wrap.c | 203 +++ >>>> drivers/usb/cdns3/core.c | 554 +++ >>>> drivers/usb/cdns3/core.h | 109 ++ >>>> drivers/usb/cdns3/debug.h | 171 ++ >>>> drivers/usb/cdns3/debugfs.c| 87 ++ >>>> drivers/usb/cdns3/drd.c| 390 + >>>> drivers/usb/cdns3/drd.h| 166 ++ >>>> drivers/usb/cdns3/ep0.c| 914 +++ >>>> drivers/usb/cdns3/gadget-export.h | 28 + >>>> drivers/usb/cdns3/gadget.c | 2338 >>>> drivers/usb/cdns3/gadget.h | 1321 >>>> drivers/usb/cdns3/host-export.h| 28 + >>>> drivers/usb/cdns3/host.c | 71 + >>>> drivers/usb/cdns3/trace.c | 11 + >>>> drivers/usb/cdns3/trace.h | 493 ++ >>>> 19 files changed, 6951 insertions(+) >>>> create mode 100644 drivers/usb/cdns3/Kconfig >>>> create mode 100644 drivers/usb/cdns3/Makefile >>>> create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c >>>> create mode 100644 drivers/usb/cdns3/core.c >>>> create mode 100644 drivers/usb/cdns3/core.h >>>> create mode 100644 drivers/usb/cdns3/debug.h >>>> create mode 100644 drivers/usb/cdns3/debugfs.c >>>> create mode 100644 drivers/usb/cdns3/drd.c >>>> create mode 100644 drivers/usb/cdns3/drd.h >>>> create mode 100644 drivers/usb/cdns3/ep0.c >>>> create mode 100644 drivers/usb/cdns3/gadget-export.h >>>> create mode 100644 drivers/usb/cdns3/gadget.c >>>> create mode 100644 drivers/usb/cdns3/gadget.h >>>> create mode 100644 drivers/usb/cdns3/host-export.h >>>> create mode 100644 drivers/usb/cdns3/host.c >>>> create mode 100644 drivers/usb/cdns3/trace.c >>>> create mode 100644 drivers/usb/cdns3/trace.h >>>> > > > >>> >>>> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c >>>> new file mode 100644 >>>> index ..291f08be56fe >>>> --- /dev/null >>>> +++ b/drivers/usb/cdns3/gadget.c >>>> @@ -0,0 +1,2338 @@ >>>> +// SPDX-License-Identifier: GPL-2.0 >>>> +/* >>>> + * Cadence USBSS DRD Driver - gadget side. >>>> + * >>>> + * Copyright (C) 2018-2019 Cadence Design Systems. >>>> + * Copyright (C) 2017-2018 NXP >>>> + * >>>> + * Authors: Pawel Jez , >>>> + * Pawel Laszczak >>>> + * Peter Chen >>>> + */ >>>> + >>> >>> >>> >>>> +/** >>>> + * cdns3_device_irq_handler- interrupt handler for device part of >>>> controller >>>> + * >>>> + * @irq: irq number for cdns3 core device >>>> + * @data: structure of cdns3 >>>> + * >>>> + * Returns IRQ_HANDLED or IRQ_NONE >>>> + */ >>>> +static irqreturn_t cdns3_device_irq_handler(int irq, void *data) >>>> +{ >>>> + struct cdns3_device *priv_dev; >>>> + struct cdns3 *cdns = data; >>>> + irqreturn_t ret = IRQ_NONE; >>>> + unsigned long flags; >>>> + u32 reg; >>>> + >>>> + priv_dev = cdns->gadget_dev; >>>> + spin_lock_irqsave(&priv_dev->lock, flags); >>>> + >>>> + /
RE: [PATCH 02/31] usb: usbssp: Added some decoding functions.
HI, All Please stop review of this series. It's a pity of your time. Probably the design of USBSSP device controller will be significantly changed and simplified, so I will have to create new driver. The planed change include: - simplification and change registers map - removing command queue - simplification in input/output endpoint context - and other. It was not my decision. Thanks for all your comments. I will take them into account in new driver. Cheers, Pawell >On Tue, Sep 11, 2018 at 08:48:43AM +0300, Felipe Balbi wrote: >> >> Hi, >> >> Greg Kroah-Hartman writes: >> > On Thu, Jul 19, 2018 at 06:57:35PM +0100, Pawel Laszczak wrote: >> >> This patch add additional functions that converts some fields to string. >> >> >> >> For example function usbssp_trb_comp_code_string take completion >> >> code value and return string describing completion code. >> >> >> >> Signed-off-by: Pawel Laszczak >> >> --- >> >> drivers/usb/usbssp/gadget.h | 580 >> >> 1 file changed, 580 insertions(+) >> >> >> >> diff --git a/drivers/usb/usbssp/gadget.h b/drivers/usb/usbssp/gadget.h >> >> index 49e7271187cc..b5c17603af78 100644 >> >> --- a/drivers/usb/usbssp/gadget.h >> >> +++ b/drivers/usb/usbssp/gadget.h >> >> @@ -930,6 +930,73 @@ struct usbssp_transfer_event { >> >> #define COMP_UNDEFINED_ERROR 33 >> >> #define COMP_INVALID_STREAM_ID_ERROR 34 >> >> >> >> +static inline const char *usbssp_trb_comp_code_string(u8 status) >> > >> > >> > >> > >> > You have _giant_ inline functions here, why? >> > >> > Please just put this all in a .c file and let the linker properly handle >> > things. You do not want to duplicate all of these crazy strings all >> > over the place where ever you call these functions. >> > >> > And I am guessing this is only for some sort of "debugging" mode? If >> > so, shouldn't there be a way to not even build this in? Some systems >> > are very space constrained... >> >> many of them seem to be a straight copy from xhci. > >Which doesn't mean it's a great model to copy :) > >Let's learn from our past mistakes, having had to try to slim down a >kernel for a limited memory system is a chore that no one should have to >manually hack up the source tree just to accomplish it. > >thanks, > >greg k-h
[RFC PATCH v1 12/14] usb:cdns3: Adds transfer related function.
Patch implements a set of function handling transfer on none-default endpoints. For handling transfer controller use cdns3_trb structure. Each transfer request block (TRB) contains data buffer address, length and some control bits. Each transfer can consist of many trbs. Such group of trbs is called transfer descriptors (TD). Each endpoint has own array of trbs that make up a transfer ring. The last element on ring is reserved and is set as Link TRB that point to the first TRB. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/gadget.c | 235 - 1 file changed, 233 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index e5c4d9236f07..905cad1a8229 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -229,6 +229,45 @@ void cdns3_gadget_unconfig(struct cdns3_device *priv_dev) priv_dev->out_mem_is_allocated = 0; } +/** + * cdns3_ep_inc_trb - increment a trb index. + * @index: Pointer to the TRB index to increment. + * @cs: Cycle state + * + * The index should never point to the link TRB. After incrementing, + * if it is point to the link TRB, wrap around to the beginning and revert + * cycle state bit The + * link TRB is always at the last TRB entry. + */ +static void cdns3_ep_inc_trb(int *index, u8 *cs) +{ + (*index)++; + if (*index == (TRBS_PER_SEGMENT - 1)) { + *index = 0; + *cs ^= 1; + } +} + +/** + * cdns3_ep_inc_enq - increment endpoint's enqueue pointer + * @priv_ep: The endpoint whose enqueue pointer we're incrementing + */ +static void cdns3_ep_inc_enq(struct cdns3_endpoint *priv_ep) +{ + priv_ep->free_trbs--; + cdns3_ep_inc_trb(&priv_ep->enqueue, &priv_ep->pcs); +} + +/** + * cdns3_ep_inc_deq - increment endpoint's dequeue pointer + * @priv_ep: The endpoint whose dequeue pointer we're incrementing + */ +static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep) +{ + priv_ep->free_trbs++; + cdns3_ep_inc_trb(&priv_ep->dequeue, &priv_ep->ccs); +} + void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable) { if (enable) @@ -268,7 +307,27 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, struct cdns3_request *priv_req, int status) { - //TODO: Implements this function. + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct usb_request *request = &priv_req->request; + + list_del_init(&request->list); + if (request->status == -EINPROGRESS) + request->status = status; + + usb_gadget_unmap_request_by_dev(priv_dev->sysdev, request, + priv_ep->dir); + + priv_req->on_ring = 0; + + if (request->complete) { + spin_unlock(&priv_dev->lock); + usb_gadget_giveback_request(&priv_ep->endpoint, + request); + spin_lock(&priv_dev->lock); + } + + if (request->buf == priv_dev->zlp_buf) + cdns3_gadget_ep_free_request(&priv_ep->endpoint, request); } /** @@ -280,13 +339,185 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, struct usb_request *request) { + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_request *priv_req; + struct cdns3_trb *trb; + dma_addr_t trb_dma; + int sg_iter = 0; + u32 first_pcs; + int num_trb; + int address; + int pcs; + + if (!request) + return -EINVAL; + + num_trb = request->num_sgs ? request->num_sgs : 1; + + if (num_trb > priv_ep->free_trbs) + return -EINVAL; + + priv_req = to_cdns3_request(request); + address = priv_ep->endpoint.desc->bEndpointAddress; + + if (priv_req->on_ring) + goto arm; + + priv_ep->flags |= EP_PENDING_REQUEST; + trb_dma = request->dma; + + /* must allocate buffer aligned to 8 */ + if ((request->dma % ADDR_MODULO_8)) { + if (request->length <= CDNS3_UNALIGNED_BUF_SIZE) { + memcpy(priv_ep->aligned_buff, request->buf, + request->length); + trb_dma = priv_ep->aligned_dma_addr; + } else { + return -ENOMEM; + } + } + + trb = priv_ep->trb_pool + priv_ep->enqueue; + priv_req->trb = trb; + priv_req->start_trb = priv_ep->enqueue; + + //prepare ring + if ((priv_ep->enqueue + num_trb) >= (TRBS_PER_SEGMENT - 1)) { + /*updating C bt in Link TRB bef
[RFC PATCH v1 13/14] usb:cdns3: Adds debugging function.
Patch implements some function used for debugging driver. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Makefile | 2 +- drivers/usb/cdns3/debug.c | 128 + drivers/usb/cdns3/ep0.c| 3 + drivers/usb/cdns3/gadget.c | 12 drivers/usb/cdns3/gadget.h | 13 +++- 5 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 drivers/usb/cdns3/debug.c diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index f4cfc978626f..34e60d03c4ec 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -2,6 +2,6 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o cdns3-y:= core.o drd.o -cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o debug.o cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/debug.c b/drivers/usb/cdns3/debug.c new file mode 100644 index ..bebf22c4d18e --- /dev/null +++ b/drivers/usb/cdns3/debug.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include "gadget.h" + +static inline char *cdns3_decode_ep_irq(u32 ep_sts, const char *ep_name) +{ + static char str[256]; + int ret; + + ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts); + + if (ep_sts & EP_STS_SETUP) + ret += sprintf(str + ret, "SETUP "); + if (ep_sts & EP_STS_IOC) + ret += sprintf(str + ret, "IOC "); + if (ep_sts & EP_STS_ISP) + ret += sprintf(str + ret, "ISP "); + if (ep_sts & EP_STS_DESCMIS) + ret += sprintf(str + ret, "DESCMIS "); + if (ep_sts & EP_STS_STREAMR) + ret += sprintf(str + ret, "STREAMR "); + if (ep_sts & EP_STS_MD_EXIT) + ret += sprintf(str + ret, "MD_EXIT "); + if (ep_sts & EP_STS_TRBERR) + ret += sprintf(str + ret, "TRBERR "); + if (ep_sts & EP_STS_NRDY) + ret += sprintf(str + ret, "NRDY "); + if (ep_sts & EP_STS_PRIME) + ret += sprintf(str + ret, "PRIME "); + if (ep_sts & EP_STS_SIDERR) + ret += sprintf(str + ret, "SIDERRT "); + if (ep_sts & EP_STS_OUTSMM) + ret += sprintf(str + ret, "OUTSMM "); + if (ep_sts & EP_STS_ISOERR) + ret += sprintf(str + ret, "ISOERR "); + if (ep_sts & EP_STS_IOT) + ret += sprintf(str + ret, "IOT "); + + return str; +} + +char *cdns3_decode_epx_irq(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + priv_ep->name); +} + +char *cdns3_decode_ep0_irq(struct cdns3_device *priv_dev, int dir) +{ + if (dir) + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + "ep0IN"); + else + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + "ep0OUT"); +} + +void cdns3_dbg_setup(struct cdns3_device *priv_dev) +{ + struct usb_ctrlrequest *setup = priv_dev->setup; + + dev_dbg(&priv_dev->dev, + "SETUP BRT: %02x BR: %02x V: %04x I: %04x L: %04x\n", + setup->bRequestType, + setup->bRequest, + le16_to_cpu(setup->wValue), + le16_to_cpu(setup->wIndex), + le16_to_cpu(setup->wLength)); +} + +/** + * Debug a transfer ring. + * + * Prints out all TRBs in the endpoint ring, even those after the Link TRB. + *. + */ +void cdns3_dbg_ring(struct cdns3_device *priv_dev, + struct cdns3_endpoint *priv_ep) +{ + u64 addr = priv_ep->trb_pool_dma; + struct cdns3_trb *trb; + int i; + + for (i = 0; i < TRBS_PER_SEGMENT; ++i) { + trb = &priv_ep->trb_pool[i]; + dev_dbg(&priv_dev->dev, "@%016llx %08x %08x %08x\n", addr, + le32_to_cpu(trb->buffer), + le32_to_cpu(trb->length), + le32_to_cpu(trb->control)); + addr += sizeof(*trb); + } +} + +void cdns3_dbg_ring_ptrs(struct cdns3_device *priv_dev, +struct cdns3_endpoint *priv_ep) +{ + struct cdns3_trb *trb; + + trb = &priv_ep->trb_pool[priv_
[RFC PATCH v1 14/14] usb:cdns3: Feature for changing role
Patch adds feature that allow to change role from user space. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Makefile | 2 +- drivers/usb/cdns3/core.c| 2 + drivers/usb/cdns3/debugfs.c | 94 + drivers/usb/cdns3/drd.h | 3 ++ 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/cdns3/debugfs.c diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index 34e60d03c4ec..08e6cdbebd46 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_USB_CDNS3)+= cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o -cdns3-y:= core.o drd.o +cdns3-y:= core.o drd.o debugfs.o cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o debug.o cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index 20ae9e76940e..4012f1007da9 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -309,6 +309,7 @@ static int cdns3_probe(struct platform_device *pdev) if (ret) goto err4; + cdns3_debugfs_init(cdns); device_set_wakeup_capable(dev, true); pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -346,6 +347,7 @@ static int cdns3_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); + cdns3_debugfs_exit(cdns); cdns3_remove_roles(cdns); usb_phy_shutdown(cdns->usbphy); diff --git a/drivers/usb/cdns3/debugfs.c b/drivers/usb/cdns3/debugfs.c new file mode 100644 index ..d4871bc1a69d --- /dev/null +++ b/drivers/usb/cdns3/debugfs.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Controller DebugFS filer. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include +#include +#include +#include + +#include "core.h" +#include "gadget.h" + +static int cdns3_mode_show(struct seq_file *s, void *unused) +{ + struct cdns3*cdns = s->private; + + switch (cdns->role) { + case CDNS3_ROLE_HOST: + seq_puts(s, "host\n"); + break; + case CDNS3_ROLE_GADGET: + seq_puts(s, "device\n"); + break; + case CDNS3_ROLE_OTG: + case CDNS3_ROLE_END: + seq_puts(s, "otg\n"); + break; + default: + seq_puts(s, "UNKNOWN mode\n"); + } + + return 0; +} + +static int cdns3_mode_open(struct inode *inode, struct file *file) +{ + return single_open(file, cdns3_mode_show, inode->i_private); +} + +static ssize_t cdns3_mode_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct cdns3*cdns = s->private; + u32 mode = 0; + charbuf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "host", 4)) + mode = USB_DR_MODE_HOST; + + if (!strncmp(buf, "device", 6)) + mode = USB_DR_MODE_PERIPHERAL; + + if (!strncmp(buf, "otg", 3)) + mode = USB_DR_MODE_OTG; + + cdns->desired_role = mode; + queue_work(system_freezable_wq, &cdns->role_switch_wq); + return count; +} + +static const struct file_operations cdns3_mode_fops = { + .open = cdns3_mode_open, + .write = cdns3_mode_write, + .read = seq_read, + .llseek = seq_lseek, + .release= single_release, +}; + +void cdns3_debugfs_init(struct cdns3 *cdns) +{ + struct dentry *root; + + root = debugfs_create_dir(dev_name(cdns->dev), NULL); + cdns->root = root; + if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET) && + IS_ENABLED(CONFIG_USB_CDNS3_HOST)) + debugfs_create_file("mode", 0644, root, cdns, + &cdns3_mode_fops); +} + +void cdns3_debugfs_exit(struct cdns3 *cdns) +{ + debugfs_remove_recursive(cdns->root); +} diff --git a/drivers/usb/cdns3/drd.h b/drivers/usb/cdns3/drd.h index 85731f3b693c..5344290c76f2 100644 --- a/drivers/usb/cdns3/drd.h +++ b/drivers/usb/cdns3/drd.h @@ -119,4 +119,7 @@ int cdns3_drd_probe(struct cdns3 *cdns); void cdns3_set_hw_mode(struct cdns3 *cdns, u32 mode); irqreturn_t cdns3_drd_irq(struct cdns3 *cdns); +void cdns3_debugfs_init(struct cdns3 *cdns); +void cdns3_debugfs_exit(struct cdns3 *cdns); + #endif /* __LINUX_CDNS3_DRD */ -- 2.17.1
[RFC PATCH v1 11/14] usb:cdns3: Adds enumeration related function.
Patch implements a set of function related to enumeration process. Some standard requests are handled on controller driver level and other are delegated to gadget core driver. All class requests are delegated to gadget core driver. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/ep0.c| 490 - drivers/usb/cdns3/gadget.c | 119 + drivers/usb/cdns3/gadget.h | 4 + 3 files changed, 609 insertions(+), 4 deletions(-) diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index 369bd6748416..555ac7f6842e 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -10,6 +10,7 @@ * Peter Chen */ +#include #include "gadget.h" static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { @@ -52,9 +53,31 @@ static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev, writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd); } +/** + * cdns3_ep0_delegate_req - Returns status of handling setup packet + * Setup is handled by gadget driver + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns zero on success or negative value on failure + */ +static int cdns3_ep0_delegate_req(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + int ret; + + spin_unlock(&priv_dev->lock); + priv_dev->setup_pending = 1; + ret = priv_dev->gadget_driver->setup(&priv_dev->gadget, ctrl_req); + priv_dev->setup_pending = 0; + spin_lock(&priv_dev->lock); + return ret; +} + static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) { - //TODO: Implements this function + priv_dev->ep0_data_dir = 0; + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 8, 0); } static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) @@ -90,9 +113,430 @@ static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) } } +/** + * cdns3_req_ep0_set_configuration - Handling of SET_CONFIG standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, 0x7FFF on deferred status stage, error code on error + */ +static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + enum usb_device_state device_state = priv_dev->gadget.state; + struct cdns3_endpoint *priv_ep, *temp_ep; + u32 config = le16_to_cpu(ctrl_req->wValue); + int result = 0; + + switch (device_state) { + case USB_STATE_ADDRESS: + /* Configure non-control EPs */ + list_for_each_entry_safe(priv_ep, temp_ep, +&priv_dev->ep_match_list, +ep_match_pending_list) + cdns3_ep_config(priv_ep); + + result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + + if (result) + return result; + + if (config) { + cdns3_set_hw_configuration(priv_dev); + } else { + cdns3_gadget_unconfig(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, +USB_STATE_ADDRESS); + } + break; + case USB_STATE_CONFIGURED: + result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + + if (!config && !result) { + cdns3_gadget_unconfig(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, +USB_STATE_ADDRESS); + } + break; + default: + result = -EINVAL; + } + + return result; +} + +/** + * cdns3_req_ep0_set_address - Handling of SET_ADDRESS standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev, +struct usb_ctrlrequest *ctrl_req) +{ + enum usb_device_state device_state = priv_dev->gadget.state; + u32 reg; + u32 addr; + + addr = le16_to_cpu(ctrl_req->wValue); + + if (addr > DEVICE_ADDRESS_MAX) { + dev_err(&priv_dev->dev, + "Device address (%d) cannot be greater than %d\n", + addr, DEVICE_ADDRESS_MAX); + return -EINVAL; + } + + if (device_state == USB_STATE_CONFIGURED) { + dev_err(&priv_dev->dev, "USB device already configured\n"); +
[RFC PATCH v1 03/14] usb:cdns3: Driver initialization code.
Patch adds core.c and core.h file that implements initialization of platform driver and adds function responsible for selecting, switching and running appropriate Device/Host mode. Patch also adds gadget.c, host.c, gadget-export.h, host-export.h. These files contains templates functions used during initialization. The implementation will be added in next patches. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Kconfig | 20 ++ drivers/usb/cdns3/Makefile| 4 + drivers/usb/cdns3/core.c | 373 ++ drivers/usb/cdns3/core.h | 88 +++ drivers/usb/cdns3/gadget-export.h | 27 +++ drivers/usb/cdns3/gadget.c| 36 +++ drivers/usb/cdns3/host-export.h | 30 +++ drivers/usb/cdns3/host.c | 28 +++ 8 files changed, 606 insertions(+) create mode 100644 drivers/usb/cdns3/core.c create mode 100644 drivers/usb/cdns3/core.h create mode 100644 drivers/usb/cdns3/gadget-export.h create mode 100644 drivers/usb/cdns3/gadget.c create mode 100644 drivers/usb/cdns3/host-export.h create mode 100644 drivers/usb/cdns3/host.c diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig index 888458372adb..5f88a4932e58 100644 --- a/drivers/usb/cdns3/Kconfig +++ b/drivers/usb/cdns3/Kconfig @@ -10,6 +10,26 @@ config USB_CDNS3 if USB_CDNS3 +config USB_CDNS3_GADGET + bool "Cadence USB3 device controller" + depends on USB_GADGET + help + Say Y here to enable device controller functionality of the + cadence USBSS-DEV driver. + + This controller support FF, HS and SS mode. It doeasn't support + LS and SSP mode + +config USB_CDNS3_HOST + bool "Cadence USB3 host controller" + depends on USB_XHCI_HCD + help + Say Y here to enable host controller functionality of the + cadence driver. + + Host controller is compliance with XHCI so it will use + standard XHCI driver. + config USB_CDNS3_PCI_WRAP tristate "PCIe-based Platforms" depends on USB_PCI && ACPI diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index dcdd62003c6a..083676c7748f 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -1,3 +1,7 @@ +obj-$(CONFIG_USB_CDNS3)+= cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o +cdns3-y:= core.o +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c new file mode 100644 index ..727136235957 --- /dev/null +++ b/drivers/usb/cdns3/core.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * + * Author: Peter Chen + * Pawel Laszczak + */ + +#include +#include +#include +#include +#include + +#include "gadget.h" +#include "core.h" +#include "host-export.h" +#include "gadget-export.h" + +static inline struct cdns3_role_driver *cdns3_role(struct cdns3 *cdns) +{ + WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); + return cdns->roles[cdns->role]; +} + +static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles role) +{ + int ret; + + if (role >= CDNS3_ROLE_END) + return 0; + + if (!cdns->roles[role]) + return -ENXIO; + + mutex_lock(&cdns->mutex); + cdns->role = role; + ret = cdns->roles[role]->start(cdns); + mutex_unlock(&cdns->mutex); + return ret; +} + +static inline void cdns3_role_stop(struct cdns3 *cdns) +{ + enum cdns3_roles role = cdns->role; + + if (role == CDNS3_ROLE_END) + return; + + mutex_lock(&cdns->mutex); + cdns->roles[role]->stop(cdns); + cdns->role = CDNS3_ROLE_END; + mutex_unlock(&cdns->mutex); +} + +static void cdns3_set_role(struct cdns3 *cdns, enum cdns3_roles role) +{ + if (role == CDNS3_ROLE_END) + return; + + if (role == CDNS3_ROLE_HOST) { + //TODO: set host role + } else { /* gadget mode */ + //TODO: set device role + } +} + +static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) +{ + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { + //TODO: implements selecting device/host mode + return CDNS3_ROLE_HOST; + } + return cdns->roles[CDNS3_ROLE_HOST] + ? CDNS3_ROLE_HOST + : CDNS3_ROLE_GADGET; +} + +/** + * cdns3_core_init_role - initialize role of operation + * @cdns: Pointer to cdns3 structure + * + * Returns 0 on success othe
[RFC PATCH v1 05/14] usb:cdns3: Added Wrapper to XCHI driver
Patch implements functions that allow to initialize, start and stop XHCI host driver. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/host.c | 230 ++- 1 file changed, 227 insertions(+), 3 deletions(-) diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c index 37300985e2d6..f3b100a27cd6 100644 --- a/drivers/usb/cdns3/host.c +++ b/drivers/usb/cdns3/host.c @@ -9,20 +9,244 @@ * Pawel Laszczak */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../host/xhci.h" #include "core.h" +#include "host-export.h" + +static struct hc_driver __read_mostly xhci_cdns3_hc_driver; + +static void xhci_cdns3_quirks(struct device *dev, struct xhci_hcd *xhci) +{ + /* +* As of now platform drivers don't provide MSI support so we ensure +* here that the generic code does not try to make a pci_dev from our +* dev struct in order to setup MSI +*/ + xhci->quirks |= XHCI_PLAT; +} + +static int xhci_cdns3_setup(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + u32 command; + int ret; + + ret = xhci_gen_setup(hcd, xhci_cdns3_quirks); + if (ret) + return ret; + + /* set usbcmd.EU3S */ + command = readl(&xhci->op_regs->command); + command |= CMD_PM_INDEX; + writel(command, &xhci->op_regs->command); + + return 0; +} + +static const struct xhci_driver_overrides xhci_cdns3_overrides __initconst = { + .extra_priv_size = sizeof(struct xhci_hcd), + .reset = xhci_cdns3_setup, +}; + +struct cdns3_host { + struct device dev; + struct usb_hcd *hcd; +}; + +static irqreturn_t cdns3_host_irq(struct cdns3 *cdns) +{ + struct device *dev = cdns->host_dev; + struct usb_hcd *hcd; + + if (dev) + hcd = dev_get_drvdata(dev); + else + return IRQ_NONE; + + if (hcd) + return usb_hcd_irq(cdns->irq, hcd); + else + return IRQ_NONE; +} + +static void cdns3_host_release(struct device *dev) +{ + struct cdns3_host *host = container_of(dev, struct cdns3_host, dev); + + kfree(host); +} + +static int cdns3_host_start(struct cdns3 *cdns) +{ + struct cdns3_host *host; + struct device *dev; + struct device *sysdev; + struct xhci_hcd *xhci; + int ret; + + host = kzalloc(sizeof(*host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + dev = &host->dev; + dev->release = cdns3_host_release; + dev->parent = cdns->dev; + dev_set_name(dev, "xhci-cdns3"); + cdns->host_dev = dev; + ret = device_register(dev); + if (ret) + goto err1; + + sysdev = cdns->dev; + /* Try to set 64-bit DMA first */ + if (WARN_ON(!sysdev->dma_mask)) + /* Platform did not initialize dma_mask */ + ret = dma_coerce_mask_and_coherent(sysdev, + DMA_BIT_MASK(64)); + else + ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64)); + + /* If setting 64-bit DMA mask fails, fall back to 32-bit DMA mask */ + if (ret) { + ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + } + + pm_runtime_set_active(dev); + pm_runtime_no_callbacks(dev); + pm_runtime_enable(dev); + host->hcd = __usb_create_hcd(&xhci_cdns3_hc_driver, sysdev, dev, +dev_name(dev), NULL); + if (!host->hcd) { + ret = -ENOMEM; + goto err2; + } + + host->hcd->regs = cdns->xhci_regs; + host->hcd->rsrc_start = cdns->xhci_res->start; + host->hcd->rsrc_len = resource_size(cdns->xhci_res); + + device_wakeup_enable(host->hcd->self.controller); + xhci = hcd_to_xhci(host->hcd); + + xhci->main_hcd = host->hcd; + xhci->shared_hcd = __usb_create_hcd(&xhci_cdns3_hc_driver, sysdev, dev, + dev_name(dev), host->hcd); + if (!xhci->shared_hcd) { + ret = -ENOMEM; + goto err3; + } + + host->hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); + xhci->shared_hcd->tpl_support = host->hcd->tpl_support; + ret = usb_add_hcd(host->hcd, 0, IRQF_SHARED); + if (ret) + goto err4; + + ret = usb_add_hcd(xhci->shared_hcd, 0, IRQF_SHARED); + if (ret) + goto err5; + + device_set_wakeup_capable(dev, true); + + return 0; + +err5: + usb_remove_hcd(host->hcd); +err4: + usb_p
[RFC PATCH v1 02/14] usb:cdns3: Device side header file.
Patch defines macros used by device side of controller, structures holding registers, and some other object used by device controller. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/gadget.h | 1067 1 file changed, 1067 insertions(+) create mode 100644 drivers/usb/cdns3/gadget.h diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h new file mode 100644 index ..c4b07827aae7 --- /dev/null +++ b/drivers/usb/cdns3/gadget.h @@ -0,0 +1,1067 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * USBSS device controller driver + * + * Copyright (C) 2018 Cadence. + * Copyright (C) 2018 NXP + * + * Author: Pawel Laszczak + * Pawel Jez + * Peter Chen + */ +#ifndef __LINUX_CDNS3_GADGET +#define __LINUX_CDNS3_GADGET +#include + +/* + * USBSS-DEV register interface. + * This corresponds to the USBSS Device Controller Interface + */ + +/** + * struct xhci_cap_regs - xHCI Host Controller Capability Registers. + * @usb_conf: Global Configuration Register. + * @usb_sts: Global Status Register. + * @usb_cmd: Global Command Register. + * @usb_iptn: ITP/SOF number Register. + * @usb_lpm: Global Command Register. + * @usb_ien: USB Interrupt Enable Register. + * @usb_ists: USB Interrupt Status Register. + * @ep_sel:Endpoint Select Register. + * @ep_traddr: Endpoint Transfer Ring Address Register. + * @ep_cfg:Endpoint Configuration Register. + * @ep_cmd:Endpoint Command Register. + * @ep_sts:Endpoint Status Register. + * @ep_sts_sid:Endpoint Status Register. + * @ep_sts_en: Endpoint Status Register Enable. + * @drbl: Doorbell Register. + * @ep_ien:EP Interrupt Enable Register. + * @ep_ists: EP Interrupt Status Register. + * @usb_pwr: Global Power Configuration Register. + * @usb_conf2: Global Configuration Register 2. + * @usb_cap1: Capability Register 1. + * @usb_cap2: Capability Register 2. + * @usb_cap3: Capability Register 3. + * @usb_cap4: Capability Register 4. + * @usb_cap5: Capability Register 5. + * @usb_cap6: Capability Register 6. + * @usb_cpkt1: Custom Packet Register 1. + * @usb_cpkt2: Custom Packet Register 2. + * @usb_cpkt3: Custom Packet Register 3. + * @reserved1: Reserved. + * @cfg_regs: Configuration registers. + * @reserved2: Reserved. + * @dma_axi_ctrl: AXI Control register. + * @dma_axi_id:AXI ID register. + * @dma_axi_cap: AXI Capability register. + * @dma_axi_ctrl0: AXI Control 0 register. + * @dma_axi_ctrl1: AXI Control 1 register. + */ +struct cdns3_usb_regs { + __le32 usb_conf; + __le32 usb_sts; + __le32 usb_cmd; + __le32 usb_iptn; + __le32 usb_lpm; + __le32 usb_ien; + __le32 usb_ists; + __le32 ep_sel; + __le32 ep_traddr; + __le32 ep_cfg; + __le32 ep_cmd; + __le32 ep_sts; + __le32 ep_sts_sid; + __le32 ep_sts_en; + __le32 drbl; + __le32 ep_ien; + __le32 ep_ists; + __le32 usb_pwr; + __le32 usb_conf2; + __le32 usb_cap1; + __le32 usb_cap2; + __le32 usb_cap3; + __le32 usb_cap4; + __le32 usb_cap5; + __le32 usb_cap6; + __le32 usb_cpkt1; + __le32 usb_cpkt2; + __le32 usb_cpkt3; + __le32 reserved1[36]; + __le32 cfg_reg1; + __le32 dbg_link1; + __le32 dbg_link2; + __le32 cfg_regs[74]; + __le32 reserved2[34]; + __le32 dma_axi_ctrl; + __le32 dma_axi_id; + __le32 dma_axi_cap; + __le32 dma_axi_ctrl0; + __le32 dma_axi_ctrl1; +}; + +/* USB_CONF - bitmasks */ +/* Reset USB device configuration. */ +#define USB_CONF_CFGRSTBIT(0) +/* Set Configuration. */ +#define USB_CONF_CFGSETBIT(1) +/* Disconnect USB device in SuperSpeed. */ +#define USB_CONF_USB3DIS BIT(3) +/* Disconnect USB device in HS/FS */ +#define USB_CONF_USB2DIS BIT(4) +/* Little Endian access - default */ +#define USB_CONF_LENDIAN BIT(5) +/* + * Big Endian access. Driver assume that byte order for + * SFRs access always is as Little Endian so this bit + * is not used. + */ +#define USB_CONF_BENDIAN BIT(6) +/* Device software reset. */ +#define USB_CONF_SWRST BIT(7) +/* Singular DMA transfer mode. */ +#define USB_CONF_DSING BIT(8) +/* Multiple DMA transfers mode. */ +#define USB_CONF_DMULT BIT(9) +/* DMA clock turn-off enable. */ +#define USB_CONF_DMAOFFEN BIT(10) +/* DMA clock turn-off disable. */ +#define USB_CONF_DMAOFFDS BIT(11) +/* Clear Force Full Speed. */ +#define USB_CONF_CFORCE_FS BIT(12) +/* Set Force Full Speed. */ +#define USB_CONF_SFORCE_FS BIT(13) +/* Device enable. */ +#define USB_CONF_DEVEN BIT(14) +/* Device disable. */ +#define USB_CONF_DEVDS BIT(15) +/* L1 LPM state entry enable (used in HS/FS mode). */ +#define USB_CONF_L1EN
[RFC PATCH v1 08/14] usb:cdns3: EpX operations part of the API
Patch implements callback functions for non-default endpoints defined in usb_ep_ops object. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/ep0.c| 18 ++ drivers/usb/cdns3/gadget.c | 430 - drivers/usb/cdns3/gadget.h | 3 + 3 files changed, 449 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index c08d02665f9d..ca1795467155 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -23,6 +23,24 @@ static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) //TODO: Implements this function } +/** + * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint + * @ep: endpoint object + * + * Returns 0 + */ +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + dev_dbg(&priv_dev->dev, "Wedge for %s\n", ep->name); + cdns3_gadget_ep_set_halt(ep, 1); + priv_ep->flags |= EP_WEDGE; + + return 0; +} + /** * cdns3_ep0_config - Configures default endpoint * @priv_dev: extended gadget object diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index ff8306ac070e..b08e0836f9a5 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -58,6 +58,19 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask) writel(mask, ptr); } +/** + * cdns3_next_request - returns next request from list + * @list: list containing requests + * + * Returns request or NULL if no requests in list + */ +struct usb_request *cdns3_next_request(struct list_head *list) +{ + if (list_empty(list)) + return NULL; + return list_first_entry(list, struct usb_request, list); +} + /** * select_ep - selects endpoint * @priv_dev: extended gadget object @@ -75,6 +88,46 @@ void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) wmb(); } +/** + * cdns3_allocate_trb_pool - Allocates TRB's pool for selected endpoint + * @priv_ep: endpoint object + * + * Function will return 0 on success or -ENOMEM on allocation error + */ +static int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_trb *link_trb; + + priv_ep->trb_pool = dma_zalloc_coherent(priv_dev->sysdev, + TRB_SIZE * TRBS_PER_SEGMENT, + &priv_ep->trb_pool_dma, + GFP_DMA); + if (!priv_ep->trb_pool) + return -ENOMEM; + + priv_ep->aligned_buff = dma_alloc_coherent(priv_dev->sysdev, + CDNS3_UNALIGNED_BUF_SIZE, + &priv_ep->aligned_dma_addr, + GFP_DMA); + if (!priv_ep->aligned_buff) { + dma_free_coherent(priv_dev->sysdev, + TRB_SIZE * TRBS_PER_SEGMENT, + priv_ep->trb_pool, priv_ep->trb_pool_dma); + priv_ep->trb_pool = NULL; + + return -ENOMEM; + } + + /* Initialize the last TRB as Link TRB */ + link_trb = (priv_ep->trb_pool + TRBS_PER_SEGMENT - 1); + link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma); + link_trb->control = TRB_CYCLE | TRB_TYPE(TRB_LINK) | + TRB_CHAIN | TRB_TOGGLE; + + return 0; +} + static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) { struct cdns3_device *priv_dev = priv_ep->cdns3_dev; @@ -89,6 +142,73 @@ static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) priv_ep->aligned_buff = NULL; } +/** + * cdns3_data_flush - flush data at onchip buffer + * @priv_ep: endpoint object + * + * Endpoint must be selected before call to this function + * + * Returns zero on success or negative value on failure + */ +static int cdns3_data_flush(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd); + + /* wait for DFLUSH cleared */ + return cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); +} + +/** + * cdns3_ep_stall_flush - Stalls and flushes selected endpoint + * @priv_ep: endpoint object + * + * Endpoint must be selected before call to this function + */ +static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + writel(EP_CMD_DFLUSH | EP_CMD_ERDY | EP_CMD_SSTALL, + &priv_dev->regs->ep_cmd); + + /* wait for DFLUSH cleared */ + cdns3_handshake(&priv_dev->regs->
[RFC PATCH v1 06/14] usb:cdns3: Initialization code for Device side
Patch implements a set of functions responsible for initialization, configuration, starting and stopping device mode. This patch also adds new ep0.c that holds all functions related to endpoint 0. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Makefile | 2 +- drivers/usb/cdns3/ep0.c| 105 +++ drivers/usb/cdns3/gadget.c | 361 - drivers/usb/cdns3/gadget.h | 4 + 4 files changed, 468 insertions(+), 4 deletions(-) create mode 100644 drivers/usb/cdns3/ep0.c diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index d4ccfb49d844..f4cfc978626f 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -2,6 +2,6 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o cdns3-y:= core.o drd.o -cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c new file mode 100644 index ..c08d02665f9d --- /dev/null +++ b/drivers/usb/cdns3/ep0.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver - gadget side. + * + * Copyright (C) 2018 Cadence Design Systems. + * Copyright (C) 2017 NXP + * + * Authors: Pawel Jez , + * Pawel Laszczak + * Peter Chen + */ + +#include "gadget.h" + +static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, +}; + +static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) +{ + //TODO: Implements this function +} + +/** + * cdns3_ep0_config - Configures default endpoint + * @priv_dev: extended gadget object + * + * Functions sets parameters: maximal packet size and enables interrupts + */ +void cdns3_ep0_config(struct cdns3_device *priv_dev) +{ + struct cdns3_usb_regs __iomem *regs; + u32 max_packet_size = 64; + + regs = priv_dev->regs; + + if (priv_dev->gadget.speed == USB_SPEED_SUPER) + max_packet_size = 512; + + if (priv_dev->ep0_request) { + list_del_init(&priv_dev->ep0_request->list); + priv_dev->ep0_request = NULL; + } + + priv_dev->gadget.ep0->maxpacket = max_packet_size; + cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(max_packet_size); + + /* init ep out */ + cdns3_select_ep(priv_dev, USB_DIR_OUT); + + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), + ®s->ep_cfg); + + writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN, + ®s->ep_sts_en); + + /* init ep in */ + cdns3_select_ep(priv_dev, USB_DIR_IN); + + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), + ®s->ep_cfg); + + writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, ®s->ep_sts_en); + + cdns3_set_register_bit(®s->usb_conf, USB_CONF_U1DS | USB_CONF_U2DS); + cdns3_prepare_setup_packet(priv_dev); +} + +/** + * cdns3_init_ep0 Initializes software endpoint 0 of gadget + * @cdns3: extended gadget object + * + * Returns 0 on success, error code elsewhere + */ +int cdns3_init_ep0(struct cdns3_device *priv_dev) +{ + struct cdns3_endpoint *ep0; + + ep0 = devm_kzalloc(&priv_dev->dev, sizeof(struct cdns3_endpoint), + GFP_KERNEL); + + if (!ep0) + return -ENOMEM; + + ep0->cdns3_dev = priv_dev; + sprintf(ep0->name, "ep0"); + + /* fill linux fields */ + //TODO: implements cdns3_gadget_ep0_ops object + //ep0->endpoint.ops = &cdns3_gadget_ep0_ops; + ep0->endpoint.maxburst = 1; + usb_ep_set_maxpacket_limit(&ep0->endpoint, ENDPOINT0_MAX_PACKET_LIMIT); + ep0->endpoint.address = 0; + ep0->endpoint.caps.type_control = 1; + ep0->endpoint.caps.dir_in = 1; + ep0->endpoint.caps.dir_out = 1; + ep0->endpoint.name = ep0->name; + ep0->endpoint.desc = &cdns3_gadget_ep0_desc; + priv_dev->gadget.ep0 = &ep0->endpoint; + INIT_LIST_HEAD(&ep0->request_list); + + return 0; +} diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 41ce696719d7..e7975b00b21a 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -10,7 +10,261 @@ * Peter Chen */ +#include +#include + #include "core.h" +#include "gadget-export.h" +#include "gadget.h" + +/** + * cdns3_set_register_bit - set bit in given register. + * @ptr: address of device controller register to be read and
[RFC PATCH v1 09/14] usb:cdns3: Ep0 operations part of the API
Patch implements related to default endpoint callback functions defined in usb_ep_ops object Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/ep0.c| 188 - drivers/usb/cdns3/gadget.c | 8 ++ drivers/usb/cdns3/gadget.h | 10 ++ 3 files changed, 204 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index ca1795467155..f838e1e71183 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -18,11 +18,185 @@ static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { .bmAttributes = USB_ENDPOINT_XFER_CONTROL, }; +/** + * cdns3_ep0_run_transfer - Do transfer on default endpoint hardware + * @priv_dev: extended gadget object + * @dma_addr: physical address where data is/will be stored + * @length: data length + * @erdy: set it to 1 when ERDY packet should be sent - + *exit from flow control state + */ +static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev, + dma_addr_t dma_addr, + unsigned int length, int erdy) +{ + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; + + priv_dev->trb_ep0->buffer = TRB_BUFFER(dma_addr); + priv_dev->trb_ep0->length = TRB_LEN(length); + priv_dev->trb_ep0->control = TRB_CYCLE | TRB_IOC | TRB_TYPE(TRB_NORMAL); + + cdns3_select_ep(priv_dev, + priv_dev->ep0_data_dir ? USB_DIR_IN : USB_DIR_OUT); + + writel(EP_TRADDR_TRADDR(priv_dev->trb_ep0_dma), ®s->ep_traddr); + + dev_dbg(&priv_dev->dev, "//Ding Dong ep0%s\n", + priv_dev->ep0_data_dir ? "IN" : "OUT"); + + /* TRB should be prepared before starting transfer */ + wmb(); + writel(EP_CMD_DRDY, ®s->ep_cmd); + + if (erdy) + writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd); +} + static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) { //TODO: Implements this function } +static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) +{ + struct cdns3_endpoint *priv_ep; + struct usb_request *request; + struct usb_ep *ep; + int result = 0; + + if (priv_dev->hw_configured_flag) + return; + + writel(USB_CONF_CFGSET, &priv_dev->regs->usb_conf); + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + + cdns3_set_register_bit(&priv_dev->regs->usb_conf, + USB_CONF_U1EN | USB_CONF_U2EN); + + /* wait until configuration set */ + result = cdns3_handshake(&priv_dev->regs->usb_sts, +USB_STS_CFGSTS_MASK, 1, 100); + + priv_dev->hw_configured_flag = 1; + cdns3_enable_l1(priv_dev, 1); + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + if (ep->enabled) { + priv_ep = ep_to_cdns3_ep(ep); + request = cdns3_next_request(&priv_ep->request_list); + if (request) + cdns3_ep_run_transfer(priv_ep, request); + } + } +} + +/** + * cdns3_gadget_ep0_enable + * Function shouldn't be called by gadget driver, + * endpoint 0 is allways active + */ +static int cdns3_gadget_ep0_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + return -EINVAL; +} + +/** + * cdns3_gadget_ep0_disable + * Function shouldn't be called by gadget driver, + * endpoint 0 is allways active + */ +static int cdns3_gadget_ep0_disable(struct usb_ep *ep) +{ + return -EINVAL; +} + +/** + * cdns3_gadget_ep0_set_halt + * @ep: pointer to endpoint zero object + * @value: 1 for set stall, 0 for clear stall + * + * Returns 0 + */ +static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value) +{ + /* TODO */ + return 0; +} + +/** + * cdns3_gadget_ep0_queue Transfer data on endpoint zero + * @ep: pointer to endpoint zero object + * @request: pointer to request object + * @gfp_flags: gfp flags + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_ep0_queue(struct usb_ep *ep, + struct usb_request *request, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + unsigned long flags; + int erdy_sent = 0; + int ret = 0; + + dev_dbg(&priv_dev->dev, "Queue to Ep0%s L: %d\n", + priv_dev->ep0_data_dir ? "IN" : "OUT", + request->length); + + /* send STATUS stage */ + if (request->length == 0 && request->zero == 0) { +
[RFC PATCH v1 10/14] usb:cdns3: Implements ISR functionality.
Patch adds set of generic functions used for handling interrupts generated by controller. Interrupt related functions are divided into three groups. The first is related to ep0 and is placed in ep0.c. The second is responsible for non-default endpoints and is implemented in gadget.c file. The last group is not related to endpoints interrupts and is placed in gadget.c. All groups have common entry point in cdns3_irq_handler_thread function. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/ep0.c| 63 +++ drivers/usb/cdns3/gadget.c | 224 - drivers/usb/cdns3/gadget.h | 1 + 3 files changed, 287 insertions(+), 1 deletion(-) diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index f838e1e71183..369bd6748416 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -90,6 +90,69 @@ static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) } } +static void __pending_setup_status_handler(struct cdns3_device *priv_dev) +{ + //TODO: Implements this function +} + +/** + * cdns3_ep0_setup_phase - Handling setup USB requests + * @priv_dev: extended gadget object + */ +static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev) +{ + //TODO: Implements this function. +} + +static void cdns3_transfer_completed(struct cdns3_device *priv_dev) +{ + //TODO: Implements this function +} + +/** + * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0 + * @priv_dev: extended gadget object + * @dir: 1 for IN direction, 0 for OUT direction + */ +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir) +{ + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; + u32 ep_sts_reg; + + cdns3_select_ep(priv_dev, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT)); + ep_sts_reg = readl(®s->ep_sts); + + __pending_setup_status_handler(priv_dev); + + if ((ep_sts_reg & EP_STS_SETUP) && dir == 0) { + struct usb_ctrlrequest *setup = priv_dev->setup; + + writel(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP, ®s->ep_sts); + + priv_dev->ep0_data_dir = setup->bRequestType & USB_DIR_IN; + cdns3_ep0_setup_phase(priv_dev); + ep_sts_reg &= ~(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP); + } + + if (ep_sts_reg & EP_STS_TRBERR) + writel(EP_STS_TRBERR, &priv_dev->regs->ep_sts); + + if (ep_sts_reg & EP_STS_DESCMIS) { + writel(EP_STS_DESCMIS, &priv_dev->regs->ep_sts); + + if (dir == 0 && !priv_dev->setup_pending) { + priv_dev->ep0_data_dir = 0; + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, + 8, 0); + } + } + + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) { + writel(EP_STS_IOC, &priv_dev->regs->ep_sts); + cdns3_transfer_completed(priv_dev); + } +} + /** * cdns3_gadget_ep0_enable * Function shouldn't be called by gadget driver, diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index cd6023c04be9..cb8a3473449b 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -58,6 +58,18 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask) writel(mask, ptr); } +/** + * cdns3_ep_reg_pos_to_index - Macro converts bit position of ep_ists register + * to index of endpoint object in cdns3_device.eps[] container + * @i: bit position of endpoint for which endpoint object is required + * + * Remember that endpoint container doesn't contain default endpoint + */ +static u8 cdns3_ep_reg_pos_to_index(int i) +{ + return ((i / 16) + (((i % 16) - 2) * 2)); +} + /** * cdns3_next_request - returns next request from list * @list: list containing requests @@ -178,6 +190,21 @@ static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep) priv_ep->flags |= EP_STALL; } +/** + * cdns3_gadget_unconfig - reset device configuration + * @priv_dev: extended gadget object + */ +void cdns3_gadget_unconfig(struct cdns3_device *priv_dev) +{ + /* RESET CONFIGURATION */ + writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf); + + cdns3_enable_l1(priv_dev, 0); + priv_dev->hw_configured_flag = 0; + priv_dev->onchip_mem_allocated_size = 0; + priv_dev->out_mem_is_allocated = 0; +} + void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable) { if (enable) @@ -186,6 +213,23 @@ void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable) writel(USB_CONF_L1DS, &priv_dev->regs->usb_conf); } +static enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev) +{ + u32 reg; + + reg = readl(&priv_dev->
[RFC PATCH v1 07/14] usb:cdns3: Implements device operations part of the API
Patch adds implementation callback function defined in usb_gadget_ops object. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/gadget.c | 244 - 1 file changed, 242 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index e7975b00b21a..ff8306ac070e 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -17,6 +17,36 @@ #include "gadget-export.h" #include "gadget.h" +/** + * cdns3_handshake - spin reading until handshake completes or fails + * @ptr: address of device controller register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @usec: timeout in microseconds + * + * Returns negative errno, or zero on success + * + * Success happens when the "mask" bits have the specified value (hardware + * handshake done). There are two failure modes: "usec" have passed (major + * hardware flakeout), or the register reads as all-ones (hardware removed). + */ +int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = readl(ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + /** * cdns3_set_register_bit - set bit in given register. * @ptr: address of device controller register to be read and changed @@ -45,6 +75,20 @@ void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) wmb(); } +static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + dma_free_coherent(priv_dev->sysdev, + TRB_SIZE * TRBS_PER_SEGMENT, + priv_ep->trb_pool, priv_ep->trb_pool_dma); + priv_ep->trb_pool = NULL; + + dma_free_coherent(priv_dev->sysdev, CDNS3_UNALIGNED_BUF_SIZE, + priv_ep->aligned_buff, priv_ep->aligned_dma_addr); + priv_ep->aligned_buff = NULL; +} + /** * cdns3_irq_handler - irq line interrupt handler * @cdns: cdns3 instance @@ -60,6 +104,114 @@ static irqreturn_t cdns3_irq_handler_thread(struct cdns3 *cdns) return ret; } +/* Find correct direction for HW endpoint according to description */ +static int cdns3_ep_dir_is_correct(struct usb_endpoint_descriptor *desc, + struct cdns3_endpoint *priv_ep) +{ + return (priv_ep->endpoint.caps.dir_in && usb_endpoint_dir_in(desc)) || + (priv_ep->endpoint.caps.dir_out && usb_endpoint_dir_out(desc)); +} + +static struct cdns3_endpoint *cdns3_find_available_ss_ep(struct cdns3_device *priv_dev, +struct usb_endpoint_descriptor *desc) +{ + struct usb_ep *ep; + struct cdns3_endpoint *priv_ep; + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + unsigned long num; + int ret; + /* ep name pattern likes epXin or epXout */ + char c[2] = {ep->name[2], '\0'}; + + ret = kstrtoul(c, 10, &num); + if (ret) + return ERR_PTR(ret); + + priv_ep = ep_to_cdns3_ep(ep); + if (cdns3_ep_dir_is_correct(desc, priv_ep)) { + if (!(priv_ep->flags & EP_USED)) { + priv_ep->num = num; + priv_ep->flags |= EP_USED; + return priv_ep; + } + } + } + return ERR_PTR(-ENOENT); +} + +static struct usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *comp_desc) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + struct cdns3_endpoint *priv_ep; + unsigned long flags; + + priv_ep = cdns3_find_available_ss_ep(priv_dev, desc); + if (IS_ERR(priv_ep)) { + dev_err(&priv_dev->dev, "no available ep\n"); + return NULL; + } + + dev_dbg(&priv_dev->dev, "match endpoint: %s\n", priv_ep->name); + + spin_lock_irqsave(&priv_dev->lock, flags); + priv_ep->endpoint.desc = desc; + priv_ep->dir = usb_endpoint_dir_in(desc) ? USB_DIR_IN : USB_DIR_OUT; + priv_ep->type = usb_endpoint_type(desc); + + list_add_tail(&priv_ep->ep_match_pending_list, +
[RFC PATCH v1 04/14] usb:cdns3: Added DRD support
Patch adds supports for detecting Host/Device mode. Controller has additional OTG register that allow implement even whole OTG functionality. At this moment patch adds support only for detecting the appropriate mode based on strap pins and ID pin. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Makefile | 2 +- drivers/usb/cdns3/core.c | 22 ++-- drivers/usb/cdns3/drd.c| 219 + drivers/usb/cdns3/drd.h| 122 + 4 files changed, 356 insertions(+), 9 deletions(-) create mode 100644 drivers/usb/cdns3/drd.c create mode 100644 drivers/usb/cdns3/drd.h diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index 083676c7748f..d4ccfb49d844 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_USB_CDNS3)+= cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o -cdns3-y:= core.o +cdns3-y:= core.o drd.o cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index 727136235957..20ae9e76940e 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -18,6 +18,7 @@ #include "core.h" #include "host-export.h" #include "gadget-export.h" +#include "drd.h" static inline struct cdns3_role_driver *cdns3_role(struct cdns3 *cdns) { @@ -70,8 +71,10 @@ static void cdns3_set_role(struct cdns3 *cdns, enum cdns3_roles role) static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) { if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { - //TODO: implements selecting device/host mode - return CDNS3_ROLE_HOST; + if (cdns3_is_host(cdns)) + return CDNS3_ROLE_HOST; + if (cdns3_is_device(cdns)) + return CDNS3_ROLE_GADGET; } return cdns->roles[CDNS3_ROLE_HOST] ? CDNS3_ROLE_HOST @@ -141,6 +144,12 @@ static irqreturn_t cdns3_irq(int irq, void *data) return IRQ_HANDLED; } + if (cdns->dr_mode == USB_DR_MODE_OTG) { + ret = cdns3_drd_irq(cdns); + if (ret == IRQ_HANDLED) + return ret; + } + /* Handle device/host interrupt */ if (cdns->role != CDNS3_ROLE_END) ret = cdns3_role(cdns)->irq(cdns); @@ -202,12 +211,8 @@ static void cdns3_role_switch(struct work_struct *work) bool device, host; cdns = container_of(work, struct cdns3, role_switch_wq); - - //TODO: implements this functions. - //host = cdns3_is_host(cdns); - //device = cdns3_is_device(cdns); - host = 1; - device = 0; + host = cdns3_is_host(cdns); + device = cdns3_is_device(cdns); if (host) { if (cdns->roles[CDNS3_ROLE_HOST]) @@ -286,6 +291,7 @@ static int cdns3_probe(struct platform_device *pdev) if (ret) goto err3; + ret = cdns3_drd_probe(cdns); if (ret) goto err3; diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c new file mode 100644 index ..5d988432edb8 --- /dev/null +++ b/drivers/usb/cdns3/drd.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak +#include +#include +#include + +#include "gadget.h" +#include "drd.h" + +/** + * cdns3_set_mode - change mode of OTG Core + * @cdns: pointer to context structure + * @mode: selected mode from cdns_role + */ +void cdns3_set_mode(struct cdns3 *cdns, u32 mode) +{ + u32 reg; + + switch (mode) { + case CDNS3_ROLE_GADGET: + dev_info(cdns->dev, "Set controller to Gadget mode\n"); + writel(OTGCMD_DEV_BUS_REQ | OTGCMD_OTG_DIS, + &cdns->otg_regs->cmd); + break; + case CDNS3_ROLE_HOST: + dev_info(cdns->dev, "Set controller to Host mode\n"); + writel(OTGCMD_HOST_BUS_REQ | OTGCMD_OTG_DIS, + &cdns->otg_regs->cmd); + break; + case CDNS3_ROLE_OTG: + dev_info(cdns->dev, "Set controller to OTG mode\n"); + reg = readl(&cdns->otg_regs->ctrl1); + reg |= OTGCTRL1_IDPULLUP; + writel(reg, &cdns->otg_regs->ctrl1); + + /* wait until valid ID (ID_VALUE) can be sampled (50ms). */ + mdelay(50); + break; + default: + dev_err(cdns->dev, "Unsupported
[RFC PATCH v1 00/14] Introduced new Cadence USBSS DRD Driver
This patch set introduce new Cadence USBSS DRD driver to linux kernel. The Cadence USBSS DRD Driver s a highly configurable IP Core which can be instantiated as Dual-Role Device (DRD), Peripheral Only and Host Only (XHCI) configurations. The current driver has been validated with FPGA burned. We have support for PCIe bus, which is used on FPGA prototyping. The host site of USBSS controller is compliance with XHCI specification, so it works with standard XHCI linux driver. --- Pawel Laszczak (14): usb:cdns3: add pci to platform driver wrapper. usb:cdns3: Device side header file. usb:cdns3: Driver initialization code. usb:cdns3: Added DRD support usb:cdns3: Added Wrapper to XCHI driver usb:cdns3: Initialization code for Device side usb:cdns3: Implements device operations part of the API usb:cdns3: EpX operations part of the API usb:cdns3: Ep0 operations part of the API usb:cdns3: Implements ISR functionality. usb:cdns3: Adds enumeration related function. usb:cdns3: Adds transfer related function. usb:cdns3: Adds debugging function. usb:cdns3: Feature for changing role drivers/usb/Kconfig|2 + drivers/usb/Makefile |2 + drivers/usb/cdns3/Kconfig | 44 + drivers/usb/cdns3/Makefile |7 + drivers/usb/cdns3/cdns3-pci-wrap.c | 162 +++ drivers/usb/cdns3/core.c | 381 +++ drivers/usb/cdns3/core.h | 88 ++ drivers/usb/cdns3/debug.c | 128 +++ drivers/usb/cdns3/debugfs.c| 94 ++ drivers/usb/cdns3/drd.c| 219 drivers/usb/cdns3/drd.h| 125 +++ drivers/usb/cdns3/ep0.c| 855 ++ drivers/usb/cdns3/gadget-export.h | 27 + drivers/usb/cdns3/gadget.c | 1649 drivers/usb/cdns3/gadget.h | 1100 +++ drivers/usb/cdns3/host-export.h| 30 + drivers/usb/cdns3/host.c | 252 + 17 files changed, 5165 insertions(+) create mode 100644 drivers/usb/cdns3/Kconfig create mode 100644 drivers/usb/cdns3/Makefile create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c create mode 100644 drivers/usb/cdns3/core.c create mode 100644 drivers/usb/cdns3/core.h create mode 100644 drivers/usb/cdns3/debug.c create mode 100644 drivers/usb/cdns3/debugfs.c create mode 100644 drivers/usb/cdns3/drd.c create mode 100644 drivers/usb/cdns3/drd.h create mode 100644 drivers/usb/cdns3/ep0.c create mode 100644 drivers/usb/cdns3/gadget-export.h create mode 100644 drivers/usb/cdns3/gadget.c create mode 100644 drivers/usb/cdns3/gadget.h create mode 100644 drivers/usb/cdns3/host-export.h create mode 100644 drivers/usb/cdns3/host.c -- 2.17.1
[RFC PATCH v1 01/14] usb:cdns3: add pci to platform driver wrapper.
Patch adds PCI specific glue drivier that creaties and registers in system cdns-usb3 platform device. Thanks to that we will be able to use the cdns-usb3 platform driver for USBSS-DEV controller build on PCI board Signed-off-by: Pawel Laszczak --- drivers/usb/Kconfig| 2 + drivers/usb/Makefile | 2 + drivers/usb/cdns3/Kconfig | 24 + drivers/usb/cdns3/Makefile | 3 + drivers/usb/cdns3/cdns3-pci-wrap.c | 162 + 5 files changed, 193 insertions(+) create mode 100644 drivers/usb/cdns3/Kconfig create mode 100644 drivers/usb/cdns3/Makefile create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 987fc5ba6321..5f9334019d04 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig" endif +source "drivers/usb/cdns3/Kconfig" + source "drivers/usb/mtu3/Kconfig" source "drivers/usb/musb/Kconfig" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 7d1b8c82b208..82093a60ea2c 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -8,6 +8,8 @@ obj-$(CONFIG_USB) += core/ obj-$(CONFIG_USB_SUPPORT) += phy/ +obj-$(CONFIG_USB_CDNS3)+= cdns3/ + obj-$(CONFIG_USB_DWC3) += dwc3/ obj-$(CONFIG_USB_DWC2) += dwc2/ obj-$(CONFIG_USB_ISP1760) += isp1760/ diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig new file mode 100644 index ..888458372adb --- /dev/null +++ b/drivers/usb/cdns3/Kconfig @@ -0,0 +1,24 @@ +config USB_CDNS3 + tristate "Cadence USB3 Dual-Role Controller" + depends on ((USB_XHCI_HCD && USB_GADGET) || (USB_XHCI_HCD && !USB_GADGET) || (!USB_XHCI_HCD && USB_GADGET)) && HAS_DMA + help + Say Y here if your system has a cadence USB3 dual-role controller. + It supports: dual-role switch Host-only, and Peripheral-only. + + If you choose to build this driver is a dynamically linked + module, the module will be called cdns3.ko. + +if USB_CDNS3 + +config USB_CDNS3_PCI_WRAP + tristate "PCIe-based Platforms" + depends on USB_PCI && ACPI + default USB_CDNS3 + help + If you're using the USBSS Core IP with a PCIe, please say + 'Y' or 'M' here. + + If you choose to build this driver as module it will + be dynamically linked and module will be called cdns3-pci.ko + +endif diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile new file mode 100644 index ..dcdd62003c6a --- /dev/null +++ b/drivers/usb/cdns3/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o + +cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c new file mode 100644 index ..6c229ab6dffb --- /dev/null +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS PCI Glue driver + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include +#include +#include +#include +#include +#include + +struct cdns3_wrap { + struct platform_device *plat_dev; + struct pci_dev *hg_dev; + struct resource dev_res[4]; +}; + +struct cdns3_wrap wrap; + +#define RES_IRQ_ID 0 +#define RES_HOST_ID1 +#define RES_DEV_ID 2 +#define RES_DRD_ID 3 + +#define PCI_BAR_HOST 0 +#define PCI_BAR_DEV2 +#define PCI_BAR_OTG4 + +#define PCI_DEV_FN_HOST_DEVICE 0 +#define PCI_DEV_FN_OTG 1 + +#define PCI_DRIVER_NAME"cdns3-pci-usbss" +#define PLAT_DRIVER_NAME "cdns-usb3" + +#define CDNS_VENDOR_ID 0x17cd +#define CDNS_DEVICE_ID 0x0100 + +/** + * cdns3_pci_probe - Probe function for Cadence USB wrapper driver + * @pdev: platform device object + * @id: pci device id + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct platform_device_info plat_info; + struct cdns3_wrap *wrap; + struct resource *res; + int err; + + /* +* for GADGET/HOST PCI (devfn) function number is 0, +* for OTG PCI (devfn) function number is 1 +*/ + if (!id || pdev->devfn != PCI_DEV_FN_HOST_DEVICE) + return -EINVAL; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err); + return err; + } + + pci_set_master(pdev); + wrap = devm_kzalloc(&pdev->dev, sizeof(*wrap), GFP_KERNEL); +
RE: [RFC PATCH v1 13/14] usb:cdns3: Adds debugging function.
>> Patch implements some function used for debugging driver. >[] >> +static inline char *cdns3_decode_ep_irq(u32 ep_sts, const char *ep_name) >> +{ >> +static char str[256]; >> +int ret; >> + >> +ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts); >> + >> +if (ep_sts & EP_STS_SETUP) >> +ret += sprintf(str + ret, "SETUP "); >> +if (ep_sts & EP_STS_IOC) >> +ret += sprintf(str + ret, "IOC "); >> +if (ep_sts & EP_STS_ISP) >> +ret += sprintf(str + ret, "ISP "); >> +if (ep_sts & EP_STS_DESCMIS) >> +ret += sprintf(str + ret, "DESCMIS "); >> +if (ep_sts & EP_STS_STREAMR) >> +ret += sprintf(str + ret, "STREAMR "); >> +if (ep_sts & EP_STS_MD_EXIT) >> +ret += sprintf(str + ret, "MD_EXIT "); >> +if (ep_sts & EP_STS_TRBERR) >> +ret += sprintf(str + ret, "TRBERR "); >> +if (ep_sts & EP_STS_NRDY) >> +ret += sprintf(str + ret, "NRDY "); >> +if (ep_sts & EP_STS_PRIME) >> +ret += sprintf(str + ret, "PRIME "); >> +if (ep_sts & EP_STS_SIDERR) >> +ret += sprintf(str + ret, "SIDERRT "); >> +if (ep_sts & EP_STS_OUTSMM) >> +ret += sprintf(str + ret, "OUTSMM "); >> +if (ep_sts & EP_STS_ISOERR) >> +ret += sprintf(str + ret, "ISOERR "); >> +if (ep_sts & EP_STS_IOT) >> +ret += sprintf(str + ret, "IOT "); >> + >> +return str; >> +} > >This bit is pretty unsightly. >Especially the static in each inline Hi Joe. I understood that you mean line static char str[256]; This array will be defined several times. I will remove inline form function definition. It's not necessary. >> + >> +char *cdns3_decode_epx_irq(struct cdns3_endpoint *priv_ep) >> +{ >> +struct cdns3_device *priv_dev = priv_ep->cdns3_dev; >> + >> +return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), >> + priv_ep->name); >> +} >> + >> +char *cdns3_decode_ep0_irq(struct cdns3_device *priv_dev, int dir) >> +{ >> +if (dir) >> +return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), >> + "ep0IN"); >> +else >> +return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), >> + "ep0OUT"); >> +} >> + >[] >> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c >[] >> @@ -604,12 +604,15 @@ void cdns3_check_ep0_interrupt_proceed(struct >> cdns3_device *priv_dev, int dir) >> cdns3_select_ep(priv_dev, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT)); >> ep_sts_reg = readl(®s->ep_sts); >> >> +dev_dbg(&priv_dev->dev, "%s\n", cdns3_decode_ep0_irq(priv_dev, dir)); >[] >> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c >[] >> @@ -537,6 +547,8 @@ static int cdns3_check_ep_interrupt_proceed(struct >> cdns3_endpoint *priv_ep) >> cdns3_select_ep(priv_dev, priv_ep->endpoint.address); >> ep_sts_reg = readl(®s->ep_sts); >> >> +dev_dbg(&priv_dev->dev, "%s\n", cdns3_decode_epx_irq(priv_ep)); >> Thank you for comment. Cheers Pawel
RE: [RFC PATCH v1 01/14] usb:cdns3: add pci to platform driver wrapper.
Hi Roger, > >Hi Pawel, > >On 03/11/18 19:51, Pawel Laszczak wrote: >> Patch adds PCI specific glue drivier that creaties and registers in > >s/drivier/driver >s/creaties/creates >s/in system/in-system > >> system cdns-usb3 platform device. Thanks to that we will be able to use >> the cdns-usb3 platform driver for USBSS-DEV controller >> build on PCI board >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/Kconfig| 2 + >> drivers/usb/Makefile | 2 + >> drivers/usb/cdns3/Kconfig | 24 + >> drivers/usb/cdns3/Makefile | 3 + >> drivers/usb/cdns3/cdns3-pci-wrap.c | 162 + >> 5 files changed, 193 insertions(+) >> create mode 100644 drivers/usb/cdns3/Kconfig >> create mode 100644 drivers/usb/cdns3/Makefile >> create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c >> >> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig >> index 987fc5ba6321..5f9334019d04 100644 >> --- a/drivers/usb/Kconfig >> +++ b/drivers/usb/Kconfig >> @@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig" >> >> endif >> >> +source "drivers/usb/cdns3/Kconfig" >> + >> source "drivers/usb/mtu3/Kconfig" >> >> source "drivers/usb/musb/Kconfig" >> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile >> index 7d1b8c82b208..82093a60ea2c 100644 >> --- a/drivers/usb/Makefile >> +++ b/drivers/usb/Makefile >> @@ -8,6 +8,8 @@ >> obj-$(CONFIG_USB) += core/ >> obj-$(CONFIG_USB_SUPPORT) += phy/ >> >> +obj-$(CONFIG_USB_CDNS3) += cdns3/ >> + >> obj-$(CONFIG_USB_DWC3) += dwc3/ >> obj-$(CONFIG_USB_DWC2) += dwc2/ >> obj-$(CONFIG_USB_ISP1760) += isp1760/ >> diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig >> new file mode 100644 >> index ..888458372adb >> --- /dev/null >> +++ b/drivers/usb/cdns3/Kconfig >> @@ -0,0 +1,24 @@ >> +config USB_CDNS3 >> +tristate "Cadence USB3 Dual-Role Controller" >> +depends on ((USB_XHCI_HCD && USB_GADGET) || (USB_XHCI_HCD && >> !USB_GADGET) || (!USB_XHCI_HCD && USB_GADGET)) && >HAS_DMA > >Why not depend on USB instead of USB_XHCI_HCD? I will replace it with this: Depend on USB_SUPPORT && (USB l| USB_GADGET) && HAS_DMA >> +help >> + Say Y here if your system has a cadence USB3 dual-role controller. >> + It supports: dual-role switch Host-only, and Peripheral-only. > >Need a coma between switch and Host-only. > >> + >> + If you choose to build this driver is a dynamically linked >> + module, the module will be called cdns3.ko. >> + >> +if USB_CDNS3 >> + >> +config USB_CDNS3_PCI_WRAP >> +tristate "PCIe-based Platforms" >> +depends on USB_PCI && ACPI >> +default USB_CDNS3 >> +help >> + If you're using the USBSS Core IP with a PCIe, please say >> + 'Y' or 'M' here. >> + >> + If you choose to build this driver as module it will >> + be dynamically linked and module will be called cdns3-pci.ko >> + >> +endif >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> new file mode 100644 >> index ..dcdd62003c6a >> --- /dev/null >> +++ b/drivers/usb/cdns3/Makefile >> @@ -0,0 +1,3 @@ >> +obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> + >> +cdns3-pci-y := cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c >> b/drivers/usb/cdns3/cdns3-pci-wrap.c >> new file mode 100644 >> index ..6c229ab6dffb >> --- /dev/null >> +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c >> @@ -0,0 +1,162 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Cadence USBSS PCI Glue driver >> + * >> + * Copyright (C) 2018 Cadence. >> + * >> + * Author: Pawel Laszczak >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +struct cdns3_wrap { >> +struct platform_device *plat_dev; >> +struct pci_dev *hg_dev; >> +struct resource dev_res[4]; >> +}; >> + >> +struct cdns3_wrap wrap; >> + >> +#define RES_IRQ_ID 0 >> +#define RES_HOST_ID 1 >> +#define RES_DEV_ID
RE: [RFC PATCH v1 03/14] usb:cdns3: Driver initialization code.
>On 03/11/18 19:51, Pawel Laszczak wrote: >> Patch adds core.c and core.h file that implements initialization >> of platform driver and adds function responsible for selecting, >> switching and running appropriate Device/Host mode. >> >> Patch also adds gadget.c, host.c, gadget-export.h, host-export.h. >> These files contains templates functions used during initialization. >> The implementation will be added in next patches. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Kconfig | 20 ++ >> drivers/usb/cdns3/Makefile| 4 + >> drivers/usb/cdns3/core.c | 373 ++ >> drivers/usb/cdns3/core.h | 88 +++ >> drivers/usb/cdns3/gadget-export.h | 27 +++ >> drivers/usb/cdns3/gadget.c| 36 +++ >> drivers/usb/cdns3/host-export.h | 30 +++ >> drivers/usb/cdns3/host.c | 28 +++ >> 8 files changed, 606 insertions(+) >> create mode 100644 drivers/usb/cdns3/core.c >> create mode 100644 drivers/usb/cdns3/core.h >> create mode 100644 drivers/usb/cdns3/gadget-export.h >> create mode 100644 drivers/usb/cdns3/gadget.c >> create mode 100644 drivers/usb/cdns3/host-export.h >> create mode 100644 drivers/usb/cdns3/host.c >> >> diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig >> index 888458372adb..5f88a4932e58 100644 >> --- a/drivers/usb/cdns3/Kconfig >> +++ b/drivers/usb/cdns3/Kconfig >> @@ -10,6 +10,26 @@ config USB_CDNS3 >> >> if USB_CDNS3 >> >> +config USB_CDNS3_GADGET >> +bool "Cadence USB3 device controller" >> +depends on USB_GADGET >> +help >> + Say Y here to enable device controller functionality of the >> + cadence USBSS-DEV driver. >> + >> + This controller support FF, HS and SS mode. It doeasn't support >> + LS and SSP mode >> + >> +config USB_CDNS3_HOST >> +bool "Cadence USB3 host controller" >> +depends on USB_XHCI_HCD >> +help >> + Say Y here to enable host controller functionality of the >> + cadence driver. >> + >> + Host controller is compliance with XHCI so it will use >> + standard XHCI driver. >> + > >Is it better to split this patch into 3 parts? >1) host support >2) gadget support >3) DRD support (along with patch 4) Currently we have: 0003-usb-cdns3-Driver-initialization-code.patch - generic initialization common code. I agree that some fragment could be moved to next free patches. It could improve understanding of code. 0004-usb-cdns3-Added-DRD-support.patch - it's short file so contains initialization and other related to DRD function. 0005-usb-cdns3-Added-Wrapper-to-XCHI-driver.patch - host support - quite short patch 0006-usb-cdns3-Initialization-code-for-Device-side - device initialization > >> config USB_CDNS3_PCI_WRAP >> tristate "PCIe-based Platforms" >> depends on USB_PCI && ACPI >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index dcdd62003c6a..083676c7748f 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -1,3 +1,7 @@ >> +obj-$(CONFIG_USB_CDNS3) += cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> >> +cdns3-y := core.o >> +cdns3-$(CONFIG_USB_CDNS3_GADGET)+= gadget.o >> +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o >> cdns3-pci-y := cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> new file mode 100644 >> index ..727136235957 >> --- /dev/null >> +++ b/drivers/usb/cdns3/core.c >> @@ -0,0 +1,373 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Cadence USBSS DRD Driver. >> + * >> + * Copyright (C) 2018 Cadence. >> + * >> + * Author: Peter Chen >> + * Pawel Laszczak >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "gadget.h" >> +#include "core.h" >> +#include "host-export.h" >> +#include "gadget-export.h" >> + >> +static inline struct cdns3_role_driver *cdns3_role(struct cdns3 *cdns) > >how about naming this to cnds3_get_current_role_driver() ? It's better. I've changed it. > >> +{ >> +WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); >> +
RE: [RFC PATCH v1 04/14] usb:cdns3: Added DRD support
Hi Roger, >On 03/11/18 19:51, Pawel Laszczak wrote: >> Patch adds supports for detecting Host/Device mode. >> Controller has additional OTG register that allow >> implement even whole OTG functionality. >> At this moment patch adds support only for detecting >> the appropriate mode based on strap pins and ID pin. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Makefile | 2 +- >> drivers/usb/cdns3/core.c | 22 ++-- >> drivers/usb/cdns3/drd.c| 219 + >> drivers/usb/cdns3/drd.h| 122 + >> 4 files changed, 356 insertions(+), 9 deletions(-) >> create mode 100644 drivers/usb/cdns3/drd.c >> create mode 100644 drivers/usb/cdns3/drd.h >> >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index 083676c7748f..d4ccfb49d844 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -1,7 +1,7 @@ >> obj-$(CONFIG_USB_CDNS3) += cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> >> -cdns3-y := core.o >> +cdns3-y := core.o drd.o >> cdns3-$(CONFIG_USB_CDNS3_GADGET)+= gadget.o >> cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o >> cdns3-pci-y := cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> index 727136235957..20ae9e76940e 100644 >> --- a/drivers/usb/cdns3/core.c >> +++ b/drivers/usb/cdns3/core.c >> @@ -18,6 +18,7 @@ >> #include "core.h" >> #include "host-export.h" >> #include "gadget-export.h" >> +#include "drd.h" >> >> static inline struct cdns3_role_driver *cdns3_role(struct cdns3 *cdns) >> { >> @@ -70,8 +71,10 @@ static void cdns3_set_role(struct cdns3 *cdns, enum >> cdns3_roles role) >> static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >> { >> if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >> -//TODO: implements selecting device/host mode >> -return CDNS3_ROLE_HOST; >> +if (cdns3_is_host(cdns)) >> +return CDNS3_ROLE_HOST; >> +if (cdns3_is_device(cdns)) >> +return CDNS3_ROLE_GADGET; >> } >> return cdns->roles[CDNS3_ROLE_HOST] >> ? CDNS3_ROLE_HOST >> @@ -141,6 +144,12 @@ static irqreturn_t cdns3_irq(int irq, void *data) >> return IRQ_HANDLED; >> } >> >> +if (cdns->dr_mode == USB_DR_MODE_OTG) { >> +ret = cdns3_drd_irq(cdns); >> +if (ret == IRQ_HANDLED) >> +return ret; >> +} >> + >> /* Handle device/host interrupt */ >> if (cdns->role != CDNS3_ROLE_END) >> ret = cdns3_role(cdns)->irq(cdns); >> @@ -202,12 +211,8 @@ static void cdns3_role_switch(struct work_struct *work) >> bool device, host; >> >> cdns = container_of(work, struct cdns3, role_switch_wq); >> - >> -//TODO: implements this functions. >> -//host = cdns3_is_host(cdns); >> -//device = cdns3_is_device(cdns); >> -host = 1; >> -device = 0; >> +host = cdns3_is_host(cdns); >> +device = cdns3_is_device(cdns); >> >> if (host) { >> if (cdns->roles[CDNS3_ROLE_HOST]) >> @@ -286,6 +291,7 @@ static int cdns3_probe(struct platform_device *pdev) >> if (ret) >> goto err3; >> >> +ret = cdns3_drd_probe(cdns); >> if (ret) >> goto err3; >> >> diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c >> new file mode 100644 >> index ..5d988432edb8 >> --- /dev/null >> +++ b/drivers/usb/cdns3/drd.c >> @@ -0,0 +1,219 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Cadence USBSS DRD Driver. >> + * >> + * Copyright (C) 2018 Cadence. >> + * >> + * Author: Pawel Laszczak > + * >> + */ >> +#include >> +#include >> +#include >> +#include >> + >> +#include "gadget.h" >> +#include "drd.h" >> + >> +/** >> + * cdns3_set_mode - change mode of OTG Core >> + * @cdns: pointer to context structure >> + * @mode: selected mode from cdns_role >> + */ >> +void cdns3_set_mode(struct cdns3 *cdns, u32 mode) >> +{ >>
RE: [RFC PATCH v1 03/14] usb:cdns3: Driver initialization code.
>On 03/11/18 19:51, Pawel Laszczak wrote: >> Patch adds core.c and core.h file that implements initialization >> of platform driver and adds function responsible for selecting, >> switching and running appropriate Device/Host mode. >> >> Patch also adds gadget.c, host.c, gadget-export.h, host-export.h. >> These files contains templates functions used during initialization. >> The implementation will be added in next patches. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Kconfig | 20 ++ >> drivers/usb/cdns3/Makefile| 4 + >> drivers/usb/cdns3/core.c | 373 ++ >> drivers/usb/cdns3/core.h | 88 +++ >> drivers/usb/cdns3/gadget-export.h | 27 +++ >> drivers/usb/cdns3/gadget.c| 36 +++ >> drivers/usb/cdns3/host-export.h | 30 +++ >> drivers/usb/cdns3/host.c | 28 +++ >> 8 files changed, 606 insertions(+) >> create mode 100644 drivers/usb/cdns3/core.c >> create mode 100644 drivers/usb/cdns3/core.h >> create mode 100644 drivers/usb/cdns3/gadget-export.h >> create mode 100644 drivers/usb/cdns3/gadget.c >> create mode 100644 drivers/usb/cdns3/host-export.h >> create mode 100644 drivers/usb/cdns3/host.c >> > > > > >> diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h >> new file mode 100644 >> index ..e7159c474308 >> --- /dev/null >> +++ b/drivers/usb/cdns3/core.h >> @@ -0,0 +1,88 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Cadence USBSS DRD Driver. >> + * >> + * Copyright (C) 2017 NXP >> + * Copyright (C) 2018 Cadence. >> + * >> + * Authors: Peter Chen >> + * Pawel Laszczak >> + */ >> +#include >> + >> +#ifndef __LINUX_CDNS3_CORE_H >> +#define __LINUX_CDNS3_CORE_H >> + >> +struct cdns3; >> +enum cdns3_roles { >> +CDNS3_ROLE_HOST = 0, >> +CDNS3_ROLE_GADGET, >> +CDNS3_ROLE_END, >> +CDNS3_ROLE_OTG, >> +}; >> + >> +/** >> + * struct cdns3_role_driver - host/gadget role driver >> + * @start: start this role >> + * @stop: stop this role >> + * @suspend: suspend callback for this role >> + * @resume: resume callback for this role >> + * @irq: irq handler for this role >> + * @name: role name string (host/gadget) >> + */ >> +struct cdns3_role_driver { >> +int (*start)(struct cdns3 *cdns); >> +void (*stop)(struct cdns3 *cdns); >> +int (*suspend)(struct cdns3 *cdns, bool do_wakeup); >> +int (*resume)(struct cdns3 *cdns, bool hibernated); >> +irqreturn_t (*irq)(struct cdns3 *cdns); > >Why does role driver need hook to irq handler? > >Can't each driver host or gadget handle it's respective irq >on its own? If the same IRQ line is used it could be requested >as a shared IRQ. When controller is working as Device then host part of controller is held in reset and vice versa, so driver has restricted access to registers. >> +const char *name; >> +}; >> + > >cheers, >-roger > >-- >Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. >Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki Thanks, Cheers, Pawel Laszczak
RE: [RFC PATCH v1 14/14] usb:cdns3: Feature for changing role
>On 03/11/18 19:51, Pawel Laszczak wrote: >> Patch adds feature that allow to change role from user space. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Makefile | 2 +- >> drivers/usb/cdns3/core.c| 2 + >> drivers/usb/cdns3/debugfs.c | 94 + >> drivers/usb/cdns3/drd.h | 3 ++ >> 4 files changed, 100 insertions(+), 1 deletion(-) >> create mode 100644 drivers/usb/cdns3/debugfs.c >> >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index 34e60d03c4ec..08e6cdbebd46 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -1,7 +1,7 @@ >> obj-$(CONFIG_USB_CDNS3) += cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> >> -cdns3-y := core.o drd.o >> +cdns3-y := core.o drd.o debugfs.o >> cdns3-$(CONFIG_USB_CDNS3_GADGET)+= gadget.o ep0.o debug.o >> cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o >> cdns3-pci-y := cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> index 20ae9e76940e..4012f1007da9 100644 >> --- a/drivers/usb/cdns3/core.c >> +++ b/drivers/usb/cdns3/core.c >> @@ -309,6 +309,7 @@ static int cdns3_probe(struct platform_device *pdev) >> if (ret) >> goto err4; >> >> +cdns3_debugfs_init(cdns); >> device_set_wakeup_capable(dev, true); >> pm_runtime_set_active(dev); >> pm_runtime_enable(dev); >> @@ -346,6 +347,7 @@ static int cdns3_remove(struct platform_device *pdev) >> pm_runtime_get_sync(&pdev->dev); >> pm_runtime_disable(&pdev->dev); >> pm_runtime_put_noidle(&pdev->dev); >> +cdns3_debugfs_exit(cdns); >> cdns3_remove_roles(cdns); >> usb_phy_shutdown(cdns->usbphy); >> >> diff --git a/drivers/usb/cdns3/debugfs.c b/drivers/usb/cdns3/debugfs.c >> new file mode 100644 >> index ..d4871bc1a69d >> --- /dev/null >> +++ b/drivers/usb/cdns3/debugfs.c >> @@ -0,0 +1,94 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Cadence USBSS DRD Controller DebugFS filer. >> + * >> + * Copyright (C) 2018 Cadence. >> + * >> + * Author: Pawel Laszczak >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> + >> +#include "core.h" >> +#include "gadget.h" >> + >> +static int cdns3_mode_show(struct seq_file *s, void *unused) >> +{ >> +struct cdns3*cdns = s->private; >> + >> +switch (cdns->role) { >> +case CDNS3_ROLE_HOST: >> +seq_puts(s, "host\n"); >> +break; >> +case CDNS3_ROLE_GADGET: >> +seq_puts(s, "device\n"); >> +break; >> +case CDNS3_ROLE_OTG: >> +case CDNS3_ROLE_END: >> +seq_puts(s, "otg\n"); >> +break; >> +default: >> +seq_puts(s, "UNKNOWN mode\n"); >> +} >> + >> +return 0; >> +} >> + >> +static int cdns3_mode_open(struct inode *inode, struct file *file) >> +{ >> +return single_open(file, cdns3_mode_show, inode->i_private); >> +} >> + >> +static ssize_t cdns3_mode_write(struct file *file, >> +const char __user *ubuf, >> +size_t count, loff_t *ppos) >> +{ >> +struct seq_file *s = file->private_data; >> +struct cdns3*cdns = s->private; >> +u32 mode = 0; >> +charbuf[32]; >> + >> +if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) >> +return -EFAULT; >> + >> +if (!strncmp(buf, "host", 4)) >> +mode = USB_DR_MODE_HOST; >> + >> +if (!strncmp(buf, "device", 6)) >> +mode = USB_DR_MODE_PERIPHERAL; >> + >> +if (!strncmp(buf, "otg", 3)) >> +mode = USB_DR_MODE_OTG; >> + >> +cdns->desired_role = mode; >> +queue_work(system_freezable_wq, &cdns->role_switch_wq); > >If we start with OTG mode and user says change mode to device will we still >switch to host based on ID pin change? > >If it does then this isn't working correctly. >We need
RE: [RFC PATCH v1 13/14] usb:cdns3: Adds debugging function.
>Hi, > >On 03/11/18 19:51, Pawel Laszczak wrote: >> Patch implements some function used for debugging driver. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Makefile | 2 +- >> drivers/usb/cdns3/debug.c | 128 + >> drivers/usb/cdns3/ep0.c| 3 + >> drivers/usb/cdns3/gadget.c | 12 >> drivers/usb/cdns3/gadget.h | 13 +++- >> 5 files changed, 156 insertions(+), 2 deletions(-) >> create mode 100644 drivers/usb/cdns3/debug.c >> >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index f4cfc978626f..34e60d03c4ec 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -2,6 +2,6 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> >> cdns3-y := core.o drd.o >> -cdns3-$(CONFIG_USB_CDNS3_GADGET)+= gadget.o ep0.o >> +cdns3-$(CONFIG_USB_CDNS3_GADGET)+= gadget.o ep0.o debug.o >> cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o >> cdns3-pci-y := cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/debug.c b/drivers/usb/cdns3/debug.c >> new file mode 100644 >> index ..bebf22c4d18e >> --- /dev/null >> +++ b/drivers/usb/cdns3/debug.c >> @@ -0,0 +1,128 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Cadence USBSS DRD Driver. >> + * >> + * Copyright (C) 2018 Cadence. >> + * >> + * Author: Pawel Laszczak >> + */ >> + >> +#include "gadget.h" >> + >> +static inline char *cdns3_decode_ep_irq(u32 ep_sts, const char *ep_name) >> +{ >> +static char str[256]; >> +int ret; >> + >> +ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts); >> + >> +if (ep_sts & EP_STS_SETUP) >> +ret += sprintf(str + ret, "SETUP "); >> +if (ep_sts & EP_STS_IOC) >> +ret += sprintf(str + ret, "IOC "); >> +if (ep_sts & EP_STS_ISP) >> +ret += sprintf(str + ret, "ISP "); >> +if (ep_sts & EP_STS_DESCMIS) >> +ret += sprintf(str + ret, "DESCMIS "); >> +if (ep_sts & EP_STS_STREAMR) >> +ret += sprintf(str + ret, "STREAMR "); >> +if (ep_sts & EP_STS_MD_EXIT) >> +ret += sprintf(str + ret, "MD_EXIT "); >> +if (ep_sts & EP_STS_TRBERR) >> +ret += sprintf(str + ret, "TRBERR "); >> +if (ep_sts & EP_STS_NRDY) >> +ret += sprintf(str + ret, "NRDY "); >> +if (ep_sts & EP_STS_PRIME) >> +ret += sprintf(str + ret, "PRIME "); >> +if (ep_sts & EP_STS_SIDERR) >> +ret += sprintf(str + ret, "SIDERRT "); >> +if (ep_sts & EP_STS_OUTSMM) >> +ret += sprintf(str + ret, "OUTSMM "); >> +if (ep_sts & EP_STS_ISOERR) >> +ret += sprintf(str + ret, "ISOERR "); >> +if (ep_sts & EP_STS_IOT) >> +ret += sprintf(str + ret, "IOT "); >> + >> +return str; >> +} >> + >> +char *cdns3_decode_epx_irq(struct cdns3_endpoint *priv_ep) >> +{ >> +struct cdns3_device *priv_dev = priv_ep->cdns3_dev; >> + >> +return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), >> + priv_ep->name); >> +} >> + >> +char *cdns3_decode_ep0_irq(struct cdns3_device *priv_dev, int dir) >> +{ >> +if (dir) >> +return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), >> + "ep0IN"); >> +else >> +return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), >> + "ep0OUT"); >> +} >> + >> +void cdns3_dbg_setup(struct cdns3_device *priv_dev) >> +{ >> +struct usb_ctrlrequest *setup = priv_dev->setup; >> + >> +dev_dbg(&priv_dev->dev, >> +"SETUP BRT: %02x BR: %02x V: %04x I: %04x L: %04x\n", >> +setup->bRequestType, >> +setup->bRequest, >> +le16_to_cpu(setup->wValue), >> +le16_to_cpu(setup->wIndex), >> +le16_to_cpu(setup->wLength)); >> +} >> + >> +/** >> + * Debug a tran
[RFC PATCH v2 09/15] usb:cdns3: EpX operations part of the API
Patch implements callback functions for non-default endpoints defined in usb_ep_ops object. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/ep0.c| 18 ++ drivers/usb/cdns3/gadget.c | 442 - drivers/usb/cdns3/gadget.h | 3 + 3 files changed, 461 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index c08d02665f9d..ca1795467155 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -23,6 +23,24 @@ static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) //TODO: Implements this function } +/** + * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint + * @ep: endpoint object + * + * Returns 0 + */ +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + dev_dbg(&priv_dev->dev, "Wedge for %s\n", ep->name); + cdns3_gadget_ep_set_halt(ep, 1); + priv_ep->flags |= EP_WEDGE; + + return 0; +} + /** * cdns3_ep0_config - Configures default endpoint * @priv_dev: extended gadget object diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 702a05faa664..1f2a434486dc 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -58,6 +58,19 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask) writel(mask, ptr); } +/** + * cdns3_next_request - returns next request from list + * @list: list containing requests + * + * Returns request or NULL if no requests in list + */ +struct usb_request *cdns3_next_request(struct list_head *list) +{ + if (list_empty(list)) + return NULL; + return list_first_entry(list, struct usb_request, list); +} + /** * select_ep - selects endpoint * @priv_dev: extended gadget object @@ -73,6 +86,53 @@ void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) writel(ep, &priv_dev->regs->ep_sel); } +/** + * cdns3_allocate_trb_pool - Allocates TRB's pool for selected endpoint + * @priv_ep: endpoint object + * + * Function will return 0 on success or -ENOMEM on allocation error + */ +static int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_trb *link_trb; + + if (!priv_ep->trb_pool) { + priv_ep->trb_pool = dma_zalloc_coherent(priv_dev->sysdev, + TRB_RIGN_SIZE, + &priv_ep->trb_pool_dma, + GFP_DMA); + if (!priv_ep->trb_pool) + return -ENOMEM; + } else { + memset(priv_ep->trb_pool, 0, TRB_RIGN_SIZE); + } + + if (!priv_ep->aligned_buff) { + priv_ep->aligned_buff = dma_alloc_coherent(priv_dev->sysdev, + CDNS3_UNALIGNED_BUF_SIZE, + &priv_ep->aligned_dma_addr, + GFP_DMA); + if (!priv_ep->aligned_buff) { + dma_free_coherent(priv_dev->sysdev, + TRB_RIGN_SIZE, + priv_ep->trb_pool, + priv_ep->trb_pool_dma); + priv_ep->trb_pool = NULL; + + return -ENOMEM; + } + } + + /* Initialize the last TRB as Link TRB */ + link_trb = (priv_ep->trb_pool + TRBS_PER_SEGMENT - 1); + link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma); + link_trb->control = TRB_CYCLE | TRB_TYPE(TRB_LINK) | + TRB_CHAIN | TRB_TOGGLE; + + return 0; +} + static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) { struct cdns3_device *priv_dev = priv_ep->cdns3_dev; @@ -92,6 +152,73 @@ static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) } } +/** + * cdns3_data_flush - flush data at onchip buffer + * @priv_ep: endpoint object + * + * Endpoint must be selected before call to this function + * + * Returns zero on success or negative value on failure + */ +static int cdns3_data_flush(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd); + + /* wait for DFLUSH cleared */ + return cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); +} + +/** + * cdns3_ep_stall_flush - Stalls and flushes selected endpoint + * @priv_ep: endpoint object + * + * Endpoint must be selected before call to this functi
[RFC PATCH v2 00/15] Introduced new Cadence USBSS DRD Driver
This patch set introduce new Cadence USBSS DRD driver to linux kernel. The Cadence USBSS DRD Driver s a highly configurable IP Core which can be instantiated as Dual-Role Device (DRD), Peripheral Only and Host Only (XHCI) configurations. The current driver has been validated with FPGA burned. We have support for PCIe bus, which is used on FPGA prototyping. The host site of USBSS controller is compliance with XHCI specification, so it works with standard XHCI linux driver. Changes since v1: - Reorganize patch 3, 5, 6 as suggested by Roger Quadros. - Remove inline in debug.c file according with Joe Perches suggestion. - Fix condition with no effect in drd.c file. - Remove compiler warning generated by sh4-linux-gnu-gcc. - Fix bug with xhci_suspend/resume undefined, that appeared for PM disabled. - Add CONFIG_OF support in core.c file and dt-binding documentation. - Add template function related to CONFIG_PM configuration option. - Fix bug: CONFIG_USB_CDNS3_DEVICE instead of CONFIG_USB_CDNS3_ - Correct depend on condition in Kconfig as suggested by Roger Quadros. - Remove Config options from cdns3_pci_wrap.c as suggested by Roger Quadros. - Replace dev_info with dev_dbg in cdns3_pci_wrap.c file as suggested by Roger. - Change cdns3_role to cnds3_get_current_role_driver as suggested by Roger. - Addressed other review comments from Roger. - Fix issues with ENABLE_U1/U2 Set/Clear_Fature request. - Fix issues with Cycle State bit. - Some other minor code changes related to readability. TODO: - Test isochronous transfer with some class or tester. - Test changing role according to ID pin. - Resolve issue related with shared on-chip buffer for OUT direction. - Add tracepoint. - Implement suspend/resume functionality. --- Pawel Laszczak (15): usb:cdns3: add pci to platform driver wrapper. usb:cdns3: Device side header file. dt-bindings: add binding for USBSS-DRD controller. usb:cdns3: Driver initialization code. usb:cdns3: Added DRD support usb:cdns3: Adds Host support usb:cdns3: Adds Device mode support - initialization. usb:cdns3: Implements device operations part of the API usb:cdns3: EpX operations part of the API usb:cdns3: Ep0 operations part of the API usb:cdns3: Implements ISR functionality. usb:cdns3: Adds enumeration related function. usb:cdns3: Adds transfer related function. usb:cdns3: Adds debugging function. usb:cdns3: Feature for changing role .../devicetree/bindings/usb/cdns3-usb.txt | 17 + drivers/usb/Kconfig |2 + drivers/usb/Makefile |2 + drivers/usb/cdns3/Kconfig | 44 + drivers/usb/cdns3/Makefile|7 + drivers/usb/cdns3/cdns3-pci-wrap.c| 157 ++ drivers/usb/cdns3/core.c | 434 + drivers/usb/cdns3/core.h | 100 + drivers/usb/cdns3/debug.c | 128 ++ drivers/usb/cdns3/debugfs.c | 93 + drivers/usb/cdns3/drd.c | 229 +++ drivers/usb/cdns3/drd.h | 125 ++ drivers/usb/cdns3/ep0.c | 859 + drivers/usb/cdns3/gadget-export.h | 27 + drivers/usb/cdns3/gadget.c| 1665 + drivers/usb/cdns3/gadget.h| 1104 +++ drivers/usb/cdns3/host-export.h | 30 + drivers/usb/cdns3/host.c | 256 +++ 18 files changed, 5279 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/cdns3-usb.txt create mode 100644 drivers/usb/cdns3/Kconfig create mode 100644 drivers/usb/cdns3/Makefile create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c create mode 100644 drivers/usb/cdns3/core.c create mode 100644 drivers/usb/cdns3/core.h create mode 100644 drivers/usb/cdns3/debug.c create mode 100644 drivers/usb/cdns3/debugfs.c create mode 100644 drivers/usb/cdns3/drd.c create mode 100644 drivers/usb/cdns3/drd.h create mode 100644 drivers/usb/cdns3/ep0.c create mode 100644 drivers/usb/cdns3/gadget-export.h create mode 100644 drivers/usb/cdns3/gadget.c create mode 100644 drivers/usb/cdns3/gadget.h create mode 100644 drivers/usb/cdns3/host-export.h create mode 100644 drivers/usb/cdns3/host.c -- 2.17.1
[RFC PATCH v2 14/15] usb:cdns3: Adds debugging function.
Patch implements some function used for debugging driver. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Makefile | 4 +- drivers/usb/cdns3/debug.c | 128 + drivers/usb/cdns3/ep0.c| 3 + drivers/usb/cdns3/gadget.c | 12 drivers/usb/cdns3/gadget.h | 13 +++- 5 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 drivers/usb/cdns3/debug.c diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index bea6173bf37f..34e60d03c4ec 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -2,6 +2,6 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o cdns3-y:= core.o drd.o -cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o -cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o debug.o +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/debug.c b/drivers/usb/cdns3/debug.c new file mode 100644 index ..b9a779b35789 --- /dev/null +++ b/drivers/usb/cdns3/debug.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include "gadget.h" + +static char *cdns3_decode_ep_irq(u32 ep_sts, const char *ep_name) +{ + static char str[256]; + int ret; + + ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts); + + if (ep_sts & EP_STS_SETUP) + ret += sprintf(str + ret, "SETUP "); + if (ep_sts & EP_STS_IOC) + ret += sprintf(str + ret, "IOC "); + if (ep_sts & EP_STS_ISP) + ret += sprintf(str + ret, "ISP "); + if (ep_sts & EP_STS_DESCMIS) + ret += sprintf(str + ret, "DESCMIS "); + if (ep_sts & EP_STS_STREAMR) + ret += sprintf(str + ret, "STREAMR "); + if (ep_sts & EP_STS_MD_EXIT) + ret += sprintf(str + ret, "MD_EXIT "); + if (ep_sts & EP_STS_TRBERR) + ret += sprintf(str + ret, "TRBERR "); + if (ep_sts & EP_STS_NRDY) + ret += sprintf(str + ret, "NRDY "); + if (ep_sts & EP_STS_PRIME) + ret += sprintf(str + ret, "PRIME "); + if (ep_sts & EP_STS_SIDERR) + ret += sprintf(str + ret, "SIDERRT "); + if (ep_sts & EP_STS_OUTSMM) + ret += sprintf(str + ret, "OUTSMM "); + if (ep_sts & EP_STS_ISOERR) + ret += sprintf(str + ret, "ISOERR "); + if (ep_sts & EP_STS_IOT) + ret += sprintf(str + ret, "IOT "); + + return str; +} + +char *cdns3_decode_epx_irq(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + priv_ep->name); +} + +char *cdns3_decode_ep0_irq(struct cdns3_device *priv_dev, int dir) +{ + if (dir) + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + "ep0IN"); + else + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + "ep0OUT"); +} + +void cdns3_dbg_setup(struct cdns3_device *priv_dev) +{ + struct usb_ctrlrequest *setup = priv_dev->setup; + + dev_dbg(&priv_dev->dev, + "SETUP BRT: %02x BR: %02x V: %04x I: %04x L: %04x\n", + setup->bRequestType, + setup->bRequest, + le16_to_cpu(setup->wValue), + le16_to_cpu(setup->wIndex), + le16_to_cpu(setup->wLength)); +} + +/** + * Debug a transfer ring. + * + * Prints out all TRBs in the endpoint ring, even those after the Link TRB. + *. + */ +void cdns3_dbg_ring(struct cdns3_device *priv_dev, + struct cdns3_endpoint *priv_ep) +{ + u64 addr = priv_ep->trb_pool_dma; + struct cdns3_trb *trb; + int i; + + for (i = 0; i < TRBS_PER_SEGMENT; ++i) { + trb = &priv_ep->trb_pool[i]; + dev_dbg(&priv_dev->dev, "@%016llx %08x %08x %08x\n", addr, + le32_to_cpu(trb->buffer), + le32_to_cpu(trb->length), + le32_to_cpu(trb->control)); + addr += sizeof(*trb); + } +} + +void cdns3_dbg_ring_ptrs(struct cdns3_device *priv_dev, +struct cdns3_endpoint *priv_ep) +{ + struct cdns
[RFC PATCH v2 05/15] usb:cdns3: Added DRD support
Patch adds supports for detecting Host/Device mode. Controller has additional OTG register that allow implement even whole OTG functionality. At this moment patch adds support only for detecting the appropriate mode based on strap pins and ID pin. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Makefile | 2 +- drivers/usb/cdns3/core.c | 27 +++-- drivers/usb/cdns3/drd.c| 229 + drivers/usb/cdns3/drd.h| 122 4 files changed, 372 insertions(+), 8 deletions(-) create mode 100644 drivers/usb/cdns3/drd.c create mode 100644 drivers/usb/cdns3/drd.h diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index 02d25b23c5d3..e779b2a2f8eb 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_USB_CDNS3)+= cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o -cdns3-y:= core.o +cdns3-y:= core.o drd.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index f9055d4da67f..dbee4325da7f 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -17,6 +17,7 @@ #include "gadget.h" #include "core.h" +#include "drd.h" static inline struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) { @@ -57,8 +58,10 @@ static inline void cdns3_role_stop(struct cdns3 *cdns) static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) { if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { - //TODO: implements selecting device/host mode - return CDNS3_ROLE_HOST; + if (cdns3_is_host(cdns)) + return CDNS3_ROLE_HOST; + if (cdns3_is_device(cdns)) + return CDNS3_ROLE_GADGET; } return cdns->roles[CDNS3_ROLE_HOST] ? CDNS3_ROLE_HOST @@ -124,6 +127,12 @@ static irqreturn_t cdns3_irq(int irq, void *data) struct cdns3 *cdns = data; irqreturn_t ret = IRQ_NONE; + if (cdns->dr_mode == USB_DR_MODE_OTG) { + ret = cdns3_drd_irq(cdns); + if (ret == IRQ_HANDLED) + return ret; + } + /* Handle device/host interrupt */ if (cdns->role != CDNS3_ROLE_END) ret = cdns3_get_current_role_driver(cdns)->irq(cdns); @@ -176,11 +185,8 @@ static void cdns3_role_switch(struct work_struct *work) cdns = container_of(work, struct cdns3, role_switch_wq); - //TODO: implements this functions. - //host = cdns3_is_host(cdns); - //device = cdns3_is_device(cdns); - host = 1; - device = 0; + host = cdns3_is_host(cdns); + device = cdns3_is_device(cdns); if (host) role = CDNS3_ROLE_HOST; @@ -194,6 +200,12 @@ static void cdns3_role_switch(struct work_struct *work) pm_runtime_get_sync(cdns->dev); cdns3_role_stop(cdns); + if (cdns->desired_dr_mode != cdns->current_dr_mode) { + cdns3_drd_update_mode(cdns); + host = cdns3_is_host(cdns); + device = cdns3_is_device(cdns); + } + if (host) { if (cdns->roles[CDNS3_ROLE_HOST]) cdns3_do_role_switch(cdns, CDNS3_ROLE_HOST); @@ -287,6 +299,7 @@ static int cdns3_probe(struct platform_device *pdev) if (ret) goto err2; + ret = cdns3_drd_init(cdns); if (ret) goto err2; diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c new file mode 100644 index ..ac741c80e776 --- /dev/null +++ b/drivers/usb/cdns3/drd.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak +#include +#include +#include + +#include "gadget.h" +#include "drd.h" + +/** + * cdns3_set_mode - change mode of OTG Core + * @cdns: pointer to context structure + * @mode: selected mode from cdns_role + */ +void cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode) +{ + u32 reg; + + cdns->current_dr_mode = mode; + switch (mode) { + case USB_DR_MODE_PERIPHERAL: + dev_info(cdns->dev, "Set controller to Gadget mode\n"); + writel(OTGCMD_DEV_BUS_REQ | OTGCMD_OTG_DIS, + &cdns->otg_regs->cmd); + break; + case USB_DR_MODE_HOST: + dev_info(cdns->dev, "Set controller to Host mode\n"); + writel(OTGCMD_HOST_BUS_REQ | OTGCMD_OTG_DIS, + &cdns->otg_regs->cmd); + break; + case USB_DR_MODE_OTG: +
[RFC PATCH v2 12/15] usb:cdns3: Adds enumeration related function.
Patch implements a set of function related to enumeration process. Some standard requests are handled on controller driver level and other are delegated to gadget core driver. All class requests are delegated to gadget core driver. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/ep0.c| 491 - drivers/usb/cdns3/gadget.c | 119 + drivers/usb/cdns3/gadget.h | 4 + 3 files changed, 610 insertions(+), 4 deletions(-) diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index eb92fd234bd7..6f33d98f7684 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -10,6 +10,7 @@ * Peter Chen */ +#include #include "gadget.h" static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { @@ -52,9 +53,31 @@ static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev, writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd); } +/** + * cdns3_ep0_delegate_req - Returns status of handling setup packet + * Setup is handled by gadget driver + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns zero on success or negative value on failure + */ +static int cdns3_ep0_delegate_req(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + int ret; + + spin_unlock(&priv_dev->lock); + priv_dev->setup_pending = 1; + ret = priv_dev->gadget_driver->setup(&priv_dev->gadget, ctrl_req); + priv_dev->setup_pending = 0; + spin_lock(&priv_dev->lock); + return ret; +} + static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) { - //TODO: Implements this function + priv_dev->ep0_data_dir = 0; + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 8, 0); } static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) @@ -90,9 +113,431 @@ static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) } } +/** + * cdns3_req_ep0_set_configuration - Handling of SET_CONFIG standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, 0x7FFF on deferred status stage, error code on error + */ +static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + enum usb_device_state device_state = priv_dev->gadget.state; + struct cdns3_endpoint *priv_ep, *temp_ep; + u32 config = le16_to_cpu(ctrl_req->wValue); + int result = 0; + + switch (device_state) { + case USB_STATE_ADDRESS: + /* Configure non-control EPs */ + list_for_each_entry_safe(priv_ep, temp_ep, +&priv_dev->ep_match_list, +ep_match_pending_list) + cdns3_ep_config(priv_ep); + + result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + + if (result) + return result; + + if (config) { + cdns3_set_hw_configuration(priv_dev); + } else { + cdns3_gadget_unconfig(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, +USB_STATE_ADDRESS); + } + break; + case USB_STATE_CONFIGURED: + result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + + if (!config && !result) { + cdns3_gadget_unconfig(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, +USB_STATE_ADDRESS); + } + break; + default: + result = -EINVAL; + } + + return result; +} + +/** + * cdns3_req_ep0_set_address - Handling of SET_ADDRESS standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev, +struct usb_ctrlrequest *ctrl_req) +{ + enum usb_device_state device_state = priv_dev->gadget.state; + u32 reg; + u32 addr; + + addr = le16_to_cpu(ctrl_req->wValue); + + if (addr > DEVICE_ADDRESS_MAX) { + dev_err(&priv_dev->dev, + "Device address (%d) cannot be greater than %d\n", + addr, DEVICE_ADDRESS_MAX); + return -EINVAL; + } + + if (device_state == USB_STATE_CONFIGURED) { + dev_err(&priv_dev->dev, "USB device already configured\n"); +
[RFC PATCH v2 15/15] usb:cdns3: Feature for changing role
Patch adds feature that allow to change role from user space. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Makefile | 2 +- drivers/usb/cdns3/core.c| 2 + drivers/usb/cdns3/debugfs.c | 93 + drivers/usb/cdns3/drd.h | 3 ++ 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/cdns3/debugfs.c diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index 34e60d03c4ec..08e6cdbebd46 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_USB_CDNS3)+= cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o -cdns3-y:= core.o drd.o +cdns3-y:= core.o drd.o debugfs.o cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o debug.o cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index 1fa233415901..304323b643f2 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -323,6 +323,7 @@ static int cdns3_probe(struct platform_device *pdev) goto err2; } + cdns3_debugfs_init(cdns); device_set_wakeup_capable(dev, true); pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -358,6 +359,7 @@ static int cdns3_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); + cdns3_debugfs_exit(cdns); cdns3_remove_roles(cdns); return 0; diff --git a/drivers/usb/cdns3/debugfs.c b/drivers/usb/cdns3/debugfs.c new file mode 100644 index ..189b12d96cbf --- /dev/null +++ b/drivers/usb/cdns3/debugfs.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Controller DebugFS filer. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include +#include +#include +#include + +#include "core.h" +#include "gadget.h" + +static int cdns3_mode_show(struct seq_file *s, void *unused) +{ + struct cdns3*cdns = s->private; + + switch (cdns->current_dr_mode) { + case USB_DR_MODE_HOST: + seq_puts(s, "host\n"); + break; + case USB_DR_MODE_PERIPHERAL: + seq_puts(s, "device\n"); + break; + case USB_DR_MODE_OTG: + seq_puts(s, "otg\n"); + break; + default: + seq_puts(s, "UNKNOWN mode\n"); + } + + return 0; +} + +static int cdns3_mode_open(struct inode *inode, struct file *file) +{ + return single_open(file, cdns3_mode_show, inode->i_private); +} + +static ssize_t cdns3_mode_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct cdns3*cdns = s->private; + u32 mode = 0; + charbuf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "host", 4)) + mode = USB_DR_MODE_HOST; + + if (!strncmp(buf, "device", 6)) + mode = USB_DR_MODE_PERIPHERAL; + + if (!strncmp(buf, "otg", 3)) + mode = USB_DR_MODE_OTG; + + cdns->desired_dr_mode = mode; + queue_work(system_freezable_wq, &cdns->role_switch_wq); + return count; +} + +static const struct file_operations cdns3_mode_fops = { + .open = cdns3_mode_open, + .write = cdns3_mode_write, + .read = seq_read, + .llseek = seq_lseek, + .release= single_release, +}; + +void cdns3_debugfs_init(struct cdns3 *cdns) +{ + struct dentry *root; + + root = debugfs_create_dir(dev_name(cdns->dev), NULL); + cdns->root = root; + if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET) && + IS_ENABLED(CONFIG_USB_CDNS3_HOST)) + debugfs_create_file("mode", 0644, root, cdns, + &cdns3_mode_fops); +} + +void cdns3_debugfs_exit(struct cdns3 *cdns) +{ + debugfs_remove_recursive(cdns->root); +} diff --git a/drivers/usb/cdns3/drd.h b/drivers/usb/cdns3/drd.h index 0faa7520ecac..8367032e12a3 100644 --- a/drivers/usb/cdns3/drd.h +++ b/drivers/usb/cdns3/drd.h @@ -119,4 +119,7 @@ int cdns3_drd_init(struct cdns3 *cdns); int cdns3_drd_update_mode(struct cdns3 *cdns); irqreturn_t cdns3_drd_irq(struct cdns3 *cdns); +void cdns3_debugfs_init(struct cdns3 *cdns); +void cdns3_debugfs_exit(struct cdns3 *cdns); + #endif /* __LINUX_CDNS3_DRD */ -- 2.17.1
[RFC PATCH v2 10/15] usb:cdns3: Ep0 operations part of the API
Patch implements related to default endpoint callback functions defined in usb_ep_ops object Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/ep0.c| 191 - drivers/usb/cdns3/gadget.c | 8 ++ drivers/usb/cdns3/gadget.h | 10 ++ 3 files changed, 207 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index ca1795467155..d05169e73631 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -18,11 +18,185 @@ static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { .bmAttributes = USB_ENDPOINT_XFER_CONTROL, }; +/** + * cdns3_ep0_run_transfer - Do transfer on default endpoint hardware + * @priv_dev: extended gadget object + * @dma_addr: physical address where data is/will be stored + * @length: data length + * @erdy: set it to 1 when ERDY packet should be sent - + *exit from flow control state + */ +static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev, + dma_addr_t dma_addr, + unsigned int length, int erdy) +{ + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; + + priv_dev->trb_ep0->buffer = TRB_BUFFER(dma_addr); + priv_dev->trb_ep0->length = TRB_LEN(length); + priv_dev->trb_ep0->control = TRB_CYCLE | TRB_IOC | TRB_TYPE(TRB_NORMAL); + + cdns3_select_ep(priv_dev, + priv_dev->ep0_data_dir ? USB_DIR_IN : USB_DIR_OUT); + + writel(EP_STS_TRBERR, ®s->ep_sts); + writel(EP_TRADDR_TRADDR(priv_dev->trb_ep0_dma), ®s->ep_traddr); + + dev_dbg(&priv_dev->dev, "//Ding Dong ep0%s\n", + priv_dev->ep0_data_dir ? "IN" : "OUT"); + + /* TRB should be prepared before starting transfer */ + writel(EP_CMD_DRDY, ®s->ep_cmd); + + if (erdy) + writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd); +} + static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) { //TODO: Implements this function } +static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) +{ + struct cdns3_endpoint *priv_ep; + struct usb_request *request; + struct usb_ep *ep; + int result = 0; + + if (priv_dev->hw_configured_flag) + return; + + writel(USB_CONF_CFGSET, &priv_dev->regs->usb_conf); + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + + cdns3_set_register_bit(&priv_dev->regs->usb_conf, + USB_CONF_U1EN | USB_CONF_U2EN); + + /* wait until configuration set */ + result = cdns3_handshake(&priv_dev->regs->usb_sts, +USB_STS_CFGSTS_MASK, 1, 100); + + priv_dev->hw_configured_flag = 1; + cdns3_enable_l1(priv_dev, 1); + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + if (ep->enabled) { + priv_ep = ep_to_cdns3_ep(ep); + request = cdns3_next_request(&priv_ep->request_list); + if (request) + cdns3_ep_run_transfer(priv_ep, request); + } + } +} + +/** + * cdns3_gadget_ep0_enable + * Function shouldn't be called by gadget driver, + * endpoint 0 is allways active + */ +static int cdns3_gadget_ep0_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + return -EINVAL; +} + +/** + * cdns3_gadget_ep0_disable + * Function shouldn't be called by gadget driver, + * endpoint 0 is allways active + */ +static int cdns3_gadget_ep0_disable(struct usb_ep *ep) +{ + return -EINVAL; +} + +/** + * cdns3_gadget_ep0_set_halt + * @ep: pointer to endpoint zero object + * @value: 1 for set stall, 0 for clear stall + * + * Returns 0 + */ +static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value) +{ + /* TODO */ + return 0; +} + +/** + * cdns3_gadget_ep0_queue Transfer data on endpoint zero + * @ep: pointer to endpoint zero object + * @request: pointer to request object + * @gfp_flags: gfp flags + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_ep0_queue(struct usb_ep *ep, + struct usb_request *request, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + unsigned long flags; + int erdy_sent = 0; + int ret = 0; + + dev_dbg(&priv_dev->dev, "Queue to Ep0%s L: %d\n", + priv_dev->ep0_data_dir ? "IN" : "OUT", + request->length); + + /* send STATUS stage */ + if (request-
[RFC PATCH v2 13/15] usb:cdns3: Adds transfer related function.
Patch implements a set of function handling transfer on none-default endpoints. For handling transfer controller use cdns3_trb structure. Each transfer request block (TRB) contains data buffer address, length and some control bits. Each transfer can consist of many trbs. Such group of trbs is called transfer descriptors (TD). Each endpoint has own array of trbs that make up a transfer ring. The last element on ring is reserved and is set as Link TRB that point to the first TRB. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/gadget.c | 235 - 1 file changed, 233 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 0202ff5f6c90..911d9b8c1c8f 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -239,6 +239,45 @@ void cdns3_gadget_unconfig(struct cdns3_device *priv_dev) priv_dev->out_mem_is_allocated = 0; } +/** + * cdns3_ep_inc_trb - increment a trb index. + * @index: Pointer to the TRB index to increment. + * @cs: Cycle state + * + * The index should never point to the link TRB. After incrementing, + * if it is point to the link TRB, wrap around to the beginning and revert + * cycle state bit The + * link TRB is always at the last TRB entry. + */ +static void cdns3_ep_inc_trb(int *index, u8 *cs) +{ + (*index)++; + if (*index == (TRBS_PER_SEGMENT - 1)) { + *index = 0; + *cs ^= 1; + } +} + +/** + * cdns3_ep_inc_enq - increment endpoint's enqueue pointer + * @priv_ep: The endpoint whose enqueue pointer we're incrementing + */ +static void cdns3_ep_inc_enq(struct cdns3_endpoint *priv_ep) +{ + priv_ep->free_trbs--; + cdns3_ep_inc_trb(&priv_ep->enqueue, &priv_ep->pcs); +} + +/** + * cdns3_ep_inc_deq - increment endpoint's dequeue pointer + * @priv_ep: The endpoint whose dequeue pointer we're incrementing + */ +static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep) +{ + priv_ep->free_trbs++; + cdns3_ep_inc_trb(&priv_ep->dequeue, &priv_ep->ccs); +} + void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable) { if (enable) @@ -278,7 +317,27 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, struct cdns3_request *priv_req, int status) { - //TODO: Implements this function. + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct usb_request *request = &priv_req->request; + + list_del_init(&request->list); + if (request->status == -EINPROGRESS) + request->status = status; + + usb_gadget_unmap_request_by_dev(priv_dev->sysdev, request, + priv_ep->dir); + + priv_req->on_ring = 0; + + if (request->complete) { + spin_unlock(&priv_dev->lock); + usb_gadget_giveback_request(&priv_ep->endpoint, + request); + spin_lock(&priv_dev->lock); + } + + if (request->buf == priv_dev->zlp_buf) + cdns3_gadget_ep_free_request(&priv_ep->endpoint, request); } /** @@ -290,13 +349,185 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, struct usb_request *request) { + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_request *priv_req; + struct cdns3_trb *trb; + dma_addr_t trb_dma; + int sg_iter = 0; + u32 first_pcs; + int num_trb; + int address; + int pcs; + + if (!request) + return -EINVAL; + + num_trb = request->num_sgs ? request->num_sgs : 1; + + if (num_trb > priv_ep->free_trbs) + return -EINVAL; + + priv_req = to_cdns3_request(request); + address = priv_ep->endpoint.desc->bEndpointAddress; + + if (priv_req->on_ring) + goto arm; + + priv_ep->flags |= EP_PENDING_REQUEST; + trb_dma = request->dma; + + /* must allocate buffer aligned to 8 */ + if ((request->dma % ADDR_MODULO_8)) { + if (request->length <= CDNS3_UNALIGNED_BUF_SIZE) { + memcpy(priv_ep->aligned_buff, request->buf, + request->length); + trb_dma = priv_ep->aligned_dma_addr; + } else { + return -ENOMEM; + } + } + + trb = priv_ep->trb_pool + priv_ep->enqueue; + priv_req->trb = trb; + priv_req->start_trb = priv_ep->enqueue; + + //prepare ring + if ((priv_ep->enqueue + num_trb) >= (TRBS_PER_SEGMENT - 1)) { + /*updating C bt in Link TRB bef
[RFC PATCH v2 07/15] usb:cdns3: Adds Device mode support - initialization.
Patch implements a set of functions responsible for initialization, configuration, starting and stopping device mode. This patch also adds new ep0.c that holds all functions related to endpoint 0. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Kconfig | 10 + drivers/usb/cdns3/Makefile| 1 + drivers/usb/cdns3/core.c | 5 +- drivers/usb/cdns3/ep0.c | 105 drivers/usb/cdns3/gadget-export.h | 27 +++ drivers/usb/cdns3/gadget.c| 390 ++ drivers/usb/cdns3/gadget.h| 4 + 7 files changed, 541 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/cdns3/ep0.c create mode 100644 drivers/usb/cdns3/gadget-export.h create mode 100644 drivers/usb/cdns3/gadget.c diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig index d92bc3d68eb0..b7d71b5c4f60 100644 --- a/drivers/usb/cdns3/Kconfig +++ b/drivers/usb/cdns3/Kconfig @@ -10,6 +10,16 @@ config USB_CDNS3 if USB_CDNS3 +config USB_CDNS3_GADGET +bool "Cadence USB3 device controller" +depends on USB_GADGET +help + Say Y here to enable device controller functionality of the + cadence USBSS-DEV driver. + + This controller support FF, HS and SS mode. It doeasn't support + LS and SSP mode + config USB_CDNS3_HOST bool "Cadence USB3 host controller" depends on USB_XHCI_HCD diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index 976117ba67ff..bea6173bf37f 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -2,5 +2,6 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o cdns3-y:= core.o drd.o +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index 4cb820be9ff3..1fa233415901 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -18,6 +18,7 @@ #include "gadget.h" #include "core.h" #include "host-export.h" +#include "gadget-export.h" #include "drd.h" static inline struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) @@ -104,7 +105,8 @@ static int cdns3_core_init_role(struct cdns3 *cdns) } if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { - //TODO: implements device initialization + if (cdns3_gadget_init(cdns)) + dev_info(dev, "doesn't support gadget\n"); } if (!cdns->roles[CDNS3_ROLE_HOST] && !cdns->roles[CDNS3_ROLE_GADGET]) { @@ -144,6 +146,7 @@ static irqreturn_t cdns3_irq(int irq, void *data) static void cdns3_remove_roles(struct cdns3 *cdns) { + cdns3_gadget_remove(cdns); cdns3_host_remove(cdns); } diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c new file mode 100644 index ..c08d02665f9d --- /dev/null +++ b/drivers/usb/cdns3/ep0.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver - gadget side. + * + * Copyright (C) 2018 Cadence Design Systems. + * Copyright (C) 2017 NXP + * + * Authors: Pawel Jez , + * Pawel Laszczak + * Peter Chen + */ + +#include "gadget.h" + +static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, +}; + +static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) +{ + //TODO: Implements this function +} + +/** + * cdns3_ep0_config - Configures default endpoint + * @priv_dev: extended gadget object + * + * Functions sets parameters: maximal packet size and enables interrupts + */ +void cdns3_ep0_config(struct cdns3_device *priv_dev) +{ + struct cdns3_usb_regs __iomem *regs; + u32 max_packet_size = 64; + + regs = priv_dev->regs; + + if (priv_dev->gadget.speed == USB_SPEED_SUPER) + max_packet_size = 512; + + if (priv_dev->ep0_request) { + list_del_init(&priv_dev->ep0_request->list); + priv_dev->ep0_request = NULL; + } + + priv_dev->gadget.ep0->maxpacket = max_packet_size; + cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(max_packet_size); + + /* init ep out */ + cdns3_select_ep(priv_dev, USB_DIR_OUT); + + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), + ®s->ep_cfg); + + writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN, + ®s->ep_sts_en); + + /* init ep in */ + cdns3_select_ep(priv_d
[RFC PATCH v2 03/15] dt-bindings: add binding for USBSS-DRD controller.
Thsi patch aim at documenting USB related dt-bindings for the Cadence USBSS-DRD controller. Signed-off-by: Pawel Laszczak --- .../devicetree/bindings/usb/cdns3-usb.txt | 17 + 1 file changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/cdns3-usb.txt diff --git a/Documentation/devicetree/bindings/usb/cdns3-usb.txt b/Documentation/devicetree/bindings/usb/cdns3-usb.txt new file mode 100644 index ..f9e953f32d47 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/cdns3-usb.txt @@ -0,0 +1,17 @@ +Binding for the Cadence USBSS-DRD controller + +Required properties: + - reg: Physical base address and size of the controller's register area. + - compatible: Should contain: "cdns,usb3" + - interrupts: Interrupt specifier. Refer to interrupt bindings. + + +Example: + cdns3@f300 { + compatible = "cdns,usb3"; + interrupts = ; + reg = <0xf300 0x1 //memory area for OTG/DRD registers + 0xf301 0x1 //memory area for HOST registers + 0xf302 0x1>;//memory area for Device registers + }; + -- 2.17.1
[RFC PATCH v2 01/15] usb:cdns3: add pci to platform driver wrapper.
Patch adds PCI specific glue driver that creates and registers in-system cdns-usb3 platform device. Thanks to that we will be able to use the cdns-usb3 platform driver for USBSS-DEV controller build on PCI board Signed-off-by: Pawel Laszczak --- drivers/usb/Kconfig| 2 + drivers/usb/Makefile | 2 + drivers/usb/cdns3/Kconfig | 24 + drivers/usb/cdns3/Makefile | 3 + drivers/usb/cdns3/cdns3-pci-wrap.c | 157 + 5 files changed, 188 insertions(+) create mode 100644 drivers/usb/cdns3/Kconfig create mode 100644 drivers/usb/cdns3/Makefile create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 987fc5ba6321..5f9334019d04 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig" endif +source "drivers/usb/cdns3/Kconfig" + source "drivers/usb/mtu3/Kconfig" source "drivers/usb/musb/Kconfig" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 7d1b8c82b208..82093a60ea2c 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -8,6 +8,8 @@ obj-$(CONFIG_USB) += core/ obj-$(CONFIG_USB_SUPPORT) += phy/ +obj-$(CONFIG_USB_CDNS3)+= cdns3/ + obj-$(CONFIG_USB_DWC3) += dwc3/ obj-$(CONFIG_USB_DWC2) += dwc2/ obj-$(CONFIG_USB_ISP1760) += isp1760/ diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig new file mode 100644 index ..eb22a8692991 --- /dev/null +++ b/drivers/usb/cdns3/Kconfig @@ -0,0 +1,24 @@ +config USB_CDNS3 + tristate "Cadence USB3 Dual-Role Controller" + depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA + help + Say Y here if your system has a cadence USB3 dual-role controller. + It supports: dual-role switch, Host-only, and Peripheral-only. + + If you choose to build this driver is a dynamically linked + module, the module will be called cdns3.ko. + +if USB_CDNS3 + +config USB_CDNS3_PCI_WRAP + tristate "PCIe-based Platforms" + depends on USB_PCI && ACPI + default USB_CDNS3 + help + If you're using the USBSS Core IP with a PCIe, please say + 'Y' or 'M' here. + + If you choose to build this driver as module it will + be dynamically linked and module will be called cdns3-pci.ko + +endif diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile new file mode 100644 index ..dcdd62003c6a --- /dev/null +++ b/drivers/usb/cdns3/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o + +cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c new file mode 100644 index ..d0a15cc0b738 --- /dev/null +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS PCI Glue driver + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include +#include +#include +#include +#include +#include + +struct cdns3_wrap { + struct platform_device *plat_dev; + struct pci_dev *hg_dev; + struct resource dev_res[4]; +}; + +struct cdns3_wrap wrap; + +#define RES_IRQ_ID 0 +#define RES_HOST_ID1 +#define RES_DEV_ID 2 +#define RES_DRD_ID 3 + +#define PCI_BAR_HOST 0 +#define PCI_BAR_DEV2 +#define PCI_BAR_OTG4 + +#define PCI_DEV_FN_HOST_DEVICE 0 +#define PCI_DEV_FN_OTG 1 + +#define PCI_DRIVER_NAME"cdns3-pci-usbss" +#define PLAT_DRIVER_NAME "cdns-usb3" + +#define CDNS_VENDOR_ID 0x17cd +#define CDNS_DEVICE_ID 0x0100 + +/** + * cdns3_pci_probe - Probe function for Cadence USB wrapper driver + * @pdev: platform device object + * @id: pci device id + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct platform_device_info plat_info; + struct cdns3_wrap *wrap; + struct resource *res; + int err; + + /* +* for GADGET/HOST PCI (devfn) function number is 0, +* for OTG PCI (devfn) function number is 1 +*/ + if (!id || pdev->devfn != PCI_DEV_FN_HOST_DEVICE) + return -EINVAL; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err); + return err; + } + + pci_set_master(pdev); + wrap = devm_kzalloc(&pdev->dev, sizeof(*wrap), GFP_KERNEL); + if (!wrap) { + dev_err(&pdev->dev, "Failed to
[RFC PATCH v2 11/15] usb:cdns3: Implements ISR functionality.
Patch adds set of generic functions used for handling interrupts generated by controller. Interrupt related functions are divided into three groups. The first is related to ep0 and is placed in ep0.c. The second is responsible for non-default endpoints and is implemented in gadget.c file. The last group is not related to endpoints interrupts and is placed in gadget.c. All groups have common entry point in cdns3_irq_handler_thread function. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/ep0.c| 63 +++ drivers/usb/cdns3/gadget.c | 224 - drivers/usb/cdns3/gadget.h | 1 + 3 files changed, 287 insertions(+), 1 deletion(-) diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index d05169e73631..eb92fd234bd7 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -90,6 +90,69 @@ static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) } } +static void __pending_setup_status_handler(struct cdns3_device *priv_dev) +{ + //TODO: Implements this function +} + +/** + * cdns3_ep0_setup_phase - Handling setup USB requests + * @priv_dev: extended gadget object + */ +static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev) +{ + //TODO: Implements this function. +} + +static void cdns3_transfer_completed(struct cdns3_device *priv_dev) +{ + //TODO: Implements this function +} + +/** + * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0 + * @priv_dev: extended gadget object + * @dir: 1 for IN direction, 0 for OUT direction + */ +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir) +{ + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; + u32 ep_sts_reg; + + cdns3_select_ep(priv_dev, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT)); + ep_sts_reg = readl(®s->ep_sts); + + __pending_setup_status_handler(priv_dev); + + if ((ep_sts_reg & EP_STS_SETUP) && dir == 0) { + struct usb_ctrlrequest *setup = priv_dev->setup; + + writel(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP, ®s->ep_sts); + + priv_dev->ep0_data_dir = setup->bRequestType & USB_DIR_IN; + cdns3_ep0_setup_phase(priv_dev); + ep_sts_reg &= ~(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP); + } + + if (ep_sts_reg & EP_STS_TRBERR) + writel(EP_STS_TRBERR, &priv_dev->regs->ep_sts); + + if (ep_sts_reg & EP_STS_DESCMIS) { + writel(EP_STS_DESCMIS, &priv_dev->regs->ep_sts); + + if (dir == 0 && !priv_dev->setup_pending) { + priv_dev->ep0_data_dir = 0; + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, + 8, 0); + } + } + + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) { + writel(EP_STS_IOC, &priv_dev->regs->ep_sts); + cdns3_transfer_completed(priv_dev); + } +} + /** * cdns3_gadget_ep0_enable * Function shouldn't be called by gadget driver, diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index c965da16c0c8..309202474e57 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -58,6 +58,18 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask) writel(mask, ptr); } +/** + * cdns3_ep_reg_pos_to_index - Macro converts bit position of ep_ists register + * to index of endpoint object in cdns3_device.eps[] container + * @i: bit position of endpoint for which endpoint object is required + * + * Remember that endpoint container doesn't contain default endpoint + */ +static u8 cdns3_ep_reg_pos_to_index(int i) +{ + return ((i / 16) + (((i % 16) - 2) * 2)); +} + /** * cdns3_next_request - returns next request from list * @list: list containing requests @@ -188,6 +200,21 @@ static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep) priv_ep->flags |= EP_STALL; } +/** + * cdns3_gadget_unconfig - reset device configuration + * @priv_dev: extended gadget object + */ +void cdns3_gadget_unconfig(struct cdns3_device *priv_dev) +{ + /* RESET CONFIGURATION */ + writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf); + + cdns3_enable_l1(priv_dev, 0); + priv_dev->hw_configured_flag = 0; + priv_dev->onchip_mem_allocated_size = 0; + priv_dev->out_mem_is_allocated = 0; +} + void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable) { if (enable) @@ -196,6 +223,23 @@ void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable) writel(USB_CONF_L1DS, &priv_dev->regs->usb_conf); } +static enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev) +{ + u32 reg; + + reg = readl(&priv_dev->
[RFC PATCH v2 06/15] usb:cdns3: Adds Host support
Patch adds host-export.h and host.c file and mplements functions that allow to initialize, start and stop XHCI host driver. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Kconfig | 10 ++ drivers/usb/cdns3/Makefile | 1 + drivers/usb/cdns3/core.c| 7 +- drivers/usb/cdns3/host-export.h | 30 drivers/usb/cdns3/host.c| 256 5 files changed, 302 insertions(+), 2 deletions(-) create mode 100644 drivers/usb/cdns3/host-export.h create mode 100644 drivers/usb/cdns3/host.c diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig index eb22a8692991..d92bc3d68eb0 100644 --- a/drivers/usb/cdns3/Kconfig +++ b/drivers/usb/cdns3/Kconfig @@ -10,6 +10,16 @@ config USB_CDNS3 if USB_CDNS3 +config USB_CDNS3_HOST +bool "Cadence USB3 host controller" +depends on USB_XHCI_HCD +help + Say Y here to enable host controller functionality of the + cadence driver. + + Host controller is compliance with XHCI so it will use + standard XHCI driver. + config USB_CDNS3_PCI_WRAP tristate "PCIe-based Platforms" depends on USB_PCI && ACPI diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index e779b2a2f8eb..976117ba67ff 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o cdns3-y:= core.o drd.o +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index dbee4325da7f..4cb820be9ff3 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -17,6 +17,7 @@ #include "gadget.h" #include "core.h" +#include "host-export.h" #include "drd.h" static inline struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) @@ -98,7 +99,8 @@ static int cdns3_core_init_role(struct cdns3 *cdns) } if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { - //TODO: implements host initialization + if (cdns3_host_init(cdns)) + dev_info(dev, "doesn't support host\n"); } if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { @@ -142,7 +144,7 @@ static irqreturn_t cdns3_irq(int irq, void *data) static void cdns3_remove_roles(struct cdns3 *cdns) { - //TODO: implements this function + cdns3_host_remove(cdns); } static int cdns3_do_role_switch(struct cdns3 *cdns, enum cdns3_roles role) @@ -410,6 +412,7 @@ static struct platform_driver cdns3_driver = { static int __init cdns3_driver_platform_register(void) { + cdns3_host_driver_init(); return platform_driver_register(&cdns3_driver); } module_init(cdns3_driver_platform_register); diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h new file mode 100644 index ..f8f3b230b472 --- /dev/null +++ b/drivers/usb/cdns3/host-export.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USBSS DRD Driver -Host Export APIs + * + * Copyright (C) 2017 NXP + * + * Authors: Peter Chen + */ +#ifndef __LINUX_CDNS3_HOST_EXPORT +#define __LINUX_CDNS3_HOST_EXPORT + +#ifdef CONFIG_USB_CDNS3_HOST + +int cdns3_host_init(struct cdns3 *cdns); +void cdns3_host_remove(struct cdns3 *cdns); +void cdns3_host_driver_init(void); + +#else + +static inline int cdns3_host_init(struct cdns3 *cdns) +{ + return -ENXIO; +} + +static inline void cdns3_host_remove(struct cdns3 *cdns) { } +static inline void cdns3_host_driver_init(void) {} + +#endif /* CONFIG_USB_CDNS3_HOST */ + +#endif /* __LINUX_CDNS3_HOST_EXPORT */ diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c new file mode 100644 index ..0dd47976cb28 --- /dev/null +++ b/drivers/usb/cdns3/host.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver - host side + * + * Copyright (C) 2018 Cadence Design Systems. + * Copyright (C) 2018 NXP + * + * Authors: Peter Chen + * Pawel Laszczak + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../host/xhci.h" +#include "core.h" +#include "host-export.h" + +static struct hc_driver __read_mostly xhci_cdns3_hc_driver; + +static void xhci_cdns3_quirks(struct device *dev, struct xhci_hcd *xhci) +{ + /* +* As of now platform drivers don't provide MSI support so we ensure +* here that the generic code does not try to make a pci_dev from our +* dev struct in order to setup MSI +*/ + xhci->quirks |= XHCI_PLAT; +} + +static int xh
[RFC PATCH v2 02/15] usb:cdns3: Device side header file.
Patch defines macros used by device side of controller, structures holding registers, and some other object used by device controller. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/gadget.h | 1071 1 file changed, 1071 insertions(+) create mode 100644 drivers/usb/cdns3/gadget.h diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h new file mode 100644 index ..75ca6214e79a --- /dev/null +++ b/drivers/usb/cdns3/gadget.h @@ -0,0 +1,1071 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * USBSS device controller driver + * + * Copyright (C) 2018 Cadence. + * Copyright (C) 2018 NXP + * + * Author: Pawel Laszczak + * Pawel Jez + * Peter Chen + */ +#ifndef __LINUX_CDNS3_GADGET +#define __LINUX_CDNS3_GADGET +#include + +/* + * USBSS-DEV register interface. + * This corresponds to the USBSS Device Controller Interface + */ + +/** + * struct xhci_cap_regs - xHCI Host Controller Capability Registers. + * @usb_conf: Global Configuration Register. + * @usb_sts: Global Status Register. + * @usb_cmd: Global Command Register. + * @usb_iptn: ITP/SOF number Register. + * @usb_lpm: Global Command Register. + * @usb_ien: USB Interrupt Enable Register. + * @usb_ists: USB Interrupt Status Register. + * @ep_sel:Endpoint Select Register. + * @ep_traddr: Endpoint Transfer Ring Address Register. + * @ep_cfg:Endpoint Configuration Register. + * @ep_cmd:Endpoint Command Register. + * @ep_sts:Endpoint Status Register. + * @ep_sts_sid:Endpoint Status Register. + * @ep_sts_en: Endpoint Status Register Enable. + * @drbl: Doorbell Register. + * @ep_ien:EP Interrupt Enable Register. + * @ep_ists: EP Interrupt Status Register. + * @usb_pwr: Global Power Configuration Register. + * @usb_conf2: Global Configuration Register 2. + * @usb_cap1: Capability Register 1. + * @usb_cap2: Capability Register 2. + * @usb_cap3: Capability Register 3. + * @usb_cap4: Capability Register 4. + * @usb_cap5: Capability Register 5. + * @usb_cap6: Capability Register 6. + * @usb_cpkt1: Custom Packet Register 1. + * @usb_cpkt2: Custom Packet Register 2. + * @usb_cpkt3: Custom Packet Register 3. + * @reserved1: Reserved. + * @cfg_regs: Configuration registers. + * @reserved2: Reserved. + * @dma_axi_ctrl: AXI Control register. + * @dma_axi_id:AXI ID register. + * @dma_axi_cap: AXI Capability register. + * @dma_axi_ctrl0: AXI Control 0 register. + * @dma_axi_ctrl1: AXI Control 1 register. + */ +struct cdns3_usb_regs { + __le32 usb_conf; + __le32 usb_sts; + __le32 usb_cmd; + __le32 usb_iptn; + __le32 usb_lpm; + __le32 usb_ien; + __le32 usb_ists; + __le32 ep_sel; + __le32 ep_traddr; + __le32 ep_cfg; + __le32 ep_cmd; + __le32 ep_sts; + __le32 ep_sts_sid; + __le32 ep_sts_en; + __le32 drbl; + __le32 ep_ien; + __le32 ep_ists; + __le32 usb_pwr; + __le32 usb_conf2; + __le32 usb_cap1; + __le32 usb_cap2; + __le32 usb_cap3; + __le32 usb_cap4; + __le32 usb_cap5; + __le32 usb_cap6; + __le32 usb_cpkt1; + __le32 usb_cpkt2; + __le32 usb_cpkt3; + __le32 reserved1[36]; + __le32 cfg_reg1; + __le32 dbg_link1; + __le32 dbg_link2; + __le32 cfg_regs[74]; + __le32 reserved2[34]; + __le32 dma_axi_ctrl; + __le32 dma_axi_id; + __le32 dma_axi_cap; + __le32 dma_axi_ctrl0; + __le32 dma_axi_ctrl1; +}; + +/* USB_CONF - bitmasks */ +/* Reset USB device configuration. */ +#define USB_CONF_CFGRSTBIT(0) +/* Set Configuration. */ +#define USB_CONF_CFGSETBIT(1) +/* Disconnect USB device in SuperSpeed. */ +#define USB_CONF_USB3DIS BIT(3) +/* Disconnect USB device in HS/FS */ +#define USB_CONF_USB2DIS BIT(4) +/* Little Endian access - default */ +#define USB_CONF_LENDIAN BIT(5) +/* + * Big Endian access. Driver assume that byte order for + * SFRs access always is as Little Endian so this bit + * is not used. + */ +#define USB_CONF_BENDIAN BIT(6) +/* Device software reset. */ +#define USB_CONF_SWRST BIT(7) +/* Singular DMA transfer mode. */ +#define USB_CONF_DSING BIT(8) +/* Multiple DMA transfers mode. */ +#define USB_CONF_DMULT BIT(9) +/* DMA clock turn-off enable. */ +#define USB_CONF_DMAOFFEN BIT(10) +/* DMA clock turn-off disable. */ +#define USB_CONF_DMAOFFDS BIT(11) +/* Clear Force Full Speed. */ +#define USB_CONF_CFORCE_FS BIT(12) +/* Set Force Full Speed. */ +#define USB_CONF_SFORCE_FS BIT(13) +/* Device enable. */ +#define USB_CONF_DEVEN BIT(14) +/* Device disable. */ +#define USB_CONF_DEVDS BIT(15) +/* L1 LPM state entry enable (used in HS/FS mode). */ +#define USB_CONF_L1EN
[RFC PATCH v2 08/15] usb:cdns3: Implements device operations part of the API
Patch adds implementation callback function defined in usb_gadget_ops object. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/gadget.c | 249 - 1 file changed, 247 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 376b68b13d1b..702a05faa664 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -17,6 +17,36 @@ #include "gadget-export.h" #include "gadget.h" +/** + * cdns3_handshake - spin reading until handshake completes or fails + * @ptr: address of device controller register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @usec: timeout in microseconds + * + * Returns negative errno, or zero on success + * + * Success happens when the "mask" bits have the specified value (hardware + * handshake done). There are two failure modes: "usec" have passed (major + * hardware flakeout), or the register reads as all-ones (hardware removed). + */ +int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = readl(ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + /** * cdns3_set_register_bit - set bit in given register. * @ptr: address of device controller register to be read and changed @@ -43,6 +73,25 @@ void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) writel(ep, &priv_dev->regs->ep_sel); } +static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + if (priv_ep->trb_pool) { + dma_free_coherent(priv_dev->sysdev, + TRB_RIGN_SIZE, + priv_ep->trb_pool, priv_ep->trb_pool_dma); + priv_ep->trb_pool = NULL; + } + + if (priv_ep->aligned_buff) { + dma_free_coherent(priv_dev->sysdev, CDNS3_UNALIGNED_BUF_SIZE, + priv_ep->aligned_buff, + priv_ep->aligned_dma_addr); + priv_ep->aligned_buff = NULL; + } +} + /** * cdns3_irq_handler - irq line interrupt handler * @cdns: cdns3 instance @@ -58,6 +107,114 @@ static irqreturn_t cdns3_irq_handler_thread(struct cdns3 *cdns) return ret; } +/* Find correct direction for HW endpoint according to description */ +static int cdns3_ep_dir_is_correct(struct usb_endpoint_descriptor *desc, + struct cdns3_endpoint *priv_ep) +{ + return (priv_ep->endpoint.caps.dir_in && usb_endpoint_dir_in(desc)) || + (priv_ep->endpoint.caps.dir_out && usb_endpoint_dir_out(desc)); +} + +static struct cdns3_endpoint *cdns3_find_available_ss_ep(struct cdns3_device *priv_dev, +struct usb_endpoint_descriptor *desc) +{ + struct usb_ep *ep; + struct cdns3_endpoint *priv_ep; + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + unsigned long num; + int ret; + /* ep name pattern likes epXin or epXout */ + char c[2] = {ep->name[2], '\0'}; + + ret = kstrtoul(c, 10, &num); + if (ret) + return ERR_PTR(ret); + + priv_ep = ep_to_cdns3_ep(ep); + if (cdns3_ep_dir_is_correct(desc, priv_ep)) { + if (!(priv_ep->flags & EP_USED)) { + priv_ep->num = num; + priv_ep->flags |= EP_USED; + return priv_ep; + } + } + } + return ERR_PTR(-ENOENT); +} + +static struct usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *comp_desc) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + struct cdns3_endpoint *priv_ep; + unsigned long flags; + + priv_ep = cdns3_find_available_ss_ep(priv_dev, desc); + if (IS_ERR(priv_ep)) { + dev_err(&priv_dev->dev, "no available ep\n"); + return NULL; + } + + dev_dbg(&priv_dev->dev, "match endpoint: %s\n", priv_ep->name); + + spin_lock_irqsave(&priv_dev->lock, flags); + priv_ep->endpoint
[RFC PATCH v2 04/15] usb:cdns3: Driver initialization code.
Patch adds core.c and core.h file that implements initialization of platform driver and adds function responsible for selecting, switching and running appropriate Device/Host mode. Signed-off-by: Pawel Laszczak --- drivers/usb/cdns3/Makefile | 2 + drivers/usb/cdns3/core.c | 413 + drivers/usb/cdns3/core.h | 100 + 3 files changed, 515 insertions(+) create mode 100644 drivers/usb/cdns3/core.c create mode 100644 drivers/usb/cdns3/core.h diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index dcdd62003c6a..02d25b23c5d3 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -1,3 +1,5 @@ +obj-$(CONFIG_USB_CDNS3)+= cdns3.o obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o +cdns3-y:= core.o cdns3-pci-y:= cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c new file mode 100644 index ..f9055d4da67f --- /dev/null +++ b/drivers/usb/cdns3/core.c @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * + * Author: Peter Chen + * Pawel Laszczak + */ + +#include +#include +#include +#include +#include +#include + +#include "gadget.h" +#include "core.h" + +static inline struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) +{ + WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); + return cdns->roles[cdns->role]; +} + +static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles role) +{ + int ret; + + if (role >= CDNS3_ROLE_END) + return 0; + + if (!cdns->roles[role]) + return -ENXIO; + + mutex_lock(&cdns->mutex); + cdns->role = role; + ret = cdns->roles[role]->start(cdns); + mutex_unlock(&cdns->mutex); + return ret; +} + +static inline void cdns3_role_stop(struct cdns3 *cdns) +{ + enum cdns3_roles role = cdns->role; + + if (role == CDNS3_ROLE_END) + return; + + mutex_lock(&cdns->mutex); + cdns->roles[role]->stop(cdns); + cdns->role = CDNS3_ROLE_END; + mutex_unlock(&cdns->mutex); +} + +static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) +{ + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { + //TODO: implements selecting device/host mode + return CDNS3_ROLE_HOST; + } + return cdns->roles[CDNS3_ROLE_HOST] + ? CDNS3_ROLE_HOST + : CDNS3_ROLE_GADGET; +} + +/** + * cdns3_core_init_role - initialize role of operation + * @cdns: Pointer to cdns3 structure + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_core_init_role(struct cdns3 *cdns) +{ + struct device *dev = cdns->dev; + enum usb_dr_mode dr_mode; + + dr_mode = usb_get_dr_mode(dev); + cdns->role = CDNS3_ROLE_END; + + /* +* If driver can't read mode by means of usb_get_dr_mdoe function then +* chooses mode according with Kernel configuration. This setting +* can be restricted later depending on strap pin configuration. +*/ + if (dr_mode == USB_DR_MODE_UNKNOWN) { + if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) && + IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) + dr_mode = USB_DR_MODE_OTG; + else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST)) + dr_mode = USB_DR_MODE_HOST; + else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) + dr_mode = USB_DR_MODE_PERIPHERAL; + } + + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { + //TODO: implements host initialization + } + + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { + //TODO: implements device initialization + } + + if (!cdns->roles[CDNS3_ROLE_HOST] && !cdns->roles[CDNS3_ROLE_GADGET]) { + dev_err(dev, "no supported roles\n"); + return -ENODEV; + } + + cdns->dr_mode = dr_mode; + return 0; +} + +/** + * cdns3_irq - interrupt handler for cdns3 core device + * + * @irq: irq number for cdns3 core device + * @data: structure of cdns3 + * + * Returns IRQ_HANDLED or IRQ_NONE + */ +static irqreturn_t cdns3_irq(int irq, void *data) +{ + struct cdns3 *cdns = data; + irqreturn_t ret = IRQ_NONE; + + /* Handle device/host interrupt */ + if (cdns->role != CDNS3_ROLE_END) + ret = cdns3_get_current_role_driver(cdns)->irq(cdns); + + return ret; +} + +static void cdns3_remove_roles(struct cdns3 *cdns) +{
RE: [RFC PATCH v2 03/15] dt-bindings: add binding for USBSS-DRD controller.
Hi Roger >On 18/11/18 12:08, Pawel Laszczak wrote: >> Thsi patch aim at documenting USB related dt-bindings for the > >s/Thsi/This > >> Cadence USBSS-DRD controller. >> >> Signed-off-by: Pawel Laszczak >> --- >> .../devicetree/bindings/usb/cdns3-usb.txt | 17 + >> 1 file changed, 17 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/usb/cdns3-usb.txt >> >> diff --git a/Documentation/devicetree/bindings/usb/cdns3-usb.txt >> b/Documentation/devicetree/bindings/usb/cdns3-usb.txt >> new file mode 100644 >> index ..f9e953f32d47 >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/usb/cdns3-usb.txt >> @@ -0,0 +1,17 @@ >> +Binding for the Cadence USBSS-DRD controller >> + >> +Required properties: >> + - reg: Physical base address and size of the controller's register area. >> + - compatible: Should contain: "cdns,usb3" >> + - interrupts: Interrupt specifier. Refer to interrupt bindings. > >Do you also comply with USB generic bindings for dr_mode, speed, etc? >i.e. Documentation/devicetree/bindings/usb/generic.txt > >If yes it must be mentioned in Optional properties: I took a look at this document and I think that only dr_mode and maximum-speed make sense as optional parameters. I will add these two as optional. Thanks. > >> + >> + >> +Example: >> +cdns3@f300 { >> +compatible = "cdns,usb3"; >> +interrupts = ; >> +reg = <0xf300 0x1 //memory area for OTG/DRD >> registers >> +0xf301 0x1 //memory area for HOST registers >> +0xf302 0x1>;//memory area for Device >> registers >> +}; >> + >> > >cheers, >-roger >-- >Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. >Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki Cheers, Pawel
RE: [RFC PATCH v2 04/15] usb:cdns3: Driver initialization code.
Hi Roger >On 18/11/18 12:09, Pawel Laszczak wrote: >> Patch adds core.c and core.h file that implements initialization >> of platform driver and adds function responsible for selecting, >> switching and running appropriate Device/Host mode. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Makefile | 2 + >> drivers/usb/cdns3/core.c | 413 + >> drivers/usb/cdns3/core.h | 100 + >> 3 files changed, 515 insertions(+) >> create mode 100644 drivers/usb/cdns3/core.c >> create mode 100644 drivers/usb/cdns3/core.h >> >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index dcdd62003c6a..02d25b23c5d3 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -1,3 +1,5 @@ >> +obj-$(CONFIG_USB_CDNS3) += cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> >> +cdns3-y := core.o >> cdns3-pci-y := cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> new file mode 100644 >> index ..f9055d4da67f >> --- /dev/null >> +++ b/drivers/usb/cdns3/core.c >> @@ -0,0 +1,413 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Cadence USBSS DRD Driver. >> + * >> + * Copyright (C) 2018 Cadence. >> + * >> + * Author: Peter Chen >> + * Pawel Laszczak >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "gadget.h" >> +#include "core.h" >> + >> +static inline struct cdns3_role_driver >> *cdns3_get_current_role_driver(struct cdns3 *cdns) >> +{ >> +WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); >> +return cdns->roles[cdns->role]; >> +} >> + >> +static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles >> role) >> +{ >> +int ret; >> + >> +if (role >= CDNS3_ROLE_END) > >WARN_ON()? I agree. > >> +return 0; >> + >> +if (!cdns->roles[role]) >> +return -ENXIO; >> + >> +mutex_lock(&cdns->mutex); >> +cdns->role = role; >> +ret = cdns->roles[role]->start(cdns); >> +mutex_unlock(&cdns->mutex); >> +return ret; >> +} >> + >> +static inline void cdns3_role_stop(struct cdns3 *cdns) >> +{ >> +enum cdns3_roles role = cdns->role; >> + >> +if (role == CDNS3_ROLE_END) > >WARN_ON(role >= CNDS3_ROLE_END) ? I agree > >> +return; >> + >> +mutex_lock(&cdns->mutex); >> +cdns->roles[role]->stop(cdns); >> +cdns->role = CDNS3_ROLE_END; > >Why change the role here? You are just stopping the role not changing it. >I think cdns->role should remain unchanged, so we can call cdns3_role_start() >if required without error. This line is unnecessary. > >> +mutex_unlock(&cdns->mutex); >> +} >> + >> +static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >> +{ >> +if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >> +//TODO: implements selecting device/host mode >> +return CDNS3_ROLE_HOST; >> +} >> +return cdns->roles[CDNS3_ROLE_HOST] >> +? CDNS3_ROLE_HOST >> +: CDNS3_ROLE_GADGET; > >Why not just > return cdns->role; > >I'm wondering if we really need this function TODO will look likie: if (cdns3_is_host(cdns)) return CDNS3_ROLE_HOST; if (cdns3_is_device(cdns)) return CDNS3_ROLE_GADGET; Function selects initial role. Before invoking it the role is unknown. I think that function name should be changed because current name can be misleading. I will change it to cdns3_get_initial_role. . >> +} > >> + >> +/** >> + * cdns3_core_init_role - initialize role of operation >> + * @cdns: Pointer to cdns3 structure >> + * >> + * Returns 0 on success otherwise negative errno >> + */ >> +static int cdns3_core_init_role(struct cdns3 *cdns) >> +{ >> +struct device *dev = cdns->dev; >> +enum usb_dr_mode dr_mode; >> + >> +dr_mode = usb_get_dr_mode(dev); >> +cdns->role = CDNS3_ROLE_END; >> + >>
RE: [RFC PATCH v2 05/15] usb:cdns3: Added DRD support
Hi Roger, >On 18/11/18 12:09, Pawel Laszczak wrote: >> Patch adds supports for detecting Host/Device mode. >> Controller has additional OTG register that allow >> implement even whole OTG functionality. >> At this moment patch adds support only for detecting >> the appropriate mode based on strap pins and ID pin. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Makefile | 2 +- >> drivers/usb/cdns3/core.c | 27 +++-- >> drivers/usb/cdns3/drd.c| 229 + >> drivers/usb/cdns3/drd.h| 122 >> 4 files changed, 372 insertions(+), 8 deletions(-) >> create mode 100644 drivers/usb/cdns3/drd.c >> create mode 100644 drivers/usb/cdns3/drd.h >> >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index 02d25b23c5d3..e779b2a2f8eb 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -1,5 +1,5 @@ >> obj-$(CONFIG_USB_CDNS3) += cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> >> -cdns3-y := core.o >> +cdns3-y := core.o drd.o >> cdns3-pci-y := cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> index f9055d4da67f..dbee4325da7f 100644 >> --- a/drivers/usb/cdns3/core.c >> +++ b/drivers/usb/cdns3/core.c >> @@ -17,6 +17,7 @@ >> >> #include "gadget.h" >> #include "core.h" >> +#include "drd.h" >> >> static inline struct cdns3_role_driver >> *cdns3_get_current_role_driver(struct cdns3 *cdns) >> { >> @@ -57,8 +58,10 @@ static inline void cdns3_role_stop(struct cdns3 *cdns) >> static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >> { >> if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >> -//TODO: implements selecting device/host mode >> -return CDNS3_ROLE_HOST; >> +if (cdns3_is_host(cdns)) >> +return CDNS3_ROLE_HOST; >> +if (cdns3_is_device(cdns)) >> +return CDNS3_ROLE_GADGET; >> } >> return cdns->roles[CDNS3_ROLE_HOST] >> ? CDNS3_ROLE_HOST >> @@ -124,6 +127,12 @@ static irqreturn_t cdns3_irq(int irq, void *data) >> struct cdns3 *cdns = data; >> irqreturn_t ret = IRQ_NONE; >> >> +if (cdns->dr_mode == USB_DR_MODE_OTG) { >> +ret = cdns3_drd_irq(cdns); >> +if (ret == IRQ_HANDLED) >> +return ret; >> +} > >The kernel's shared IRQ model takes care of sharing the same interrupt >between different devices and their drivers. You don't need to manually >handle it here. Just let all 3 drivers do a request_irq() and have >handlers check if the IRQ was theirs or not and return IRQ_HANDLED or >IRQ_NONE accordingly. > >Looks like you can do away with irq member of the role driver struct. Ok, I will split it into 3 separate part, but in this case, I additionally have to check the current role in ISR function. Driver can't read host side registers when controller works in device role and vice versa. One part of controller is kept in reset. Only DRD registers are common and are all accessible. >> + >> /* Handle device/host interrupt */ >> if (cdns->role != CDNS3_ROLE_END) >> ret = cdns3_get_current_role_driver(cdns)->irq(cdns); >> @@ -176,11 +185,8 @@ static void cdns3_role_switch(struct work_struct *work) >> >> cdns = container_of(work, struct cdns3, role_switch_wq); >> >> -//TODO: implements this functions. >> -//host = cdns3_is_host(cdns); >> -//device = cdns3_is_device(cdns); >> -host = 1; >> -device = 0; >> +host = cdns3_is_host(cdns); >> +device = cdns3_is_device(cdns); > >What if there is a ID transition between the 2 functions so that >and both host and device become true? >Since you are checking the ID level separately in both the functions. > >How about instead having cdns3_get_id() and using >it to start/stop relevant roles if we are in OTG mode. > >Is this going to be used for a role switch even if we're not in OTG mode? >If not then it is a BUG if we get here. > Good point. User can change current mode by debugfs and then this function will also invoked. Probably I use cdns3_get_id as you suggest. >> >> if (host) >> role = CDNS3_ROL
RE: [RFC PATCH v2 06/15] usb:cdns3: Adds Host support
>EXTERNAL MAIL > > >On 18/11/18 12:09, Pawel Laszczak wrote: >> Patch adds host-export.h and host.c file and mplements functions that >> allow to initialize, start and stop XHCI host driver. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Kconfig | 10 ++ >> drivers/usb/cdns3/Makefile | 1 + >> drivers/usb/cdns3/core.c| 7 +- >> drivers/usb/cdns3/host-export.h | 30 >> drivers/usb/cdns3/host.c| 256 >> 5 files changed, 302 insertions(+), 2 deletions(-) >> create mode 100644 drivers/usb/cdns3/host-export.h >> create mode 100644 drivers/usb/cdns3/host.c >> >> diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig >> index eb22a8692991..d92bc3d68eb0 100644 >> --- a/drivers/usb/cdns3/Kconfig >> +++ b/drivers/usb/cdns3/Kconfig >> @@ -10,6 +10,16 @@ config USB_CDNS3 >> >> if USB_CDNS3 >> >> +config USB_CDNS3_HOST >> +bool "Cadence USB3 host controller" >> +depends on USB_XHCI_HCD >> +help >> + Say Y here to enable host controller functionality of the >> + cadence driver. >> + >> + Host controller is compliance with XHCI so it will use >> + standard XHCI driver. >> + >> config USB_CDNS3_PCI_WRAP >> tristate "PCIe-based Platforms" >> depends on USB_PCI && ACPI >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index e779b2a2f8eb..976117ba67ff 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -2,4 +2,5 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> >> cdns3-y := core.o drd.o >> +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o >> cdns3-pci-y := cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> index dbee4325da7f..4cb820be9ff3 100644 >> --- a/drivers/usb/cdns3/core.c >> +++ b/drivers/usb/cdns3/core.c >> @@ -17,6 +17,7 @@ >> >> #include "gadget.h" >> #include "core.h" >> +#include "host-export.h" >> #include "drd.h" >> >> static inline struct cdns3_role_driver >> *cdns3_get_current_role_driver(struct cdns3 *cdns) >> @@ -98,7 +99,8 @@ static int cdns3_core_init_role(struct cdns3 *cdns) >> } >> >> if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { >> -//TODO: implements host initialization >> +if (cdns3_host_init(cdns)) >> +dev_info(dev, "doesn't support host\n"); > >dev_err() > >And you need to error out with error code. ok, but I assume that even if host returns error then we can use only device role. Only when both functions return errors, then it's a critical error and function return error code. > >> } >> >> if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { >> @@ -142,7 +144,7 @@ static irqreturn_t cdns3_irq(int irq, void *data) >> >> static void cdns3_remove_roles(struct cdns3 *cdns) >> { >> -//TODO: implements this function > >if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) > >> +cdns3_host_remove(cdns); > >How about calling it cdns3_host_exit() to complement cdns3_host_init(). > >> } >> >> static int cdns3_do_role_switch(struct cdns3 *cdns, enum cdns3_roles role) >> @@ -410,6 +412,7 @@ static struct platform_driver cdns3_driver = { >> >> static int __init cdns3_driver_platform_register(void) >> { >> +cdns3_host_driver_init(); >> return platform_driver_register(&cdns3_driver); >> } >> module_init(cdns3_driver_platform_register); >> diff --git a/drivers/usb/cdns3/host-export.h >> b/drivers/usb/cdns3/host-export.h >> new file mode 100644 >> index ..f8f3b230b472 >> --- /dev/null >> +++ b/drivers/usb/cdns3/host-export.h >> @@ -0,0 +1,30 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Cadence USBSS DRD Driver -Host Export APIs >> + * >> + * Copyright (C) 2017 NXP >> + * >> + * Authors: Peter Chen >> + */ >> +#ifndef __LINUX_CDNS3_HOST_EXPORT >> +#define __LINUX_CDNS3_HOST_EXPORT >> + >> +#ifdef CONFIG_USB_CDNS3_HOST >> + >> +int cdns3_host_init(struct cdns3 *cdns); >> +void cdns3_
RE: [RFC PATCH v2 05/15] usb:cdns3: Added DRD support
> >Pawel, > >On 26/11/18 09:23, Pawel Laszczak wrote: >> Hi Roger, >> >>> On 18/11/18 12:09, Pawel Laszczak wrote: >>>> Patch adds supports for detecting Host/Device mode. >>>> Controller has additional OTG register that allow >>>> implement even whole OTG functionality. >>>> At this moment patch adds support only for detecting >>>> the appropriate mode based on strap pins and ID pin. >>>> >>>> Signed-off-by: Pawel Laszczak >>>> --- >>>> drivers/usb/cdns3/Makefile | 2 +- >>>> drivers/usb/cdns3/core.c | 27 +++-- >>>> drivers/usb/cdns3/drd.c| 229 + >>>> drivers/usb/cdns3/drd.h| 122 >>>> 4 files changed, 372 insertions(+), 8 deletions(-) >>>> create mode 100644 drivers/usb/cdns3/drd.c >>>> create mode 100644 drivers/usb/cdns3/drd.h >>>> >>>> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >>>> index 02d25b23c5d3..e779b2a2f8eb 100644 >>>> --- a/drivers/usb/cdns3/Makefile >>>> +++ b/drivers/usb/cdns3/Makefile >>>> @@ -1,5 +1,5 @@ >>>> obj-$(CONFIG_USB_CDNS3) += cdns3.o >>>> obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o >>>> >>>> -cdns3-y := core.o >>>> +cdns3-y := core.o drd.o >>>> cdns3-pci-y := cdns3-pci-wrap.o >>>> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >>>> index f9055d4da67f..dbee4325da7f 100644 >>>> --- a/drivers/usb/cdns3/core.c >>>> +++ b/drivers/usb/cdns3/core.c >>>> @@ -17,6 +17,7 @@ >>>> >>>> #include "gadget.h" >>>> #include "core.h" >>>> +#include "drd.h" >>>> >>>> static inline struct cdns3_role_driver >>>> *cdns3_get_current_role_driver(struct cdns3 *cdns) >>>> { >>>> @@ -57,8 +58,10 @@ static inline void cdns3_role_stop(struct cdns3 *cdns) >>>> static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >>>> { >>>>if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >>>> - //TODO: implements selecting device/host mode >>>> - return CDNS3_ROLE_HOST; >>>> + if (cdns3_is_host(cdns)) >>>> + return CDNS3_ROLE_HOST; >>>> + if (cdns3_is_device(cdns)) >>>> + return CDNS3_ROLE_GADGET; >>>>} >>>>return cdns->roles[CDNS3_ROLE_HOST] >>>>? CDNS3_ROLE_HOST >>>> @@ -124,6 +127,12 @@ static irqreturn_t cdns3_irq(int irq, void *data) >>>>struct cdns3 *cdns = data; >>>>irqreturn_t ret = IRQ_NONE; >>>> >>>> + if (cdns->dr_mode == USB_DR_MODE_OTG) { >>>> + ret = cdns3_drd_irq(cdns); >>>> + if (ret == IRQ_HANDLED) >>>> + return ret; >>>> + } >>> >>> The kernel's shared IRQ model takes care of sharing the same interrupt >>> between different devices and their drivers. You don't need to manually >>> handle it here. Just let all 3 drivers do a request_irq() and have >>> handlers check if the IRQ was theirs or not and return IRQ_HANDLED or >>> IRQ_NONE accordingly. >>> >>> Looks like you can do away with irq member of the role driver struct. >> >> Ok, I will split it into 3 separate part, but in this case, I additionally >> have to check the current >> role in ISR function. Driver can't read host side registers when controller >> works in device role >> and vice versa. One part of controller is kept in reset. Only DRD registers >> are common and are all accessible. >> > >In which ISR do you need to check current role? > >I'm not sure if we are on the same page. >Core (drd) driver shouldn't read host/device side registers. All 3 drivers, >i.e. DRD(core), Host (xhci) and device (cdns3) should do a request_irq() >and process their respective IRQ events. Yes, I understand. I need to check this in cdns3_irq_handler_thread and cdns3_host_irq. Core (drd) has register that are always accessible. Core (device) - registers are available also in device mode Core (host) - registers are available only in host mode So we can use separate requ
RE: [RFC PATCH v2 05/15] usb:cdns3: Added DRD support
>>> >>> Pawel, >>> >>> On 26/11/18 09:23, Pawel Laszczak wrote: >>>> Hi Roger, >>>> >>>>> On 18/11/18 12:09, Pawel Laszczak wrote: >>>>>> Patch adds supports for detecting Host/Device mode. >>>>>> Controller has additional OTG register that allow >>>>>> implement even whole OTG functionality. >>>>>> At this moment patch adds support only for detecting >>>>>> the appropriate mode based on strap pins and ID pin. >>>>>> >>>>>> Signed-off-by: Pawel Laszczak >>>>>> --- >>>>>> drivers/usb/cdns3/Makefile | 2 +- >>>>>> drivers/usb/cdns3/core.c | 27 +++-- >>>>>> drivers/usb/cdns3/drd.c| 229 + >>>>>> drivers/usb/cdns3/drd.h| 122 >>>>>> 4 files changed, 372 insertions(+), 8 deletions(-) >>>>>> create mode 100644 drivers/usb/cdns3/drd.c >>>>>> create mode 100644 drivers/usb/cdns3/drd.h >>>>>> >>>>>> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >>>>>> index 02d25b23c5d3..e779b2a2f8eb 100644 >>>>>> --- a/drivers/usb/cdns3/Makefile >>>>>> +++ b/drivers/usb/cdns3/Makefile >>>>>> @@ -1,5 +1,5 @@ >>>>>> obj-$(CONFIG_USB_CDNS3) += cdns3.o >>>>>> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >>>>>> >>>>>> -cdns3-y := core.o >>>>>> +cdns3-y := core.o drd.o >>>>>> cdns3-pci-y := cdns3-pci-wrap.o >>>>>> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >>>>>> index f9055d4da67f..dbee4325da7f 100644 >>>>>> --- a/drivers/usb/cdns3/core.c >>>>>> +++ b/drivers/usb/cdns3/core.c >>>>>> @@ -17,6 +17,7 @@ >>>>>> >>>>>> #include "gadget.h" >>>>>> #include "core.h" >>>>>> +#include "drd.h" >>>>>> >>>>>> static inline struct cdns3_role_driver >>>>>> *cdns3_get_current_role_driver(struct cdns3 *cdns) >>>>>> { >>>>>> @@ -57,8 +58,10 @@ static inline void cdns3_role_stop(struct cdns3 *cdns) >>>>>> static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >>>>>> { >>>>>> if (cdns->roles[CDNS3_ROLE_HOST] && >>>>>> cdns->roles[CDNS3_ROLE_GADGET]) { >>>>>> -//TODO: implements selecting device/host mode >>>>>> -return CDNS3_ROLE_HOST; >>>>>> +if (cdns3_is_host(cdns)) >>>>>> +return CDNS3_ROLE_HOST; >>>>>> +if (cdns3_is_device(cdns)) >>>>>> +return CDNS3_ROLE_GADGET; >>>>>> } >>>>>> return cdns->roles[CDNS3_ROLE_HOST] >>>>>> ? CDNS3_ROLE_HOST >>>>>> @@ -124,6 +127,12 @@ static irqreturn_t cdns3_irq(int irq, void *data) >>>>>> struct cdns3 *cdns = data; >>>>>> irqreturn_t ret = IRQ_NONE; >>>>>> >>>>>> +if (cdns->dr_mode == USB_DR_MODE_OTG) { >>>>>> +ret = cdns3_drd_irq(cdns); >>>>>> +if (ret == IRQ_HANDLED) >>>>>> +return ret; >>>>>> +} >>>>> >>>>> The kernel's shared IRQ model takes care of sharing the same interrupt >>>>> between different devices and their drivers. You don't need to manually >>>>> handle it here. Just let all 3 drivers do a request_irq() and have >>>>> handlers check if the IRQ was theirs or not and return IRQ_HANDLED or >>>>> IRQ_NONE accordingly. >>>>> >>>>> Looks like you can do away with irq member of the role driver struct. >>>> >>>> Ok, I will split it into 3 separate part, but in this case, I additionally >>>> have to check the current >>>> role in ISR function. Driver can't read host side registers when >>>>
RE: [RFC PATCH v2 06/15] usb:cdns3: Adds Host support
> >Hi, > >On 26/11/18 10:24, Pawel Laszczak wrote: >>> EXTERNAL MAIL >>> >>> >>> On 18/11/18 12:09, Pawel Laszczak wrote: >>>> Patch adds host-export.h and host.c file and mplements functions that >>>> allow to initialize, start and stop XHCI host driver. >>>> >>>> Signed-off-by: Pawel Laszczak >>>> --- >>>> drivers/usb/cdns3/Kconfig | 10 ++ >>>> drivers/usb/cdns3/Makefile | 1 + >>>> drivers/usb/cdns3/core.c| 7 +- >>>> drivers/usb/cdns3/host-export.h | 30 >>>> drivers/usb/cdns3/host.c| 256 >>>> 5 files changed, 302 insertions(+), 2 deletions(-) >>>> create mode 100644 drivers/usb/cdns3/host-export.h >>>> create mode 100644 drivers/usb/cdns3/host.c >>>> >>>> diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig >>>> index eb22a8692991..d92bc3d68eb0 100644 >>>> --- a/drivers/usb/cdns3/Kconfig >>>> +++ b/drivers/usb/cdns3/Kconfig >>>> @@ -10,6 +10,16 @@ config USB_CDNS3 >>>> >>>> if USB_CDNS3 >>>> >>>> +config USB_CDNS3_HOST >>>> +bool "Cadence USB3 host controller" >>>> +depends on USB_XHCI_HCD >>>> +help >>>> + Say Y here to enable host controller functionality of the >>>> + cadence driver. >>>> + >>>> + Host controller is compliance with XHCI so it will use >>>> + standard XHCI driver. >>>> + >>>> config USB_CDNS3_PCI_WRAP >>>>tristate "PCIe-based Platforms" >>>>depends on USB_PCI && ACPI >>>> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >>>> index e779b2a2f8eb..976117ba67ff 100644 >>>> --- a/drivers/usb/cdns3/Makefile >>>> +++ b/drivers/usb/cdns3/Makefile >>>> @@ -2,4 +2,5 @@ obj-$(CONFIG_USB_CDNS3)+= cdns3.o >>>> obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o >>>> >>>> cdns3-y := core.o drd.o >>>> +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o >>>> cdns3-pci-y := cdns3-pci-wrap.o >>>> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >>>> index dbee4325da7f..4cb820be9ff3 100644 >>>> --- a/drivers/usb/cdns3/core.c >>>> +++ b/drivers/usb/cdns3/core.c >>>> @@ -17,6 +17,7 @@ >>>> >>>> #include "gadget.h" >>>> #include "core.h" >>>> +#include "host-export.h" >>>> #include "drd.h" >>>> >>>> static inline struct cdns3_role_driver >>>> *cdns3_get_current_role_driver(struct cdns3 *cdns) >>>> @@ -98,7 +99,8 @@ static int cdns3_core_init_role(struct cdns3 *cdns) >>>>} >>>> >>>>if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { >>>> - //TODO: implements host initialization >>>> + if (cdns3_host_init(cdns)) >>>> + dev_info(dev, "doesn't support host\n"); >>> >>> dev_err() >>> >>> And you need to error out with error code. >> >> ok, but I assume that even if host returns error then we can use >> only device role. Only when both functions return errors, then it's a >> critical error >> and function return error code. > >But at this point we are in OTG or HOST dr_mode and without host functional >both will not function correctly. So we must error out so user can debug. Ok, > >>> >>>>} >>>> >>>>if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { >>>> @@ -142,7 +144,7 @@ static irqreturn_t cdns3_irq(int irq, void *data) >>>> >>>> static void cdns3_remove_roles(struct cdns3 *cdns) >>>> { >>>> - //TODO: implements this function >>> >>> if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) >>> >>>> + cdns3_host_remove(cdns); >>> >>> How about calling it cdns3_host_exit() to complement cdns3_host_init(). >>> >>>> } >>>> >>>> static int cdns3_do_role_switch(struct cdns3 *cdns, enum cdns3_roles role) >>>> @@ -410,6 +412,7 @@ static st
RE: [RFC PATCH v2 05/15] usb:cdns3: Added DRD support
Hi Roger >>> Patch adds supports for detecting Host/Device mode. >>> + >>> +static int cdns3_otg_get_id(struct cdns3 *cdns) >>> +{ >>> + int id; >>> + >>> + id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE; >>> + dev_dbg(cdns->dev, "OTG ID: %d", id); >>> + return id; >>> +} >>> + >>> +int cdns3_is_host(struct cdns3 *cdns) >>> +{ >>> + if (cdns->current_dr_mode == USB_DR_MODE_HOST) >>> + return 1; >> >>Why do you need this? > >I assumed that some SoC could have cut DRD /OTG and Device or Host part. >In such case the driver cannot be based on ID pin. >For only HOST it's not a problem because >the standard XHCI driver will be used. Probably I will remove this fragment. I've removed this condition but it is necessary and I've restored it again. When driver works in only HOST mode then ID is always 0. For current_dr_mode == USB_DR_MODE_HOST driver has to just simple returns 1. current_dr_mode can be changed from user space depending on dr_mode field. I have the additional question. Because I have many changes in source code if I should post the next RFC PATCH v3 or should I wait for comments for rest patches ? >> >>> + else if (cdns->current_dr_mode == USB_DR_MODE_OTG) >>> + if (!cdns3_otg_get_id(cdns)) >>> + return 1; >>> + >>> + return 0; >>> +} >>> + Thanks, Cheers, Pawel
RE: [RFC PATCH v2 07/15] usb:cdns3: Adds Device mode support - initialization.
Hi, >> Roger Quadros writes: >> >> +static void cdns3_gadget_config(struct cdns3_device *priv_dev) { >> >> + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; >> >> + >> >> + cdns3_ep0_config(priv_dev); >> >> + >> >> + /* enable interrupts for endpoint 0 (in and out) */ >> >> + writel(EP_IEN_EP_OUT0 | EP_IEN_EP_IN0, ®s->ep_ien); >> >> + >> >> + /* enable generic interrupt*/ >> >> + writel(USB_IEN_INIT, ®s->usb_ien); >> >> + writel(USB_CONF_CLK2OFFDS | USB_CONF_L1DS, ®s->usb_conf); >> >> + writel(USB_CONF_DMULT, ®s->usb_conf); >> >> + writel(USB_CONF_DEVEN, ®s->usb_conf); >> > >> > If you are enabling interrupts in this patch you should handle them in the >> > ISR. >> >> Frankly, I don't understand why this is a series. It's a single driver and >> splitting it into >> a series just makes it more difficult to review, actually. >> >> Sure, a single patch will be large, but there's no way to have a functional >> driver until >> all patches are applied, anyway. >> > >Yes, I agree with Felipe. Pawel, you could remove the "RFC" prefix, and send >the whole >one as one patch. I will test it at my hardware. Ok, I will prepare such single patch. Peter I know that you have little different platform. Probably you should made some additional changes for your platform. I assume that core.c should be common file. Probably we should add also some platform specific file. Thanks. Pawel.
RE: [RFC PATCH v2 07/15] usb:cdns3: Adds Device mode support - initialization.
Hi, > >+Felipe. > >Pawel, > >Please copy Felipe Balbi as he maintains the USB gadget stack. > >On 18/11/18 12:09, Pawel Laszczak wrote: >> Patch implements a set of functions responsible for initialization, >> configuration, starting and stopping device mode. >> This patch also adds new ep0.c that holds all functions related >> to endpoint 0. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Kconfig | 10 + >> drivers/usb/cdns3/Makefile| 1 + >> drivers/usb/cdns3/core.c | 5 +- >> drivers/usb/cdns3/ep0.c | 105 >> drivers/usb/cdns3/gadget-export.h | 27 +++ >> drivers/usb/cdns3/gadget.c| 390 ++ >> drivers/usb/cdns3/gadget.h| 4 + >> 7 files changed, 541 insertions(+), 1 deletion(-) >> create mode 100644 drivers/usb/cdns3/ep0.c >> create mode 100644 drivers/usb/cdns3/gadget-export.h >> create mode 100644 drivers/usb/cdns3/gadget.c >> >> diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig >> index d92bc3d68eb0..b7d71b5c4f60 100644 >> --- a/drivers/usb/cdns3/Kconfig >> +++ b/drivers/usb/cdns3/Kconfig >> @@ -10,6 +10,16 @@ config USB_CDNS3 >> >> if USB_CDNS3 >> >> +config USB_CDNS3_GADGET >> +bool "Cadence USB3 device controller" >> +depends on USB_GADGET >> +help >> + Say Y here to enable device controller functionality of the >> + cadence USBSS-DEV driver. >> + >> + This controller support FF, HS and SS mode. It doeasn't support > >s/support/supports >s/doeasn't/doesn't > >> + LS and SSP mode >> + >> config USB_CDNS3_HOST >> bool "Cadence USB3 host controller" >> depends on USB_XHCI_HCD >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index 976117ba67ff..bea6173bf37f 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -2,5 +2,6 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> >> cdns3-y := core.o drd.o >> +cdns3-$(CONFIG_USB_CDNS3_GADGET)+= gadget.o ep0.o >> cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o >> cdns3-pci-y := cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> index 4cb820be9ff3..1fa233415901 100644 >> --- a/drivers/usb/cdns3/core.c >> +++ b/drivers/usb/cdns3/core.c >> @@ -18,6 +18,7 @@ >> #include "gadget.h" >> #include "core.h" >> #include "host-export.h" >> +#include "gadget-export.h" >> #include "drd.h" >> >> static inline struct cdns3_role_driver >> *cdns3_get_current_role_driver(struct cdns3 *cdns) >> @@ -104,7 +105,8 @@ static int cdns3_core_init_role(struct cdns3 *cdns) >> } >> >> if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { >> -//TODO: implements device initialization >> +if (cdns3_gadget_init(cdns)) >> +dev_info(dev, "doesn't support gadget\n"); > >dev_err() and we should should error out with error code returned by >cdns3_gadget_init(). Ok, > >> } >> >> if (!cdns->roles[CDNS3_ROLE_HOST] && !cdns->roles[CDNS3_ROLE_GADGET]) { >> @@ -144,6 +146,7 @@ static irqreturn_t cdns3_irq(int irq, void *data) >> >> static void cdns3_remove_roles(struct cdns3 *cdns) >> { > >if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) I had to little change this fragment. In the latest version only single driver (role) can be initialized and started so this code has changed to : static void cdns3_exit_roles(struct cdns3 *cdns) { cdns3_role_stop(cdns); cdns3_drd_exit(cdns); } Functions cdns3_gadget_remove and cdns3_host_remove are no longer needed. >> +cdns3_gadget_remove(cdns); >> cdns3_host_remove(cdns); >> } >> >> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c >> new file mode 100644 >> index ..c08d02665f9d >> --- /dev/null >> +++ b/drivers/usb/cdns3/ep0.c >> @@ -0,0 +1,105 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Cadence USBSS DRD Driver - gadget side. >> + * >> + * Copyright (C) 2018 Cadence Design Systems. >> + * Copyright (C) 2017 NXP >> + * >>
RE: [RFC PATCH v2 08/15] usb:cdns3: Implements device operations part of the API
Hi, >> Patch adds implementation callback function defined in >> usb_gadget_ops object. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/gadget.c | 249 - >> 1 file changed, 247 insertions(+), 2 deletions(-) >> >> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c >> index 376b68b13d1b..702a05faa664 100644 >> --- a/drivers/usb/cdns3/gadget.c >> +++ b/drivers/usb/cdns3/gadget.c >> @@ -17,6 +17,36 @@ >> #include "gadget-export.h" >> #include "gadget.h" >> >> +/** >> + * cdns3_handshake - spin reading until handshake completes or fails >> + * @ptr: address of device controller register to be read >> + * @mask: bits to look at in result of read >> + * @done: value of those bits when handshake succeeds >> + * @usec: timeout in microseconds >> + * >> + * Returns negative errno, or zero on success >> + * >> + * Success happens when the "mask" bits have the specified value (hardware >> + * handshake done). There are two failure modes: "usec" have passed (major >> + * hardware flakeout), or the register reads as all-ones (hardware removed). >> + */ >> +int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) >> +{ >> +u32 result; >> + >> +do { >> +result = readl(ptr); >> +if (result == ~(u32)0) /* card removed */ >> +return -ENODEV; > >Is this applicable to all registers? >What is meant by card removed? We're not connected to host? > >how does EP reset behave when there is no USB connection? > Function was adopted from XHCI driver (xhci_handshake). I think it's about PCI card. If this happens driver should read 0x from any register. I need to confirm it with hardware team or test it. I remember that I had such situation some time ago. My testing platform consist of separate FPGA board and PC. Both has PCI adapter and are connected by means of special PCI cable. >> +result &= mask; >> +if (result == done) >> +return 0; >> +udelay(1); >> +usec--; >> +} while (usec > 0); >> +return -ETIMEDOUT; >> +} >> + >> /** >> * cdns3_set_register_bit - set bit in given register. >> * @ptr: address of device controller register to be read and changed >> @@ -43,6 +73,25 @@ void cdns3_select_ep(struct cdns3_device *priv_dev, u32 >> ep) >> writel(ep, &priv_dev->regs->ep_sel); >> } >> >> +static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) >> +{ >> +struct cdns3_device *priv_dev = priv_ep->cdns3_dev; >> + >> +if (priv_ep->trb_pool) { >> +dma_free_coherent(priv_dev->sysdev, >> + TRB_RIGN_SIZE, >> + priv_ep->trb_pool, priv_ep->trb_pool_dma); >> +priv_ep->trb_pool = NULL; >> +} >> + >> +if (priv_ep->aligned_buff) { >> +dma_free_coherent(priv_dev->sysdev, CDNS3_UNALIGNED_BUF_SIZE, >> + priv_ep->aligned_buff, >> + priv_ep->aligned_dma_addr); >> +priv_ep->aligned_buff = NULL; >> +} >> +} >> + >> /** >> * cdns3_irq_handler - irq line interrupt handler >> * @cdns: cdns3 instance >> @@ -58,6 +107,114 @@ static irqreturn_t cdns3_irq_handler_thread(struct >> cdns3 *cdns) >> return ret; >> } >> >> +/* Find correct direction for HW endpoint according to description */ >> +static int cdns3_ep_dir_is_correct(struct usb_endpoint_descriptor *desc, >> + struct cdns3_endpoint *priv_ep) >> +{ >> +return (priv_ep->endpoint.caps.dir_in && usb_endpoint_dir_in(desc)) || >> + (priv_ep->endpoint.caps.dir_out && usb_endpoint_dir_out(desc)); >> +} >> + >> +static struct cdns3_endpoint *cdns3_find_available_ss_ep(struct >> cdns3_device *priv_dev, >> + struct >> usb_endpoint_descriptor *desc) > >why is this function called ss_ep? This doesn't seem like only for superspeed >endpoints. I will remove _ss_. > >> +{ >> +struct usb_ep *ep; >> +struct cdns3_endpoint *priv_ep; >> + >> +list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { >> +
RE: [RFC PATCH v2 09/15] usb:cdns3: EpX operations part of the API
Hi >> Patch implements callback functions for non-default endpoints >> defined in usb_ep_ops object. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/ep0.c| 18 ++ >> drivers/usb/cdns3/gadget.c | 442 - >> drivers/usb/cdns3/gadget.h | 3 + >> 3 files changed, 461 insertions(+), 2 deletions(-) >> >> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c >> index c08d02665f9d..ca1795467155 100644 >> --- a/drivers/usb/cdns3/ep0.c >> +++ b/drivers/usb/cdns3/ep0.c >> @@ -23,6 +23,24 @@ static void cdns3_prepare_setup_packet(struct >> cdns3_device *priv_dev) >> //TODO: Implements this function >> } >> >> +/** >> + * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint >> + * @ep: endpoint object >> + * >> + * Returns 0 >> + */ >> +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) >> +{ >> +struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); >> +struct cdns3_device *priv_dev = priv_ep->cdns3_dev; >> + >> +dev_dbg(&priv_dev->dev, "Wedge for %s\n", ep->name); >> +cdns3_gadget_ep_set_halt(ep, 1); >> +priv_ep->flags |= EP_WEDGE; >> + >> +return 0; >> +} >> + >> /** >> * cdns3_ep0_config - Configures default endpoint >> * @priv_dev: extended gadget object >> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c >> index 702a05faa664..1f2a434486dc 100644 >> --- a/drivers/usb/cdns3/gadget.c >> +++ b/drivers/usb/cdns3/gadget.c >> @@ -58,6 +58,19 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask) >> writel(mask, ptr); >> } >> >> +/** >> + * cdns3_next_request - returns next request from list >> + * @list: list containing requests >> + * >> + * Returns request or NULL if no requests in list >> + */ >> +struct usb_request *cdns3_next_request(struct list_head *list) >> +{ >> +if (list_empty(list)) >> +return NULL; >> +return list_first_entry(list, struct usb_request, list); >> +} >> + >> /** >> * select_ep - selects endpoint >> * @priv_dev: extended gadget object >> @@ -73,6 +86,53 @@ void cdns3_select_ep(struct cdns3_device *priv_dev, u32 >> ep) >> writel(ep, &priv_dev->regs->ep_sel); >> } >> >> +/** >> + * cdns3_allocate_trb_pool - Allocates TRB's pool for selected endpoint >> + * @priv_ep: endpoint object >> + * >> + * Function will return 0 on success or -ENOMEM on allocation error >> + */ >> +static int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) >> +{ >> +struct cdns3_device *priv_dev = priv_ep->cdns3_dev; >> +struct cdns3_trb *link_trb; >> + >> +if (!priv_ep->trb_pool) { >> +priv_ep->trb_pool = dma_zalloc_coherent(priv_dev->sysdev, >> +TRB_RIGN_SIZE, > >TRB_RING_SIZE > >> +&priv_ep->trb_pool_dma, >> +GFP_DMA); >> +if (!priv_ep->trb_pool) >> +return -ENOMEM; >> +} else { >> +memset(priv_ep->trb_pool, 0, TRB_RIGN_SIZE); > >here too. > >> +} >> + >> +if (!priv_ep->aligned_buff) { >> +priv_ep->aligned_buff = dma_alloc_coherent(priv_dev->sysdev, >> + >> CDNS3_UNALIGNED_BUF_SIZE, > >CDNS3_ALIGNED_BUF_SIZE > >> + >> &priv_ep->aligned_dma_addr, >> + GFP_DMA); >> +if (!priv_ep->aligned_buff) { >> +dma_free_coherent(priv_dev->sysdev, >> + TRB_RIGN_SIZE, >> + priv_ep->trb_pool, >> + priv_ep->trb_pool_dma); >> +priv_ep->trb_pool = NULL; >> + >> +return -ENOMEM; >> +} >> +} >> + >> +/* Initialize the last TRB as Link TRB */ >> +link_trb = (priv_ep->trb_pool + TRBS_PER_SEGMENT - 1); >> +link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma); >> +link_trb->control = TRB_CYCLE | TRB_TYPE(TRB_LINK) | >> +T
RE: [RFC PATCH v2 10/15] usb:cdns3: Ep0 operations part of the API
>> Patch implements related to default endpoint callback functions >> defined in usb_ep_ops object >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/ep0.c| 191 - >> drivers/usb/cdns3/gadget.c | 8 ++ >> drivers/usb/cdns3/gadget.h | 10 ++ >> 3 files changed, 207 insertions(+), 2 deletions(-) >> >> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c >> index ca1795467155..d05169e73631 100644 >> --- a/drivers/usb/cdns3/ep0.c >> +++ b/drivers/usb/cdns3/ep0.c >> @@ -18,11 +18,185 @@ static struct usb_endpoint_descriptor >> cdns3_gadget_ep0_desc = { >> .bmAttributes = USB_ENDPOINT_XFER_CONTROL, >> }; >> >> +/** >> + * cdns3_ep0_run_transfer - Do transfer on default endpoint hardware >> + * @priv_dev: extended gadget object >> + * @dma_addr: physical address where data is/will be stored >> + * @length: data length >> + * @erdy: set it to 1 when ERDY packet should be sent - >> + *exit from flow control state >> + */ >> +static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev, >> + dma_addr_t dma_addr, >> + unsigned int length, int erdy) >> +{ >> +struct cdns3_usb_regs __iomem *regs = priv_dev->regs; >> + >> +priv_dev->trb_ep0->buffer = TRB_BUFFER(dma_addr); >> +priv_dev->trb_ep0->length = TRB_LEN(length); >> +priv_dev->trb_ep0->control = TRB_CYCLE | TRB_IOC | TRB_TYPE(TRB_NORMAL); >> + >> +cdns3_select_ep(priv_dev, >> +priv_dev->ep0_data_dir ? USB_DIR_IN : USB_DIR_OUT); >> + >> +writel(EP_STS_TRBERR, ®s->ep_sts); >> +writel(EP_TRADDR_TRADDR(priv_dev->trb_ep0_dma), ®s->ep_traddr); >> + >> +dev_dbg(&priv_dev->dev, "//Ding Dong ep0%s\n", >> +priv_dev->ep0_data_dir ? "IN" : "OUT"); >> + >> +/* TRB should be prepared before starting transfer */ >> +writel(EP_CMD_DRDY, ®s->ep_cmd); >> + >> +if (erdy) >> +writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd); >> +} >> + >> static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) >> { >> //TODO: Implements this function >> } >> >> +static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) > >Is this going to be used only for ep0? >If yes then let's have ep0 in the name. >If not then this function should be in gadget.c It going to be used only in ep0.c file but general it's related to all non-control endpoints. The controller has one strange limitation, namely endpoints configuration in controller can be set only once. and this function inform control about this. II think that, will be better to move this function to gadget.c then adding ep0 to name. > >> +{ >> +struct cdns3_endpoint *priv_ep; >> +struct usb_request *request; >> +struct usb_ep *ep; >> +int result = 0; >> + >> +if (priv_dev->hw_configured_flag) >> +return; >> + >> +writel(USB_CONF_CFGSET, &priv_dev->regs->usb_conf); >> +writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); >> + >> +cdns3_set_register_bit(&priv_dev->regs->usb_conf, >> + USB_CONF_U1EN | USB_CONF_U2EN); > >Shouldn't U1/U2 be enabled only if the >USB_DEVICE_U1_ENABLE/USB_DEVICE_U2_ENABLE >device request was received? These bits only inform the controller that it should enter to U1/U2 only if host asks for such a transition. Device to force transition to U1/U2 must use other bits. >> + >> +/* wait until configuration set */ >> +result = cdns3_handshake(&priv_dev->regs->usb_sts, >> + USB_STS_CFGSTS_MASK, 1, 100); >> + >> +priv_dev->hw_configured_flag = 1; >> +cdns3_enable_l1(priv_dev, 1); >> + >> +list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { >> +if (ep->enabled) { >> +priv_ep = ep_to_cdns3_ep(ep); >> +request = cdns3_next_request(&priv_ep->request_list); >> +if (request) >> +cdns3_ep_run_transfer(priv_ep, request); > >why are you starting transfers in a function that is supposed to set hw >configuration only. Because we can't start transfer before configuring endpoints in hardware. Also we can'
RE: [RFC PATCH v2 11/15] usb:cdns3: Implements ISR functionality.
Hi, >> Patch adds set of generic functions used for handling interrupts >> generated by controller. Interrupt related functions are divided >> into three groups. The first is related to ep0 and is placed in ep0.c. >> The second is responsible for non-default endpoints and is >> implemented in gadget.c file. The last group is not related to >> endpoints interrupts and is placed in gadget.c. >> All groups have common entry point in cdns3_irq_handler_thread function. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/ep0.c| 63 +++ >> drivers/usb/cdns3/gadget.c | 224 - >> drivers/usb/cdns3/gadget.h | 1 + >> 3 files changed, 287 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c >> index d05169e73631..eb92fd234bd7 100644 >> --- a/drivers/usb/cdns3/ep0.c >> +++ b/drivers/usb/cdns3/ep0.c >> @@ -90,6 +90,69 @@ static void cdns3_set_hw_configuration(struct >> cdns3_device *priv_dev) >> } >> } >> >> +static void __pending_setup_status_handler(struct cdns3_device *priv_dev) >> +{ >> +//TODO: Implements this function >> +} >> + >> +/** >> + * cdns3_ep0_setup_phase - Handling setup USB requests >> + * @priv_dev: extended gadget object >> + */ >> +static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev) >> +{ >> +//TODO: Implements this function. >> +} >> + >> +static void cdns3_transfer_completed(struct cdns3_device *priv_dev) >> +{ >> +//TODO: Implements this function >> +} >> + >> +/** >> + * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to >> endpoint 0 >> + * @priv_dev: extended gadget object >> + * @dir: 1 for IN direction, 0 for OUT direction >> + */ >> +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int >> dir) >> +{ >> +struct cdns3_usb_regs __iomem *regs = priv_dev->regs; >> +u32 ep_sts_reg; >> + >> +cdns3_select_ep(priv_dev, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT)); >> +ep_sts_reg = readl(®s->ep_sts); >> + >> +__pending_setup_status_handler(priv_dev); >> + >> +if ((ep_sts_reg & EP_STS_SETUP) && dir == 0) { >> +struct usb_ctrlrequest *setup = priv_dev->setup; >> + >> +writel(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP, ®s->ep_sts); > >instead you can just clear all events at the end of this function by > writel(ep_sts_reg, ®s->ep_sts); But I can delete events that can appear during processing this function. I think that safer is to add this fragment at the beginning, below line ep_sts_reg = readl(®s->ep_sts); >> + >> +priv_dev->ep0_data_dir = setup->bRequestType & USB_DIR_IN; >> +cdns3_ep0_setup_phase(priv_dev); >> +ep_sts_reg &= ~(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP); > >Not required. Why not ? I must clear at least EP_STS_IOC | EP_STS_ISP. I don't want to handle the last condition in this function, of course if SETUP was reported. Of course I can also change the construction of function and then I could delete this statement. > >> +} >> + >> +if (ep_sts_reg & EP_STS_TRBERR) >> +writel(EP_STS_TRBERR, &priv_dev->regs->ep_sts); > >Can be omitted. >> + >> +if (ep_sts_reg & EP_STS_DESCMIS) { >> +writel(EP_STS_DESCMIS, &priv_dev->regs->ep_sts); > >This as well. >> + >> +if (dir == 0 && !priv_dev->setup_pending) { >> +priv_dev->ep0_data_dir = 0; >> +cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, >> + 8, 0); >> +} >> +} >> + >> +if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) { >> +writel(EP_STS_IOC, &priv_dev->regs->ep_sts); > >this write can be omitted. >> +cdns3_transfer_completed(priv_dev); >> +} > >here you can do > writel(ep_sts_reg, ®s->ep_sts); >> +} >> + >> /** >> * cdns3_gadget_ep0_enable >> * Function shouldn't be called by gadget driver, >> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c >> index c965da16c0c8..309202474e57 100644 >> --- a/drivers/usb/cdns3/gadget.c >> +++ b/drivers/usb/cdns3/gadget.c >> @@ -58,6 +58,18 @@ void cdns3_set_re
RE: [RFC PATCH v2 11/15] usb:cdns3: Implements ISR functionality.
>Hi, > >>> Patch adds set of generic functions used for handling interrupts >>> generated by controller. Interrupt related functions are divided >>> into three groups. The first is related to ep0 and is placed in ep0.c. >>> The second is responsible for non-default endpoints and is >>> implemented in gadget.c file. The last group is not related to >>> endpoints interrupts and is placed in gadget.c. >>> All groups have common entry point in cdns3_irq_handler_thread function. >>> >>> Signed-off-by: Pawel Laszczak >>> --- >>> drivers/usb/cdns3/ep0.c| 63 +++ >>> drivers/usb/cdns3/gadget.c | 224 - >>> drivers/usb/cdns3/gadget.h | 1 + >>> 3 files changed, 287 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c >>> index d05169e73631..eb92fd234bd7 100644 >>> --- a/drivers/usb/cdns3/ep0.c >>> +++ b/drivers/usb/cdns3/ep0.c >>> @@ -90,6 +90,69 @@ static void cdns3_set_hw_configuration(struct >>> cdns3_device *priv_dev) >>> } >>> } >>> >>> +static void __pending_setup_status_handler(struct cdns3_device *priv_dev) >>> +{ >>> + //TODO: Implements this function >>> +} >>> + >>> +/** >>> + * cdns3_ep0_setup_phase - Handling setup USB requests >>> + * @priv_dev: extended gadget object >>> + */ >>> +static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev) >>> +{ >>> + //TODO: Implements this function. >>> +} >>> + >>> +static void cdns3_transfer_completed(struct cdns3_device *priv_dev) >>> +{ >>> + //TODO: Implements this function >>> +} >>> + >>> +/** >>> + * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to >>> endpoint 0 >>> + * @priv_dev: extended gadget object >>> + * @dir: 1 for IN direction, 0 for OUT direction >>> + */ >>> +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int >>> dir) >>> +{ >>> + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; >>> + u32 ep_sts_reg; >>> + >>> + cdns3_select_ep(priv_dev, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT)); >>> + ep_sts_reg = readl(®s->ep_sts); >>> + >>> + __pending_setup_status_handler(priv_dev); >>> + >>> + if ((ep_sts_reg & EP_STS_SETUP) && dir == 0) { >>> + struct usb_ctrlrequest *setup = priv_dev->setup; >>> + >>> + writel(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP, ®s->ep_sts); >> >>instead you can just clear all events at the end of this function by >> writel(ep_sts_reg, ®s->ep_sts); > >But I can delete events that can appear during processing this function. >I think that safer is to add this fragment at the beginning, below line >ep_sts_reg = readl(®s->ep_sts); > > >>> + >>> + priv_dev->ep0_data_dir = setup->bRequestType & USB_DIR_IN; >>> + cdns3_ep0_setup_phase(priv_dev); >>> + ep_sts_reg &= ~(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP); >> >>Not required. >Why not ? I must clear at least EP_STS_IOC | EP_STS_ISP. >I don't want to handle the last condition in this function, of course if >SETUP was reported. > >Of course I can also change the construction of function and then I could >delete this statement. >> >>> + } >>> + >>> + if (ep_sts_reg & EP_STS_TRBERR) >>> + writel(EP_STS_TRBERR, &priv_dev->regs->ep_sts); >> >>Can be omitted. >>> + >>> + if (ep_sts_reg & EP_STS_DESCMIS) { >>> + writel(EP_STS_DESCMIS, &priv_dev->regs->ep_sts); >> >>This as well. >>> + >>> + if (dir == 0 && !priv_dev->setup_pending) { >>> + priv_dev->ep0_data_dir = 0; >>> + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, >>> + 8, 0); >>> + } >>> + } >>> + >>> + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) { >>> + writel(EP_STS_IOC, &priv_dev->regs->ep_sts); >> >>this write can be omitted. >>> + cdns3_transfer_completed(priv_dev); >>> + } >> >>here you can do >> writel(ep_sts_reg,
RE: [RFC PATCH v2 12/15] usb:cdns3: Adds enumeration related function.
>On 18/11/18 12:09, Pawel Laszczak wrote: >> Patch implements a set of function related to enumeration process. >> Some standard requests are handled on controller driver level and >> other are delegated to gadget core driver. >> All class requests are delegated to gadget core driver. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/ep0.c| 491 - >> drivers/usb/cdns3/gadget.c | 119 + >> drivers/usb/cdns3/gadget.h | 4 + >> 3 files changed, 610 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c >> index eb92fd234bd7..6f33d98f7684 100644 >> --- a/drivers/usb/cdns3/ep0.c >> +++ b/drivers/usb/cdns3/ep0.c >> @@ -10,6 +10,7 @@ >> * Peter Chen >> */ >> >> +#include >> #include "gadget.h" >> >> static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { >> @@ -52,9 +53,31 @@ static void cdns3_ep0_run_transfer(struct cdns3_device >> *priv_dev, >> writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd); >> } >> >> +/** >> + * cdns3_ep0_delegate_req - Returns status of handling setup packet >> + * Setup is handled by gadget driver >> + * @priv_dev: extended gadget object >> + * @ctrl_req: pointer to received setup packet >> + * >> + * Returns zero on success or negative value on failure >> + */ >> +static int cdns3_ep0_delegate_req(struct cdns3_device *priv_dev, >> + struct usb_ctrlrequest *ctrl_req) >> +{ >> +int ret; >> + >> +spin_unlock(&priv_dev->lock); >> +priv_dev->setup_pending = 1; >> +ret = priv_dev->gadget_driver->setup(&priv_dev->gadget, ctrl_req); >> +priv_dev->setup_pending = 0; > >Why is setup_pending flag being set and cleared? This flag is checking during handling DESCMISS interrupt. If this flag is set then driver not start DMA for SETUP packet waiting in on-chip buffer. > >> +spin_lock(&priv_dev->lock); >> +return ret; >> +} >> + >> static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) >> { >> -//TODO: Implements this function >> +priv_dev->ep0_data_dir = 0; >> +cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 8, 0); > >why hardcode to 8? >Don't vendor specific requests have different lengths? SETUP packet always has 8 bytes. I will change this to sizeof(struct struct usb_ctrlrequest). It says more. > >> } >> >> static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) >> @@ -90,9 +113,431 @@ static void cdns3_set_hw_configuration(struct >> cdns3_device *priv_dev) >> } >> } >> >> +/** >> + * cdns3_req_ep0_set_configuration - Handling of SET_CONFIG standard USB >> request >> + * @priv_dev: extended gadget object >> + * @ctrl_req: pointer to received setup packet >> + * >> + * Returns 0 if success, 0x7FFF on deferred status stage, error code on >> error > >what is this magic number 0x7fff? We will have USB_GADGET_DELAYED_STATUS instead 0x7FFF; > >> + */ >> +static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev, >> + struct usb_ctrlrequest *ctrl_req) >> +{ >> +enum usb_device_state device_state = priv_dev->gadget.state; >> +struct cdns3_endpoint *priv_ep, *temp_ep; >> +u32 config = le16_to_cpu(ctrl_req->wValue); >> +int result = 0; >> + >> +switch (device_state) { >> +case USB_STATE_ADDRESS: >> +/* Configure non-control EPs */ >> +list_for_each_entry_safe(priv_ep, temp_ep, >> + &priv_dev->ep_match_list, >> + ep_match_pending_list) >> +cdns3_ep_config(priv_ep); > >Why configure here? They should be configured at ep_enable. no? >And you don't need to maintain a ep_match/pending_list. It's a little tricky. We need to configure all endpoint on SET_CONFIGURATION request. After reset we can set only once CFGSET bit in usb_conf register. We don't need to enable endpoint, but we need set all other parameters. Not all endpoints are enabled before SET_CONFIGURATION, but most of them, or even all are claimed during loading function by means of usb_ep_autoconfig. After setting CFGSET bit we can't change configuration of any endpoint. We can only enable or disable th
RE: [RFC PATCH v2 02/15] usb:cdns3: Device side header file.
Hi Peter >> + >> +/* >> + * USBSS-DEV register interface. >> + * This corresponds to the USBSS Device Controller Interface */ >> +/** >> + * struct xhci_cap_regs - xHCI Host Controller Capability Registers. > >struct cdns3_usb_regs - device controller registers thanks, I had this from beginning. I don't know why. I > >> +struct cdns3_device; >> + >> +struct cdns3_endpoint { >> +struct usb_ep endpoint; >> +struct list_headrequest_list; >> +struct list_headep_match_pending_list; >> + >> +struct cdns3_trb*trb_pool; >> +dma_addr_t trb_pool_dma; >> + >> +struct cdns3_device *cdns3_dev; >> +charname[20]; >> + >> +#define EP_ENABLED BIT(0) >> +#define EP_STALLBIT(1) >> +#define EP_WEDGEBIT(2) >> +#define EP_TRANSFER_STARTED BIT(3) >> +#define EP_UPDATE_EP_TRBADDRBIT(4) >> +#define EP_PENDING_REQUEST BIT(5) >> +#define EP_USED BIT(5) >> +u32 flags; >> + >> +void*aligned_buff; >> +dma_addr_t aligned_dma_addr; >> +u8 dir; >> +u8 num; >> +u8 type; >> + >> +int free_trbs; >> +u8 pcs; >> +u8 ccs; >> +int enqueue; >> +int dequeue; >> +}; >> + > >Would you please add kernel doc for above structure? Done. > >> +struct cdns3_request { >> +struct usb_request request; >> +struct cdns3_endpoint *priv_ep; >> +struct cdns3_trb *trb; >> +int start_trb; >> +int end_trb; >> +int on_ring:1; >> +}; >> + >> +#define to_cdns3_request(r) (container_of(r, struct cdns3_request, >> +request)) >> + >> +struct cdns3_device { >> +struct device dev; >> +struct cdns3_usb_regs __iomem *regs; >> + >> +struct usb_gadget gadget; >> +struct usb_gadget_driver*gadget_driver; >> + >> +struct usb_ctrlrequest *setup; >> +dma_addr_t setup_dma; >> +dma_addr_t trb_ep0_dma; >> +struct cdns3_trb*trb_ep0; >> +void*zlp_buf; >> + >> +struct cdns3_endpoint *eps[USB_SS_ENDPOINTS_MAX_COUNT]; >> +int ep_nums; >> +/* >> + * field used for improving performance. It holds the last >> + * selected endpoint number >> + */ >> +u32 selected_ep; >> +struct usb_request *ep0_request; >> +int ep0_data_dir; >> +int hw_configured_flag; >> +int wake_up_flag; >> +u16 isoch_delay; >> +/* generic spin-lock for drivers */ >> +spinlock_t lock; >> + >> +unsignedis_connected:1; >> +unsignedin_standby_mode:1; >> +unsignedstatus_completion_no_call:1; >> +unsignedu1_allowed:1; >> +unsignedu2_allowed:1; >> + >> +u32 usb_ien; >> +u32 ep_ien; >> +int setup_pending; >> +struct device *sysdev; >> +/* The device mode is enabled */ >> +int start_gadget; >> +struct list_headep_match_list; >> +/* KB */ >> +int onchip_mem_allocated_size; >> +/* Memory is allocated for OUT */ >> +int out_mem_is_allocated:1; >> +struct work_struct pending_status_wq; >> +struct usb_request *pending_status_request; >> +}; >> + Cheers Pawel
RE: [RFC PATCH v2 04/15] usb:cdns3: Driver initialization code.
>> >> Patch adds core.c and core.h file that implements initialization >> of platform driver and adds function responsible for selecting, >> switching and running appropriate Device/Host mode. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Makefile | 2 + >> drivers/usb/cdns3/core.c | 413 + >> drivers/usb/cdns3/core.h | 100 + >> 3 files changed, 515 insertions(+) >> create mode 100644 drivers/usb/cdns3/core.c >> create mode 100644 drivers/usb/cdns3/core.h >> >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index dcdd62003c6a..02d25b23c5d3 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -1,3 +1,5 @@ >> +obj-$(CONFIG_USB_CDNS3)+= cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o >> >> +cdns3-y:= core.o >> cdns3-pci-y:= cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> new file mode 100644 >> index ..f9055d4da67f >> --- /dev/null >> +++ b/drivers/usb/cdns3/core.c >> @@ -0,0 +1,413 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Cadence USBSS DRD Driver. >> + * >> + * Copyright (C) 2018 Cadence. >> + * > >Please add NXP copyright too. Ok, I don't know why I omitted this. I know that you are the main author of this file Sorry for that. One additional question. What year I should add in Copyright for NXP?. The original year 2017 or I should modified all to 2018. >> + * Author: Peter Chen >> + * Pawel Laszczak >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "gadget.h" >> +#include "core.h" >> + >> +static inline struct cdns3_role_driver >> *cdns3_get_current_role_driver(struct cdns3 *cdns) >> +{ >> + WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); >> + return cdns->roles[cdns->role]; >> +} >> + > >Can we delete "current", and use cdns3_get_role_driver directly? Yes, sure. Role is always current. >> +static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles >> role) >> +{ >> + int ret; >> + >> + if (role >= CDNS3_ROLE_END) >> + return 0; >> + >> + if (!cdns->roles[role]) >> + return -ENXIO; >> + >> + mutex_lock(&cdns->mutex); >> + cdns->role = role; >> + ret = cdns->roles[role]->start(cdns); >> + mutex_unlock(&cdns->mutex); >> + return ret; >> +} >> + >> +static inline void cdns3_role_stop(struct cdns3 *cdns) >> +{ >> + enum cdns3_roles role = cdns->role; >> + >> + if (role == CDNS3_ROLE_END) >> + return; >> + >> + mutex_lock(&cdns->mutex); >> + cdns->roles[role]->stop(cdns); >> + cdns->role = CDNS3_ROLE_END; >> + mutex_unlock(&cdns->mutex); >> +} >> + >> +static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >> +{ >> + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >> + //TODO: implements selecting device/host mode >> + return CDNS3_ROLE_HOST; >> + } >> + return cdns->roles[CDNS3_ROLE_HOST] >> + ? CDNS3_ROLE_HOST >> + : CDNS3_ROLE_GADGET; >> +} >> + >> +/** >> + * cdns3_core_init_role - initialize role of operation >> + * @cdns: Pointer to cdns3 structure >> + * >> + * Returns 0 on success otherwise negative errno >> + */ >> +static int cdns3_core_init_role(struct cdns3 *cdns) >> +{ >> + struct device *dev = cdns->dev; >> + enum usb_dr_mode dr_mode; >> + >> + dr_mode = usb_get_dr_mode(dev); >> + cdns->role = CDNS3_ROLE_END; >> + >> + /* >> +* If driver can't read mode by means of usb_get_dr_mdoe function >> then >> +* chooses mode according with Kernel configuration. This setting >> +* can be restricted later depending on strap pin configuration. >> +*/ >> + if (dr_mode == USB_DR_MODE_UNKNOWN) { >> +
RE: [RFC PATCH v2 08/15] usb:cdns3: Implements device operations part of the API
Hi >>> + >>> +static struct usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, >>> + struct usb_endpoint_descriptor >>> *desc, >>> + struct usb_ss_ep_comp_descriptor >>> *comp_desc) >>> +{ >>> + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); >>> + struct cdns3_endpoint *priv_ep; >>> + unsigned long flags; >>> + >>> + priv_ep = cdns3_find_available_ss_ep(priv_dev, desc); >>> + if (IS_ERR(priv_ep)) { >>> + dev_err(&priv_dev->dev, "no available ep\n"); >>> + return NULL; >>> + } >>> + >>> + dev_dbg(&priv_dev->dev, "match endpoint: %s\n", priv_ep->name); >>> + >>> + spin_lock_irqsave(&priv_dev->lock, flags); >>> + priv_ep->endpoint.desc = desc; >>> + priv_ep->dir = usb_endpoint_dir_in(desc) ? USB_DIR_IN : USB_DIR_OUT; >>> + priv_ep->type = usb_endpoint_type(desc); >>> + >>> + list_add_tail(&priv_ep->ep_match_pending_list, >>> + &priv_dev->ep_match_list); >>> + spin_unlock_irqrestore(&priv_dev->lock, flags); >>> + return &priv_ep->endpoint; >>> +} >> >>Why do you need a custom match_ep? >>doesn't usb_ep_autoconfig suffice? > >I need to test it but at first glance it looks like usb_ep_autoconfig suffice. > >> >>You can check if EP is claimed or not by checking the ep->claimed flag. >> I checked it and did not work correct. The flag claimed is set in usb_ep_autoconf, but a little bit later during USB RESET this flag is cleared. So, I can't base on this flag. I think that it's incorrect behavior in gadget core driver or in function drivers. Maybe we should have additional flag in usb_ep object used during resetting, or usb_ep_autoconf function should be called after each USB RESET. I notice that I can based on ep->address it is set also in usb_ep_autoconf and probably is not cleared anywhere. It's little tricky, but It looks like it works correct. I add some comment for this checking. Maybe in feature I will be able to replace it with claimed flag. Felipe what's your opinion about claimed flag. It's should be fixed or not ? Cheers Pawel
RE: [RFC PATCH v2 04/15] usb:cdns3: Driver initialization code.
Hi, >> >> >> >> Patch adds core.c and core.h file that implements initialization >> >> of platform driver and adds function responsible for selecting, >> >> switching and running appropriate Device/Host mode. >> >> >> >> Signed-off-by: Pawel Laszczak >> >> --- >> >> drivers/usb/cdns3/Makefile | 2 + >> >> drivers/usb/cdns3/core.c | 413 + >> >> drivers/usb/cdns3/core.h | 100 + >> >> 3 files changed, 515 insertions(+) >> >> create mode 100644 drivers/usb/cdns3/core.c >> >> create mode 100644 drivers/usb/cdns3/core.h >> >> >> >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> >> index dcdd62003c6a..02d25b23c5d3 100644 >> >> --- a/drivers/usb/cdns3/Makefile >> >> +++ b/drivers/usb/cdns3/Makefile >> >> @@ -1,3 +1,5 @@ >> >> +obj-$(CONFIG_USB_CDNS3)+= cdns3.o >> >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o >> >> >> >> +cdns3-y:= core.o >> >> cdns3-pci-y:= cdns3-pci-wrap.o >> >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> >> new file mode 100644 >> >> index ..f9055d4da67f >> >> --- /dev/null >> >> +++ b/drivers/usb/cdns3/core.c >> >> @@ -0,0 +1,413 @@ >> >> +// SPDX-License-Identifier: GPL-2.0 >> >> +/* >> >> + * Cadence USBSS DRD Driver. >> >> + * >> >> + * Copyright (C) 2018 Cadence. >> >> + * >> > >> >Please add NXP copyright too. >> >> Ok, I don't know why I omitted this. >> I know that you are the main author of this file >> Sorry for that. >> >> One additional question. What year I should add in Copyright for NXP?. >> The original year 2017 or I should modified all to 2018. >> >Please use below copyright, thanks. > >Copyright 2017-2018 NXP I add this in all files modified or created by you. > > > >> >> + mutex_init(&cdns->mutex); >> >> + >> >> + cdns->phy = devm_phy_get(dev, "cdns3,usbphy"); >> >> + if (IS_ERR(cdns->phy)) { >> >> + dev_info(dev, "no generic phy found\n"); >> >> + cdns->phy = NULL; >> >> + /* >> >> +* fall through here! >> >> +* if no generic phy found, phy init >> >> +* should be done under boot! >> >> +*/ >> > >> >If the phy driver is defer-probed, it will be here, it is not an error. >> >I think you could have a generic phy driver or usb generic phy driver >> >(drivers/usb/phy/phy-generic.c) even you don't need any operations for >> >PHY. It will be easy for other platforms. >> >> Yes, Roger ask me to modify this fragment. In next version it will look like: >> cdns->phy = devm_phy_get(dev, "cdns3,usbphy"); >> if (IS_ERR(cdns->phy)) { >> ret = PTR_ERR(cdns->phy); >> if (ret == -ENOSYS || ret == -ENODEV) { >> cdns->phy = NULL; >> } else if (ret == -EPROBE_DEFER) { >> return ret; >> } else { >> dev_err(dev, "no phy found\n"); >> goto err0; >> } >> } >> >> phy_init(cdns->phy); >> >> We are going to use phy driver. I don't know if it correct. >> I don't have experience in this filed. >> We need phy initialization but I don't have testing platform now. >> In most usb drivers I see that there are used usb phy driverd instead phy >> dirverd. >> > >At my CDNS3 platform, there are some USB PHY initialization for register >setting >and clock enable. You could add generic PHY driver under: drivers/phy/cadence/. > >Above PHY initialization code is OK for me. It will be added as separate driver. I think that Allan Douglas working on it. I ask him to add you to -cc in patch for phy. > > >> >> +static void __exit cdns3_driver_platform_unregister(void) >> >> +{ >> >> + platform_driver_unregister(&cdns3_driver); >> >> +} >> >> +module_exit(cdns3_driver_platform_unregister); >> >> + >> >> +MODULE_ALIAS("platform:cdns3"); >> >> +MODULE_AUTHOR("Pawel Laszczak "); >> >> +MODULE_LICENSE("GPL v2"); >> >> +MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver"); >> >> diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h >> >> new file mode 100644 >> >> index ..7c8204fe4d3d >> >> --- /dev/null >> >> +++ b/drivers/usb/cdns3/core.h >> >> @@ -0,0 +1,100 @@ >> >> +/* SPDX-License-Identifier: GPL-2.0 */ >> >> +/* >> >> + * Cadence USBSS DRD Driver. >> >> + * >> > >> >Header file >> I don't understand. What is wrong ? >> > > >The comment for this file > >Cadence USBSS DRD Core Header File Ok, thanks Cheers, Pawel
RE: [RFC PATCH v2 04/15] usb:cdns3: Driver initialization code.
Hi + Tomek >> > + * Cadence USBSS DRD Driver. >> > + * >> > + * Copyright (C) 2018 Cadence. >> > + * >> > + * Author: Peter Chen >> > + * Pawel Laszczak >> > + */ >> > + >> > +#include >> > +#include >> > +#include >> > +#include >> > +#include >> > +#include >> > + >> > +#include "gadget.h" >> > +#include "core.h" >> > + >> > +static inline struct cdns3_role_driver >> > *cdns3_get_current_role_driver(struct cdns3 *cdns) >> > +{ >> > + WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); >> > + return cdns->roles[cdns->role]; >> > +} >> > + >> > +static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles >> > role) >> > +{ >> > + int ret; >> > + >> > + if (role >= CDNS3_ROLE_END) >> >> WARN_ON()? >> >> > + return 0; >> > + >> > + if (!cdns->roles[role]) >> > + return -ENXIO; >> > + >> > + mutex_lock(&cdns->mutex); >> > + cdns->role = role; >> > + ret = cdns->roles[role]->start(cdns); >> > + mutex_unlock(&cdns->mutex); >> > + return ret; >> > +} >> > + >> > +static inline void cdns3_role_stop(struct cdns3 *cdns) >> > +{ >> > + enum cdns3_roles role = cdns->role; >> > + >> > + if (role == CDNS3_ROLE_END) >> >> WARN_ON(role >= CNDS3_ROLE_END) ? >> >> > + return; >> > + >> > + mutex_lock(&cdns->mutex); >> > + cdns->roles[role]->stop(cdns); >> > + cdns->role = CDNS3_ROLE_END; >> >> Why change the role here? You are just stopping the role not changing it. >> I think cdns->role should remain unchanged, so we can call cdns3_role_start() >> if required without error. >> > >The current version of this IP has some issues to detect vbus status correctly, >we have to force vbus status accordingly, so we need a status to indicate >vbus disconnection, and add some code to let controller know vbus >removal, in that case, the controller's state machine can be correct. >So, we increase one role 'CDNS3_ROLE_END' to for this purpose. > >CDNS3_ROLE_GADGET: gadget mode and VBUS on >CDNS3_ROLE_HOST: host mode and VBUS on >CDNS3_ROLE_END: VBUS off, eg either host or device cable on the port. > >So, we may start role from CDNS3_ROLE_END at probe when nothing is connected, >and need to set role as CDNS3_ROLE_END at ->stop for further handling at >role switch routine. > >> > + mutex_unlock(&cdns->mutex); >> > +} >> > + >> > +static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >> > +{ >> > + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >> > + //TODO: implements selecting device/host mode >> > + return CDNS3_ROLE_HOST; >> > + } >> > + return cdns->roles[CDNS3_ROLE_HOST] >> > + ? CDNS3_ROLE_HOST >> > + : CDNS3_ROLE_GADGET; >> >> Why not just >> return cdns->role; >> >> I'm wondering if we really need this function. > >cdns->role gets from cdns3_get_role, and this API tells role at the runtime. >If both roles are supported, the role is decided by external >conditions, eg, vbus/id >or external connector. If only single role is supported, only one role >structure >is allocated, cdns->roles[CDNS3_ROLE_HOST] or cdns->roles[CDNS3_ROLE_GADGET] > >> > +} >> >> > + >> > +/** >> > + * cdns3_core_init_role - initialize role of operation >> > + * @cdns: Pointer to cdns3 structure >> > + * >> > + * Returns 0 on success otherwise negative errno >> > + */ >> > +static int cdns3_core_init_role(struct cdns3 *cdns) >> > +{ >> > + struct device *dev = cdns->dev; >> > + enum usb_dr_mode dr_mode; >> > + >> > + dr_mode = usb_get_dr_mode(dev); >> > + cdns->role = CDNS3_ROLE_END; >> > + >> > + /* >> > + * If driver can't read mode by means of usb_get_dr_mdoe function >> > then >> > + * chooses mode according with Kernel configuration. This setting >> > + * can be restricted later dep
RE: [RFC PATCH v2 04/15] usb:cdns3: Driver initialization code.
+ Tomek Klimek >> > + >> > +static inline void cdns3_role_stop(struct cdns3 *cdns) >> > +{ >> > + enum cdns3_roles role = cdns->role; >> > + >> > + if (role == CDNS3_ROLE_END) >> >> WARN_ON(role >= CNDS3_ROLE_END) ? >> >> > + return; >> > + >> > + mutex_lock(&cdns->mutex); >> > + cdns->roles[role]->stop(cdns); >> > + cdns->role = CDNS3_ROLE_END; >> >> Why change the role here? You are just stopping the role not changing it. >> I think cdns->role should remain unchanged, so we can call cdns3_role_start() >> if required without error. >> > >The current version of this IP has some issues to detect vbus status correctly, >we have to force vbus status accordingly, so we need a status to indicate >vbus disconnection, and add some code to let controller know vbus >removal, in that case, the controller's state machine can be correct. >So, we increase one role 'CDNS3_ROLE_END' to for this purpose. Hi, Tomek do you have any comment for this. We have in RTL whole OTG machine and we can read all states. From otg specification we have in otg_state such bits: 5:3 host_otg_state "Current state of the OTG Host FSM. 3'b000 : H_IDLE 3'b001 : H_VBUS_ON 3'b010 : H_VBUS_FAILED 3'b011 : H_OTG_HOST_MODE 3'b100 : H_HOST_MODE 3'b101 : H_SWITCH_TO_DEVICE 3'b110 : H_A_SUSPEND 3'b111 : H_WAIT_VBUS_FALL" RO 0x0 2:0 dev_otg_state "Current state of the OTG Device FSM. 3'b000 : DEV_IDLE 3'b001 : DEV_MODE 3'b010 : DEV_SRP 3'b011 : DEV_WAIT_VBUS_FALL 3'b100 : DEV_SWITCH_TO_HOST 3'b101 : DEV_WAIT_FOR_CONN" > >CDNS3_ROLE_GADGET: gadget mode and VBUS on >CDNS3_ROLE_HOST: host mode and VBUS on >CDNS3_ROLE_END: VBUS off, eg either host or device cable on the port. > >So, we may start role from CDNS3_ROLE_END at probe when nothing is connected, >and need to set role as CDNS3_ROLE_END at ->stop for further handling at >role switch routine. > >> > + mutex_unlock(&cdns->mutex); >> > +} >> > + >> > +static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >> > +{ >> > + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >> > + //TODO: implements selecting device/host mode >> > + return CDNS3_ROLE_HOST; >> > + } >> > + return cdns->roles[CDNS3_ROLE_HOST] >> > + ? CDNS3_ROLE_HOST >> > + : CDNS3_ROLE_GADGET; Cheers Pawel,
RE: [RFC PATCH v2 04/15] usb:cdns3: Driver initialization code.
> >> Hi Roger >> >> >On 18/11/18 12:09, Pawel Laszczak wrote: >> >> Patch adds core.c and core.h file that implements initialization >> >> of platform driver and adds function responsible for selecting, >> >> switching and running appropriate Device/Host mode. >> >> >> >> Signed-off-by: Pawel Laszczak >> >> --- >> >> drivers/usb/cdns3/Makefile | 2 + >> >> drivers/usb/cdns3/core.c | 413 + >> >> drivers/usb/cdns3/core.h | 100 + >> >> 3 files changed, 515 insertions(+) >> >> create mode 100644 drivers/usb/cdns3/core.c >> >> create mode 100644 drivers/usb/cdns3/core.h >> >> >> >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> >> index dcdd62003c6a..02d25b23c5d3 100644 >> >> --- a/drivers/usb/cdns3/Makefile >> >> +++ b/drivers/usb/cdns3/Makefile >> >> @@ -1,3 +1,5 @@ >> >> +obj-$(CONFIG_USB_CDNS3) += cdns3.o >> >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP)+= cdns3-pci.o >> >> >> >> +cdns3-y := core.o >> >> cdns3-pci-y := cdns3-pci-wrap.o >> >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> >> new file mode 100644 >> >> index ..f9055d4da67f >> >> --- /dev/null >> >> +++ b/drivers/usb/cdns3/core.c >> >> @@ -0,0 +1,413 @@ >> >> +// SPDX-License-Identifier: GPL-2.0 >> >> +/* >> >> + * Cadence USBSS DRD Driver. >> >> + * >> >> + * Copyright (C) 2018 Cadence. >> >> + * >> >> + * Author: Peter Chen >> >> + * Pawel Laszczak >> >> + */ >> >> + >> >> +#include >> >> +#include >> >> +#include >> >> +#include >> >> +#include >> >> +#include >> >> + >> >> +#include "gadget.h" >> >> +#include "core.h" >> >> + >> >> +static inline struct cdns3_role_driver >> >> *cdns3_get_current_role_driver(struct cdns3 *cdns) >> >> +{ >> >> +WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); >> >> +return cdns->roles[cdns->role]; >> >> +} >> >> + >> >> +static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles >> >> role) >> >> +{ >> >> +int ret; >> >> + >> >> +if (role >= CDNS3_ROLE_END) >> > >> >WARN_ON()? >> I agree. >> > >> >> +return 0; >> >> + >> >> +if (!cdns->roles[role]) >> >> +return -ENXIO; >> >> + >> >> +mutex_lock(&cdns->mutex); >> >> +cdns->role = role; >> >> +ret = cdns->roles[role]->start(cdns); >> >> +mutex_unlock(&cdns->mutex); >> >> +return ret; >> >> +} >> >> + >> >> +static inline void cdns3_role_stop(struct cdns3 *cdns) >> >> +{ >> >> +enum cdns3_roles role = cdns->role; >> >> + >> >> +if (role == CDNS3_ROLE_END) >> > >> >WARN_ON(role >= CNDS3_ROLE_END) ? >> I agree >> > >> >> +return; >> >> + >> >> +mutex_lock(&cdns->mutex); >> >> +cdns->roles[role]->stop(cdns); >> >> +cdns->role = CDNS3_ROLE_END; >> > >> >Why change the role here? You are just stopping the role not changing it. >> >I think cdns->role should remain unchanged, so we can call >> >cdns3_role_start() >> >if required without error. >> >> This line is unnecessary. >> >> > >> >> +mutex_unlock(&cdns->mutex); >> >> +} >> >> + >> >> +static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >> >> +{ >> >> +if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >> >> +//TODO: implements selecting device/host mode >> >> +return CDNS3_ROLE_HOST; >> >> +} >> >> +return cdns->roles[CDNS3_ROLE_HOST] >> >> +? CDNS3_ROLE_HOST >> >> +: CDNS3_ROLE_GADGET;
RE: [RFC PATCH v2 05/15] usb:cdns3: Added DRD support
>> Patch adds supports for detecting Host/Device mode. >> Controller has additional OTG register that allow >> implement even whole OTG functionality. >> At this moment patch adds support only for detecting >> the appropriate mode based on strap pins and ID pin. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/cdns3/Makefile | 2 +- >> drivers/usb/cdns3/core.c | 27 +++-- >> drivers/usb/cdns3/drd.c| 229 + >> drivers/usb/cdns3/drd.h| 122 >> 4 files changed, 372 insertions(+), 8 deletions(-) >> create mode 100644 drivers/usb/cdns3/drd.c >> create mode 100644 drivers/usb/cdns3/drd.h >> >> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile >> index 02d25b23c5d3..e779b2a2f8eb 100644 >> --- a/drivers/usb/cdns3/Makefile >> +++ b/drivers/usb/cdns3/Makefile >> @@ -1,5 +1,5 @@ >> obj-$(CONFIG_USB_CDNS3)+= cdns3.o >> obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o >> >> -cdns3-y:= core.o >> +cdns3-y:= core.o drd.o >> cdns3-pci-y:= cdns3-pci-wrap.o >> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c >> index f9055d4da67f..dbee4325da7f 100644 >> --- a/drivers/usb/cdns3/core.c >> +++ b/drivers/usb/cdns3/core.c >> @@ -17,6 +17,7 @@ >> >> #include "gadget.h" >> #include "core.h" >> +#include "drd.h" >> >> static inline struct cdns3_role_driver >> *cdns3_get_current_role_driver(struct cdns3 *cdns) >> { >> @@ -57,8 +58,10 @@ static inline void cdns3_role_stop(struct cdns3 *cdns) >> static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >> { >> if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >> - //TODO: implements selecting device/host mode >> - return CDNS3_ROLE_HOST; >> + if (cdns3_is_host(cdns)) >> + return CDNS3_ROLE_HOST; >> + if (cdns3_is_device(cdns)) >> + return CDNS3_ROLE_GADGET; >> } >> return cdns->roles[CDNS3_ROLE_HOST] >> ? CDNS3_ROLE_HOST >> @@ -124,6 +127,12 @@ static irqreturn_t cdns3_irq(int irq, void *data) >> struct cdns3 *cdns = data; >> irqreturn_t ret = IRQ_NONE; >> >> + if (cdns->dr_mode == USB_DR_MODE_OTG) { >> + ret = cdns3_drd_irq(cdns); >> + if (ret == IRQ_HANDLED) >> + return ret; >> + } >> + >> /* Handle device/host interrupt */ >> if (cdns->role != CDNS3_ROLE_END) >> ret = cdns3_get_current_role_driver(cdns)->irq(cdns); >> @@ -176,11 +185,8 @@ static void cdns3_role_switch(struct work_struct *work) >> >> cdns = container_of(work, struct cdns3, role_switch_wq); >> >> - //TODO: implements this functions. >> - //host = cdns3_is_host(cdns); >> - //device = cdns3_is_device(cdns); >> - host = 1; >> - device = 0; >> + host = cdns3_is_host(cdns); >> + device = cdns3_is_device(cdns); >> >> if (host) >> role = CDNS3_ROLE_HOST; >> @@ -194,6 +200,12 @@ static void cdns3_role_switch(struct work_struct *work) >> pm_runtime_get_sync(cdns->dev); >> cdns3_role_stop(cdns); >> >> + if (cdns->desired_dr_mode != cdns->current_dr_mode) { >> + cdns3_drd_update_mode(cdns); >> + host = cdns3_is_host(cdns); >> + device = cdns3_is_device(cdns); >> + } >> + >> if (host) { >> if (cdns->roles[CDNS3_ROLE_HOST]) >> cdns3_do_role_switch(cdns, CDNS3_ROLE_HOST); >> @@ -287,6 +299,7 @@ static int cdns3_probe(struct platform_device *pdev) >> if (ret) >> goto err2; >> >> + ret = cdns3_drd_init(cdns); >> if (ret) >> goto err2; >> >> diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c >> new file mode 100644 >> index ..ac741c80e776 >> --- /dev/null >> +++ b/drivers/usb/cdns3/drd.c >> @@ -0,0 +1,229 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Cadence USBSS DRD Driver. >> + * >> + * Copyright (C) 201
RE: [RFC PATCH v2 04/15] usb:cdns3: Driver initialization code.
Hi, >On 04/12/18 10:50, Peter Chen wrote: >>>> + * Cadence USBSS DRD Driver. >>>> + * >>>> + * Copyright (C) 2018 Cadence. >>>> + * >>>> + * Author: Peter Chen >>>> + * Pawel Laszczak >>>> + */ >>>> + >>>> +#include >>>> +#include >>>> +#include >>>> +#include >>>> +#include >>>> +#include >>>> + >>>> +#include "gadget.h" >>>> +#include "core.h" >>>> + >>>> +static inline struct cdns3_role_driver >>>> *cdns3_get_current_role_driver(struct cdns3 *cdns) >>>> +{ >>>> + WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); >>>> + return cdns->roles[cdns->role]; >>>> +} >>>> + >>>> +static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles >>>> role) >>>> +{ >>>> + int ret; >>>> + >>>> + if (role >= CDNS3_ROLE_END) >>> >>> WARN_ON()? >>> >>>> + return 0; >>>> + >>>> + if (!cdns->roles[role]) >>>> + return -ENXIO; >>>> + >>>> + mutex_lock(&cdns->mutex); >>>> + cdns->role = role; >>>> + ret = cdns->roles[role]->start(cdns); >>>> + mutex_unlock(&cdns->mutex); >>>> + return ret; >>>> +} >>>> + >>>> +static inline void cdns3_role_stop(struct cdns3 *cdns) >>>> +{ >>>> + enum cdns3_roles role = cdns->role; >>>> + >>>> + if (role == CDNS3_ROLE_END) >>> >>> WARN_ON(role >= CNDS3_ROLE_END) ? >>> >>>> + return; >>>> + >>>> + mutex_lock(&cdns->mutex); >>>> + cdns->roles[role]->stop(cdns); >>>> + cdns->role = CDNS3_ROLE_END; >>> >>> Why change the role here? You are just stopping the role not changing it. >>> I think cdns->role should remain unchanged, so we can call >>> cdns3_role_start() >>> if required without error. >>> >> >> The current version of this IP has some issues to detect vbus status >> correctly, >> we have to force vbus status accordingly, so we need a status to indicate >> vbus disconnection, and add some code to let controller know vbus >> removal, in that case, the controller's state machine can be correct. >> So, we increase one role 'CDNS3_ROLE_END' to for this purpose. >> >> CDNS3_ROLE_GADGET: gadget mode and VBUS on >> CDNS3_ROLE_HOST: host mode and VBUS on >> CDNS3_ROLE_END: VBUS off, eg either host or device cable on the port. >> >> So, we may start role from CDNS3_ROLE_END at probe when nothing is connected, >> and need to set role as CDNS3_ROLE_END at ->stop for further handling at >> role switch routine. > >OK. but still this (changing to ROLE_END) must be moved to the role switch >routine >and the explanation you just mentioned must be added there. > >> >>>> + mutex_unlock(&cdns->mutex); >>>> +} >>>> + >>>> +static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >>>> +{ >>>> + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { >>>> + //TODO: implements selecting device/host mode >>>> + return CDNS3_ROLE_HOST; >>>> + } >>>> + return cdns->roles[CDNS3_ROLE_HOST] >>>> + ? CDNS3_ROLE_HOST >>>> + : CDNS3_ROLE_GADGET; >>> >>> Why not just >>> return cdns->role; >>> >>> I'm wondering if we really need this function. >> >> cdns->role gets from cdns3_get_role, and this API tells role at the runtime. >> If both roles are supported, the role is decided by external >> conditions, eg, vbus/id >> or external connector. If only single role is supported, only one role >> structure >> is allocated, cdns->roles[CDNS3_ROLE_HOST] or cdns->roles[CDNS3_ROLE_GADGET] >> > >How about adding this description in function documentation. Ok, I will do it. > >>>> +} >>> >>>> + >>>> +/** >>>> + * cdns3_core_init_role - initialize role of operation >>>> + * @cdns: Pointer t
RE: [RFC PATCH v2 04/15] usb:cdns3: Driver initialization code.
Hi, >>> > + >>> > +static inline void cdns3_role_stop(struct cdns3 *cdns) >>> > +{ >>> > + enum cdns3_roles role = cdns->role; >>> > + >>> > + if (role == CDNS3_ROLE_END) >>> >>> WARN_ON(role >= CNDS3_ROLE_END) ? >>> >>> > + return; >>> > + >>> > + mutex_lock(&cdns->mutex); >>> > + cdns->roles[role]->stop(cdns); >>> > + cdns->role = CDNS3_ROLE_END; >>> >>> Why change the role here? You are just stopping the role not changing it. >>> I think cdns->role should remain unchanged, so we can call >>> cdns3_role_start() >>> if required without error. >>> >> >>The current version of this IP has some issues to detect vbus status >>correctly, >>we have to force vbus status accordingly, so we need a status to indicate >>vbus disconnection, and add some code to let controller know vbus >>removal, in that case, the controller's state machine can be correct. >>So, we increase one role 'CDNS3_ROLE_END' to for this purpose. > >Hi, Tomek do you have any comment for this. >We have in RTL whole OTG machine and we can read all states. It's not the IP issue, but with PHY. I told with Tomek and he confirmed this issue. In my testing platform I use different phy version and I don't have such issue. CDNS3_ROLE_END stay in driver for compatibility with Peter PHY version. >From otg specification we have in otg_state such bits: >5:3host_otg_state "Current state of the OTG Host FSM. >3'b000 : H_IDLE >3'b001 : H_VBUS_ON >3'b010 : H_VBUS_FAILED >3'b011 : H_OTG_HOST_MODE >3'b100 : H_HOST_MODE >3'b101 : H_SWITCH_TO_DEVICE >3'b110 : H_A_SUSPEND >3'b111 : H_WAIT_VBUS_FALL" RO 0x0 >2:0dev_otg_state "Current state of the OTG Device FSM. >3'b000 : DEV_IDLE >3'b001 : DEV_MODE >3'b010 : DEV_SRP >3'b011 : DEV_WAIT_VBUS_FALL >3'b100 : DEV_SWITCH_TO_HOST >3'b101 : DEV_WAIT_FOR_CONN" > >> >>CDNS3_ROLE_GADGET: gadget mode and VBUS on >>CDNS3_ROLE_HOST: host mode and VBUS on >>CDNS3_ROLE_END: VBUS off, eg either host or device cable on the port. >> >>So, we may start role from CDNS3_ROLE_END at probe when nothing is connected, >>and need to set role as CDNS3_ROLE_END at ->stop for further handling at >>role switch routine. >> > >>> > + mutex_unlock(&cdns->mutex); >>> > +} >>> > + >>> > +static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns) >>> > +{ >>> > + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) >>> > { >>> > + //TODO: implements selecting device/host mode >>> > + return CDNS3_ROLE_HOST; >>> > + } >>> > + return cdns->roles[CDNS3_ROLE_HOST] >>> > + ? CDNS3_ROLE_HOST >>> > + : CDNS3_ROLE_GADGET; Cheers Pawel
RE: [RFC PATCH v2 03/15] dt-bindings: add binding for USBSS-DRD controller.
Hi, >On Sun, Nov 18, 2018 at 10:08:59AM +0000, Pawel Laszczak wrote: >> Thsi patch aim at documenting USB related dt-bindings for the > >typo > >> Cadence USBSS-DRD controller. >> >> Signed-off-by: Pawel Laszczak >> --- >> .../devicetree/bindings/usb/cdns3-usb.txt | 17 + >> 1 file changed, 17 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/usb/cdns3-usb.txt >> >> diff --git a/Documentation/devicetree/bindings/usb/cdns3-usb.txt >> b/Documentation/devicetree/bindings/usb/cdns3-usb.txt >> new file mode 100644 >> index ..f9e953f32d47 >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/usb/cdns3-usb.txt >> @@ -0,0 +1,17 @@ >> +Binding for the Cadence USBSS-DRD controller >> + >> +Required properties: >> + - reg: Physical base address and size of the controller's register area. > >1 or 3 regions? If 3, what is each one and the order? I will add extra description. > >> + - compatible: Should contain: "cdns,usb3" > >Only one version and one set of bugs? Yes, currently we have only one version. > >> + - interrupts: Interrupt specifier. Refer to interrupt bindings. > >How many interrupts? Single line for Device/Host/OTG I will add description > >> + >> + >> +Example: >> +cdns3@f300 { > >usb@... > Ok. >> +compatible = "cdns,usb3"; >> +interrupts = ; >> +reg = <0xf300 0x1 //memory area for OTG/DRD >> registers >> +0xf301 0x1 //memory area for HOST registers >> +0xf302 0x1>;//memory area for Device >> registers >> +}; >> + >> -- >> 2.17.1 >> Thanks, Cheers Pawel
[PATCH v1 1/2] dt-bindings: add binding for USBSS-DRD controller.
This patch aim at documenting USB related dt-bindings for the Cadence USBSS-DRD controller. Signed-off-by: Pawel Laszczak --- .../devicetree/bindings/usb/cdns3-usb.txt | 31 +++ 1 file changed, 31 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/cdns3-usb.txt diff --git a/Documentation/devicetree/bindings/usb/cdns3-usb.txt b/Documentation/devicetree/bindings/usb/cdns3-usb.txt new file mode 100644 index ..ae4a255f0b10 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/cdns3-usb.txt @@ -0,0 +1,31 @@ +Binding for the Cadence USBSS-DRD controller + +Required properties: + - reg: Physical base address and size of the controller's register areas. +Controller has 3 different regions: +region 1 - HOST registers area +region 2 - DEVICE registers area +region 3 - OTG/DRD registers area + - compatible: Should contain: "cdns,usb3" + - interrupts: Interrupt specifier. Refer to interrupt bindings. + Driver supports only single interrupt line. +This single interrupt is shared between Device, + host and OTG/DRD part of driver. + +Optional propertiesi: + - maximum-speed : valid arguments are "super-speed", "high-speed" and + "full-speed"; refer to usb/generic.txt + - dr_mode: Should be one of "host", "peripheral" or "otg". + - phys: reference to the USB PHY + - phy-names: name of the USB PHY, should be "cdns3,usbphy" + + +Example: + usb@f300 { + compatible = "cdns,usb3"; + interrupts = ; + reg = <0xf300 0x1 //memory area for HOST registers + 0xf301 0x1 //memory area for DEVICE registers + 0xf302 0x1>;//memory area for OTG/DRD registers + }; + -- 2.17.1
[PATCH v1 0/2] Introduced new Cadence USBSS DRD Driver.
This patch set introduce new Cadence USBSS DRD driver to linux kernel. The Cadence USBSS DRD Driver s a highly configurable IP Core which can be instantiated as Dual-Role Device (DRD), Peripheral Only and Host Only (XHCI) configurations. The current driver has been validated with FPGA burned. We have support for PCIe bus, which is used on FPGA prototyping. The host site of USBSS controller is compliance with XHCI specification, so it works with standard XHCI linux driver. --- Pawel Laszczak (2): dt-bindings: add binding for USBSS-DRD controller. usb:cdns3 Add Cadence USB3 DRD Driver .../devicetree/bindings/usb/cdns3-usb.txt | 31 + drivers/usb/Kconfig |2 + drivers/usb/Makefile |2 + drivers/usb/cdns3/Kconfig | 44 + drivers/usb/cdns3/Makefile| 16 + drivers/usb/cdns3/cdns3-pci-wrap.c| 157 ++ drivers/usb/cdns3/core.c | 451 + drivers/usb/cdns3/core.h | 108 + drivers/usb/cdns3/debug.h | 346 drivers/usb/cdns3/debugfs.c | 168 ++ drivers/usb/cdns3/drd.c | 315 +++ drivers/usb/cdns3/drd.h | 129 ++ drivers/usb/cdns3/ep0.c | 864 drivers/usb/cdns3/gadget-export.h | 28 + drivers/usb/cdns3/gadget.c| 1802 + drivers/usb/cdns3/gadget.h| 1177 +++ drivers/usb/cdns3/host-export.h | 28 + drivers/usb/cdns3/host.c | 74 + drivers/usb/cdns3/trace.c | 11 + drivers/usb/cdns3/trace.h | 343 20 files changed, 6096 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/cdns3-usb.txt create mode 100644 drivers/usb/cdns3/Kconfig create mode 100644 drivers/usb/cdns3/Makefile create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c create mode 100644 drivers/usb/cdns3/core.c create mode 100644 drivers/usb/cdns3/core.h create mode 100644 drivers/usb/cdns3/debug.h create mode 100644 drivers/usb/cdns3/debugfs.c create mode 100644 drivers/usb/cdns3/drd.c create mode 100644 drivers/usb/cdns3/drd.h create mode 100644 drivers/usb/cdns3/ep0.c create mode 100644 drivers/usb/cdns3/gadget-export.h create mode 100644 drivers/usb/cdns3/gadget.c create mode 100644 drivers/usb/cdns3/gadget.h create mode 100644 drivers/usb/cdns3/host-export.h create mode 100644 drivers/usb/cdns3/host.c create mode 100644 drivers/usb/cdns3/trace.c create mode 100644 drivers/usb/cdns3/trace.h -- 2.17.1
RE: [PATCH v1 2/2] usb:cdns3 Add Cadence USB3 DRD Driver
Hi, >On 10/12/18 14:39, Pawel Laszczak wrote: >> This patch introduce new Cadence USBSS DRD driver >> to linux kernel. >> >> The Cadence USBSS DRD Driver is a highly >> configurable IP Core which can be >> instantiated as Dual-Role Device (DRD), >> Peripheral Only and Host Only (XHCI) >> configurations. >> >> The current driver has been validated with >> FPGA burned. We have support for PCIe >> bus, which is used on FPGA prototyping. >> >> The host side of USBSS-DRD controller is compliance >> with XHCI specification, so it works with >> standard XHCI linux driver. >> >> Signed-off-by: Pawel Laszczak >> --- >> drivers/usb/Kconfig|2 + >> drivers/usb/Makefile |2 + >> drivers/usb/cdns3/Kconfig | 44 + >> drivers/usb/cdns3/Makefile | 16 + >> drivers/usb/cdns3/cdns3-pci-wrap.c | 157 +++ >> drivers/usb/cdns3/core.c | 451 +++ >> drivers/usb/cdns3/core.h | 108 ++ >> drivers/usb/cdns3/debug.h | 346 ++ >> drivers/usb/cdns3/debugfs.c| 168 +++ >> drivers/usb/cdns3/drd.c| 315 + >> drivers/usb/cdns3/drd.h| 129 ++ >> drivers/usb/cdns3/ep0.c| 864 + >> drivers/usb/cdns3/gadget-export.h | 28 + >> drivers/usb/cdns3/gadget.c | 1802 >> drivers/usb/cdns3/gadget.h | 1177 ++ >> drivers/usb/cdns3/host-export.h| 28 + >> drivers/usb/cdns3/host.c | 74 ++ >> drivers/usb/cdns3/trace.c | 11 + >> drivers/usb/cdns3/trace.h | 343 ++ > >You went to the other extreme of combining everything (host/gadget/drd) >together >which again makes this very hard to review. > >I think what Felipe meant was to only combine the gadget driver code into one >patch. > >The series could be split into 6 patches like so. >-dt binding >-pci glue >-core driver >-host driver >-gadget driver >-drd driver Felipe wrote: " Frankly, I don't understand why this is a series. It's a single driver and splitting it into a series just makes it more difficult to review, actually. Sure, a single patch will be large, but there's no way to have a functional driver until all patches are applied, anyway. " Felipe should I split this driver as suggested by Roger ?. Now it's very big patch but it's still a single driver. >> 19 files changed, 6065 insertions(+) >> create mode 100644 drivers/usb/cdns3/Kconfig >> create mode 100644 drivers/usb/cdns3/Makefile >> create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c >> create mode 100644 drivers/usb/cdns3/core.c >> create mode 100644 drivers/usb/cdns3/core.h >> create mode 100644 drivers/usb/cdns3/debug.h >> create mode 100644 drivers/usb/cdns3/debugfs.c >> create mode 100644 drivers/usb/cdns3/drd.c >> create mode 100644 drivers/usb/cdns3/drd.h >> create mode 100644 drivers/usb/cdns3/ep0.c >> create mode 100644 drivers/usb/cdns3/gadget-export.h >> create mode 100644 drivers/usb/cdns3/gadget.c >> create mode 100644 drivers/usb/cdns3/gadget.h >> create mode 100644 drivers/usb/cdns3/host-export.h >> create mode 100644 drivers/usb/cdns3/host.c >> create mode 100644 drivers/usb/cdns3/trace.c >> create mode 100644 drivers/usb/cdns3/trace.h >> > > Cheers Pawel
RE: [PATCH v1 2/2] usb:cdns3 Add Cadence USB3 DRD Driver
Hi, > >Pawel Laszczak writes: >> +static int cdns3_probe(struct platform_device *pdev) >> +{ >> +struct device *dev = &pdev->dev; >> +struct resource *res; >> +struct cdns3 *cdns; >> +void __iomem *regs; >> +int ret; >> + >> +cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL); >> +if (!cdns) >> +return -ENOMEM; >> + >> +cdns->dev = dev; >> + >> +platform_set_drvdata(pdev, cdns); >> + >> +res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); >> +if (!res) { >> +dev_err(dev, "missing IRQ\n"); >> +return -ENODEV; >> +} >> +cdns->irq = res->start; >> + >> +cdns->xhci_res[0] = *res; >> + >> +/* >> + * Request memory region >> + * region-0: xHCI >> + * region-1: Peripheral >> + * region-2: OTG registers >> + */ >> +res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> +cdns->xhci_res[1] = *res; >> + >> +res = platform_get_resource(pdev, IORESOURCE_MEM, 1); >> +regs = devm_ioremap_resource(dev, res); >> +if (IS_ERR(regs)) >> +return PTR_ERR(regs); >> +cdns->dev_regs = regs; >> + >> +res = platform_get_resource(pdev, IORESOURCE_MEM, 2); >> +regs = devm_ioremap_resource(dev, res); >> +if (IS_ERR(regs)) >> +return PTR_ERR(regs); >> +cdns->otg_regs = regs; >> + >> +mutex_init(&cdns->mutex); >> + >> +cdns->phy = devm_phy_get(dev, "cdns3,usbphy"); >> +if (IS_ERR(cdns->phy)) { >> +ret = PTR_ERR(cdns->phy); >> +if (ret == -ENOSYS || ret == -ENODEV) { > >Are you sure you can get ENOSYS here? Have you checked output of >checkpatch --strict? Yes this error code can be returned by related to phy function if CONFIG_GENERIC_PHY is disabled. I have seen this warning in output of checkpatch --strict . > >-:852: WARNING: ENOSYS means 'invalid syscall nr' and nothing else > >> +#ifdef CONFIG_PM_SLEEP >> +static int cdns3_suspend(struct device *dev) >> +{ >> +/* TODO: Implements this function. */ >> +return 0; >> +} >> + >> +static int cdns3_resume(struct device *dev) >> +{ >> +/* TODO: Implements this function. */ >> +return 0; >> +} >> +#endif /* CONFIG_PM_SLEEP */ >> +static int cdns3_runtime_suspend(struct device *dev) >> +{ /* TODO: Implements this function. */ >> +return 0; >> +} >> + >> +static int cdns3_runtime_resume(struct device *dev) >> +{ >> +/* TODO: Implements this function. */ >> +return 0; >> +} >> +#endif /* CONFIG_PM */ > >please no TODO stubs. Just get rid of your dev_pm_ops if you don't >implement them. Come up with a later patch adding a proper >implementation for PM. Ok. > >> +static int __init cdns3_driver_platform_register(void) >> +{ >> +return platform_driver_register(&cdns3_driver); >> +} >> +module_init(cdns3_driver_platform_register); >> + >> +static void __exit cdns3_driver_platform_unregister(void) >> +{ >> +platform_driver_unregister(&cdns3_driver); >> +} >> +module_exit(cdns3_driver_platform_unregister); > >module_platform_driver() Ok, > >> diff --git a/drivers/usb/cdns3/debug.h b/drivers/usb/cdns3/debug.h >> new file mode 100644 >> index ..afb81d224718 >> --- /dev/null >> +++ b/drivers/usb/cdns3/debug.h >> @@ -0,0 +1,346 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Cadence USBSS DRD Driver. >> + * Debug header file. >> + * >> + * Copyright (C) 2018 Cadence. >> + * >> + * Author: Pawel Laszczak >> + */ >> +#ifndef __LINUX_CDNS3_DEBUG >> +#define __LINUX_CDNS3_DEBUG >> +#include "gadget.h" >> + >> +static inline void cdns3_decode_get_status(u8 bRequestType, u16 wIndex, >> + u16 wLength, char *str) >> +{ >> +switch (bRequestType & USB_RECIP_MASK) { >> +case USB_RECIP_INTERFACE: >> +sprintf(str, "Get Interface Status Intf = %d, L: = %d", >> +wIndex, wLength); >> +break; >> +case USB_RECIP_ENDPOINT: >> +sprintf(str, "Get Endpoint Status ep%d%s", >> +wIndex & ~USB_DIR_IN, >> +wIndex & USB_DIR_I
RE: [RFC PATCH v2 08/15] usb:cdns3: Implements device operations part of the API
Hi, >On 10/12/18 7:42 AM, Peter Chen wrote: +static struct usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *comp_desc) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + struct cdns3_endpoint *priv_ep; + unsigned long flags; + + priv_ep = cdns3_find_available_ss_ep(priv_dev, desc); + if (IS_ERR(priv_ep)) { + dev_err(&priv_dev->dev, "no available ep\n"); + return NULL; + } + + dev_dbg(&priv_dev->dev, "match endpoint: %s\n", priv_ep->name); + + spin_lock_irqsave(&priv_dev->lock, flags); + priv_ep->endpoint.desc = desc; + priv_ep->dir = usb_endpoint_dir_in(desc) ? USB_DIR_IN : USB_DIR_OUT; + priv_ep->type = usb_endpoint_type(desc); + + list_add_tail(&priv_ep->ep_match_pending_list, + &priv_dev->ep_match_list); + spin_unlock_irqrestore(&priv_dev->lock, flags); + return &priv_ep->endpoint; +} >>> Why do you need a custom match_ep? >>> doesn't usb_ep_autoconfig suffice? >>> >>> You can check if EP is claimed or not by checking the ep->claimed flag. >>> >> It is a special requirement for this IP, the EP type and MaxPacketSize >> changing can't be done at runtime, eg, at ep->enable. See below commit >> for detail. >> >> usb: cdns3: gadget: configure all endpoints before set configuration >> >> Cadence IP has one limitation that all endpoints must be configured >> (Type & MaxPacketSize) before setting configuration through hardware >> register, it means we can't change endpoints configuration after >> set_configuration. >> >> In this patch, we add non-control endpoint through usb_ss->ep_match_list, >> which is added when the gadget driver uses usb_ep_autoconfig to configure >> specific endpoint; When the udc driver receives set_configurion request, >> it goes through usb_ss->ep_match_list, and configure all endpoints >> accordingly. >> >> At usb_ep_ops.enable/disable, we only enable and disable endpoint through >> ep_cfg register which can be changed after set_configuration, and do >> some software operation accordingly. > >All this should be part of comments in code along with information about >controller versions which suffer from the errata. > >Is there a version of controller available which does not have the >defect? Is there a future plan to fix this? > >If any of that is yes, you probably want to handle this with runtime >detection of version (like done with DWC3_REVISION_XXX macros). >Sometimes the hardware-read versions themselves are incorrect, so its >better to introduce a version specific compatible too like >"cdns,usb-1.0.0" (as hinted to by Rob Herring as well). > custom match_ep is used and works with all versions of the gen1 controller. Future (gen2) releases of the controller won’t have such limitation but there is no plan to change current (gen1) functionality of the controller. I will add comment before cdns3_gadget_match_ep function. Also I will change cdns,usb3 to cdns,usb3-1.0.0 and add additional cdns,usb3-1.0.1 compatible. cdns,usb3-1.0.1 will be for current version of controller which I use. cdns,usb3-1.0.0 will be for older version - Peter Chan platform. I now that I have some changes in controller, and one of them require some changes in DRD driver. It will be safer to add two separate version in compatibles. Thanks Pawel
RE: [PATCH v1 1/2] dt-bindings: add binding for USBSS-DRD controller.
Hi, >On Tue, Dec 11, 2018 at 6:19 PM Roger Quadros wrote: >> >> Pawel, >> >> On 10/12/18 14:39, Pawel Laszczak wrote: >> > This patch aim at documenting USB related dt-bindings for the >> > Cadence USBSS-DRD controller. >> > >> > Signed-off-by: Pawel Laszczak >> > --- >> > .../devicetree/bindings/usb/cdns3-usb.txt | 31 +++ >> > 1 file changed, 31 insertions(+) >> > create mode 100644 Documentation/devicetree/bindings/usb/cdns3-usb.txt >> > >> > diff --git a/Documentation/devicetree/bindings/usb/cdns3-usb.txt >> > b/Documentation/devicetree/bindings/usb/cdns3-usb.txt >> > new file mode 100644 >> > index ..ae4a255f0b10 >> > --- /dev/null >> > +++ b/Documentation/devicetree/bindings/usb/cdns3-usb.txt >> > @@ -0,0 +1,31 @@ >> > +Binding for the Cadence USBSS-DRD controller >> > + >> > +Required properties: >> > + - reg: Physical base address and size of the controller's register >> > areas. >> > + Controller has 3 different regions: >> > + region 1 - HOST registers area >> > + region 2 - DEVICE registers area >> > + region 3 - OTG/DRD registers area >> > + - compatible: Should contain: "cdns,usb3" >> > + - interrupts: Interrupt specifier. Refer to interrupt bindings. >> > + Driver supports only single interrupt line. >> > +This single interrupt is shared between Device, >> > + host and OTG/DRD part of driver. >> > + >> > +Optional propertiesi: >> >> s/propertiesi/properties >> >> > + - maximum-speed : valid arguments are "super-speed", "high-speed" and >> > + "full-speed"; refer to usb/generic.txt >> > + - dr_mode: Should be one of "host", "peripheral" or "otg". >> > + - phys: reference to the USB PHY >> > + - phy-names: name of the USB PHY, should be "cdns3,usbphy" >> > + >> > + >> > +Example: >> > + usb@f300 { >> > + compatible = "cdns,usb3"; >> > + interrupts = ; >> > + reg = <0xf300 0x1 //memory area for HOST >> > registers >> > + 0xf301 0x1 //memory area for DEVICE >> > registers >> > + 0xf302 0x1>;//memory area for OTG/DRD >> > registers >> >> Use "/* */" instead. >> >> > + }; >> > + >> > > >When running git am to apply patch, it has below warning, please fix them. > >Applying: dt-bindings: add binding for USBSS-DRD controller. >.git/rebase-apply/patch:42: new blank line at EOF. >+ >warning: 1 line adds whitespace errors. Ok, thanks Cheers Pawel
RE: [RFC PATCH v2 08/15] usb:cdns3: Implements device operations part of the API
Hi, > >On Wed, Dec 12, 2018 at 3:49 AM Pawel Laszczak wrote: >> >> Hi, >> >> >On 10/12/18 7:42 AM, Peter Chen wrote: >> >>>> +static struct usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, >> >>>> + struct >> >>>> usb_endpoint_descriptor *desc, >> >>>> + struct >> >>>> usb_ss_ep_comp_descriptor *comp_desc) >> >>>> +{ >> >>>> + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); >> >>>> + struct cdns3_endpoint *priv_ep; >> >>>> + unsigned long flags; >> >>>> + >> >>>> + priv_ep = cdns3_find_available_ss_ep(priv_dev, desc); >> >>>> + if (IS_ERR(priv_ep)) { >> >>>> + dev_err(&priv_dev->dev, "no available ep\n"); >> >>>> + return NULL; >> >>>> + } >> >>>> + >> >>>> + dev_dbg(&priv_dev->dev, "match endpoint: %s\n", priv_ep->name); >> >>>> + >> >>>> + spin_lock_irqsave(&priv_dev->lock, flags); >> >>>> + priv_ep->endpoint.desc = desc; >> >>>> + priv_ep->dir = usb_endpoint_dir_in(desc) ? USB_DIR_IN : >> >>>> USB_DIR_OUT; >> >>>> + priv_ep->type = usb_endpoint_type(desc); >> >>>> + >> >>>> + list_add_tail(&priv_ep->ep_match_pending_list, >> >>>> + &priv_dev->ep_match_list); >> >>>> + spin_unlock_irqrestore(&priv_dev->lock, flags); >> >>>> + return &priv_ep->endpoint; >> >>>> +} >> >>> Why do you need a custom match_ep? >> >>> doesn't usb_ep_autoconfig suffice? >> >>> >> >>> You can check if EP is claimed or not by checking the ep->claimed flag. >> >>> >> >> It is a special requirement for this IP, the EP type and MaxPacketSize >> >> changing can't be done at runtime, eg, at ep->enable. See below commit >> >> for detail. >> >> >> >> usb: cdns3: gadget: configure all endpoints before set configuration >> >> >> >> Cadence IP has one limitation that all endpoints must be configured >> >> (Type & MaxPacketSize) before setting configuration through hardware >> >> register, it means we can't change endpoints configuration after >> >> set_configuration. >> >> >> >> In this patch, we add non-control endpoint through >> >> usb_ss->ep_match_list, >> >> which is added when the gadget driver uses usb_ep_autoconfig to >> >> configure >> >> specific endpoint; When the udc driver receives set_configurion >> >> request, >> >> it goes through usb_ss->ep_match_list, and configure all endpoints >> >> accordingly. >> >> >> >> At usb_ep_ops.enable/disable, we only enable and disable endpoint >> >> through >> >> ep_cfg register which can be changed after set_configuration, and do >> >> some software operation accordingly. >> > >> >All this should be part of comments in code along with information about >> >controller versions which suffer from the errata. >> > >> >Is there a version of controller available which does not have the >> >defect? Is there a future plan to fix this? >> > >> >If any of that is yes, you probably want to handle this with runtime >> >detection of version (like done with DWC3_REVISION_XXX macros). >> >Sometimes the hardware-read versions themselves are incorrect, so its >> >better to introduce a version specific compatible too like >> >"cdns,usb-1.0.0" (as hinted to by Rob Herring as well). >> > >> >> custom match_ep is used and works with all versions of the gen1 >> controller. Future (gen2) releases of the controller won’t have such >> limitation but there is no plan to change current (gen1) functionality >> of the controller. >> >> I will add comment before cdns3_gadget_match_ep function. >> Also I will change cdns,usb3 to cdns,usb3-1.0.0 and add additional >> cdns,usb3-1.0.1 compatible. >> >> cdns,usb3-1.0.1 will be for current version of controller which I use. >> cdns,usb3-1.0.0 will be for older version - Peter Chan platform. >> I now that I have some changes in controller, and one of them require >> some changes in DRD driver. It will be safer to add two separate >> version in compatibles. >> > >Pawel, could we have correct register to show controller version? It is >better we could version judgement at runtime instead of static compatible. > Ok, I will tray do this in this way. Pawel
RE: [PATCH v1 2/2] usb:cdns3 Add Cadence USB3 DRD Driver
Hi Peter >On Mon, Dec 10, 2018 at 8:55 PM Pawel Laszczak wrote: >> >> This patch introduce new Cadence USBSS DRD driver >> to linux kernel. >> >> The Cadence USBSS DRD Driver is a highly >> configurable IP Core which can be >> instantiated as Dual-Role Device (DRD), >> Peripheral Only and Host Only (XHCI) >> configurations. >> >> The current driver has been validated with >> FPGA burned. We have support for PCIe >> bus, which is used on FPGA prototyping. >> >> The host side of USBSS-DRD controller is compliance >> with XHCI specification, so it works with >> standard XHCI linux driver. >> >> Signed-off-by: Pawel Laszczak >> --- > >I have compiled it at my ARM64 platform, and will give you more feedback after >adding platform support. Below is one compile warning, please fix > > CC drivers/usb/cdns3/host.o > AR drivers/usb/cdns3/cdns3-pci.o >/home/b29397/work/projects/linux-imx/drivers/usb/cdns3/gadget.c: In >function ‘cdns3_gadget_ep_disable’: >/home/b29397/work/projects/linux-imx/drivers/usb/cdns3/gadget.c:1122:19: >warning: ‘priv_dev’ may be used uninitialized in this function >[-Wmaybe-uninitialized] > dev_dbg(priv_dev->dev, "usbss: invalid parameters\n"); > ^~ > AR drivers/usb/cdns3/cdns3.o > I found this also. Some time ago I changed pr_err("usbss: invalid parameters\n"); to dev_err(priv_dev->dev, "usbss: invalid parameters\n"); In cdns3_gadget_ep_disable function and it was mistake. I don't know why I didn't see this warning before posting patch. Cheers Pawel