From a3a3d7d32e11d1cb3a179fdfbe25a88403134da0 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:16:59 +0800 Subject: [PATCH 01/12] dt-bindings: clock: thead: add TH1520 MISC subsys clock controller TH1520 has a subsystem clock controller called MISC_SUBSYS in its manual, mainly controlling clocks for USB and MMC/SD in non-TEE environment. Add device tree binding for it. Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- .../devicetree/bindings/clock/thead,th1520-clk-ap.yaml | 5 +++-- include/dt-bindings/clock/thead,th1520-clk-ap.h | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml b/Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml index 9d058c00ab3d59..d46d13597466fe 100644 --- a/Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml +++ b/Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml @@ -23,6 +23,7 @@ properties: compatible: enum: - thead,th1520-clk-ap + - thead,th1520-clk-misc - thead,th1520-clk-vo reg: @@ -32,8 +33,8 @@ properties: items: - description: | One input clock: - - For "thead,th1520-clk-ap": the clock input must be the 24 MHz - main oscillator. + - For "thead,th1520-clk-ap" and "thead,th1520-clk-misc": the clock + input must be the 24 MHz main oscillator. - For "thead,th1520-clk-vo": the clock input must be the VIDEO_PLL, which is configured by the AP clock controller. According to the TH1520 manual, VIDEO_PLL is a Silicon Creations Sigma-Delta PLL diff --git a/include/dt-bindings/clock/thead,th1520-clk-ap.h b/include/dt-bindings/clock/thead,th1520-clk-ap.h index 68b35cc6120413..642c2a69a57971 100644 --- a/include/dt-bindings/clock/thead,th1520-clk-ap.h +++ b/include/dt-bindings/clock/thead,th1520-clk-ap.h @@ -128,4 +128,14 @@ #define CLK_MIPIDSI1_PIXCLK 29 #define CLK_HDMI_PIXCLK 30 +/* MISC clocks */ +#define CLK_MISCSYS_ACLK 0 +#define CLK_USB 1 +#define CLK_USB_CTL_REF 2 +#define CLK_USB_PHY_REF 3 +#define CLK_USB_SUSPEND 4 +#define CLK_EMMC 5 +#define CLK_SDIO0 6 +#define CLK_SDIO1 7 + #endif From 4fedad82f73f4f914640b2ab79cb7bd7b136f4bf Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:17:00 +0800 Subject: [PATCH 02/12] clk: thead: th1520-ap: add support for MISC subsys clocks The TH1520 SoC contains a MISC_SUBSYS clock controller, which allows controlling of USB related clocks and MMC/SD controller AHB bus clocks. Add support for this clock controller, in order to enable USB support. Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- drivers/clk/thead/clk-th1520-ap.c | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index 3a6847f1c950fc..24f785f0b329a7 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -1266,6 +1266,41 @@ static CCU_GATE(CLK_MIPIDSI1_PIXCLK, mipi_dsi1_pixclk, "mipi-dsi1-pixclk", static CCU_GATE(CLK_HDMI_PIXCLK, hdmi_pixclk, "hdmi-pixclk", video_pll_clk_pd, 0x4, 0, 0); +static struct clk_fixed_factor usb_suspend_div_clk = { + .div = 24, + .mult = 1, + .hw.init = CLK_HW_INIT_PARENTS_DATA("usb-suspend-div", + osc_24m_clk, + &clk_fixed_factor_ops, + 0), +}; + +static const struct clk_parent_data usb_suspend_parents[] = { + { .hw = &usb_suspend_div_clk.hw }, +}; + +static CCU_GATE(CLK_MISCSYS_ACLK, miscsys_aclk, "miscsys-aclk", axi_aclk_pd, + 0x0, 0, CLK_IS_CRITICAL); + +static const struct clk_parent_data miscsys_aclk_pd[] = { + { .hw = &miscsys_aclk.gate.hw }, +}; + +static CCU_GATE(CLK_USB, usb_clk, "usb", miscsys_aclk_pd, 0x4, 0, + CLK_IS_CRITICAL); +static CCU_GATE(CLK_USB_CTL_REF, usb_ctl_ref_clk, "usb-ctl-ref", osc_24m_clk, + 0x4, 1, 0); +static CCU_GATE(CLK_USB_PHY_REF, usb_phy_ref_clk, "usb-phy-ref", osc_24m_clk, + 0x4, 2, 0); +static CCU_GATE(CLK_USB_SUSPEND, usb_suspend_clk, "usb-suspend", + usb_suspend_parents, 0x4, 3, 0); +static CCU_GATE(CLK_EMMC, emmc_clk, "emmc", perisys_ahb_hclk_pd, 0x8, 0, + 0); +static CCU_GATE(CLK_SDIO0, sdio0_clk, "sdio0", perisys_ahb_hclk_pd, 0xc, 0, + 0); +static CCU_GATE(CLK_SDIO1, sdio1_clk, "sdio1", perisys_ahb_hclk_pd, 0x10, 0, + 0); + static CLK_FIXED_FACTOR_HW(gmac_pll_clk_100m, "gmac-pll-clk-100m", &gmac_pll_clk.common.hw, 10, 1, 0); @@ -1410,6 +1445,17 @@ static struct ccu_gate *th1520_vo_gate_clks[] = { &hdmi_pixclk }; +static struct ccu_gate *th1520_misc_gate_clks[] = { + &miscsys_aclk, + &usb_clk, + &usb_ctl_ref_clk, + &usb_phy_ref_clk, + &usb_suspend_clk, + &emmc_clk, + &sdio0_clk, + &sdio1_clk +}; + static const struct regmap_config th1520_clk_regmap_config = { .reg_bits = 32, .val_bits = 32, @@ -1451,6 +1497,14 @@ static const struct th1520_plat_data th1520_vo_platdata = { .nr_gate_clks = ARRAY_SIZE(th1520_vo_gate_clks), }; +static const struct th1520_plat_data th1520_misc_platdata = { + .th1520_gate_clks = th1520_misc_gate_clks, + + .nr_clks = CLK_SDIO1 + 1, + + .nr_gate_clks = ARRAY_SIZE(th1520_misc_gate_clks), +}; + /* * Maintain clock rate of c910_bus_clk below TH1520_C910_BUS_MAX_RATE (750MHz) * when its parent, c910_clk, changes the rate. @@ -1609,6 +1663,12 @@ static int th1520_clk_probe(struct platform_device *pdev) return ret; } + if (plat_data == &th1520_ap_platdata) { + ret = devm_clk_hw_register(dev, &usb_suspend_div_clk.hw); + if (ret) + return ret; + } + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, priv); if (ret) return ret; @@ -1625,6 +1685,10 @@ static const struct of_device_id th1520_clk_match[] = { .compatible = "thead,th1520-clk-vo", .data = &th1520_vo_platdata, }, + { + .compatible = "thead,th1520-clk-misc", + .data = &th1520_misc_platdata, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, th1520_clk_match); From 69806b8d36b2ff24cefc769001074591a2f7d64e Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:17:01 +0800 Subject: [PATCH 03/12] riscv: dts: thead: add device tree node for MISC clock controller The MISC_SUBSYS clock controller on TH1520 SoC is a clock controller mainly controlling USB-related clocks (which isn't utilized yet) and MMC/SD controllers' AHB bus clocks. Add the device tree node for it along with the missing bus clock references for MMC/SD controllers. Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- arch/riscv/boot/dts/thead/th1520.dtsi | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 5e91dc1d2b9b7e..c9930e63bbe93f 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -366,8 +366,8 @@ compatible = "thead,th1520-dwcmshc"; reg = <0xff 0xe7080000 0x0 0x10000>; interrupts = <62 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clk CLK_EMMC_SDIO>; - clock-names = "core"; + clocks = <&clk CLK_EMMC_SDIO>, <&clk_misc CLK_EMMC>; + clock-names = "core", "bus"; status = "disabled"; }; @@ -375,8 +375,8 @@ compatible = "thead,th1520-dwcmshc"; reg = <0xff 0xe7090000 0x0 0x10000>; interrupts = <64 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clk CLK_EMMC_SDIO>; - clock-names = "core"; + clocks = <&clk CLK_EMMC_SDIO>, <&clk_misc CLK_SDIO0>; + clock-names = "core", "bus"; status = "disabled"; }; @@ -384,8 +384,8 @@ compatible = "thead,th1520-dwcmshc"; reg = <0xff 0xe70a0000 0x0 0x10000>; interrupts = <71 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clk CLK_EMMC_SDIO>; - clock-names = "core"; + clocks = <&clk CLK_EMMC_SDIO>, <&clk_misc CLK_SDIO1>; + clock-names = "core", "bus"; status = "disabled"; }; @@ -533,6 +533,13 @@ #reset-cells = <1>; }; + clk_misc: clock-controller@ffec02c100 { + compatible = "thead,th1520-clk-misc"; + reg = <0xff 0xec02c100 0x0 0x100>; + clocks = <&osc>; + #clock-cells = <1>; + }; + rst_vp: reset-controller@ffecc30000 { compatible = "thead,th1520-reset-vp"; reg = <0xff 0xecc30000 0x0 0x14>; From 3736f6e263d82b7ddbce2eb5af0bc0b28661af2f Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:17:02 +0800 Subject: [PATCH 04/12] dt-bindings: phy: add binding for T-Head TH1520 USB PHY The TH1520 SoC features a Synopsys USB 3.0 FemtoPHY with some custom glue logic configuring PHY parameters. Add a binding for it. Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- .../bindings/phy/thead,th1520-usb-phy.yaml | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/thead,th1520-usb-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/thead,th1520-usb-phy.yaml b/Documentation/devicetree/bindings/phy/thead,th1520-usb-phy.yaml new file mode 100644 index 00000000000000..37f5cfb95bad01 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/thead,th1520-usb-phy.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/thead,th1520-usb-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-Head TH1520 USB PHY + +description: | + The T-HEAD TH1520 USB PHY is a Synopsys USB 3.0 FemtoPHY glued with some + custom logic to configure PHY parameters. + +maintainers: + - Icenowy Zheng + - Wei Fu + - Drew Fustini + +properties: + compatible: + const: thead,th1520-usb-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + clocks: + items: + - description: PHY bus clock + - description: PHY reference clock + + clock-names: + items: + - const: bus + - const: ref + + resets: + items: + - description: PHY bus reset + - description: PHY reset + + reset-names: + items: + - const: bus + - const: phy + + avdd33-usb3-supply: + description: | + 3.3V power supply for the PHY, named AVDD33_USB3 in the SoC pin list. + +required: + - compatible + - "#phy-cells" + - clocks + - clock-names + - resets + - reset-names + - avdd33-usb3-supply + +additionalProperties: false + +examples: + - | + phy@ec030000 { + compatible = "thead,th1520-usb-phy"; + reg = <0xec030000 0x10000>; + #phy-cells = <0>; + clocks = <&clk_misc 1>, <&clk_misc 3>; + clock-names = "bus", "ref"; + resets = <&rst_misc 6>, <&rst_misc 7>; + reset-names = "bus", "phy"; + avdd33-usb3-supply = <&avdd33_usb3>; + }; From 2031076c11102e4e15941f08bbe4002ba3b2049c Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:17:03 +0800 Subject: [PATCH 05/12] phy: add a driver for T-Head TH1520 USB PHY The USB PHY on T-Head TH1520 SoC is a Synopsys USB 3.0 FemtoPHY, with some PHY parameters exported as another system controller along with it. As a few PHY parameters' default value isn't ready to work, add a driver configuring them before letting the PHY run, in addition to clock/reset/regulator management. Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 1 + drivers/phy/thead/Kconfig | 12 ++ drivers/phy/thead/Makefile | 2 + drivers/phy/thead/phy-th1520-usb.c | 197 +++++++++++++++++++++++++++++ 5 files changed, 213 insertions(+) create mode 100644 drivers/phy/thead/Kconfig create mode 100644 drivers/phy/thead/Makefile create mode 100644 drivers/phy/thead/phy-th1520-usb.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 227b9a4c612e8c..ea1a52e14b8397 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -164,6 +164,7 @@ source "drivers/phy/st/Kconfig" source "drivers/phy/starfive/Kconfig" source "drivers/phy/sunplus/Kconfig" source "drivers/phy/tegra/Kconfig" +source "drivers/phy/thead/Kconfig" source "drivers/phy/ti/Kconfig" source "drivers/phy/xilinx/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f49d83f00a3d87..4604522548c913 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -48,5 +48,6 @@ obj-$(CONFIG_GENERIC_PHY) += allwinner/ \ starfive/ \ sunplus/ \ tegra/ \ + thead/ \ ti/ \ xilinx/ diff --git a/drivers/phy/thead/Kconfig b/drivers/phy/thead/Kconfig new file mode 100644 index 00000000000000..14012db5973c4b --- /dev/null +++ b/drivers/phy/thead/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +config PHY_TH1520_USB + tristate "USB PHY driver for T-Head TH1520 SoC" + depends on ARCH_THEAD || COMPILE_TEST + depends on COMMON_CLK + depends on HAS_IOMEM + depends on OF + depends on RESET_CONTROLLER + select GENERIC_PHY + default ARCH_THEAD + help + Enable support for the USB PHY on the T-Head TH1520 SoC. diff --git a/drivers/phy/thead/Makefile b/drivers/phy/thead/Makefile new file mode 100644 index 00000000000000..5b459bc7004bda --- /dev/null +++ b/drivers/phy/thead/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_PHY_TH1520_USB) += phy-th1520-usb.o diff --git a/drivers/phy/thead/phy-th1520-usb.c b/drivers/phy/thead/phy-th1520-usb.c new file mode 100644 index 00000000000000..c87bd779bbb74b --- /dev/null +++ b/drivers/phy/thead/phy-th1520-usb.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Institute of Software, Chinese Academy of Sciences (ISCAS) + * + * Authors: + * Icenowy Zheng + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define USB_SYSCON_OFFSET 0xf000 + +/* All the below registers are in the USB syscon region */ +#define USB_CLK_GATE_STS 0x0 +#define USB_LOGIC_ANALYZER_TRACE_STS0 0x4 +#define USB_LOGIC_ANALYZER_TRACE_STS1 0x8 +#define USB_GPIO 0xc +#define USB_DEBUG_STS0 0x10 +#define USB_DEBUG_STS1 0x14 +#define USB_DEBUG_STS2 0x18 +#define USBCTL_CLK_CTRL0 0x1c +#define USBPHY_CLK_CTRL1 0x20 +#define USBPHY_TEST_CTRL0 0x24 +#define USBPHY_TEST_CTRL1 0x28 +#define USBPHY_TEST_CTRL2 0x2c +#define USBPHY_TEST_CTRL3 0x30 +#define USB_SSP_EN 0x34 +#define USB_HADDR_SEL 0x38 +#define USB_SYS 0x3c +#define USB_HOST_STATUS 0x40 +#define USB_HOST_CTRL 0x44 +#define USBPHY_HOST_CTRL 0x48 +#define USBPHY_HOST_STATUS 0x4c +#define USB_TEST_REG0 0x50 +#define USB_TEST_REG1 0x54 +#define USB_TEST_REG2 0x58 +#define USB_TEST_REG3 0x5c + +#define USB_SYS_COMMONONN BIT(0) + +#define USB_SSP_EN_REF_SSP_EN BIT(0) + +struct th1520_usb_phy { + struct platform_device *pdev; + struct phy *phy; + struct regmap *regmap; + struct clk *ref_clk; + struct reset_control *phy_reset; +}; + +static int th1520_usb_phy_init(struct phy *phy) +{ + struct th1520_usb_phy *th1520_phy = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare_enable(th1520_phy->ref_clk); + if (ret) + return ret; + + ret = reset_control_assert(th1520_phy->phy_reset); + if (ret) + goto err_disable_clk; + + /* + * Do some initial PHY setup: + * - Set COMMONONN to allow the PHY to automatically power down. + * - Set REF_SSP_EN to enable feeding reference clock to SuperSpeed + * PHY clock PLL. + */ + regmap_set_bits(th1520_phy->regmap, USB_SYS, USB_SYS_COMMONONN); + regmap_set_bits(th1520_phy->regmap, USB_SSP_EN, USB_SSP_EN_REF_SSP_EN); + + ret = reset_control_deassert(th1520_phy->phy_reset); + if (ret) + goto err_disable_clk; + + udelay(10); + + return 0; + +err_disable_clk: + clk_disable_unprepare(th1520_phy->ref_clk); + return ret; +} + +static int th1520_usb_phy_exit(struct phy *phy) +{ + struct th1520_usb_phy *th1520_phy = phy_get_drvdata(phy); + int ret; + + ret = reset_control_assert(th1520_phy->phy_reset); + if (ret) + return ret; + + clk_disable_unprepare(th1520_phy->ref_clk); + + return 0; +} + +static const struct phy_ops th1520_usb_phy_ops = { + .init = th1520_usb_phy_init, + .exit = th1520_usb_phy_exit, + .owner = THIS_MODULE, +}; + +static const struct regmap_config phy_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = USB_TEST_REG3, +}; + +static int th1520_usb_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct th1520_usb_phy *th1520_phy; + struct reset_control *bus_reset; + void __iomem *base; + int ret; + + th1520_phy = devm_kzalloc(dev, sizeof(*th1520_phy), GFP_KERNEL); + if (!th1520_phy) + return -ENOMEM; + + th1520_phy->pdev = pdev; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + th1520_phy->ref_clk = devm_clk_get(dev, "ref"); + if (IS_ERR(th1520_phy->ref_clk)) + return PTR_ERR(th1520_phy->ref_clk); + + /* De-assert the bus reset and leave it that way */ + bus_reset = devm_reset_control_get_exclusive_deasserted(dev, "bus"); + if (IS_ERR(bus_reset)) + return PTR_ERR(bus_reset); + + th1520_phy->phy_reset = devm_reset_control_get_exclusive(dev, "phy"); + if (IS_ERR(th1520_phy->phy_reset)) + return PTR_ERR(th1520_phy->phy_reset); + + /* + * Schematics of several boards (Lichee Module 4A/Milk-V Meles) + * describe this power rail as always-on. + */ + ret = devm_regulator_get_enable(dev, "avdd33-usb3"); + if (ret) + return ret; + + th1520_phy->regmap = devm_regmap_init_mmio_clk(dev, "bus", + base + USB_SYSCON_OFFSET, + &phy_regmap_config); + if (IS_ERR(th1520_phy->regmap)) + return dev_err_probe(dev, PTR_ERR(th1520_phy->regmap), + "Failed to init regmap\n"); + + th1520_phy->phy = devm_phy_create(dev, dev->of_node, &th1520_usb_phy_ops); + if (IS_ERR(th1520_phy->phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(th1520_phy->phy); + } + + phy_set_drvdata(th1520_phy->phy, th1520_phy); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id th1520_usb_phy_of_table[] = { + { .compatible = "thead,th1520-usb-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, th1520_usb_phy_of_table); + +static struct platform_driver th1520_usb_phy_driver = { + .driver = { + .name = "th1520-usb-phy", + .of_match_table = th1520_usb_phy_of_table, + }, + .probe = th1520_usb_phy_probe, +}; + +module_platform_driver(th1520_usb_phy_driver); + +MODULE_DESCRIPTION("T-Head TH1520 USB PHY driver"); +MODULE_LICENSE("GPL"); From 3092344fc93d8e80465983c6f2d63aba5668ec68 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:17:04 +0800 Subject: [PATCH 06/12] riscv: dts: thead: add device nodes for USB The TH1520 SoC contains a Synopsys DesignWare Cores SuperSpeed USB3.0 Dual Role Device controller in addition to a USB2+USB3 combo PHY based on Synopsys USB3.0 FemtoPHY. Add device tree nodes for them. The USB controller is quite generic, new and properly configured during silicon design, but the PHY is a little quirky. Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- arch/riscv/boot/dts/thead/th1520.dtsi | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index c9930e63bbe93f..a6a3e114d0d2fd 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -316,6 +316,20 @@ status = "disabled"; }; + usb: usb@ffe7040000 { + compatible = "snps,dwc3"; + reg = <0xff 0xe7040000 0x0 0x10000>; + interrupts = <68 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_misc CLK_USB>, + <&clk_misc CLK_USB_CTL_REF>, + <&clk_misc CLK_USB_SUSPEND>; + clock-names = "bus_early", "ref", "suspend"; + resets = <&rst_misc TH1520_RESET_ID_USB3_VCC>; + phys = <&usb_phy>; + phy-names = "usb3-phy"; + status = "disabled"; + }; + gmac1: ethernet@ffe7060000 { compatible = "thead,th1520-gmac", "snps,dwmac-3.70a"; reg = <0xff 0xe7060000 0x0 0x2000>, <0xff 0xec004000 0x0 0x1000>; @@ -540,6 +554,19 @@ #clock-cells = <1>; }; + usb_phy: phy@ffec030000 { + compatible = "thead,th1520-usb-phy"; + reg = <0xff 0xec030000 0x0 0x10000>; + clocks = <&clk_misc CLK_USB>, + <&clk_misc CLK_USB_PHY_REF>; + clock-names = "bus", "ref"; + resets = <&rst_misc TH1520_RESET_ID_USB3_APB>, + <&rst_misc TH1520_RESET_ID_USB3_PHY>; + reset-names = "bus", "phy"; + #phy-cells = <0>; + status = "disabled"; + }; + rst_vp: reset-controller@ffecc30000 { compatible = "thead,th1520-reset-vp"; reg = <0xff 0xecc30000 0x0 0x14>; From 6329c09c02e0e8342be23384ec59ad2870a59635 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:17:05 +0800 Subject: [PATCH 07/12] dt-bindings: gpio: dwapb: allow GPIO hogs GPIO hogs are described in the gpio.txt binding as automatic default GPIO configuration items. Allow them for GPIO ports in DesignWare APB GPIO controller nodes. Cc: Hoan Tran Cc: Linus Walleij Cc: Bartosz Golaszewski Cc: Serge Semin Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- .../devicetree/bindings/gpio/snps,dw-apb-gpio.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml index bba6f5b6606fdf..55069533f6d912 100644 --- a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml @@ -95,6 +95,12 @@ patternProperties: '#interrupt-cells': const: 2 + patternProperties: + "^.+-hog(-[0-9]+)?$": + type: object + required: + - gpio-hog + required: - compatible - reg From 9e009b8143fa55d7b9657c301ab876e77596c756 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:17:06 +0800 Subject: [PATCH 08/12] dt-bindings: usb: vialab,vl817: allow ports property As a USB hub device, VL817 can surely be connected to external USB connectors. The binding for such connectors connection is already described in the generic usb-hub.yaml binding with ports subnode, but it's not yet allowed in the VL817 binding. Switch the reference binding from usb-device.yaml to usb-hub.yaml (which recursively references usb-device.yaml and contains definition for ports subnode) and allow ports subnode in VL817 binding. Cc: Anand Moon Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- Documentation/devicetree/bindings/usb/vialab,vl817.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/vialab,vl817.yaml b/Documentation/devicetree/bindings/usb/vialab,vl817.yaml index c815010ba9c2e8..7387f4fae54d1e 100644 --- a/Documentation/devicetree/bindings/usb/vialab,vl817.yaml +++ b/Documentation/devicetree/bindings/usb/vialab,vl817.yaml @@ -10,7 +10,7 @@ maintainers: - Anand Moon allOf: - - $ref: usb-device.yaml# + - $ref: usb-hub.yaml# properties: compatible: @@ -34,6 +34,8 @@ properties: description: phandle to the peer hub on the controller. + ports: true + required: - compatible - reg From 62dcde38f73a30863b5dcc02b5f436c8ce6b9eba Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:17:07 +0800 Subject: [PATCH 09/12] riscv: dts: thead: lpi4a: sort nodes Although "D" and "H" are earlier in the alphabet than "P", the DPU and HDMI nodes were added after PADCTRL node in the Lichee Pi 4A device tree. Sort the nodes in this device tree. Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 7cb7d28683bce7..4198dbf953f06b 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -96,6 +96,20 @@ }; +&dpu { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&hdmi_out_port { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + &padctrl0_apsys { fan_pins: fan-0 { pwm1-pins { @@ -132,20 +146,6 @@ }; }; -&dpu { - status = "okay"; -}; - -&hdmi { - status = "okay"; -}; - -&hdmi_out_port { - hdmi_out_con: endpoint { - remote-endpoint = <&hdmi_con_in>; - }; -}; - &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins>; From 0101fae02c3a851352b46f87446c9bc7a3eb416c Mon Sep 17 00:00:00 2001 From: Thomas Bonnefille Date: Thu, 7 May 2026 16:17:08 +0800 Subject: [PATCH 10/12] riscv: dts: thead: Add TH1520 I2C nodes Add nodes for the six I2C on the T-Head TH1520 RISCV SoC. Signed-off-by: Thomas Bonnefille Reviewed-by: Drew Fustini [Icenowy: rebase on top of v7.1-rc2] Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- arch/riscv/boot/dts/thead/th1520.dtsi | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index a6a3e114d0d2fd..df49f8f749ef78 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -425,6 +425,36 @@ status = "disabled"; }; + i2c0: i2c@ffe7f20000 { + compatible = "thead,th1520-i2c", "snps,designware-i2c"; + reg = <0xff 0xe7f20000 0x0 0x4000>; + interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_I2C0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@ffe7f24000 { + compatible = "thead,th1520-i2c", "snps,designware-i2c"; + reg = <0xff 0xe7f24000 0x0 0x4000>; + interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_I2C1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@ffe7f28000 { + compatible = "thead,th1520-i2c", "snps,designware-i2c"; + reg = <0xff 0xe7f28000 0x0 0x4000>; + interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_I2C4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + gpio@ffe7f34000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xe7f34000 0x0 0x1000>; @@ -523,6 +553,16 @@ thead,pad-group = <3>; }; + i2c2: i2c@ffec00c000 { + compatible = "thead,th1520-i2c", "snps,designware-i2c"; + reg = <0xff 0xec00c000 0x0 0x4000>; + interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_I2C2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + uart2: serial@ffec010000 { compatible = "snps,dw-apb-uart"; reg = <0xff 0xec010000 0x0 0x4000>; @@ -534,6 +574,16 @@ status = "disabled"; }; + i2c3: i2c@ffec014000 { + compatible = "thead,th1520-i2c", "snps,designware-i2c"; + reg = <0xff 0xec014000 0x0 0x4000>; + interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_I2C3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pwm: pwm@ffec01c000 { compatible = "thead,th1520-pwm"; reg = <0xff 0xec01c000 0x0 0x4000>; @@ -759,6 +809,16 @@ status = "disabled"; }; + i2c5: i2c@fff7f2c000 { + compatible = "thead,th1520-i2c", "snps,designware-i2c"; + reg = <0xff 0xf7f2c000 0x0 0x4000>; + interrupts = <49 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_I2C5>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + timer4: timer@ffffc33000 { compatible = "snps,dw-apb-timer"; reg = <0xff 0xffc33000 0x0 0x14>; From e702a7f480ba42ab12051e847c47b7ad84c38684 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Thu, 7 May 2026 16:17:09 +0800 Subject: [PATCH 11/12] riscv: dts: thead: Add Lichee Pi 4A IO expansions Lichee Pi 4A has 3 I2C IO expansion chips onboard, connected to the I2C0/1/3 busses. Add device tree nodes for them. Signed-off-by: Emil Renner Berthing [Icenowy: added commit description] Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 4198dbf953f06b..354f3893aa8cf2 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -16,6 +16,9 @@ gpio3 = &gpio3; gpio4 = &gpio4; gpio5 = &aogpio; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c3 = &i2c3; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -110,6 +113,76 @@ }; }; +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + status = "okay"; + + ioexp1: gpio@18 { + compatible = "nxp,pca9557"; + reg = <0x18>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "cam0_dvdd12", + "cam0_avdd28", + "cam0_dovdd18"; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + status = "okay"; + + ioexp2: gpio@18 { + compatible = "nxp,pca9557"; + reg = <0x18>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "", + "cam0_reset", + "cam1_reset", + "cam2_reset", + "wl_host_wake", + "bt_resetn", + "", + "bt_host_wake"; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_pins>; + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + status = "okay"; + + ioexp3: gpio@18 { + compatible = "nxp,pca9557"; + reg = <0x18>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "tp0_rst", + "", + "", + "vcc5v_usb", + "vdd28_tp0", + "vdd33_lcd0", + "vdd18_lcd0", + "lcd0_reset"; + }; +}; + &padctrl0_apsys { fan_pins: fan-0 { pwm1-pins { @@ -123,6 +196,18 @@ }; }; + i2c3_pins: i2c3-0 { + i2c-pins { + pins = "I2C3_SCL", "I2C3_SDA"; + function = "i2c"; + bias-disable; /* external pull-up */ + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart0_pins: uart0-0 { tx-pins { pins = "UART0_TXD"; @@ -146,6 +231,32 @@ }; }; +&padctrl1_apsys { + i2c0_pins: i2c0-0 { + i2c-pins { + pins = "I2C0_SCL", "I2C0_SDA"; + function = "i2c"; + bias-disable; /* external pull-up */ + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + + i2c1_pins: i2c1-0 { + i2c-pins { + pins = "I2C1_SCL", "I2C1_SDA"; + function = "i2c"; + bias-disable; /* external pull-up */ + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins>; From 89a7de516fe05be177977474d015138aeae84f4c Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 7 May 2026 16:17:10 +0800 Subject: [PATCH 12/12] riscv: dts: thead: enable USB3 ports on Lichee Pi 4A The Lichee Pi 4A board features an onboard VIA VL817 hub connected to the SoC's USB3 as upstream and 4 USB-3.0-capable Type-A ports as downstream. Enable SoC USB3 and the hub on Lichee Pi 4A. Signed-off-by: Icenowy Zheng Signed-off-by: Linux RISC-V bot --- .../dts/thead/th1520-lichee-module-4a.dtsi | 15 ++ .../boot/dts/thead/th1520-lichee-pi-4a.dts | 231 ++++++++++++++++++ 2 files changed, 246 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi index 8e76b63e0100aa..bfda5a6b56b8f8 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi @@ -20,6 +20,16 @@ device_type = "memory"; reg = <0x0 0x00000000 0x2 0x00000000>; }; + + /* TODO: Switch to AON regulator when it's available. */ + avdd33_usb3: regulator-avdd33-usb3 { + compatible = "regulator-fixed"; + regulator-name = "AVDD33_USB3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + /* Marked as always on on the schematics */ + regulator-always-on; + }; }; &osc { @@ -202,3 +212,8 @@ max-frequency = <198000000>; status = "okay"; }; + +&usb_phy { + avdd33-usb3-supply = <&avdd33_usb3>; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 354f3893aa8cf2..de38f1f457e6ba 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -4,6 +4,7 @@ */ #include "th1520-lichee-module-4a.dtsi" +#include / { model = "Sipeed Lichee Pi 4A"; @@ -97,6 +98,141 @@ cooling-levels = <0 66 196 255>; }; + hub_5v: regulator-hub-5v { + compatible = "regulator-fixed"; + regulator-name = "HUB_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&ioexp3 3 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vcc5v_usb: regulator-vcc5v-usb { + compatible = "regulator-fixed"; + regulator-name = "VCC5V_USB"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; + enable-active-high; + /* + * Workaround for Linux currently being not able to power on + * Vbus for USB Type-A connectors. + */ + regulator-always-on; + }; + + connector-usb-a-1 { + compatible = "usb-a-connector"; + vbus-supply = <&vcc5v_usb>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_a_1_hs_ep: endpoint { + remote-endpoint = <&hub_hs_port1_ep>; + }; + }; + + port@1 { + reg = <1>; + + usb_a_1_ss_ep: endpoint { + remote-endpoint = <&hub_ss_port1_ep>; + }; + }; + }; + }; + + connector-usb-a-2 { + compatible = "usb-a-connector"; + vbus-supply = <&vcc5v_usb>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_a_2_hs_ep: endpoint { + remote-endpoint = <&hub_hs_port2_ep>; + }; + }; + + port@1 { + reg = <1>; + + usb_a_2_ss_ep: endpoint { + remote-endpoint = <&hub_ss_port2_ep>; + }; + }; + }; + }; + + connector-usb-a-3 { + compatible = "usb-a-connector"; + vbus-supply = <&vcc5v_usb>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_a_3_hs_ep: endpoint { + remote-endpoint = <&hub_hs_port3_ep>; + }; + }; + + port@1 { + reg = <1>; + + usb_a_3_ss_ep: endpoint { + remote-endpoint = <&hub_ss_port3_ep>; + }; + }; + }; + }; + + connector-usb-a-4 { + compatible = "usb-a-connector"; + vbus-supply = <&vcc5v_usb>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_a_4_hs_ep: endpoint { + remote-endpoint = <&hub_hs_port4_ep>; + }; + }; + + port@1 { + reg = <1>; + + usb_a_4_ss_ep: endpoint { + remote-endpoint = <&hub_ss_port4_ep>; + }; + }; + }; + }; +}; + +&aogpio { + /* Route USB2 to the onboard hub for normal operation */ + sel-usb-hub-hog { + gpio-hog; + gpios = <4 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &dpu { @@ -262,3 +398,98 @@ pinctrl-0 = <&uart0_pins>; status = "okay"; }; + +&usb { + dr_mode = "host"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + hub_hs: hub@1 { + compatible = "usb2109,2817"; + reg = <1>; + peer-hub = <&hub_ss>; + vdd-supply = <&hub_5v>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + hub_hs_port1_ep: endpoint { + remote-endpoint = <&usb_a_1_hs_ep>; + }; + }; + + port@2 { + reg = <2>; + + hub_hs_port2_ep: endpoint { + remote-endpoint = <&usb_a_2_hs_ep>; + }; + }; + + port@3 { + reg = <3>; + + hub_hs_port3_ep: endpoint { + remote-endpoint = <&usb_a_3_hs_ep>; + }; + }; + + port@4 { + reg = <4>; + + hub_hs_port4_ep: endpoint { + remote-endpoint = <&usb_a_4_hs_ep>; + }; + }; + }; + }; + + hub_ss: hub@2 { + compatible = "usb2109,817"; + reg = <2>; + peer-hub = <&hub_hs>; + vdd-supply = <&hub_5v>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + hub_ss_port1_ep: endpoint { + remote-endpoint = <&usb_a_1_ss_ep>; + }; + }; + + port@2 { + reg = <2>; + + hub_ss_port2_ep: endpoint { + remote-endpoint = <&usb_a_2_ss_ep>; + }; + }; + + port@3 { + reg = <3>; + + hub_ss_port3_ep: endpoint { + remote-endpoint = <&usb_a_3_ss_ep>; + }; + }; + + port@4 { + reg = <4>; + + hub_ss_port4_ep: endpoint { + remote-endpoint = <&usb_a_4_ss_ep>; + }; + }; + }; + }; +};