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