Skip to contentSkip to conversation

usb: cdns3: USBSSP platform driver support

PATCH Superseded Peter Chen 3 participants 6 messages Mar 16 – Mar 25

Subsystems (4)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Peter Chen

author
#0 lore raw

v2 cover usb: cdns3: USBSSP platform driver support

This series adds platform driver support for the Cadence USBSSP (CDNSP) controller, which was previously only accessible through PCI.

The USBSSP controller is auto-detected at runtime by reading the DRD/OTG Device ID register, so no additional DT compatible string is needed — both USBSS and USBSSP use "cdns,usb3".

Changes since v1:
- Update DT binding: keep compatible as "const: cdns,usb3", add description and super-speed-plus to maximum-speed, drop separate
USBSSP example.
- Drop "cdns,usbssp" compatible string; Auto-detect the controller version (USBSS vs USBSSP) at runtime by reading the DRD/OTG Device ID register in cdns_drd_init(), and select the appropriate gadget init function (cdns3_gadget_init or cdnsp_gadget_init) based on cdns->version.
This follows the same pattern already used for host initialization. (Comments from: Pawel Laszczak, Krzysztof Kozlowski)
- Export cdns_core_init_role and re-orginize the function cdns_init, and controller version could be gotten before the gadget init function is decided per controller.
- Fix PLAT_DRIVER_NAME in cdnsp-pci.c from "cdns-usbssp" to "cdns-usb3"
to match the platform driver name. (Comments from Pawel Laszczak)
- Remove unnecessary MODULE_ALIAS("platform:cdnsp"). (Comments from Krzysztof Kozlowski)
- Build cdns3-plat.o as a standalone module instead of bundling it into cdns-usb-common, so that 'make modules_install' works correctly. (Comments from Pawel Laszczak)
- Regroup USBSSP and CDNS3 Kconfig options under the USB_CDNS_SUPPORT
menu so they appear properly grouped in menuconfig. (Comments from Pawel Laszczak)
- Add Assisted-by tag per Documentation/process/coding-assistants.rst. Since the checkpatch.pl can't support this, it is added at context.

Peter Chen (2):
dt-bindings: usb: cdns,usb3: document USBSSP controller support
usb: cdns3: Add USBSSP platform driver support

 .../devicetree/bindings/usb/cdns,usb3.yaml    |  10 +-
 drivers/usb/cdns3/Kconfig                     |  50 ++--
 drivers/usb/cdns3/Makefile                    |  30 +--
 drivers/usb/cdns3/cdns3-gadget.c              |   4 +
 drivers/usb/cdns3/cdns3-plat.c                |  17 +-
 drivers/usb/cdns3/cdnsp-gadget.c              |   4 +
 drivers/usb/cdns3/cdnsp-pci.c                 | 217 ++++++++----------
 drivers/usb/cdns3/core.c                      |  11 +-
 drivers/usb/cdns3/core.h                      |   5 +-
 drivers/usb/cdns3/gadget-export.h             |   4 +-
 10 files changed, 172 insertions(+), 180 deletions(-)
Signature · 1 line
2.50.1
author
#1 lore raw

PATCH v2 1/2 dt-bindings: usb: cdns,usb3: document USBSSP controller support

Update the Cadence USBSS DRD binding to document that it also covers the USBSSP (SuperSpeed Plus, USB 3.1 gen2x1) controller. Both USBSS and USBSSP share the same DRD/OTG register interface, so the driver auto-detects the controller version at runtime — no additional compatible string is needed.

Changes to the binding:
- Update title and add description
- maximum-speed: add super-speed-plus

This patch is Assisted-by: Cursor:claude-4.6-opus

---
 Documentation/devicetree/bindings/usb/cdns,usb3.yaml | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/usb/cdns,usb3.yaml +8 -2
index f454ddd9bbaa..ad5acf956edf 100644
@@ -4,11 +4,17 @@
 $id: http://devicetree.org/schemas/usb/cdns,usb3.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Cadence USBSS-DRD controller
+title: Cadence USBSS and USBSSP DRD controller
 
 maintainers:
   - Pawel Laszczak <[email protected]>
 
+description:
+  Cadence USB dual-role controller. Covers USBSS (SuperSpeed, USB 3.0) and
+  USBSSP (SuperSpeed Plus, USB 3.1 gen2x1). Both variants share the same
+  DRD/OTG register interface, so the driver auto-detects the controller
+  version at runtime.
+
 properties:
   compatible:
     const: cdns,usb3
@@ -49,7 +55,7 @@ properties:
       cdns3 to type C connector.
 
   maximum-speed:
-    enum: [super-speed, high-speed, full-speed]
+    enum: [super-speed-plus, super-speed, high-speed, full-speed]
 
   phys:
     minItems: 1
Signature · 1 line
2.50.1
maintainer Acked-by on v2 1/2
#2 lore raw

Re: [PATCH v2 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support

Quoted 10 lines · Peter Chen

Update the Cadence USBSS DRD binding to document that it also covers the USBSSP (SuperSpeed Plus, USB 3.1 gen2x1) controller. Both USBSS and USBSSP share the same DRD/OTG register interface, so the driver auto-detects the controller version at runtime — no additional compatible string is needed.

Changes to the binding:
- Update title and add description
- maximum-speed: add super-speed-plus

Quoted 7 lines

This patch is Assisted-by: Cursor:claude-4.6-opus

---
 Documentation/devicetree/bindings/usb/cdns,usb3.yaml | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
author
#3 lore raw

PATCH v2 2/2 usb: cdns3: Add USBSSP platform driver support

In reply to Peter Chen

The Cadence USBSSP (CDNSP) controller was previously only accessible through PCI, coupling the gadget driver with the PCI glue layer into a single monolithic module (cdnsp-udc-pci). This prevented using the CDNSP IP on SoC/platform designs that expose the controller through device tree. It restructures the driver to decouple the CDNSP gadget from PCI.

- Introduce CONFIG_USB_CDNSP as a standalone tristate (analogous to CONFIG_USB_CDNS3), with USB_CDNSP_GADGET and USB_CDNSP_HOST as bool sub-options. The gadget code builds as a separate cdnsp.ko module.

- Regroup USBSSP and CDNS3 Kconfig options under the USB_CDNS_SUPPORT menu so they appear properly grouped in menuconfig.

- Refactor cdnsp-pci.c into a thin PCI-to-platform wrapper (similar to cdns3-pci-wrap.c) that registers a platform device and passes PCI resources and platform data to the common platform driver.

- Auto-detect the controller version (USBSS vs USBSSP) at runtime by reading the DRD/OTG Device ID register in cdns_drd_init(), and select the appropriate gadget init function (cdns3_gadget_init or cdnsp_gadget_init) based on cdns->version. This follows the same pattern already used for host initialization.

- Fix gadget-export.h to use IS_REACHABLE() keyed on the tristate module config (CONFIG_USB_CDNS3/CONFIG_USB_CDNSP) instead of IS_ENABLED() on the bool gadget config. The bool configs are always 'y' when enabled, causing IS_ENABLED/IS_REACHABLE to always return true and resulting in link errors when cdns-usb-common is built-in but the gadget module is loadable.

- Add missing MODULE_LICENSE()/MODULE_DESCRIPTION() and EXPORT_SYMBOL_GPL() to the cdns3 and cdnsp gadget modules, required by modpost.

- Pass override_apb_timeout through cdns3_platform_data so the PCI wrapper can communicate PCI-specific APB timeout values to the common driver.

This patch is Assisted-by: Cursor:claude-4.6-opus

---
 drivers/usb/cdns3/Kconfig         |  50 ++++---
 drivers/usb/cdns3/Makefile        |  30 ++---
 drivers/usb/cdns3/cdns3-gadget.c  |   4 +
 drivers/usb/cdns3/cdns3-plat.c    |  17 ++-
 drivers/usb/cdns3/cdnsp-gadget.c  |   4 +
 drivers/usb/cdns3/cdnsp-pci.c     | 217 +++++++++++++-----------------
 drivers/usb/cdns3/core.c          |  11 +-
 drivers/usb/cdns3/core.h          |   5 +-
 drivers/usb/cdns3/gadget-export.h |   4 +-
 9 files changed, 164 insertions(+), 178 deletions(-)
drivers/usb/cdns3/Kconfig +28 -22
index 0a514b591527..97fa84dddbca 100644
@@ -20,10 +20,6 @@ config USB_CDNS3
 	  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.
-endif
-
 if USB_CDNS3
 
 config USB_CDNS3_GADGET
@@ -89,29 +85,27 @@ config USB_CDNS3_STARFIVE
 
 	  If you choose to build this driver as module it will
 	  be dynamically linked and module will be called cdns3-starfive.ko
-endif
 
-if USB_CDNS_SUPPORT
+endif # USB_CDNS3
 
-config USB_CDNSP_PCI
-	tristate "Cadence CDNSP Dual-Role Controller"
-	depends on USB_CDNS_SUPPORT && USB_PCI && ACPI
+config USB_CDNSP
+	tristate "Cadence USBSSP Dual-Role Controller"
+	depends on USB_CDNS_SUPPORT
 	help
-	  Say Y here if your system has a Cadence CDNSP 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 cdnsp.ko.
-endif
+	  Say Y here if your system has a Cadence USBSSP dual-role controller.
+	  It supports: dual-role switch, Host-only, and Peripheral-only.
+	  Cadence CDNSP Controller device mode is very similar to XHCI controller.
+	  Therefore some algorithms used has been taken from xHCI driver.
+	  Host controller is compliant with XHCI so it uses standard XHCI driver.
 
-if USB_CDNSP_PCI
+if USB_CDNSP
 
 config USB_CDNSP_GADGET
-	bool "Cadence CDNSP device controller"
-	depends on USB_GADGET=y || USB_GADGET=USB_CDNSP_PCI
+	bool "Cadence USBSSP device controller"
+	depends on USB_GADGET=y || USB_GADGET=USB_CDNSP
 	help
 	  Say Y here to enable device controller functionality of the
-	  Cadence CDNSP-DEV driver.
+	  Cadence USBSSP-DEV driver.
 
 	  Cadence CDNSP Device Controller in device mode is
 	  very similar to XHCI controller. Therefore some algorithms
@@ -120,8 +114,8 @@ config USB_CDNSP_GADGET
 	  It doesn't support LS.
 
 config USB_CDNSP_HOST
-	bool "Cadence CDNSP host controller"
-	depends on USB=y || USB=USB_CDNSP_PCI
+	bool "Cadence USBSSP host controller"
+	depends on USB=y || USB=USB_CDNSP
 	select USB_CDNS_HOST
 	help
 	  Say Y here to enable host controller functionality of the
@@ -130,4 +124,16 @@ config USB_CDNSP_HOST
 	  Host controller is compliant with XHCI so it uses
 	  standard XHCI driver.
 
-endif
+config USB_CDNSP_PCI
+	tristate "Cadence USBSSP support on PCIe-based platforms"
+	depends on USB_PCI && ACPI
+	help
+	  If you're using the USBSSP 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 cdnsp-pci.ko
+
+endif # USB_CDNSP
+
+endif # USB_CDNS_SUPPORT
drivers/usb/cdns3/Makefile +11 -19
index 48dfae75b5aa..63484f145bb9 100644
@@ -4,41 +4,33 @@ CFLAGS_cdns3-trace.o				:= -I$(src)
 CFLAGS_cdnsp-trace.o				:= -I$(src)
 
 cdns-usb-common-y				:= core.o drd.o
-cdns3-y						:= cdns3-plat.o
 
 ifeq ($(CONFIG_USB),m)
 obj-m						+= cdns-usb-common.o
-obj-m						+= cdns3.o
+obj-m						+= cdns3-plat.o
 else
 obj-$(CONFIG_USB_CDNS_SUPPORT)			+= cdns-usb-common.o
-obj-$(CONFIG_USB_CDNS3)				+= cdns3.o
+obj-$(CONFIG_USB_CDNS_SUPPORT)			+= cdns3-plat.o
 endif
 
 cdns-usb-common-$(CONFIG_USB_CDNS_HOST) 	+= host.o
-cdns3-$(CONFIG_USB_CDNS3_GADGET)		+= cdns3-gadget.o cdns3-ep0.o
 
+# For CDNS3 gadget
 ifneq ($(CONFIG_USB_CDNS3_GADGET),)
+cdns3-y						:= cdns3-gadget.o cdns3-ep0.o
 cdns3-$(CONFIG_TRACING)				+= cdns3-trace.o
+obj-$(CONFIG_USB_CDNS3)				+= cdns3.o
 endif
-
 obj-$(CONFIG_USB_CDNS3_PCI_WRAP)		+= cdns3-pci-wrap.o
 obj-$(CONFIG_USB_CDNS3_TI)			+= cdns3-ti.o
 obj-$(CONFIG_USB_CDNS3_IMX)			+= cdns3-imx.o
 obj-$(CONFIG_USB_CDNS3_STARFIVE)		+= cdns3-starfive.o
 
-cdnsp-udc-pci-y					:= cdnsp-pci.o
-
-ifdef CONFIG_USB_CDNSP_PCI
-ifeq ($(CONFIG_USB),m)
-obj-m						+= cdnsp-udc-pci.o
-else
-obj-$(CONFIG_USB_CDNSP_PCI) 			+= cdnsp-udc-pci.o
-endif
-endif
-
-cdnsp-udc-pci-$(CONFIG_USB_CDNSP_GADGET)	+= cdnsp-ring.o cdnsp-gadget.o \
-						   cdnsp-mem.o cdnsp-ep0.o
-
+# For CDNSP gadget
 ifneq ($(CONFIG_USB_CDNSP_GADGET),)
-cdnsp-udc-pci-$(CONFIG_TRACING)			+= cdnsp-trace.o
+cdnsp-y						:= cdnsp-ring.o cdnsp-gadget.o \
+						   cdnsp-mem.o cdnsp-ep0.o
+cdnsp-$(CONFIG_TRACING)				+= cdnsp-trace.o
+obj-$(CONFIG_USB_CDNSP)				+= cdnsp.o
 endif
+obj-$(CONFIG_USB_CDNSP_PCI)			+= cdnsp-pci.o
drivers/usb/cdns3/cdns3-gadget.c +4 -0
index d59a60a16ec7..b800bd1bedd4 100644
@@ -3508,3 +3508,7 @@ int cdns3_gadget_init(struct cdns *cdns)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(cdns3_gadget_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence USBSS DRD Driver - gadget");
drivers/usb/cdns3/cdns3-plat.c +15 -2
index 735df88774e4..71c612e27b73 100644
@@ -44,6 +44,14 @@ static void set_phy_power_off(struct cdns *cdns)
 	phy_power_off(cdns->usb2_phy);
 }
 
+static int cdns3_plat_gadget_init(struct cdns *cdns)
+{
+	if (cdns->version < CDNSP_CONTROLLER_V2)
+		return cdns3_gadget_init(cdns);
+	else
+		return cdnsp_gadget_init(cdns);
+}
+
 /**
  * cdns3_plat_probe - probe for cdns3 core device
  * @pdev: Pointer to cdns3 core platform device
@@ -64,6 +72,8 @@ static int cdns3_plat_probe(struct platform_device *pdev)
 
 	cdns->dev = dev;
 	cdns->pdata = dev_get_platdata(dev);
+	if (cdns->pdata && cdns->pdata->override_apb_timeout)
+		cdns->override_apb_timeout = cdns->pdata->override_apb_timeout;
 
 	platform_set_drvdata(pdev, cdns);
 
@@ -143,12 +153,15 @@ static int cdns3_plat_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_phy_power_on;
 
-	cdns->gadget_init = cdns3_gadget_init;
-
 	ret = cdns_init(cdns);
 	if (ret)
 		goto err_cdns_init;
 
+	cdns->gadget_init = cdns3_plat_gadget_init;
+	ret = cdns_core_init_role(cdns);
+	if (ret)
+		goto err_cdns_init;
+
 	device_set_wakeup_capable(dev, true);
 	pm_runtime_set_active(dev);
 	pm_runtime_enable(dev);
drivers/usb/cdns3/cdnsp-gadget.c +4 -0
index 6b3815f8a6e5..8db7eee528a1 100644
@@ -2075,3 +2075,7 @@ int cdnsp_gadget_init(struct cdns *cdns)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(cdnsp_gadget_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence CDNSP DRD Driver - gadget");
drivers/usb/cdns3/cdnsp-pci.c +93 -124

296 lines not on this page · raw message

drivers/usb/cdns3/core.c +4 -7
index f0e32227c0b7..10f00b6c3c83 100644
@@ -80,7 +80,7 @@ static void cdns_exit_roles(struct cdns *cdns)
  *
  * Returns 0 on success otherwise negative errno
  */
-static int cdns_core_init_role(struct cdns *cdns)
+int cdns_core_init_role(struct cdns *cdns)
 {
 	struct device *dev = cdns->dev;
 	enum usb_dr_mode best_dr_mode;
@@ -197,11 +197,14 @@ static int cdns_core_init_role(struct cdns *cdns)
 		goto err;
 	}
 
+	dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
+
 	return 0;
 err:
 	cdns_exit_roles(cdns);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(cdns_core_init_role);
 
 /**
  * cdns_hw_role_state_machine  - role switch state machine based on hw events.
@@ -469,14 +472,8 @@ int cdns_init(struct cdns *cdns)
 	if (ret)
 		goto init_failed;
 
-	ret = cdns_core_init_role(cdns);
-	if (ret)
-		goto init_failed;
-
 	spin_lock_init(&cdns->lock);
 
-	dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
-
 	return 0;
 init_failed:
 	cdns_drd_exit(cdns);
drivers/usb/cdns3/core.h +3 -2
index 801be9e61340..dc8c4137de15 100644
@@ -45,6 +45,7 @@ struct cdns3_platform_data {
 	unsigned long quirks;
 #define CDNS3_DEFAULT_PM_RUNTIME_ALLOW	BIT(0)
 #define CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE	BIT(1)
+	u32 override_apb_timeout;	/* 0 = use default (e.g. for PCI) */
 };
 
 /**
@@ -119,14 +120,14 @@ struct cdns {
 	struct cdns3_platform_data	*pdata;
 	spinlock_t			lock;
 	struct xhci_plat_priv		*xhci_plat_data;
-	u32                             override_apb_timeout;
-
 	int (*gadget_init)(struct cdns *cdns);
+	u32                             override_apb_timeout;
 };
 
 int cdns_hw_role_switch(struct cdns *cdns);
 int cdns_init(struct cdns *cdns);
 int cdns_remove(struct cdns *cdns);
+int cdns_core_init_role(struct cdns *cdns);
 
 #ifdef CONFIG_PM_SLEEP
 int cdns_resume(struct cdns *cdns);
drivers/usb/cdns3/gadget-export.h +2 -2
index c37b6269b001..0cb600e2b5d2 100644
@@ -10,7 +10,7 @@
 #ifndef __LINUX_CDNS3_GADGET_EXPORT
 #define __LINUX_CDNS3_GADGET_EXPORT
 
-#if IS_ENABLED(CONFIG_USB_CDNSP_GADGET)
+#if defined(CONFIG_USB_CDNSP_GADGET) && IS_REACHABLE(CONFIG_USB_CDNSP)
 
 int cdnsp_gadget_init(struct cdns *cdns);
 #else
@@ -22,7 +22,7 @@ static inline int cdnsp_gadget_init(struct cdns *cdns)
 
 #endif /* CONFIG_USB_CDNSP_GADGET */
 
-#if IS_ENABLED(CONFIG_USB_CDNS3_GADGET)
+#if defined(CONFIG_USB_CDNS3_GADGET) && IS_REACHABLE(CONFIG_USB_CDNS3)
 
 int cdns3_gadget_init(struct cdns *cdns);
 #else
Signature · 1 line
2.50.1
maintainer Acked-by on v2 2/2
#4 lore raw

RE: [PATCH v2 2/2] usb: cdns3: Add USBSSP platform driver support

Quoted 253 lines

The Cadence USBSSP (CDNSP) controller was previously only accessible through PCI, coupling the gadget driver with the PCI glue layer into a single monolithic module (cdnsp-udc-pci). This prevented using the CDNSP IP on SoC/platform designs that expose the controller through device tree. It restructures the driver to decouple the CDNSP gadget from PCI.

- Introduce CONFIG_USB_CDNSP as a standalone tristate (analogous to CONFIG_USB_CDNS3), with USB_CDNSP_GADGET and USB_CDNSP_HOST as bool sub-options. The gadget code builds as a separate cdnsp.ko module.

- Regroup USBSSP and CDNS3 Kconfig options under the USB_CDNS_SUPPORT menu so they appear properly grouped in menuconfig.

- Refactor cdnsp-pci.c into a thin PCI-to-platform wrapper (similar to cdns3-pci-wrap.c) that registers a platform device and passes PCI resources and platform data to the common platform driver.

- Auto-detect the controller version (USBSS vs USBSSP) at runtime by reading the DRD/OTG Device ID register in cdns_drd_init(), and select the appropriate gadget init function (cdns3_gadget_init or cdnsp_gadget_init) based on cdns->version. This follows the same pattern already used for host initialization.

- Fix gadget-export.h to use IS_REACHABLE() keyed on the tristate module config (CONFIG_USB_CDNS3/CONFIG_USB_CDNSP) instead of IS_ENABLED() on the bool gadget config. The bool configs are always 'y' when enabled, causing IS_ENABLED/IS_REACHABLE to always return true and resulting in link errors when cdns-usb-common is built-in but the gadget module is loadable.

- Add missing MODULE_LICENSE()/MODULE_DESCRIPTION() and EXPORT_SYMBOL_GPL() to the cdns3 and cdnsp gadget modules, required by modpost.

- Pass override_apb_timeout through cdns3_platform_data so the PCI wrapper can communicate PCI-specific APB timeout values to the common driver.

This patch is Assisted-by: Cursor:claude-4.6-opus

---

drivers/usb/cdns3/Kconfig         |  50 ++++---
drivers/usb/cdns3/Makefile        |  30 ++---
drivers/usb/cdns3/cdns3-gadget.c  |   4 +
drivers/usb/cdns3/cdns3-plat.c    |  17 ++-
drivers/usb/cdns3/cdnsp-gadget.c  |   4 +
drivers/usb/cdns3/cdnsp-pci.c     | 217 +++++++++++++-----------------
drivers/usb/cdns3/core.c          |  11 +-
drivers/usb/cdns3/core.h          |   5 +-
drivers/usb/cdns3/gadget-export.h |   4 +-
9 files changed, 164 insertions(+), 178 deletions(-)
drivers/usb/cdns3/Kconfig +0 -4
index 0a514b591527..97fa84dddbca 100644
@@ -20,10 +20,6 @@ config USB_CDNS3
 	  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.
-endif
-

if USB_CDNS3

config USB_CDNS3_GADGET

drivers/usb/cdns3/Kconfig +7 -11
@@ -89,29 +85,27 @@ config USB_CDNS3_STARFIVE
 
 	  If you choose to build this driver as module it will
 	  be dynamically linked and module will be called cdns3-starfive.ko
-endif
 
-if USB_CDNS_SUPPORT
+endif # USB_CDNS3
 
-config USB_CDNSP_PCI
-	tristate "Cadence CDNSP Dual-Role Controller"
-	depends on USB_CDNS_SUPPORT && USB_PCI && ACPI
+config USB_CDNSP
+	tristate "Cadence USBSSP Dual-Role Controller"
+	depends on USB_CDNS_SUPPORT
 	help
-	  Say Y here if your system has a Cadence CDNSP 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 cdnsp.ko.
-endif
+	  Say Y here if your system has a Cadence USBSSP dual-role controller.
+	  It supports: dual-role switch, Host-only, and Peripheral-only.
+	  Cadence CDNSP Controller device mode is very similar to XHCI

controller.

drivers/usb/cdns3/Kconfig +3 -1
+	  Therefore some algorithms used has been taken from xHCI driver.
+	  Host controller is compliant with XHCI so it uses standard XHCI driver.
 
-if USB_CDNSP_PCI
+if USB_CDNSP

config USB_CDNSP_GADGET

drivers/usb/cdns3/Kconfig +2 -2
-	bool "Cadence CDNSP device controller"
-	depends on USB_GADGET=y || USB_GADGET=USB_CDNSP_PCI
+	bool "Cadence USBSSP device controller"
+	depends on USB_GADGET=y || USB_GADGET=USB_CDNSP

help
Say Y here to enable device controller functionality of the

drivers/usb/cdns3/Kconfig +1 -1
-	  Cadence CDNSP-DEV driver.
+	  Cadence USBSSP-DEV driver.

Cadence CDNSP Device Controller in device mode is very similar to XHCI controller. Therefore some algorithms

drivers/usb/cdns3/Kconfig +0 -0
@@ -120,8 +114,8 @@ config USB_CDNSP_GADGET
 	  It doesn't support LS.
 

config USB_CDNSP_HOST

drivers/usb/cdns3/Kconfig +2 -2
-	bool "Cadence CDNSP host controller"
-	depends on USB=y || USB=USB_CDNSP_PCI
+	bool "Cadence USBSSP host controller"
+	depends on USB=y || USB=USB_CDNSP

select USB_CDNS_HOST
help
Say Y here to enable host controller functionality of the

drivers/usb/cdns3/Kconfig +13 -1
@@ -130,4 +124,16 @@ config USB_CDNSP_HOST
 	  Host controller is compliant with XHCI so it uses
 	  standard XHCI driver.
 
-endif
+config USB_CDNSP_PCI
+	tristate "Cadence USBSSP support on PCIe-based platforms"
+	depends on USB_PCI && ACPI
+	help
+	  If you're using the USBSSP 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 cdnsp-pci.ko
+
+endif # USB_CDNSP
+
+endif # USB_CDNS_SUPPORT
drivers/usb/cdns3/Makefile +0 -0
index 48dfae75b5aa..63484f145bb9 100644
@@ -4,41 +4,33 @@ CFLAGS_cdns3-trace.o				:= -
 I$(src)
 CFLAGS_cdnsp-trace.o				:= -I$(src)
 

cdns-usb-common-y := core.o drd.o
-cdns3-y := cdns3-plat.o

ifeq ($(CONFIG_USB),m)
obj-m += cdns-usb-common.o

drivers/usb/cdns3/Makefile +1 -1
-obj-m						+= cdns3.o
+obj-m						+= cdns3-plat.o

else
obj-$(CONFIG_USB_CDNS_SUPPORT) += cdns-usb-
common.o

drivers/usb/cdns3/Makefile +1 -1
-obj-$(CONFIG_USB_CDNS3)				+= cdns3.o
+obj-$(CONFIG_USB_CDNS_SUPPORT)			+= cdns3-plat.o

endif

cdns-usb-common-$(CONFIG_USB_CDNS_HOST) += host.o
-cdns3-$(CONFIG_USB_CDNS3_GADGET) += cdns3-gadget.o
cdns3-ep0.o

+# For CDNS3 gadget
ifneq ($(CONFIG_USB_CDNS3_GADGET),)
+cdns3-y := cdns3-gadget.o
cdns3-ep0.o
cdns3-$(CONFIG_TRACING) += cdns3-trace.o
+obj-$(CONFIG_USB_CDNS3) += cdns3.o
endif
-
obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci-wrap.o
obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o
obj-$(CONFIG_USB_CDNS3_IMX) += cdns3-imx.o
obj-$(CONFIG_USB_CDNS3_STARFIVE) += cdns3-starfive.o

drivers/usb/cdns3/Makefile +0 -11
-cdnsp-udc-pci-y					:= cdnsp-pci.o
-
-ifdef CONFIG_USB_CDNSP_PCI
-ifeq ($(CONFIG_USB),m)
-obj-m						+= cdnsp-udc-pci.o
-else
-obj-$(CONFIG_USB_CDNSP_PCI) 			+= cdnsp-udc-pci.o
-endif
-endif
-
-cdnsp-udc-pci-$(CONFIG_USB_CDNSP_GADGET)	+= cdnsp-ring.o cdnsp-

gadget.o \

drivers/usb/cdns3/Makefile +1 -2
-						   cdnsp-mem.o cdnsp-ep0.o
-
+# For CDNSP gadget

ifneq ($(CONFIG_USB_CDNSP_GADGET),)

drivers/usb/cdns3/Makefile +1 -1
-cdnsp-udc-pci-$(CONFIG_TRACING)			+= cdnsp-trace.o
+cdnsp-y						:= cdnsp-ring.o cdnsp-

gadget.o \

drivers/usb/cdns3/Makefile +3 -0
+						   cdnsp-mem.o cdnsp-ep0.o
+cdnsp-$(CONFIG_TRACING)				+= cdnsp-trace.o
+obj-$(CONFIG_USB_CDNSP)				+= cdnsp.o

endif

drivers/usb/cdns3/Makefile +1 -0
+obj-$(CONFIG_USB_CDNSP_PCI)			+= cdnsp-pci.o
drivers/usb/cdns3/cdns3- renamed from drivers/usb/cdns3/cdns3-gadget.c +0 -0

gadget.c
index d59a60a16ec7..b800bd1bedd4 100644

drivers/usb/cdns3/cdns3-gadget.c +4 -0
@@ -3508,3 +3508,7 @@ int cdns3_gadget_init(struct cdns *cdns)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(cdns3_gadget_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence USBSS DRD Driver - gadget");
drivers/usb/cdns3/cdns3-plat.c +10 -0
index 735df88774e4..71c612e27b73 100644
@@ -44,6 +44,14 @@ static void set_phy_power_off(struct cdns *cdns)
 	phy_power_off(cdns->usb2_phy);
 }
 
+static int cdns3_plat_gadget_init(struct cdns *cdns)
+{
+	if (cdns->version < CDNSP_CONTROLLER_V2)
+		return cdns3_gadget_init(cdns);
+	else
+		return cdnsp_gadget_init(cdns);
+}
+
 /**
 * cdns3_plat_probe - probe for cdns3 core device
 * @pdev: Pointer to cdns3 core platform device
@@ -64,6 +72,8 @@ static int cdns3_plat_probe(struct platform_device
 *pdev)
 
 	cdns->dev = dev;
 	cdns->pdata = dev_get_platdata(dev);
+	if (cdns->pdata && cdns->pdata->override_apb_timeout)
+		cdns->override_apb_timeout = cdns->pdata-
 >override_apb_timeout;
 
	platform_set_drvdata(pdev, cdns);
drivers/usb/cdns3/cdns3-plat.c +0 -0
@@ -143,12 +153,15 @@ static int cdns3_plat_probe(struct platform_device
 *pdev)

drivers/usb/cdns3/cdns3-plat.c static int cdns3_plat_probe(struct platform_device · line 161

Quoted 10 lines
drivers/usb/cdns3/cdns3-plat.c +1 -2
 	if (ret)
 		goto err_phy_power_on;
 
-	cdns->gadget_init = cdns3_gadget_init;
-
 	ret = cdns_init(cdns);
 	if (ret)
 		goto err_cdns_init;
 
+	cdns->gadget_init = cdns3_plat_gadget_init;

The call to the following function could have been placed in cdns_init. Then assigned of gadget_init should be above of cdns_init.

Besides,

Pawel,

Quoted 443 lines
drivers/usb/cdns3/cdns3-plat.c +4 -0
+	ret = cdns_core_init_role(cdns);
+	if (ret)
+		goto err_cdns_init;
+
 	device_set_wakeup_capable(dev, true);
 	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);
drivers/usb/cdns3/cdnsp- renamed from drivers/usb/cdns3/cdnsp-gadget.c +0 -0

gadget.c
index 6b3815f8a6e5..8db7eee528a1 100644

drivers/usb/cdns3/cdnsp-gadget.c +4 -0
@@ -2075,3 +2075,7 @@ int cdnsp_gadget_init(struct cdns *cdns)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(cdnsp_gadget_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence CDNSP DRD Driver - gadget");
drivers/usb/cdns3/cdnsp-pci.c +18 -6
index 566d94e49102..432007cfe695 100644
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Cadence PCI Glue driver.
+ * Cadence USBSSP PCI Glue driver.
 *
 * Copyright (C) 2019 Cadence.
 *
@@ -16,7 +16,19 @@
 #include <linux/pci.h>
 
 #include "core.h"
-#include "gadget-export.h"
+
+struct cdnsp_wrap {
+	struct platform_device *plat_dev;
+	struct resource dev_res[6];
+	int devfn;
+};
+
+#define RES_IRQ_HOST_ID		0
+#define RES_IRQ_PERIPHERAL_ID	1
+#define RES_IRQ_OTG_ID		2
+#define RES_HOST_ID		3
+#define RES_DEV_ID		4
+#define RES_DRD_ID		5
 
 #define PCI_BAR_HOST		0
 #define PCI_BAR_OTG		0
@@ -26,16 +38,16 @@
 #define PCI_DEV_FN_OTG		1
 
 #define PCI_DRIVER_NAME		"cdns-pci-usbssp"
-#define PLAT_DRIVER_NAME	"cdns-usbssp"
+#define PLAT_DRIVER_NAME	"cdns-usb3"
 
-#define CHICKEN_APB_TIMEOUT_VALUE       0x1C20
+#define CHICKEN_APB_TIMEOUT_VALUE	0x1C20
 
 static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
 {
 	/*
 	 * Gets the second function.
-	 * Platform has two function. The fist keeps resources for
-	 * Host/Device while the secon keeps resources for DRD/OTG.
+	 * Platform has two function. The first keeps resources for
+	 * Host/Device while the second keeps resources for DRD/OTG.
 	 */
 	if (pdev->device == PCI_DEVICE_ID_CDNS_USBSSP)
 		return pci_get_device(pdev->vendor,

PCI_DEVICE_ID_CDNS_USBSS, NULL);

drivers/usb/cdns3/cdnsp-pci.c +5 -4
@@ -48,11 +60,12 @@ static struct pci_dev *cdnsp_get_second_fun(struct
 pci_dev *pdev)
 static int cdnsp_pci_probe(struct pci_dev *pdev,
 			   const struct pci_device_id *id)
 {
-	struct device *dev = &pdev->dev;
-	struct pci_dev *func;
+	struct platform_device_info plat_info;
+	static struct cdns3_platform_data pdata;
+	struct cdnsp_wrap *wrap;
 	struct resource *res;
-	struct cdns *cdnsp;
-	int ret;
+	struct pci_dev *func;
+	int ret = 0;
 
 	/*

* For GADGET/HOST PCI (devfn) function number is 0,

drivers/usb/cdns3/cdnsp-pci.c +62 -74
@@ -79,146 +92,105 @@ static int cdnsp_pci_probe(struct pci_dev *pdev,
 	}
 
 	pci_set_master(pdev);
+
 	if (pci_is_enabled(func)) {
-		cdnsp = pci_get_drvdata(func);
+		wrap = pci_get_drvdata(func);
 	} else {
-		cdnsp = kzalloc_obj(*cdnsp);
-		if (!cdnsp) {
+		wrap = kzalloc_obj(*wrap);
+		if (!wrap) {
 			ret = -ENOMEM;
 			goto put_pci;
 		}
 	}
 
-	/* For GADGET device function number is 0. */
-	if (pdev->devfn == 0) {
-		resource_size_t rsrc_start, rsrc_len;
-
-		/* Function 0: host(BAR_0) + device(BAR_1).*/
-		dev_dbg(dev, "Initialize resources\n");
-		rsrc_start = pci_resource_start(pdev, PCI_BAR_DEV);
-		rsrc_len = pci_resource_len(pdev, PCI_BAR_DEV);
-		res = devm_request_mem_region(dev, rsrc_start, rsrc_len,
 "dev");
-		if (!res) {
-			dev_dbg(dev, "controller already in use\n");
-			ret = -EBUSY;
-			goto free_cdnsp;
-		}
-
-		cdnsp->dev_regs = devm_ioremap(dev, rsrc_start, rsrc_len);
-		if (!cdnsp->dev_regs) {
-			dev_dbg(dev, "error mapping memory\n");
-			ret = -EFAULT;
-			goto free_cdnsp;
-		}
-
-		cdnsp->dev_irq = pdev->irq;
-		dev_dbg(dev, "USBSS-DEV physical base addr: %pa\n",
-			&rsrc_start);
-
-		res = &cdnsp->xhci_res[0];
-		res->start = pci_resource_start(pdev, PCI_BAR_HOST);
-		res->end = pci_resource_end(pdev, PCI_BAR_HOST);
-		res->name = "xhci";
-		res->flags = IORESOURCE_MEM;
-		dev_dbg(dev, "USBSS-XHCI physical base addr: %pa\n",
-			&res->start);
-
-		/* Interrupt for XHCI, */
-		res = &cdnsp->xhci_res[1];
-		res->start = pdev->irq;
-		res->name = "host";
-		res->flags = IORESOURCE_IRQ;
+	res = wrap->dev_res;
+
+	if (pdev->devfn == PCI_DEV_FN_HOST_DEVICE) {
+		/* Function 0: host(BAR_0) + device(BAR_2). */
+		dev_dbg(&pdev->dev, "Initialize Device resources\n");
+		res[RES_DEV_ID].start = pci_resource_start(pdev,
 PCI_BAR_DEV);
+		res[RES_DEV_ID].end = pci_resource_end(pdev,
 PCI_BAR_DEV);
+		res[RES_DEV_ID].name = "dev";
+		res[RES_DEV_ID].flags = IORESOURCE_MEM;
+		dev_dbg(&pdev->dev, "USBSSP-DEV physical base addr:
 %pa\n",
+			&res[RES_DEV_ID].start);
+
+		res[RES_HOST_ID].start = pci_resource_start(pdev,
 PCI_BAR_HOST);
+		res[RES_HOST_ID].end = pci_resource_end(pdev,
 PCI_BAR_HOST);
+		res[RES_HOST_ID].name = "xhci";
+		res[RES_HOST_ID].flags = IORESOURCE_MEM;
+		dev_dbg(&pdev->dev, "USBSSP-XHCI physical base addr:
 %pa\n",
+			&res[RES_HOST_ID].start);
+
+		/* Interrupt for XHCI */
+		wrap->dev_res[RES_IRQ_HOST_ID].start = pdev->irq;
+		wrap->dev_res[RES_IRQ_HOST_ID].name = "host";
+		wrap->dev_res[RES_IRQ_HOST_ID].flags = IORESOURCE_IRQ;
+
+		/* Interrupt for device. It's the same as for HOST. */
+		wrap->dev_res[RES_IRQ_PERIPHERAL_ID].start = pdev->irq;
+		wrap->dev_res[RES_IRQ_PERIPHERAL_ID].name =
 "peripheral";
+		wrap->dev_res[RES_IRQ_PERIPHERAL_ID].flags =
 IORESOURCE_IRQ;
 	} else {
-		res = &cdnsp->otg_res;
-		res->start = pci_resource_start(pdev, PCI_BAR_OTG);
-		res->end =   pci_resource_end(pdev, PCI_BAR_OTG);
-		res->name = "otg";
-		res->flags = IORESOURCE_MEM;
-		dev_dbg(dev, "CDNSP-DRD physical base addr: %pa\n",
-			&res->start);
+		res[RES_DRD_ID].start = pci_resource_start(pdev,
 PCI_BAR_OTG);
+		res[RES_DRD_ID].end = pci_resource_end(pdev,
 PCI_BAR_OTG);
+		res[RES_DRD_ID].name = "otg";
+		res[RES_DRD_ID].flags = IORESOURCE_MEM;
+		dev_dbg(&pdev->dev, "CDNSP-DRD physical base addr:
 %pa\n",
+			&res[RES_DRD_ID].start);
 
 		/* Interrupt for OTG/DRD. */
-		cdnsp->otg_irq = pdev->irq;
+		wrap->dev_res[RES_IRQ_OTG_ID].start = pdev->irq;
+		wrap->dev_res[RES_IRQ_OTG_ID].name = "otg";
+		wrap->dev_res[RES_IRQ_OTG_ID].flags = IORESOURCE_IRQ;
 	}
 
-	/*
-	 * Cadence PCI based platform require some longer timeout for APB
-	 * to fixes domain clock synchronization issue after resuming
-	 * controller from L1 state.
-	 */
-	cdnsp->override_apb_timeout = CHICKEN_APB_TIMEOUT_VALUE;
-	pci_set_drvdata(pdev, cdnsp);
-
 	if (pci_is_enabled(func)) {
-		cdnsp->dev = dev;
-		cdnsp->gadget_init = cdnsp_gadget_init;
-
-		ret = cdns_init(cdnsp);
-		if (ret)
-			goto free_cdnsp;
+		/* set up platform device info */
+		pdata.override_apb_timeout =
 CHICKEN_APB_TIMEOUT_VALUE;
+		memset(&plat_info, 0, sizeof(plat_info));
+		plat_info.parent = &pdev->dev;
+		plat_info.fwnode = pdev->dev.fwnode;
+		plat_info.name = PLAT_DRIVER_NAME;
+		plat_info.id = pdev->devfn;
+		plat_info.res = wrap->dev_res;
+		plat_info.num_res = ARRAY_SIZE(wrap->dev_res);
+		plat_info.dma_mask = pdev->dma_mask;
+		plat_info.data = &pdata;
+		plat_info.size_data = sizeof(pdata);
+		wrap->devfn = pdev->devfn;
+		/* register platform device */
+		wrap->plat_dev = platform_device_register_full(&plat_info);
+		if (IS_ERR(wrap->plat_dev)) {
+			ret = PTR_ERR(wrap->plat_dev);
+			kfree(wrap);
+			goto put_pci;
+		}
 	}
 
-	device_wakeup_enable(&pdev->dev);
-	if (pci_dev_run_wake(pdev))
-		pm_runtime_put_noidle(&pdev->dev);
-
-	return 0;
-
-free_cdnsp:
-	if (!pci_is_enabled(func))
-		kfree(cdnsp);
-
+	pci_set_drvdata(pdev, wrap);

put_pci:

	pci_dev_put(func);
-
	return ret;
}

static void cdnsp_pci_remove(struct pci_dev *pdev) {

drivers/usb/cdns3/cdnsp-pci.c +1 -1
-	struct cdns *cdnsp;
+	struct cdnsp_wrap *wrap;
	struct pci_dev *func;

	func = cdnsp_get_second_fun(pdev);
drivers/usb/cdns3/cdnsp-pci.c +5 -8
-	cdnsp = (struct cdns *)pci_get_drvdata(pdev);
+	wrap = pci_get_drvdata(pdev);
 
-	if (pci_dev_run_wake(pdev))
-		pm_runtime_get_noresume(&pdev->dev);
+	if (wrap->devfn == pdev->devfn)
+		platform_device_unregister(wrap->plat_dev);
 
-	if (pci_is_enabled(func)) {
-		cdns_remove(cdnsp);
-	} else {
-		kfree(cdnsp);
-	}
+	if (!pci_is_enabled(func))
+		kfree(wrap);
	pci_dev_put(func);
}
drivers/usb/cdns3/cdnsp-pci.c +0 -23
-static int __maybe_unused cdnsp_pci_suspend(struct device *dev)
-{
-	struct cdns *cdns = dev_get_drvdata(dev);
-
-	return cdns_suspend(cdns);
-}
-
-static int __maybe_unused cdnsp_pci_resume(struct device *dev)
-{
-	struct cdns *cdns = dev_get_drvdata(dev);
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&cdns->lock, flags);
-	ret = cdns_resume(cdns);
-	spin_unlock_irqrestore(&cdns->lock, flags);
-	cdns_set_active(cdns, 1);
-
-	return ret;
-}
-
-static const struct dev_pm_ops cdnsp_pci_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(cdnsp_pci_suspend,

cdnsp_pci_resume)

drivers/usb/cdns3/cdnsp-pci.c +0 -2
-};
-

static const struct pci_device_id cdnsp_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USBSSP),
.class = PCI_CLASS_SERIAL_USB_DEVICE },

drivers/usb/cdns3/cdnsp-pci.c +2 -5
@@ -230,13 +202,10 @@ static const struct pci_device_id cdnsp_pci_ids[] = {
 };
 
 static struct pci_driver cdnsp_pci_driver = {
-	.name = "cdnsp-pci",
+	.name = PCI_DRIVER_NAME,
 	.id_table = cdnsp_pci_ids,
 	.probe = cdnsp_pci_probe,
 	.remove = cdnsp_pci_remove,
-	.driver = {
-		.pm = &cdnsp_pci_pm_ops,
-	}
 };
 
 module_pci_driver(cdnsp_pci_driver);
@@ -245,4 +214,4 @@ MODULE_DEVICE_TABLE(pci, cdnsp_pci_ids);
 MODULE_ALIAS("pci:cdnsp");
 MODULE_AUTHOR("Pawel Laszczak <[email protected]>");
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Cadence CDNSP PCI driver");
+MODULE_DESCRIPTION("Cadence CDNSP PCI wrapper");
drivers/usb/cdns3/core.c +3 -1
index f0e32227c0b7..10f00b6c3c83 100644
@@ -80,7 +80,7 @@ static void cdns_exit_roles(struct cdns *cdns)
 *
 * Returns 0 on success otherwise negative errno
 */
-static int cdns_core_init_role(struct cdns *cdns)
+int cdns_core_init_role(struct cdns *cdns)
 {
 	struct device *dev = cdns->dev;
 	enum usb_dr_mode best_dr_mode;
@@ -197,11 +197,14 @@ static int cdns_core_init_role(struct cdns *cdns)
 		goto err;
 	}
 
+	dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
+
 	return 0;

err:

	cdns_exit_roles(cdns);
	return ret;
}

+EXPORT_SYMBOL_GPL(cdns_core_init_role);

/**
* cdns_hw_role_state_machine - role switch state machine based on hw
events.

drivers/usb/cdns3/core.c +0 -6
@@ -469,14 +472,8 @@ int cdns_init(struct cdns *cdns)
 	if (ret)
 		goto init_failed;
 
-	ret = cdns_core_init_role(cdns);
-	if (ret)
-		goto init_failed;
-
 	spin_lock_init(&cdns->lock);
 
-	dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
-
 	return 0;

init_failed:

	cdns_drd_exit(cdns);
drivers/usb/cdns3/core.h +3 -2
index 801be9e61340..dc8c4137de15 100644
@@ -45,6 +45,7 @@ struct cdns3_platform_data {
 	unsigned long quirks;
 #define CDNS3_DEFAULT_PM_RUNTIME_ALLOW	BIT(0)
 #define CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE	BIT(1)
+	u32 override_apb_timeout;	/* 0 = use default (e.g. for PCI) */
 };
 
 /**
@@ -119,14 +120,14 @@ struct cdns {
 	struct cdns3_platform_data	*pdata;
 	spinlock_t			lock;
 	struct xhci_plat_priv		*xhci_plat_data;
-	u32                             override_apb_timeout;
-
 	int (*gadget_init)(struct cdns *cdns);
+	u32                             override_apb_timeout;
 };
 
 int cdns_hw_role_switch(struct cdns *cdns);
 int cdns_init(struct cdns *cdns);
 int cdns_remove(struct cdns *cdns);
+int cdns_core_init_role(struct cdns *cdns);
 
 #ifdef CONFIG_PM_SLEEP
 int cdns_resume(struct cdns *cdns);
drivers/usb/cdns3/gadget- renamed from drivers/usb/cdns3/gadget-export.h +0 -0

export.h
index c37b6269b001..0cb600e2b5d2 100644

drivers/usb/cdns3/gadget-export.h +1 -1
@@ -10,7 +10,7 @@
 #ifndef __LINUX_CDNS3_GADGET_EXPORT
 #define __LINUX_CDNS3_GADGET_EXPORT
 
-#if IS_ENABLED(CONFIG_USB_CDNSP_GADGET)
+#if defined(CONFIG_USB_CDNSP_GADGET) &&
 IS_REACHABLE(CONFIG_USB_CDNSP)
 
 int cdnsp_gadget_init(struct cdns *cdns);

#else

drivers/usb/cdns3/gadget-export.h +1 -1
@@ -22,7 +22,7 @@ static inline int cdnsp_gadget_init(struct cdns *cdns)
 
 #endif /* CONFIG_USB_CDNSP_GADGET */
 
-#if IS_ENABLED(CONFIG_USB_CDNS3_GADGET)
+#if defined(CONFIG_USB_CDNS3_GADGET) &&
 IS_REACHABLE(CONFIG_USB_CDNS3)
 
 int cdns3_gadget_init(struct cdns *cdns);

#else
--
2.50.1

author
#5 lore raw

Re: [PATCH v2 2/2] usb: cdns3: Add USBSSP platform driver support

Quoted 22 lines · Pawel Laszczak
Quoted 22 lines
drivers/usb/cdns3/cdns3-plat.c +8 -2
+static int cdns3_plat_gadget_init(struct cdns *cdns)
+{
+      if (cdns->version < CDNSP_CONTROLLER_V2)
+              return cdns3_gadget_init(cdns);
+      else
+              return cdnsp_gadget_init(cdns);
+}
+
@@ -143,12 +153,15 @@ static int cdns3_plat_probe(struct platform_device
 *pdev)
      if (ret)
              goto err_phy_power_on;
 
-      cdns->gadget_init = cdns3_gadget_init;
-
      ret = cdns_init(cdns);
      if (ret)
              goto err_cdns_init;
 
Quoted 4 lines

drivers/usb/cdns3/cdns3-plat.c static int cdns3_plat_probe(struct platform_device *pdev) · line 160

Quoted 1 line
drivers/usb/cdns3/cdns3-plat.c +1 -0
+      cdns->gadget_init = cdns3_plat_gadget_init;

The call to the following function could have been placed in cdns_init. Then assigned of gadget_init should be above of cdns_init.

No. It needs to know cdns->version before assigning gadget_init to know correct .gadget_init for USBSS or USBSSP. And cdns->version is decided at cdns_init, and former cdns_init API includes cdns_core_init_role which calls cdns->gadget_init.

Peter

Quoted 450 lines

Besides,

Pawel,

Quoted 443 lines
drivers/usb/cdns3/cdns3-plat.c +4 -0
+      ret = cdns_core_init_role(cdns);
+      if (ret)
+              goto err_cdns_init;
+
      device_set_wakeup_capable(dev, true);
      pm_runtime_set_active(dev);
      pm_runtime_enable(dev);
drivers/usb/cdns3/cdnsp- renamed from drivers/usb/cdns3/cdnsp-gadget.c +0 -0

gadget.c
index 6b3815f8a6e5..8db7eee528a1 100644

drivers/usb/cdns3/cdnsp-gadget.c +4 -0
@@ -2075,3 +2075,7 @@ int cdnsp_gadget_init(struct cdns *cdns)
 
      return 0;
 }
+EXPORT_SYMBOL_GPL(cdnsp_gadget_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence CDNSP DRD Driver - gadget");
drivers/usb/cdns3/cdnsp-pci.c +18 -6
index 566d94e49102..432007cfe695 100644
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Cadence PCI Glue driver.
+ * Cadence USBSSP PCI Glue driver.
 *
 * Copyright (C) 2019 Cadence.
 *
@@ -16,7 +16,19 @@
 #include <linux/pci.h>
 
 #include "core.h"
-#include "gadget-export.h"
+
+struct cdnsp_wrap {
+      struct platform_device *plat_dev;
+      struct resource dev_res[6];
+      int devfn;
+};
+
+#define RES_IRQ_HOST_ID               0
+#define RES_IRQ_PERIPHERAL_ID 1
+#define RES_IRQ_OTG_ID                2
+#define RES_HOST_ID           3
+#define RES_DEV_ID            4
+#define RES_DRD_ID            5
 
 #define PCI_BAR_HOST          0
 #define PCI_BAR_OTG           0
@@ -26,16 +38,16 @@
 #define PCI_DEV_FN_OTG                1
 
 #define PCI_DRIVER_NAME               "cdns-pci-usbssp"
-#define PLAT_DRIVER_NAME      "cdns-usbssp"
+#define PLAT_DRIVER_NAME      "cdns-usb3"
 
-#define CHICKEN_APB_TIMEOUT_VALUE       0x1C20
+#define CHICKEN_APB_TIMEOUT_VALUE     0x1C20
 
 static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
 {
      /*
       * Gets the second function.
-       * Platform has two function. The fist keeps resources for
-       * Host/Device while the secon keeps resources for DRD/OTG.
+       * Platform has two function. The first keeps resources for
+       * Host/Device while the second keeps resources for DRD/OTG.
       */
      if (pdev->device == PCI_DEVICE_ID_CDNS_USBSSP)
              return pci_get_device(pdev->vendor,

PCI_DEVICE_ID_CDNS_USBSS, NULL);

drivers/usb/cdns3/cdnsp-pci.c +5 -4
@@ -48,11 +60,12 @@ static struct pci_dev *cdnsp_get_second_fun(struct
 pci_dev *pdev)
 static int cdnsp_pci_probe(struct pci_dev *pdev,
                         const struct pci_device_id *id)
 {
-      struct device *dev = &pdev->dev;
-      struct pci_dev *func;
+      struct platform_device_info plat_info;
+      static struct cdns3_platform_data pdata;
+      struct cdnsp_wrap *wrap;
      struct resource *res;
-      struct cdns *cdnsp;
-      int ret;
+      struct pci_dev *func;
+      int ret = 0;
 
      /*

* For GADGET/HOST PCI (devfn) function number is 0,

drivers/usb/cdns3/cdnsp-pci.c +62 -74
@@ -79,146 +92,105 @@ static int cdnsp_pci_probe(struct pci_dev *pdev,
      }
 
      pci_set_master(pdev);
+
      if (pci_is_enabled(func)) {
-              cdnsp = pci_get_drvdata(func);
+              wrap = pci_get_drvdata(func);
      } else {
-              cdnsp = kzalloc_obj(*cdnsp);
-              if (!cdnsp) {
+              wrap = kzalloc_obj(*wrap);
+              if (!wrap) {
                      ret = -ENOMEM;
                      goto put_pci;
              }
      }
 
-      /* For GADGET device function number is 0. */
-      if (pdev->devfn == 0) {
-              resource_size_t rsrc_start, rsrc_len;
-
-              /* Function 0: host(BAR_0) + device(BAR_1).*/
-              dev_dbg(dev, "Initialize resources\n");
-              rsrc_start = pci_resource_start(pdev, PCI_BAR_DEV);
-              rsrc_len = pci_resource_len(pdev, PCI_BAR_DEV);
-              res = devm_request_mem_region(dev, rsrc_start, rsrc_len,
 "dev");
-              if (!res) {
-                      dev_dbg(dev, "controller already in use\n");
-                      ret = -EBUSY;
-                      goto free_cdnsp;
-              }
-
-              cdnsp->dev_regs = devm_ioremap(dev, rsrc_start, rsrc_len);
-              if (!cdnsp->dev_regs) {
-                      dev_dbg(dev, "error mapping memory\n");
-                      ret = -EFAULT;
-                      goto free_cdnsp;
-              }
-
-              cdnsp->dev_irq = pdev->irq;
-              dev_dbg(dev, "USBSS-DEV physical base addr: %pa\n",
-                      &rsrc_start);
-
-              res = &cdnsp->xhci_res[0];
-              res->start = pci_resource_start(pdev, PCI_BAR_HOST);
-              res->end = pci_resource_end(pdev, PCI_BAR_HOST);
-              res->name = "xhci";
-              res->flags = IORESOURCE_MEM;
-              dev_dbg(dev, "USBSS-XHCI physical base addr: %pa\n",
-                      &res->start);
-
-              /* Interrupt for XHCI, */
-              res = &cdnsp->xhci_res[1];
-              res->start = pdev->irq;
-              res->name = "host";
-              res->flags = IORESOURCE_IRQ;
+      res = wrap->dev_res;
+
+      if (pdev->devfn == PCI_DEV_FN_HOST_DEVICE) {
+              /* Function 0: host(BAR_0) + device(BAR_2). */
+              dev_dbg(&pdev->dev, "Initialize Device resources\n");
+              res[RES_DEV_ID].start = pci_resource_start(pdev,
 PCI_BAR_DEV);
+              res[RES_DEV_ID].end = pci_resource_end(pdev,
 PCI_BAR_DEV);
+              res[RES_DEV_ID].name = "dev";
+              res[RES_DEV_ID].flags = IORESOURCE_MEM;
+              dev_dbg(&pdev->dev, "USBSSP-DEV physical base addr:
 %pa\n",
+                      &res[RES_DEV_ID].start);
+
+              res[RES_HOST_ID].start = pci_resource_start(pdev,
 PCI_BAR_HOST);
+              res[RES_HOST_ID].end = pci_resource_end(pdev,
 PCI_BAR_HOST);
+              res[RES_HOST_ID].name = "xhci";
+              res[RES_HOST_ID].flags = IORESOURCE_MEM;
+              dev_dbg(&pdev->dev, "USBSSP-XHCI physical base addr:
 %pa\n",
+                      &res[RES_HOST_ID].start);
+
+              /* Interrupt for XHCI */
+              wrap->dev_res[RES_IRQ_HOST_ID].start = pdev->irq;
+              wrap->dev_res[RES_IRQ_HOST_ID].name = "host";
+              wrap->dev_res[RES_IRQ_HOST_ID].flags = IORESOURCE_IRQ;
+
+              /* Interrupt for device. It's the same as for HOST. */
+              wrap->dev_res[RES_IRQ_PERIPHERAL_ID].start = pdev->irq;
+              wrap->dev_res[RES_IRQ_PERIPHERAL_ID].name =
 "peripheral";
+              wrap->dev_res[RES_IRQ_PERIPHERAL_ID].flags =
 IORESOURCE_IRQ;
      } else {
-              res = &cdnsp->otg_res;
-              res->start = pci_resource_start(pdev, PCI_BAR_OTG);
-              res->end =   pci_resource_end(pdev, PCI_BAR_OTG);
-              res->name = "otg";
-              res->flags = IORESOURCE_MEM;
-              dev_dbg(dev, "CDNSP-DRD physical base addr: %pa\n",
-                      &res->start);
+              res[RES_DRD_ID].start = pci_resource_start(pdev,
 PCI_BAR_OTG);
+              res[RES_DRD_ID].end = pci_resource_end(pdev,
 PCI_BAR_OTG);
+              res[RES_DRD_ID].name = "otg";
+              res[RES_DRD_ID].flags = IORESOURCE_MEM;
+              dev_dbg(&pdev->dev, "CDNSP-DRD physical base addr:
 %pa\n",
+                      &res[RES_DRD_ID].start);
 
              /* Interrupt for OTG/DRD. */
-              cdnsp->otg_irq = pdev->irq;
+              wrap->dev_res[RES_IRQ_OTG_ID].start = pdev->irq;
+              wrap->dev_res[RES_IRQ_OTG_ID].name = "otg";
+              wrap->dev_res[RES_IRQ_OTG_ID].flags = IORESOURCE_IRQ;
      }
 
-      /*
-       * Cadence PCI based platform require some longer timeout for APB
-       * to fixes domain clock synchronization issue after resuming
-       * controller from L1 state.
-       */
-      cdnsp->override_apb_timeout = CHICKEN_APB_TIMEOUT_VALUE;
-      pci_set_drvdata(pdev, cdnsp);
-
      if (pci_is_enabled(func)) {
-              cdnsp->dev = dev;
-              cdnsp->gadget_init = cdnsp_gadget_init;
-
-              ret = cdns_init(cdnsp);
-              if (ret)
-                      goto free_cdnsp;
+              /* set up platform device info */
+              pdata.override_apb_timeout =
 CHICKEN_APB_TIMEOUT_VALUE;
+              memset(&plat_info, 0, sizeof(plat_info));
+              plat_info.parent = &pdev->dev;
+              plat_info.fwnode = pdev->dev.fwnode;
+              plat_info.name = PLAT_DRIVER_NAME;
+              plat_info.id = pdev->devfn;
+              plat_info.res = wrap->dev_res;
+              plat_info.num_res = ARRAY_SIZE(wrap->dev_res);
+              plat_info.dma_mask = pdev->dma_mask;
+              plat_info.data = &pdata;
+              plat_info.size_data = sizeof(pdata);
+              wrap->devfn = pdev->devfn;
+              /* register platform device */
+              wrap->plat_dev = platform_device_register_full(&plat_info);
+              if (IS_ERR(wrap->plat_dev)) {
+                      ret = PTR_ERR(wrap->plat_dev);
+                      kfree(wrap);
+                      goto put_pci;
+              }
      }
 
-      device_wakeup_enable(&pdev->dev);
-      if (pci_dev_run_wake(pdev))
-              pm_runtime_put_noidle(&pdev->dev);
-
-      return 0;
-
-free_cdnsp:
-      if (!pci_is_enabled(func))
-              kfree(cdnsp);
-
+      pci_set_drvdata(pdev, wrap);

put_pci:

      pci_dev_put(func);
-
      return ret;
}

static void cdnsp_pci_remove(struct pci_dev *pdev) {

drivers/usb/cdns3/cdnsp-pci.c +6 -9
-      struct cdns *cdnsp;
+      struct cdnsp_wrap *wrap;
      struct pci_dev *func;
 
      func = cdnsp_get_second_fun(pdev);
-      cdnsp = (struct cdns *)pci_get_drvdata(pdev);
+      wrap = pci_get_drvdata(pdev);
 
-      if (pci_dev_run_wake(pdev))
-              pm_runtime_get_noresume(&pdev->dev);
+      if (wrap->devfn == pdev->devfn)
+              platform_device_unregister(wrap->plat_dev);
 
-      if (pci_is_enabled(func)) {
-              cdns_remove(cdnsp);
-      } else {
-              kfree(cdnsp);
-      }
+      if (!pci_is_enabled(func))
+              kfree(wrap);
 
      pci_dev_put(func);

}

drivers/usb/cdns3/cdnsp-pci.c +0 -23
-static int __maybe_unused cdnsp_pci_suspend(struct device *dev)
-{
-      struct cdns *cdns = dev_get_drvdata(dev);
-
-      return cdns_suspend(cdns);
-}
-
-static int __maybe_unused cdnsp_pci_resume(struct device *dev)
-{
-      struct cdns *cdns = dev_get_drvdata(dev);
-      unsigned long flags;
-      int ret;
-
-      spin_lock_irqsave(&cdns->lock, flags);
-      ret = cdns_resume(cdns);
-      spin_unlock_irqrestore(&cdns->lock, flags);
-      cdns_set_active(cdns, 1);
-
-      return ret;
-}
-
-static const struct dev_pm_ops cdnsp_pci_pm_ops = {
-      SET_SYSTEM_SLEEP_PM_OPS(cdnsp_pci_suspend,

cdnsp_pci_resume)

drivers/usb/cdns3/cdnsp-pci.c +0 -2
-};
-

static const struct pci_device_id cdnsp_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USBSSP),
.class = PCI_CLASS_SERIAL_USB_DEVICE },

drivers/usb/cdns3/cdnsp-pci.c +2 -5
@@ -230,13 +202,10 @@ static const struct pci_device_id cdnsp_pci_ids[] = {
 };
 
 static struct pci_driver cdnsp_pci_driver = {
-      .name = "cdnsp-pci",
+      .name = PCI_DRIVER_NAME,
      .id_table = cdnsp_pci_ids,
      .probe = cdnsp_pci_probe,
      .remove = cdnsp_pci_remove,
-      .driver = {
-              .pm = &cdnsp_pci_pm_ops,
-      }
 };
 
 module_pci_driver(cdnsp_pci_driver);
@@ -245,4 +214,4 @@ MODULE_DEVICE_TABLE(pci, cdnsp_pci_ids);
 MODULE_ALIAS("pci:cdnsp");
 MODULE_AUTHOR("Pawel Laszczak <[email protected]>");
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Cadence CDNSP PCI driver");
+MODULE_DESCRIPTION("Cadence CDNSP PCI wrapper");
drivers/usb/cdns3/core.c +3 -1
index f0e32227c0b7..10f00b6c3c83 100644
@@ -80,7 +80,7 @@ static void cdns_exit_roles(struct cdns *cdns)
 *
 * Returns 0 on success otherwise negative errno
 */
-static int cdns_core_init_role(struct cdns *cdns)
+int cdns_core_init_role(struct cdns *cdns)
 {
      struct device *dev = cdns->dev;
      enum usb_dr_mode best_dr_mode;
@@ -197,11 +197,14 @@ static int cdns_core_init_role(struct cdns *cdns)
              goto err;
      }
 
+      dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
+
      return 0;

err:

      cdns_exit_roles(cdns);
      return ret;
}

+EXPORT_SYMBOL_GPL(cdns_core_init_role);

/**
* cdns_hw_role_state_machine - role switch state machine based on hw
events.

drivers/usb/cdns3/core.c +0 -6
@@ -469,14 +472,8 @@ int cdns_init(struct cdns *cdns)
      if (ret)
              goto init_failed;
 
-      ret = cdns_core_init_role(cdns);
-      if (ret)
-              goto init_failed;
-
      spin_lock_init(&cdns->lock);
 
-      dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
-
      return 0;

init_failed:

      cdns_drd_exit(cdns);
drivers/usb/cdns3/core.h +3 -2
index 801be9e61340..dc8c4137de15 100644
@@ -45,6 +45,7 @@ struct cdns3_platform_data {
      unsigned long quirks;
 #define CDNS3_DEFAULT_PM_RUNTIME_ALLOW        BIT(0)
 #define CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE    BIT(1)
+      u32 override_apb_timeout;       /* 0 = use default (e.g. for PCI) */
 };
 
 /**
@@ -119,14 +120,14 @@ struct cdns {
      struct cdns3_platform_data      *pdata;
      spinlock_t                      lock;
      struct xhci_plat_priv           *xhci_plat_data;
-      u32                             override_apb_timeout;
-
      int (*gadget_init)(struct cdns *cdns);
+      u32                             override_apb_timeout;
 };
 
 int cdns_hw_role_switch(struct cdns *cdns);
 int cdns_init(struct cdns *cdns);
 int cdns_remove(struct cdns *cdns);
+int cdns_core_init_role(struct cdns *cdns);
 
 #ifdef CONFIG_PM_SLEEP
 int cdns_resume(struct cdns *cdns);
drivers/usb/cdns3/gadget- renamed from drivers/usb/cdns3/gadget-export.h +0 -0

export.h
index c37b6269b001..0cb600e2b5d2 100644

drivers/usb/cdns3/gadget-export.h +1 -1
@@ -10,7 +10,7 @@
 #ifndef __LINUX_CDNS3_GADGET_EXPORT
 #define __LINUX_CDNS3_GADGET_EXPORT
 
-#if IS_ENABLED(CONFIG_USB_CDNSP_GADGET)
+#if defined(CONFIG_USB_CDNSP_GADGET) &&
 IS_REACHABLE(CONFIG_USB_CDNSP)
 
 int cdnsp_gadget_init(struct cdns *cdns);

#else

drivers/usb/cdns3/gadget-export.h +1 -1
@@ -22,7 +22,7 @@ static inline int cdnsp_gadget_init(struct cdns *cdns)
 
 #endif /* CONFIG_USB_CDNSP_GADGET */
 
-#if IS_ENABLED(CONFIG_USB_CDNS3_GADGET)
+#if defined(CONFIG_USB_CDNS3_GADGET) &&
 IS_REACHABLE(CONFIG_USB_CDNS3)
 
 int cdns3_gadget_init(struct cdns *cdns);

#else
--
2.50.1

Signature · 2 lines
Best regards,
Peter