* [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