* [PATCH v3 0/2] usb: cdns3: USBSSP platform driver support
@ 2026-04-21 2:34 Peter Chen
2026-04-21 2:34 ` [PATCH v3 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support Peter Chen
2026-04-21 2:34 ` [PATCH v3 2/2] usb: cdns3: Add USBSSP platform driver support Peter Chen
0 siblings, 2 replies; 3+ messages in thread
From: Peter Chen @ 2026-04-21 2:34 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, arnd, 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; both USBSS and USBSSP use the "cdns,usb3" compatible string
(binding update in patch 1).
Changes since v2 (vs the v2 series on list)
v2 split CONFIG_USB_CDNSP into its own cdnsp.ko-style path and built
cdns3-plat as a standalone module next to cdns-usb-common. v3 folds the
integration back into one driver module:
- Single cdns.ko (CONFIG_USB_CDNS3) bundles core, DRD, the generic
cdns3-plat binding, optional host.o (CONFIG_USB_CDNS3_HOST) and optional
gadget objects (CONFIG_USB_CDNS3_GADGET). SoC and PCI glue stay
separate small .ko files.
- CONFIG_USB_CDNS_SUPPORT depends on USB and USB_GADGET using the usual
pattern (depends on USB || USB_GADGET; depends on USB if !USB_GADGET;
depends on USB_GADGET if !USB) so the umbrella tracks host or gadget
when either is built as a module (Suggested-by: Arnd Bergmann).
- USB_CDNS3_HOST / USB_CDNS3_GADGET are matched to the cdns.ko tristate
with USB=USB_CDNS3 and USB_GADGET=USB_CDNS3 instead of tying gadget
only to CONFIG_USB_CDNS_SUPPORT, which mis-handled =y / =m splits when
CONFIG_USB_CDNS_SUPPORT=y but CONFIG_USB_CDNS3=m.
- Drop CONFIG_USB_CDNS_HOST; Makefile and host-export.h use
CONFIG_USB_CDNS3_HOST only.
- gadget-export.h uses IS_ENABLED(CONFIG_USB_CDNS3_GADGET) for stubs now
that gadget is a bool compiled into the unified module (v2 used
IS_REACHABLE on separate CONFIG_USB_CDNS3 / CONFIG_USB_CDNSP tristates).
- Patch 2 still refactors cdnsp-pci.c into a PCI-to-platform wrapper,
keeps host_init / gadget_init callbacks, exports cdns_core_init_role,
and limits drivers/usb/cdns3/ to CONFIG_USB_CDNS_SUPPORT.
- Add Rob Herring's ACK for Patch 1.
Build verification
Exhaustive Kconfig sweep: 79 unique resolved configurations (deduped on
CONFIG_USB, CONFIG_USB_GADGET, CONFIG_USB_CDNS_SUPPORT,
CONFIG_USB_CDNS3_HOST, CONFIG_USB_CDNS3, CONFIG_USB_CDNSP_PCI,
CONFIG_USB_CDNS3_GADGET), arm64 cross-build, each run through
make O=out/cix olddefconfig, then Image + modules, then modules_install
into a clean INSTALL_MOD_PATH:
PASS 79 / 79; build failures 0; depmod / module graph failures 0.
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/Makefile | 2 -
drivers/usb/cdns3/Kconfig | 112 ++++-----
drivers/usb/cdns3/Makefile | 44 ++--
drivers/usb/cdns3/cdns3-gadget.c | 1 +
drivers/usb/cdns3/cdns3-plat.c | 27 ++-
drivers/usb/cdns3/cdnsp-gadget.c | 1 +
drivers/usb/cdns3/cdnsp-pci.c | 217 ++++++++----------
drivers/usb/cdns3/core.c | 45 ++--
drivers/usb/cdns3/core.h | 5 +-
drivers/usb/cdns3/gadget-export.h | 10 +-
drivers/usb/cdns3/host-export.h | 4 +-
12 files changed, 209 insertions(+), 269 deletions(-)
--
2.50.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v3 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support
2026-04-21 2:34 [PATCH v3 0/2] usb: cdns3: USBSSP platform driver support Peter Chen
@ 2026-04-21 2:34 ` Peter Chen
2026-04-21 2:34 ` [PATCH v3 2/2] usb: cdns3: Add USBSSP platform driver support Peter Chen
1 sibling, 0 replies; 3+ messages in thread
From: Peter Chen @ 2026-04-21 2:34 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, arnd, 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
Assisted-by: Cursor:claude-4.6-opus
Acked-by: Rob Herring (Arm) <robh@kernel.org>
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] 3+ messages in thread
* [PATCH v3 2/2] usb: cdns3: Add USBSSP platform driver support
2026-04-21 2:34 [PATCH v3 0/2] usb: cdns3: USBSSP platform driver support Peter Chen
2026-04-21 2:34 ` [PATCH v3 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support Peter Chen
@ 2026-04-21 2:34 ` Peter Chen
1 sibling, 0 replies; 3+ messages in thread
From: Peter Chen @ 2026-04-21 2:34 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, arnd, gregkh, pawell, rogerq
Cc: devicetree, linux-kernel, linux-usb, cix-kernel-upstream,
Peter Chen
Expose Cadence USBSSP through the same platform path as USBSS, trim
Kconfig and Makefile: one core loadable object plus separate glue .ko
files.
Single cdns.ko bundles core, DRD, the generic "cdns,usb3" platform
driver in cdns3-plat.c, optional host.o, and optional gadget objects.
Use CONFIG_USB_CDNS3_GADGET as a bool to compile gadget support into
that module. Remove duplicate MODULE_* declarations from cdns3-plat.c
now that it links into the same module.
Kconfig: the generic platform driver is selected via CONFIG_USB_CDNS3.
Move CONFIG_USB_CDNSP_PCI beside CONFIG_USB_CDNS3_PCI_WRAP under
"Platform glue driver support". SoC glue entries (TI, i.MX, StarFive)
depend only on CONFIG_USB_CDNS3.
Tighten CONFIG_USB_CDNS_SUPPORT dependencies so the umbrella follows
host or gadget when either is built as a module. Match host and gadget
bools to the cdns.ko tristate with USB=USB_CDNS3 and USB_GADGET=USB_CDNS3
instead of comparing against USB_CDNS_SUPPORT.
Link host.o when CONFIG_USB_CDNS3_HOST is enabled and use that symbol in
host-export.h, removing the redundant CONFIG_USB_CDNS_HOST indirection.
Export cdns_core_init_role and reorganize the function cdns_init, and
controller version could be gotten before the gadget init function is
decided per controller.
Keep host_init / gadget_init callbacks in struct cdns, so core.c does
not need direct linkage to host or gadget objects. Refactor cdnsp-pci.c
into a thin PCI-to-platform wrapper.
drivers/usb/Makefile: descend into drivers/usb/cdns3/ only when
CONFIG_USB_CDNS_SUPPORT is enabled.
Assisted-by: Cursor:claude-4.6-opus
Suggested-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Peter Chen <peter.chen@cixtech.com>
---
drivers/usb/Makefile | 2 -
drivers/usb/cdns3/Kconfig | 112 +++++++--------
drivers/usb/cdns3/Makefile | 44 +++---
drivers/usb/cdns3/cdns3-gadget.c | 1 +
drivers/usb/cdns3/cdns3-plat.c | 27 +++-
drivers/usb/cdns3/cdnsp-gadget.c | 1 +
drivers/usb/cdns3/cdnsp-pci.c | 217 +++++++++++++-----------------
drivers/usb/cdns3/core.c | 45 ++-----
drivers/usb/cdns3/core.h | 5 +-
drivers/usb/cdns3/gadget-export.h | 10 +-
drivers/usb/cdns3/host-export.h | 4 +-
11 files changed, 201 insertions(+), 267 deletions(-)
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 6f3c86149887..eecbd631fdab 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -14,8 +14,6 @@ obj-$(CONFIG_USB_DWC2) += dwc2/
obj-$(CONFIG_USB_ISP1760) += isp1760/
obj-$(CONFIG_USB_CDNS_SUPPORT) += cdns3/
-obj-$(CONFIG_USB_CDNS3) += cdns3/
-obj-$(CONFIG_USB_CDNSP_PCI) += cdns3/
obj-$(CONFIG_USB_FOTG210) += fotg210/
diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig
index 0a514b591527..39ad23d1ada8 100644
--- a/drivers/usb/cdns3/Kconfig
+++ b/drivers/usb/cdns3/Kconfig
@@ -1,6 +1,9 @@
config USB_CDNS_SUPPORT
tristate "Cadence USB Support"
- depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA
+ depends on USB_SUPPORT && HAS_DMA
+ depends on USB || USB_GADGET
+ depends on USB if !USB_GADGET
+ depends on USB_GADGET if !USB
select USB_XHCI_PLATFORM if USB_XHCI_HCD
select USB_ROLE_SWITCH
help
@@ -8,44 +11,49 @@ config USB_CDNS_SUPPORT
dual-role controller.
It supports: dual-role switch, Host-only, and Peripheral-only.
-config USB_CDNS_HOST
- bool
-
if USB_CDNS_SUPPORT
config USB_CDNS3
- tristate "Cadence USB3 Dual-Role Controller"
+ tristate "Cadence USB dual-role controller (USBSS and USBSSP)"
depends on USB_CDNS_SUPPORT
help
- Say Y here if your system has a Cadence USB3 dual-role controller.
- It supports: dual-role switch, Host-only, and Peripheral-only.
+ Say Y or M here if your system has an on-chip Cadence USB
+ dual-role controller. This covers both USBSS (USB 3.0) and
+ USBSSP (SuperSpeed Plus) IP; the driver detects the variant at
+ runtime.
- If you choose to build this driver is a dynamically linked
- as module, the module will be called cdns3.ko.
-endif
+ The core driver (core, DRD, generic platform binding for the
+ "cdns,usb3" device tree compatible, optional host and gadget)
+ builds as one module named cdns.ko when built as a loadable
+ module.
+
+ It supports: dual-role switch, Host-only, and Peripheral-only.
if USB_CDNS3
-config USB_CDNS3_GADGET
- bool "Cadence USB3 device controller"
- depends on USB_GADGET=y || USB_GADGET=USB_CDNS3
+config USB_CDNS3_HOST
+ bool "Cadence USB host controller (xHCI)"
+ depends on USB=y || USB=USB_CDNS3
help
- Say Y here to enable device controller functionality of the
- Cadence USBSS-DEV driver.
+ Say Y here to enable host controller functionality for Cadence
+ USBSS and USBSSP dual-role controllers.
- This controller supports FF, HS and SS mode. It doesn't support
- LS and SSP mode.
+ The host controller is xHCI compliant and uses the standard
+ xHCI driver.
-config USB_CDNS3_HOST
- bool "Cadence USB3 host controller"
- depends on USB=y || USB=USB_CDNS3
- select USB_CDNS_HOST
+config USB_CDNS3_GADGET
+ bool "Cadence USB device controller (USBSS and USBSSP)"
+ depends on USB_GADGET=y || USB_GADGET=USB_CDNS3
help
- Say Y here to enable host controller functionality of the
- Cadence driver.
+ Say Y here to include Cadence USB device (gadget) support for
+ both USBSS (USB 3.0) and USBSSP (SuperSpeed Plus) IP in the
+ cdns.ko module. The implementation is selected at runtime from
+ the detected controller version.
- Host controller is compliant with XHCI so it will use
- standard XHCI driver.
+ USBSS gadget supports FF, HS and SS mode (not LS or SSP).
+ USBSSP gadget supports FF, HS, SS and SSP mode (not LS).
+
+comment "Platform glue driver support"
config USB_CDNS3_PCI_WRAP
tristate "Cadence USB3 support on PCIe-based platforms"
@@ -58,6 +66,17 @@ config USB_CDNS3_PCI_WRAP
If you choose to build this driver as module it will
be dynamically linked and module will be called cdns3-pci.ko
+config USB_CDNSP_PCI
+ tristate "Cadence USBSSP support on PCIe-based platforms"
+ depends on USB_PCI && ACPI
+ default USB_CDNS3
+ 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
+
config USB_CDNS3_TI
tristate "Cadence USB3 support on TI platforms"
depends on ARCH_K3 || COMPILE_TEST
@@ -81,6 +100,7 @@ config USB_CDNS3_IMX
config USB_CDNS3_STARFIVE
tristate "Cadence USB3 support on StarFive SoC platforms"
depends on ARCH_STARFIVE || COMPILE_TEST
+ default USB_CDNS3
help
Say 'Y' or 'M' here if you are building for StarFive SoCs
platforms that contain Cadence USB3 controller core.
@@ -89,45 +109,7 @@ 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
-
-config USB_CDNSP_PCI
- tristate "Cadence CDNSP Dual-Role Controller"
- depends on USB_CDNS_SUPPORT && USB_PCI && ACPI
- 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
-
-if USB_CDNSP_PCI
-
-config USB_CDNSP_GADGET
- bool "Cadence CDNSP device controller"
- depends on USB_GADGET=y || USB_GADGET=USB_CDNSP_PCI
- help
- Say Y here to enable device controller functionality of the
- Cadence CDNSP-DEV driver.
-
- Cadence CDNSP Device Controller in device mode is
- very similar to XHCI controller. Therefore some algorithms
- used has been taken from host driver.
- This controller supports FF, HS, SS and SSP mode.
- It doesn't support LS.
-
-config USB_CDNSP_HOST
- bool "Cadence CDNSP host controller"
- depends on USB=y || USB=USB_CDNSP_PCI
- select USB_CDNS_HOST
- help
- Say Y here to enable host controller functionality of the
- Cadence driver.
- Host controller is compliant with XHCI so it uses
- standard XHCI driver.
+endif # USB_CDNS3
-endif
+endif # USB_CDNS_SUPPORT
diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile
index 48dfae75b5aa..b2e4ba6a49a3 100644
--- a/drivers/usb/cdns3/Makefile
+++ b/drivers/usb/cdns3/Makefile
@@ -3,42 +3,28 @@
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
+obj-$(CONFIG_USB_CDNS3) += cdns.o
-ifeq ($(CONFIG_USB),m)
-obj-m += cdns-usb-common.o
-obj-m += cdns3.o
-else
-obj-$(CONFIG_USB_CDNS_SUPPORT) += cdns-usb-common.o
-obj-$(CONFIG_USB_CDNS3) += cdns3.o
-endif
+cdns-y := core.o drd.o cdns3-plat.o
+cdns-$(CONFIG_USB_CDNS3_HOST) += host.o
-cdns-usb-common-$(CONFIG_USB_CDNS_HOST) += host.o
-cdns3-$(CONFIG_USB_CDNS3_GADGET) += cdns3-gadget.o cdns3-ep0.o
+ifneq ($(CONFIG_USB_CDNS3_GADGET),)
+cdns-y += cdns3-gadget.o cdns3-ep0.o \
+ cdnsp-ring.o cdnsp-gadget.o \
+ cdnsp-mem.o cdnsp-ep0.o
+endif
+ifneq ($(CONFIG_TRACING),)
ifneq ($(CONFIG_USB_CDNS3_GADGET),)
-cdns3-$(CONFIG_TRACING) += cdns3-trace.o
+cdns-y += cdns3-trace.o cdnsp-trace.o
+endif
endif
+##
+# Platform-specific glue layers (PCI wrappers, SoC integration)
+##
obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci-wrap.o
+obj-$(CONFIG_USB_CDNSP_PCI) += cdnsp-pci.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
-
-ifneq ($(CONFIG_USB_CDNSP_GADGET),)
-cdnsp-udc-pci-$(CONFIG_TRACING) += cdnsp-trace.o
-endif
diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c
index d59a60a16ec7..ff422e5204e4 100644
--- a/drivers/usb/cdns3/cdns3-gadget.c
+++ b/drivers/usb/cdns3/cdns3-gadget.c
@@ -3508,3 +3508,4 @@ int cdns3_gadget_init(struct cdns *cdns)
return 0;
}
+EXPORT_SYMBOL_GPL(cdns3_gadget_init);
diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
index 735df88774e4..3fe3109a3688 100644
--- a/drivers/usb/cdns3/cdns3-plat.c
+++ b/drivers/usb/cdns3/cdns3-plat.c
@@ -21,6 +21,7 @@
#include "core.h"
#include "gadget-export.h"
+#include "host-export.h"
#include "drd.h"
static int set_phy_power_on(struct cdns *cdns)
@@ -44,6 +45,19 @@ 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);
+}
+
+static int cdns3_plat_host_init(struct cdns *cdns)
+{
+ return cdns_host_init(cdns);
+}
+
/**
* cdns3_plat_probe - probe for cdns3 core device
* @pdev: Pointer to cdns3 core platform device
@@ -64,6 +78,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 +159,16 @@ 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;
+ cdns->host_init = cdns3_plat_host_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);
@@ -336,6 +356,3 @@ static struct platform_driver cdns3_driver = {
module_platform_driver(cdns3_driver);
MODULE_ALIAS("platform:cdns3");
-MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver");
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index 6b3815f8a6e5..18e872ad29bd 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -2075,3 +2075,4 @@ int cdnsp_gadget_init(struct cdns *cdns)
return 0;
}
+EXPORT_SYMBOL_GPL(cdnsp_gadget_init);
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..6a8d1fefbc0d 100644
--- a/drivers/usb/cdns3/core.c
+++ b/drivers/usb/cdns3/core.c
@@ -21,7 +21,6 @@
#include <linux/pm_runtime.h>
#include "core.h"
-#include "host-export.h"
#include "drd.h"
static int cdns_idle_init(struct cdns *cdns);
@@ -80,7 +79,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;
@@ -96,23 +95,13 @@ static int cdns_core_init_role(struct cdns *cdns)
* can be restricted later depending on strap pin configuration.
*/
if (dr_mode == USB_DR_MODE_UNKNOWN) {
- if (cdns->version == CDNSP_CONTROLLER_V2) {
- if (IS_ENABLED(CONFIG_USB_CDNSP_HOST) &&
- IS_ENABLED(CONFIG_USB_CDNSP_GADGET))
- dr_mode = USB_DR_MODE_OTG;
- else if (IS_ENABLED(CONFIG_USB_CDNSP_HOST))
- dr_mode = USB_DR_MODE_HOST;
- else if (IS_ENABLED(CONFIG_USB_CDNSP_GADGET))
- dr_mode = USB_DR_MODE_PERIPHERAL;
- } else {
- if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) &&
- IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
- dr_mode = USB_DR_MODE_OTG;
- else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST))
- dr_mode = USB_DR_MODE_HOST;
- else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
- dr_mode = USB_DR_MODE_PERIPHERAL;
- }
+ if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) &&
+ IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
+ dr_mode = USB_DR_MODE_OTG;
+ else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST))
+ dr_mode = USB_DR_MODE_HOST;
+ else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
+ dr_mode = USB_DR_MODE_PERIPHERAL;
}
/*
@@ -137,11 +126,8 @@ static int cdns_core_init_role(struct cdns *cdns)
dr_mode = best_dr_mode;
if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
- if ((cdns->version == CDNSP_CONTROLLER_V2 &&
- IS_ENABLED(CONFIG_USB_CDNSP_HOST)) ||
- (cdns->version < CDNSP_CONTROLLER_V2 &&
- IS_ENABLED(CONFIG_USB_CDNS3_HOST)))
- ret = cdns_host_init(cdns);
+ if (cdns->host_init)
+ ret = cdns->host_init(cdns);
else
ret = -ENXIO;
@@ -197,11 +183,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 +458,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);
@@ -576,5 +559,5 @@ EXPORT_SYMBOL_GPL(cdns_set_active);
MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
-MODULE_DESCRIPTION("Cadence USBSS and USBSSP DRD Driver");
+MODULE_DESCRIPTION("Cadence USBSS/USBSSP DRD driver (core, DRD, platform, optional host/gadget)");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h
index 801be9e61340..bca973b999a4 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) */
};
/**
@@ -82,6 +83,7 @@ struct cdns3_platform_data {
* @override_apb_timeout: hold value of APB timeout. For value 0 the default
* value in CHICKEN_BITS_3 will be preserved.
* @gadget_init: pointer to gadget initialization function
+ * @host_init: pointer to host initialization function
*/
struct cdns {
struct device *dev;
@@ -120,13 +122,14 @@ struct cdns {
spinlock_t lock;
struct xhci_plat_priv *xhci_plat_data;
u32 override_apb_timeout;
-
int (*gadget_init)(struct cdns *cdns);
+ int (*host_init)(struct cdns *cdns);
};
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..60c3177db62c 100644
--- a/drivers/usb/cdns3/gadget-export.h
+++ b/drivers/usb/cdns3/gadget-export.h
@@ -10,9 +10,10 @@
#ifndef __LINUX_CDNS3_GADGET_EXPORT
#define __LINUX_CDNS3_GADGET_EXPORT
-#if IS_ENABLED(CONFIG_USB_CDNSP_GADGET)
+#if IS_ENABLED(CONFIG_USB_CDNS3_GADGET)
int cdnsp_gadget_init(struct cdns *cdns);
+int cdns3_gadget_init(struct cdns *cdns);
#else
static inline int cdnsp_gadget_init(struct cdns *cdns)
@@ -20,13 +21,6 @@ static inline int cdnsp_gadget_init(struct cdns *cdns)
return -ENXIO;
}
-#endif /* CONFIG_USB_CDNSP_GADGET */
-
-#if IS_ENABLED(CONFIG_USB_CDNS3_GADGET)
-
-int cdns3_gadget_init(struct cdns *cdns);
-#else
-
static inline int cdns3_gadget_init(struct cdns *cdns)
{
return -ENXIO;
diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h
index cf92173ecf00..34fd1f1ad59d 100644
--- a/drivers/usb/cdns3/host-export.h
+++ b/drivers/usb/cdns3/host-export.h
@@ -9,7 +9,7 @@
#ifndef __LINUX_CDNS3_HOST_EXPORT
#define __LINUX_CDNS3_HOST_EXPORT
-#if IS_ENABLED(CONFIG_USB_CDNS_HOST)
+#if IS_ENABLED(CONFIG_USB_CDNS3_HOST)
int cdns_host_init(struct cdns *cdns);
@@ -22,6 +22,6 @@ static inline int cdns_host_init(struct cdns *cdns)
static inline void cdns_host_exit(struct cdns *cdns) { }
-#endif /* USB_CDNS_HOST */
+#endif /* CONFIG_USB_CDNS3_HOST */
#endif /* __LINUX_CDNS3_HOST_EXPORT */
--
2.50.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-04-21 2:35 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-21 2:34 [PATCH v3 0/2] usb: cdns3: USBSSP platform driver support Peter Chen
2026-04-21 2:34 ` [PATCH v3 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support Peter Chen
2026-04-21 2:34 ` [PATCH v3 2/2] usb: cdns3: Add USBSSP platform driver support Peter Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox