From f00c0038eefa696787d9e295d69c5fda1fa9f8a5 Mon Sep 17 00:00:00 2001 From: Dj <43033058+DjDeveloperr@users.noreply.github.com> Date: Mon, 26 Oct 2026 02:34:21 -0400 Subject: [PATCH] usb: dwc3: apple: Add the T6050 controller and tunables Add the T6050 DWC3 register-bank and firmware-tunable profile, including the USB3 PHY handoff. Preserve the current wakeup and host-only behavior for existing controllers. Source snapshot: t6050-gpu ee68abb105200e99636a5edfc647a5cfc1d89954 Integration base: 9cbdd0734d9e186c5f5f5949a21b909d10c2571b Signed-off-by: Dj <43033058+DjDeveloperr@users.noreply.github.com> --- .../devicetree/bindings/usb/apple,dwc3.yaml | 60 +++++++++-- drivers/usb/dwc3/Kconfig | 1 + drivers/usb/dwc3/dwc3-apple.c | 100 +++++++++++++++++- 3 files changed, 152 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/apple,dwc3.yaml b/Documentation/devicetree/bindings/usb/apple,dwc3.yaml index 74ef99bccf870..055ec40000a27 100644 --- a/Documentation/devicetree/bindings/usb/apple,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/apple,dwc3.yaml @@ -24,6 +24,32 @@ allOf: then: required: - power-domains + - if: + properties: + compatible: + contains: + const: apple,t6050-dwc3 + then: + properties: + reg: + minItems: 5 + maxItems: 5 + reg-names: + items: + - const: dwc3-core + - const: dwc3-apple + - const: drd-cfg + - const: drd-bulk + - const: drd-ausbc + required: + - apple,tunable-bulk-default + - apple,tunable-gbl-default + - apple,tunable-gbl-host + - apple,tunable-cio-default + - apple,tunable-debug-default + - apple,tunable-cfg-host + - apple,tunable-link-default + - apple,tunable-ausbc-default $defs: apple,tunable: @@ -51,22 +77,17 @@ properties: - apple,t8140-dwc3 - apple,t8142-dwc3 - const: apple,t8103-dwc3 + - const: apple,t6050-dwc3 - const: apple,t8103-dwc3 - const: apple,t8132-dwc3 reg: minItems: 2 - items: - - description: Core DWC3 region - - description: Apple-specific DWC3 region - - description: Controller configuration block (T6040) + maxItems: 5 reg-names: minItems: 2 - items: - - const: dwc3-core - - const: dwc3-apple - - const: drd-cfg + maxItems: 5 interrupts: maxItems: 1 @@ -100,6 +121,29 @@ properties: $ref: "#/$defs/apple,tunable" description: Tunables applied to the link registers of the Apple region. + apple,tunable-bulk-default: + $ref: "#/$defs/apple,tunable" + description: Producer-supplied offset, mask and value register tuples + + + + apple,tunable-cio-default: + $ref: "#/$defs/apple,tunable" + description: Producer-supplied offset, mask and value register tuples + + apple,tunable-debug-default: + $ref: "#/$defs/apple,tunable" + description: Producer-supplied offset, mask and value register tuples + + + apple,tunable-link-default: + $ref: "#/$defs/apple,tunable" + description: Producer-supplied offset, mask and value register tuples + + apple,tunable-ausbc-default: + $ref: "#/$defs/apple,tunable" + description: Producer-supplied offset, mask and value register tuples + required: - compatible - reg diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index c862e55ae3a37..4f5be5ecee562 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -227,6 +227,7 @@ config USB_DWC3_APPLE depends on OF && ARCH_APPLE default USB_DWC3 select USB_ROLE_SWITCH + select APPLE_TUNABLE help Support Apple Silicon SoCs with DesignWare Core USB3 IP. The DesignWare Core USB3 IP has to be used in dual-role diff --git a/drivers/usb/dwc3/dwc3-apple.c b/drivers/usb/dwc3/dwc3-apple.c index 998b6cffe6297..bc509ccde2371 100644 --- a/drivers/usb/dwc3/dwc3-apple.c +++ b/drivers/usb/dwc3/dwc3-apple.c @@ -132,6 +132,9 @@ struct dwc3_apple { struct device *dev; struct resource *mmio_resource; void __iomem *apple_regs; + bool t6050; + void __iomem *native_regs[3]; + struct apple_tunable *native_tunables[8]; struct reset_control *reset; struct phy *usb2_phy; @@ -215,6 +218,82 @@ static void dwc3_apple_setup_cio(struct dwc3_apple *appledwc) dwc3_apple_mask(appledwc, APPLE_DWC3_CIO_LINK_TIMER, APPLE_DWC3_CIO_PM_ENTRY_TIMER, FIELD_PREP(APPLE_DWC3_CIO_PM_ENTRY_TIMER, APPLE_DWC3_CIO_PM_ENTRY_TIMER_VALUE)); + if (appledwc->t6050) { + /* Saved native applyAllTunables uses reg0+c100 for GBL, + * reg0+cd20 for CIO, reg0+d800 for DBG and reg7 for LINK. + * The board's CIO table overrides the older fixed timer values. + * PIPE belongs to the PHY owner and is applied there. + */ + void __iomem *bases[] = { + appledwc->native_regs[1], + appledwc->dwc.regs, appledwc->dwc.regs, + appledwc->apple_regs + 0x20, + appledwc->apple_regs + 0xb00, + appledwc->native_regs[0], + appledwc->apple_regs + 0x300, + appledwc->native_regs[2], + }; + for (unsigned int i = 0; i < ARRAY_SIZE(bases); i++) + apple_tunable_apply(bases[i], appledwc->native_tunables[i]); + /* The native T8142 xHCI reset replaces + * GCTL[31:19] with 13 before applying these board tunables. + * Use the native host value instead of the inherited device value. + */ + u32 gctl = dwc3_readl(&appledwc->dwc, DWC3_GCTL); + gctl = (gctl & GENMASK(18, 0)) | (13U << 19); + dwc3_writel(&appledwc->dwc, DWC3_GCTL, gctl); + /* Native applyAllTunables clears reg0+c680 bit13 last. */ + u32 value = readl(appledwc->dwc.regs + 0x580); + writel(value & ~BIT(13), appledwc->dwc.regs + 0x580); + } +} + +static int dwc3_apple_t6050_tunables(struct platform_device *pdev, + struct dwc3_apple *appledwc) +{ + static const char * const names[] = {"drd-cfg", "drd-bulk", "drd-ausbc"}; + static const struct { + const char *property; + int resource; /* -1 = globals in core, -2 = Apple vendor aperture */ + u32 offset, minimum; + } tables[] = { + {"apple,tunable-bulk-default", 1, 0, 0x24}, + {"apple,tunable-gbl-default", -1, 0, 0x68}, + {"apple,tunable-gbl-host", -1, 0, 0x588}, + {"apple,tunable-cio-default", -2, 0x20, 0x24}, + {"apple,tunable-debug-default", -2, 0xb00, 4}, + {"apple,tunable-cfg-host", 0, 0, 0x24}, + {"apple,tunable-link-default", -2, 0x300, 0x64}, + {"apple,tunable-ausbc-default", 2, 0, 0x10}, + }; + struct resource *resources[3], *vendor; + + for (unsigned int i = 0; i < ARRAY_SIZE(names); i++) { + resources[i] = platform_get_resource_byname(pdev, IORESOURCE_MEM, names[i]); + if (!resources[i]) + return -EINVAL; + appledwc->native_regs[i] = devm_ioremap_resource(&pdev->dev, resources[i]); + if (IS_ERR(appledwc->native_regs[i])) + return PTR_ERR(appledwc->native_regs[i]); + } + vendor = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dwc3-apple"); + if (!vendor) + return -EINVAL; + for (unsigned int i = 0; i < ARRAY_SIZE(tables); i++) { + struct resource res = tables[i].resource == -1 ? *appledwc->mmio_resource : + tables[i].resource == -2 ? *vendor : *resources[tables[i].resource]; + res.start += tables[i].offset; + if (tables[i].resource == -1) + res.start += DWC3_GLOBALS_REGS_START; + if (res.start > res.end || resource_size(&res) < tables[i].minimum) + return -EINVAL; + appledwc->native_tunables[i] = devm_apple_tunable_parse(&pdev->dev, + pdev->dev.of_node, tables[i].property, &res); + if (IS_ERR(appledwc->native_tunables[i])) + return dev_err_probe(&pdev->dev, PTR_ERR(appledwc->native_tunables[i]), + "invalid %s\n", tables[i].property); + } + return 0; } /* @@ -505,6 +584,8 @@ static int dwc3_apple_core_start(struct dwc3_apple *appledwc, enum dwc3_apple_st * Both PHYs were looked up at probe, so device mode is also selected on the first * bring-up, before dwc3_core_probe() has looked them up itself. */ + if (appledwc->t6050 && state != DWC3_APPLE_HOST) + return -EOPNOTSUPP; ret = dwc3_apple_usb2_mode_before_reset(state, &mode); if (ret) { /* Unreachable unless there's a bug in this driver */ @@ -607,7 +688,8 @@ static int dwc3_apple_set_role(struct dwc3_apple *appledwc, enum dwc3_apple_stat ret = phy_set_mode(appledwc->usb3_phy, host ? PHY_MODE_USB_HOST : PHY_MODE_USB_DEVICE); if (ret) { /* A failed T8132 BIST or PIPE handoff must not start xHCI. */ - if (of_device_is_compatible(appledwc->dev->of_node, "apple,t8132-dwc3")) + if (appledwc->t6050 || + of_device_is_compatible(appledwc->dev->of_node, "apple,t8132-dwc3")) return ret; dev_warn(appledwc->dev, "USB3 PHY setup failed, USB2 only, err=%d\n", ret); } else if (appledwc->usb3_phy && @@ -661,6 +743,15 @@ static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state st dev_err(appledwc->dev, "Failed to initialize host, ret=%d\n", ret); goto core_exit; } + /* The native T6050 USB2 reset belongs after host initialization. */ + if (appledwc->t6050) { + ret = phy_reset(appledwc->usb2_phy); + if (ret) { + dev_err(appledwc->dev, "Native USB2 PHY reset failed, ret=%d\n", ret); + dwc3_host_exit(&appledwc->dwc); + goto core_exit; + } + } break; case DWC3_APPLE_DEVICE: ret = dwc3_gadget_init(&appledwc->dwc); @@ -837,6 +928,7 @@ static int dwc3_apple_probe(struct platform_device *pdev) return -ENOMEM; appledwc->dev = &pdev->dev; + appledwc->t6050 = of_device_is_compatible(dev->of_node, "apple,t6050-dwc3"); appledwc->fixed_hub = dwc3_apple_has_fixed_hub(dev); appledwc->host_only = dwc3_apple_host_only(dev); /* Tested on T6040 only, where the PHY driver and the DARTs follow runtime PM. */ @@ -886,6 +978,11 @@ static int dwc3_apple_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(appledwc->apple_regs), "Failed to map Apple-specific MMIO\n"); + if (appledwc->t6050) { + ret = dwc3_apple_t6050_tunables(pdev, appledwc); + if (ret) + return ret; + } ret = dwc3_apple_parse_tunables(appledwc, pdev); if (ret) return ret; @@ -971,6 +1068,7 @@ static void dwc3_apple_shutdown(struct platform_device *pdev) static const struct of_device_id dwc3_apple_of_match[] = { { .compatible = "apple,t8132-dwc3" }, + { .compatible = "apple,t6050-dwc3" }, { .compatible = "apple,t8103-dwc3" }, {} };