public inbox for devicetree@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] usb: cdns3: USBSSP platform driver support
@ 2026-03-16  6:48 Peter Chen
  2026-03-16  6:48 ` [PATCH v2 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support Peter Chen
  2026-03-16  6:48 ` [PATCH v2 2/2] usb: cdns3: Add USBSSP platform driver support Peter Chen
  0 siblings, 2 replies; 6+ messages in thread
From: Peter Chen @ 2026-03-16  6:48 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, gregkh, pawell, rogerq
  Cc: devicetree, linux-kernel, linux-usb, cix-kernel-upstream,
	Peter Chen

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(-)

-- 
2.50.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support
  2026-03-16  6:48 [PATCH v2 0/2] usb: cdns3: USBSSP platform driver support Peter Chen
@ 2026-03-16  6:48 ` Peter Chen
  2026-03-24  1:06   ` Rob Herring (Arm)
  2026-03-16  6:48 ` [PATCH v2 2/2] usb: cdns3: Add USBSSP platform driver support Peter Chen
  1 sibling, 1 reply; 6+ messages in thread
From: Peter Chen @ 2026-03-16  6:48 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, gregkh, pawell, rogerq
  Cc: devicetree, linux-kernel, linux-usb, cix-kernel-upstream,
	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

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

Signed-off-by: Peter Chen <peter.chen@cixtech.com>
---
 Documentation/devicetree/bindings/usb/cdns,usb3.yaml | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
index f454ddd9bbaa..ad5acf956edf 100644
--- a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
+++ b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
@@ -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 <pawell@cadence.com>
 
+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
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 2/2] usb: cdns3: Add USBSSP platform driver support
  2026-03-16  6:48 [PATCH v2 0/2] usb: cdns3: USBSSP platform driver support Peter Chen
  2026-03-16  6:48 ` [PATCH v2 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support Peter Chen
@ 2026-03-16  6:48 ` Peter Chen
  2026-03-24 12:10   ` Pawel Laszczak
  1 sibling, 1 reply; 6+ messages in thread
From: Peter Chen @ 2026-03-16  6:48 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, gregkh, pawell, rogerq
  Cc: devicetree, linux-kernel, linux-usb, cix-kernel-upstream,
	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

Signed-off-by: Peter Chen <peter.chen@cixtech.com>
---
 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(-)

diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig
index 0a514b591527..97fa84dddbca 100644
--- a/drivers/usb/cdns3/Kconfig
+++ b/drivers/usb/cdns3/Kconfig
@@ -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
diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile
index 48dfae75b5aa..63484f145bb9 100644
--- a/drivers/usb/cdns3/Makefile
+++ b/drivers/usb/cdns3/Makefile
@@ -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
diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c
index d59a60a16ec7..b800bd1bedd4 100644
--- a/drivers/usb/cdns3/cdns3-gadget.c
+++ b/drivers/usb/cdns3/cdns3-gadget.c
@@ -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");
diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
index 735df88774e4..71c612e27b73 100644
--- a/drivers/usb/cdns3/cdns3-plat.c
+++ b/drivers/usb/cdns3/cdns3-plat.c
@@ -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);
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index 6b3815f8a6e5..8db7eee528a1 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -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");
diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c
index 566d94e49102..432007cfe695 100644
--- a/drivers/usb/cdns3/cdnsp-pci.c
+++ b/drivers/usb/cdns3/cdnsp-pci.c
@@ -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);
@@ -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,
@@ -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)
 {
-	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);
 }
 
-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)
-};
-
 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 },
@@ -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 <pawell@cadence.com>");
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Cadence CDNSP PCI driver");
+MODULE_DESCRIPTION("Cadence CDNSP PCI wrapper");
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
index f0e32227c0b7..10f00b6c3c83 100644
--- a/drivers/usb/cdns3/core.c
+++ b/drivers/usb/cdns3/core.c
@@ -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);
diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h
index 801be9e61340..dc8c4137de15 100644
--- a/drivers/usb/cdns3/core.h
+++ b/drivers/usb/cdns3/core.h
@@ -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);
diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h
index c37b6269b001..0cb600e2b5d2 100644
--- a/drivers/usb/cdns3/gadget-export.h
+++ b/drivers/usb/cdns3/gadget-export.h
@@ -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
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support
  2026-03-16  6:48 ` [PATCH v2 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support Peter Chen
@ 2026-03-24  1:06   ` Rob Herring (Arm)
  0 siblings, 0 replies; 6+ messages in thread
From: Rob Herring (Arm) @ 2026-03-24  1:06 UTC (permalink / raw)
  To: Peter Chen
  Cc: rogerq, linux-kernel, cix-kernel-upstream, conor+dt, pawell,
	devicetree, gregkh, krzk+dt, linux-usb


On Mon, 16 Mar 2026 14:48:30 +0800, Peter Chen wrote:
> 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
> 
> Signed-off-by: Peter Chen <peter.chen@cixtech.com>
> ---
>  Documentation/devicetree/bindings/usb/cdns,usb3.yaml | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 

Acked-by: Rob Herring (Arm) <robh@kernel.org>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH v2 2/2] usb: cdns3: Add USBSSP platform driver support
  2026-03-16  6:48 ` [PATCH v2 2/2] usb: cdns3: Add USBSSP platform driver support Peter Chen
@ 2026-03-24 12:10   ` Pawel Laszczak
  2026-03-25  7:35     ` Peter Chen
  0 siblings, 1 reply; 6+ messages in thread
From: Pawel Laszczak @ 2026-03-24 12:10 UTC (permalink / raw)
  To: Peter Chen, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, gregkh@linuxfoundation.org,
	rogerq@kernel.org
  Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-usb@vger.kernel.org, cix-kernel-upstream@cixtech.com


>
>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
>
>Signed-off-by: Peter Chen <peter.chen@cixtech.com>
>---
> 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(-)
>
>diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig
>index 0a514b591527..97fa84dddbca 100644
>--- a/drivers/usb/cdns3/Kconfig
>+++ b/drivers/usb/cdns3/Kconfig
>@@ -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
>diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile
>index 48dfae75b5aa..63484f145bb9 100644
>--- a/drivers/usb/cdns3/Makefile
>+++ b/drivers/usb/cdns3/Makefile
>@@ -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
>diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-
>gadget.c
>index d59a60a16ec7..b800bd1bedd4 100644
>--- a/drivers/usb/cdns3/cdns3-gadget.c
>+++ b/drivers/usb/cdns3/cdns3-gadget.c
>@@ -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");
>diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
>index 735df88774e4..71c612e27b73 100644
>--- a/drivers/usb/cdns3/cdns3-plat.c
>+++ b/drivers/usb/cdns3/cdns3-plat.c
>@@ -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;

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,
Acked-by: Pawel Laszczak <pawell@cadence.com>
	
Pawel,

>+	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);
>diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-
>gadget.c
>index 6b3815f8a6e5..8db7eee528a1 100644
>--- a/drivers/usb/cdns3/cdnsp-gadget.c
>+++ b/drivers/usb/cdns3/cdnsp-gadget.c
>@@ -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");
>diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c
>index 566d94e49102..432007cfe695 100644
>--- a/drivers/usb/cdns3/cdnsp-pci.c
>+++ b/drivers/usb/cdns3/cdnsp-pci.c
>@@ -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);
>@@ -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,
>@@ -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)
> {
>-	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);
> }
>
>-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)
>-};
>-
> 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 },
>@@ -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 <pawell@cadence.com>");
> MODULE_LICENSE("GPL v2");
>-MODULE_DESCRIPTION("Cadence CDNSP PCI driver");
>+MODULE_DESCRIPTION("Cadence CDNSP PCI wrapper");
>diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
>index f0e32227c0b7..10f00b6c3c83 100644
>--- a/drivers/usb/cdns3/core.c
>+++ b/drivers/usb/cdns3/core.c
>@@ -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);
>diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h
>index 801be9e61340..dc8c4137de15 100644
>--- a/drivers/usb/cdns3/core.h
>+++ b/drivers/usb/cdns3/core.h
>@@ -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);
>diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-
>export.h
>index c37b6269b001..0cb600e2b5d2 100644
>--- a/drivers/usb/cdns3/gadget-export.h
>+++ b/drivers/usb/cdns3/gadget-export.h
>@@ -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
>--
>2.50.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 2/2] usb: cdns3: Add USBSSP platform driver support
  2026-03-24 12:10   ` Pawel Laszczak
@ 2026-03-25  7:35     ` Peter Chen
  0 siblings, 0 replies; 6+ messages in thread
From: Peter Chen @ 2026-03-25  7:35 UTC (permalink / raw)
  To: Pawel Laszczak
  Cc: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	gregkh@linuxfoundation.org, rogerq@kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-usb@vger.kernel.org, cix-kernel-upstream@cixtech.com

On 26-03-24 12:10:43, Pawel Laszczak wrote:
> >
> >+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;
> >
> >+      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

> 
> Besides,
> Acked-by: Pawel Laszczak <pawell@cadence.com>
> 
> Pawel,
> 
> >+      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);
> >diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-
> >gadget.c
> >index 6b3815f8a6e5..8db7eee528a1 100644
> >--- a/drivers/usb/cdns3/cdnsp-gadget.c
> >+++ b/drivers/usb/cdns3/cdnsp-gadget.c
> >@@ -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");
> >diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c
> >index 566d94e49102..432007cfe695 100644
> >--- a/drivers/usb/cdns3/cdnsp-pci.c
> >+++ b/drivers/usb/cdns3/cdnsp-pci.c
> >@@ -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);
> >@@ -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,
> >@@ -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)
> > {
> >-      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);
> > }
> >
> >-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)
> >-};
> >-
> > 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 },
> >@@ -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 <pawell@cadence.com>");
> > MODULE_LICENSE("GPL v2");
> >-MODULE_DESCRIPTION("Cadence CDNSP PCI driver");
> >+MODULE_DESCRIPTION("Cadence CDNSP PCI wrapper");
> >diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
> >index f0e32227c0b7..10f00b6c3c83 100644
> >--- a/drivers/usb/cdns3/core.c
> >+++ b/drivers/usb/cdns3/core.c
> >@@ -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);
> >diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h
> >index 801be9e61340..dc8c4137de15 100644
> >--- a/drivers/usb/cdns3/core.h
> >+++ b/drivers/usb/cdns3/core.h
> >@@ -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);
> >diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-
> >export.h
> >index c37b6269b001..0cb600e2b5d2 100644
> >--- a/drivers/usb/cdns3/gadget-export.h
> >+++ b/drivers/usb/cdns3/gadget-export.h
> >@@ -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
> >--
> >2.50.1
> 

-- 

Best regards,
Peter

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-03-25  7:35 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-16  6:48 [PATCH v2 0/2] usb: cdns3: USBSSP platform driver support Peter Chen
2026-03-16  6:48 ` [PATCH v2 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support Peter Chen
2026-03-24  1:06   ` Rob Herring (Arm)
2026-03-16  6:48 ` [PATCH v2 2/2] usb: cdns3: Add USBSSP platform driver support Peter Chen
2026-03-24 12:10   ` Pawel Laszczak
2026-03-25  7:35     ` Peter Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox