* [PATCH 0/2] usb: add K1 USB2 PHY and generic DWC3 support
@ 2026-10-06 4:28 Dave Klotz
2026-10-06 4:28 ` [PATCH 1/2] phy: spacemit: add K1 USB 2.0 PHY driver Dave Klotz
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Dave Klotz @ 2026-10-06 4:28 UTC (permalink / raw)
To: Yixun Lan, Marek Vasut; +Cc: u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
This series adds USB host support for the SpacemiT K1: a driver for
the K1's USB 2.0 (UTMI) PHY, and a flat-node entry for the SoC's DWC3
controller in dwc3-generic, which already handles clocks, resets, PHYs
and the host child for other flat-node SoCs. No K1-specific glue is
needed. USB 3 additionally needs the posted combo PHY series [1].
The patches apply to next at bd2f5794 and to current next (ed869863).
dwc3-generic.c is not touched by the pending DWC3 resync [2], so they
apply there too; the test builds below carried that resync (v9).
Tested on the OrangePi R2S and RV2 on October 5 with next bd2f5794, the
posted K1 clock, MMC, PHY, PCIe and SPL fixes, the DWC3 resync v9 and
these two patches (plus local hub-scan logging and an xHCI stop-path
change that are under separate review and do not change enumeration):
- R2S: a USB 3.0 stick on the root port enumerates at 5 Gb/s. Each
check is two 64 MiB raw reads into differently prefilled buffers,
byte compare and SHA-256 against a FAT copy of the same data; the
initial three pairs, then one pair after each of three 'usb reset'
and after 'usb stop' / 'usb start', all passed at 5 Gb/s with no
host-halt warning.
- RV2: the same stick behind a Genesys USB 3 hub; same checks, same
results. In an earlier run the stick once failed to re-enumerate
after the second and third 'usb reset'; that did not reproduce with
hub scan logging enabled and is being looked at in the generic hub
scan separately. It is not specific to these two patches.
- On both boards the FreeBSD EFI loader read from the stick selects its
own partition unaided and boots the kernel on the stick with the
board's native root (eMMC on R2S, NVMe on RV2).
Sandbox builds and the existing DWC3 flat-node users are unaffected.
[1] https://lists.u-boot-project.org/pipermail/u-boot/2026-October/633775.html
[2] https://lists.u-boot-project.org/pipermail/u-boot/2026-October/633722.html
Dave Klotz (2):
phy: spacemit: add K1 USB 2.0 PHY driver
usb: dwc3: generic: add SpacemiT K1 support
MAINTAINERS | 1 +
drivers/phy/spacemit/Kconfig | 9 ++
drivers/phy/spacemit/Makefile | 1 +
drivers/phy/spacemit/phy-k1-usb2.c | 173 +++++++++++++++++++++++++++++
drivers/usb/dwc3/dwc3-generic.c | 13 +--
5 files changed, 191 insertions(+), 6 deletions(-)
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/2] phy: spacemit: add K1 USB 2.0 PHY driver
2026-10-06 4:28 [PATCH 0/2] usb: add K1 USB2 PHY and generic DWC3 support Dave Klotz
@ 2026-10-06 4:28 ` Dave Klotz
2026-10-06 4:28 ` [PATCH 2/2] usb: dwc3: generic: add SpacemiT K1 support Dave Klotz
2026-10-06 12:31 ` [PATCH v2 0/2] usb: add K1 USB2 PHY and generic DWC3 support Dave Klotz
2 siblings, 0 replies; 12+ messages in thread
From: Dave Klotz @ 2026-10-06 4:28 UTC (permalink / raw)
To: Yixun Lan, Marek Vasut; +Cc: u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
The UTMI PHY at c0a30000 ("spacemit,k1-usb2-phy") feeds the K1's DWC3
USB 3 controller. Port the Linux driver: enable the PHY clock, program
the PLL divider for the 24 MHz reference, wait for the PLL, then release
the PHY's resets and enable its clocks, the HS TX clock and the
automatic host-disconnect clear.
The divider has to be written before the PLL is polled. On the OrangePi
R2S under FreeBSD, a driver that polled first and never wrote it left
the PLL stopped: the clock enables did not latch (0x60ef read back as
0x60e9), the PHY gave the controller no UTMI clock and the xHCI reset
(USBCMD.HCRST) never completed. Warn if the enables do not latch.
Also apply the vendor's HS DAC current setting (+15 %), which the
FreeBSD driver that runs the R2S port does.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
---
MAINTAINERS | 1 +
drivers/phy/spacemit/Kconfig | 9 ++
drivers/phy/spacemit/Makefile | 1 +
drivers/phy/spacemit/phy-k1-usb2.c | 173 +++++++++++++++++++++++++++++
4 files changed, 184 insertions(+)
create mode 100644 drivers/phy/spacemit/phy-k1-usb2.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 9e09f9506c..0af42acfbc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1517,6 +1517,7 @@ M: Yixun Lan <dlan@kernel.org>
S: Maintained
T: git https://git.u-boot-project.org/u-boot/custodians/u-boot-spacemit.git
F: arch/riscv/dts/k1-*-u-boot.dtsi
+F: drivers/phy/spacemit/phy-k1-usb2.c
N: spacemit
K: spacemit
diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig
index 3c47601c1f..7146965d92 100644
--- a/drivers/phy/spacemit/Kconfig
+++ b/drivers/phy/spacemit/Kconfig
@@ -9,3 +9,12 @@ config PHY_SPACEMIT_K1_PCIE
ports B and C. The combo PHY must be enabled even if port A
is not used for PCIe, because it provides calibration values
required by the other ports.
+
+config PHY_SPACEMIT_K1_USB2
+ bool "SpacemiT K1 USB 2.0 PHY driver"
+ depends on PHY && CLK
+ help
+ Enable this to support the USB 2.0 (UTMI) PHY of the SpacemiT K1
+ SoC, used by its DWC3 USB 3 controller. The driver configures the
+ PLL for the 24 MHz reference clock, releases the internal resets
+ and enables the PHY clocks before the controller is started.
diff --git a/drivers/phy/spacemit/Makefile b/drivers/phy/spacemit/Makefile
index 3496c099cd..cad47d11bf 100644
--- a/drivers/phy/spacemit/Makefile
+++ b/drivers/phy/spacemit/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_PHY_SPACEMIT_K1_PCIE) += phy-k1-pcie.o
+obj-$(CONFIG_PHY_SPACEMIT_K1_USB2) += phy-k1-usb2.o
diff --git a/drivers/phy/spacemit/phy-k1-usb2.c b/drivers/phy/spacemit/phy-k1-usb2.c
new file mode 100644
index 0000000000..c4b438219b
--- /dev/null
+++ b/drivers/phy/spacemit/phy-k1-usb2.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SpacemiT K1 USB 2.0 (UTMI) PHY driver
+ *
+ * Ported from the Linux SpacemiT K1 USB 2.0 PHY driver:
+ * Copyright (C) 2025 SpacemiT (Hangzhou) Technology Co. Ltd
+ * Copyright (C) 2025 Ze Huang <huang.ze@linux.dev>
+ *
+ * The HS DAC current setting and the clock-enable check follow the FreeBSD
+ * spacemit_usb2phy driver (BSD-2-Clause), which brought USB up on the
+ * OrangePi R2S:
+ * Copyright (c) 2026 Daniel Shue <dgshue@gmail.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+
+#define PHY_RST_MODE_CTRL 0x04
+#define PHY_PLL_RDY BIT(0)
+#define PHY_CLK_CDR_EN BIT(1)
+#define PHY_CLK_PLL_EN BIT(2)
+#define PHY_CLK_MAC_EN BIT(3)
+#define PHY_MAC_RSTN BIT(5)
+#define PHY_CDR_RSTN BIT(6)
+#define PHY_PLL_RSTN BIT(7)
+#define PHY_HS_LINE_TX_MODE BIT(13)
+#define PHY_FS_LINE_TX_MODE BIT(14)
+
+#define PHY_INIT_MODE_BITS (PHY_FS_LINE_TX_MODE | PHY_HS_LINE_TX_MODE)
+#define PHY_CLK_ENABLE_BITS (PHY_CLK_PLL_EN | PHY_CLK_CDR_EN | \
+ PHY_CLK_MAC_EN)
+#define PHY_DEASSERT_RST_BITS (PHY_PLL_RSTN | PHY_CDR_RSTN | \
+ PHY_MAC_RSTN)
+
+#define PHY_TX_HOST_CTRL 0x10
+#define PHY_HST_DISC_AUTO_CLR BIT(2)
+
+#define PHY_HSTXP_HW_CTRL 0x34
+#define PHY_HSTXP_RSTN BIT(2)
+#define PHY_CLK_HSTXP_EN BIT(3)
+#define PHY_HSTXP_MODE BIT(4)
+
+#define PHY_PLL_DIV_CFG 0x98
+#define PHY_FDIV_FRACT_8_15 GENMASK(7, 0)
+#define PHY_FDIV_FRACT_16_19 GENMASK(11, 8)
+#define PHY_FDIV_FRACT_20_21 BIT(12)
+#define PHY_FDIV_FRACT_0_1 GENMASK(14, 13)
+#define PHY_DIV_LOCAL_EN BIT(15)
+
+#define PHY_SEL_FREQ_24MHZ 0x01
+#define FDIV_REG_MASK (PHY_FDIV_FRACT_20_21 | PHY_FDIV_FRACT_16_19 | \
+ PHY_FDIV_FRACT_8_15)
+#define FDIV_REG_VAL 0x1ec4
+
+/* Vendor HS DAC current setting: +15 % drive, current regulator on */
+#define PHY_ANALOG_REG14_13 0xa4
+#define PHY_HSDAC_ISEL GENMASK(3, 0)
+#define PHY_HSDAC_ISEL_15_INC 0xc
+#define PHY_HSDAC_IREG_EN BIT(4)
+
+#define K1_USB2PHY_PLL_TIMEOUT_US 50000
+
+struct spacemit_usb2phy {
+ void __iomem *base;
+ struct clk clk;
+};
+
+static int spacemit_usb2phy_init(struct phy *phy)
+{
+ struct spacemit_usb2phy *sphy = dev_get_priv(phy->dev);
+ void __iomem *base = sphy->base;
+ u32 val;
+ int ret;
+
+ ret = clk_enable(&sphy->clk);
+ if (ret) {
+ dev_err(phy->dev, "failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ /* Let any controller reset settle before touching the PHY */
+ udelay(200);
+
+ /*
+ * Program the PLL divider for the 24 MHz reference first. Until it is
+ * written the PLL does not run, the clock enables below do not latch
+ * and the PHY gives the DWC3 no UTMI clock, so the xHCI reset
+ * (USBCMD.HCRST) never completes. Found on the OrangePi R2S under
+ * FreeBSD, whose earlier driver polled for the PLL before this write.
+ */
+ val = FIELD_PREP(FDIV_REG_MASK, FDIV_REG_VAL) |
+ FIELD_PREP(PHY_FDIV_FRACT_0_1, PHY_SEL_FREQ_24MHZ) |
+ PHY_DIV_LOCAL_EN;
+ writel(val, base + PHY_PLL_DIV_CFG);
+
+ ret = readl_poll_timeout(base + PHY_RST_MODE_CTRL, val,
+ val & PHY_PLL_RDY, K1_USB2PHY_PLL_TIMEOUT_US);
+ if (ret) {
+ dev_err(phy->dev, "PLL lock timeout\n");
+ clk_disable(&sphy->clk);
+ return ret;
+ }
+
+ /* Release the PHY's internal resets and enable its clocks */
+ writel(PHY_INIT_MODE_BITS | PHY_CLK_ENABLE_BITS | PHY_DEASSERT_RST_BITS,
+ base + PHY_RST_MODE_CTRL);
+ val = readl(base + PHY_RST_MODE_CTRL);
+ if ((val & PHY_CLK_ENABLE_BITS) != PHY_CLK_ENABLE_BITS)
+ dev_warn(phy->dev, "clock enables did not latch (%#x)\n", val);
+
+ writel(PHY_HSTXP_RSTN | PHY_CLK_HSTXP_EN | PHY_HSTXP_MODE,
+ base + PHY_HSTXP_HW_CTRL);
+
+ clrsetbits_le32(base + PHY_ANALOG_REG14_13, PHY_HSDAC_ISEL,
+ FIELD_PREP(PHY_HSDAC_ISEL, PHY_HSDAC_ISEL_15_INC) |
+ PHY_HSDAC_IREG_EN);
+
+ /* Auto-clear the HS host disconnect state on reconnect */
+ setbits_le32(base + PHY_TX_HOST_CTRL, PHY_HST_DISC_AUTO_CLR);
+
+ return 0;
+}
+
+static int spacemit_usb2phy_exit(struct phy *phy)
+{
+ struct spacemit_usb2phy *sphy = dev_get_priv(phy->dev);
+
+ return clk_disable(&sphy->clk);
+}
+
+static const struct phy_ops spacemit_usb2phy_ops = {
+ .init = spacemit_usb2phy_init,
+ .exit = spacemit_usb2phy_exit,
+};
+
+static int spacemit_usb2phy_probe(struct udevice *dev)
+{
+ struct spacemit_usb2phy *sphy = dev_get_priv(dev);
+ int ret;
+
+ sphy->base = dev_read_addr_ptr(dev);
+ if (!sphy->base)
+ return -EINVAL;
+
+ ret = clk_get_by_index(dev, 0, &sphy->clk);
+ if (ret) {
+ dev_err(dev, "failed to get clock: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id spacemit_usb2phy_ids[] = {
+ { .compatible = "spacemit,k1-usb2-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(spacemit_k1_usb2_phy) = {
+ .name = "spacemit_k1_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = spacemit_usb2phy_ids,
+ .probe = spacemit_usb2phy_probe,
+ .ops = &spacemit_usb2phy_ops,
+ .priv_auto = sizeof(struct spacemit_usb2phy),
+};
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/2] usb: dwc3: generic: add SpacemiT K1 support
2026-10-06 4:28 [PATCH 0/2] usb: add K1 USB2 PHY and generic DWC3 support Dave Klotz
2026-10-06 4:28 ` [PATCH 1/2] phy: spacemit: add K1 USB 2.0 PHY driver Dave Klotz
@ 2026-10-06 4:28 ` Dave Klotz
2026-10-06 5:15 ` Marek Vasut
2026-10-06 12:31 ` [PATCH v2 0/2] usb: add K1 USB2 PHY and generic DWC3 support Dave Klotz
2 siblings, 1 reply; 12+ messages in thread
From: Dave Klotz @ 2026-10-06 4:28 UTC (permalink / raw)
To: Yixun Lan, Marek Vasut; +Cc: u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
The K1 describes its DWC3 controller as one flat device-tree node with
the controller registers, clocks, resets and PHYs. It has no separate
wrapper registers or controller subnode.
Use the existing flat-node callback so that the generic wrapper binds
its host or peripheral child to the same node. Rename the Rockchip
flat-node ops to reflect that the callback is shared; keep the existing
Rockchip matches on the same callback.
The generic glue handles the K1 controller clocks, resets and USB 3 PHY,
while the child uses the existing generic DWC3 host/peripheral path.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
---
drivers/usb/dwc3/dwc3-generic.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 2356b3bc0a..489bc8347a 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -515,7 +515,7 @@ static const struct dwc3_glue_ops qcom_flat_dt_ops = {
.glue_get_ctrl_dev = dwc3_flat_dt_get_ctrl_dev,
};
-static const struct dwc3_glue_ops rk_ops = {
+static const struct dwc3_glue_ops flat_dt_ops = {
.glue_get_ctrl_dev = dwc3_flat_dt_get_ctrl_dev,
};
@@ -718,12 +718,13 @@ static const struct udevice_id dwc3_glue_ids[] = {
{ .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
{ .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
{ .compatible = "ti,am654-dwc3" },
- { .compatible = "rockchip,rk3328-dwc3", .data = (ulong)&rk_ops },
+ { .compatible = "rockchip,rk3328-dwc3", .data = (ulong)&flat_dt_ops },
{ .compatible = "rockchip,rk3399-dwc3" },
- { .compatible = "rockchip,rk3528-dwc3", .data = (ulong)&rk_ops },
- { .compatible = "rockchip,rk3568-dwc3", .data = (ulong)&rk_ops },
- { .compatible = "rockchip,rk3576-dwc3", .data = (ulong)&rk_ops },
- { .compatible = "rockchip,rk3588-dwc3", .data = (ulong)&rk_ops },
+ { .compatible = "rockchip,rk3528-dwc3", .data = (ulong)&flat_dt_ops },
+ { .compatible = "rockchip,rk3568-dwc3", .data = (ulong)&flat_dt_ops },
+ { .compatible = "rockchip,rk3576-dwc3", .data = (ulong)&flat_dt_ops },
+ { .compatible = "rockchip,rk3588-dwc3", .data = (ulong)&flat_dt_ops },
+ { .compatible = "spacemit,k1-dwc3", .data = (ulong)&flat_dt_ops },
{ .compatible = "qcom,dwc3", .data = (ulong)&qcom_ops },
{ .compatible = "qcom,snps-dwc3", .data = (ulong)&qcom_flat_dt_ops },
{ .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops },
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] usb: dwc3: generic: add SpacemiT K1 support
2026-10-06 4:28 ` [PATCH 2/2] usb: dwc3: generic: add SpacemiT K1 support Dave Klotz
@ 2026-10-06 5:15 ` Marek Vasut
0 siblings, 0 replies; 12+ messages in thread
From: Marek Vasut @ 2026-10-06 5:15 UTC (permalink / raw)
To: Dave Klotz, Yixun Lan, Marek Vasut
Cc: u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
On 10/6/26 6:28 AM, Dave Klotz wrote:
> The K1 describes its DWC3 controller as one flat device-tree node with
> the controller registers, clocks, resets and PHYs. It has no separate
> wrapper registers or controller subnode.
>
> Use the existing flat-node callback so that the generic wrapper binds
> its host or peripheral child to the same node. Rename the Rockchip
> flat-node ops to reflect that the callback is shared; keep the existing
> Rockchip matches on the same callback.
>
> The generic glue handles the K1 controller clocks, resets and USB 3 PHY,
> while the child uses the existing generic DWC3 host/peripheral path.
>
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
> ---
> drivers/usb/dwc3/dwc3-generic.c | 13 +++++++------
> 1 file changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
> index 2356b3bc0a..489bc8347a 100644
> --- a/drivers/usb/dwc3/dwc3-generic.c
> +++ b/drivers/usb/dwc3/dwc3-generic.c
> @@ -515,7 +515,7 @@ static const struct dwc3_glue_ops qcom_flat_dt_ops = {
> .glue_get_ctrl_dev = dwc3_flat_dt_get_ctrl_dev,
> };
>
> -static const struct dwc3_glue_ops rk_ops = {
> +static const struct dwc3_glue_ops flat_dt_ops = {
> .glue_get_ctrl_dev = dwc3_flat_dt_get_ctrl_dev,
> };
>
> @@ -718,12 +718,13 @@ static const struct udevice_id dwc3_glue_ids[] = {
> { .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
> { .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
> { .compatible = "ti,am654-dwc3" },
> - { .compatible = "rockchip,rk3328-dwc3", .data = (ulong)&rk_ops },
> + { .compatible = "rockchip,rk3328-dwc3", .data = (ulong)&flat_dt_ops },
> { .compatible = "rockchip,rk3399-dwc3" },
> - { .compatible = "rockchip,rk3528-dwc3", .data = (ulong)&rk_ops },
> - { .compatible = "rockchip,rk3568-dwc3", .data = (ulong)&rk_ops },
> - { .compatible = "rockchip,rk3576-dwc3", .data = (ulong)&rk_ops },
> - { .compatible = "rockchip,rk3588-dwc3", .data = (ulong)&rk_ops },
> + { .compatible = "rockchip,rk3528-dwc3", .data = (ulong)&flat_dt_ops },
> + { .compatible = "rockchip,rk3568-dwc3", .data = (ulong)&flat_dt_ops },
> + { .compatible = "rockchip,rk3576-dwc3", .data = (ulong)&flat_dt_ops },
> + { .compatible = "rockchip,rk3588-dwc3", .data = (ulong)&flat_dt_ops },
> + { .compatible = "spacemit,k1-dwc3", .data = (ulong)&flat_dt_ops },
The variable rename is unnecessary and makes the change harder to review.
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 0/2] usb: add K1 USB2 PHY and generic DWC3 support
2026-10-06 4:28 [PATCH 0/2] usb: add K1 USB2 PHY and generic DWC3 support Dave Klotz
2026-10-06 4:28 ` [PATCH 1/2] phy: spacemit: add K1 USB 2.0 PHY driver Dave Klotz
2026-10-06 4:28 ` [PATCH 2/2] usb: dwc3: generic: add SpacemiT K1 support Dave Klotz
@ 2026-10-06 12:31 ` Dave Klotz
2026-10-06 12:32 ` [PATCH v2 1/2] phy: spacemit: add K1 USB 2.0 PHY driver Dave Klotz
2026-10-06 12:32 ` [PATCH v2 2/2] usb: dwc3: generic: add SpacemiT K1 support Dave Klotz
2 siblings, 2 replies; 12+ messages in thread
From: Dave Klotz @ 2026-10-06 12:31 UTC (permalink / raw)
To: Yixun Lan, Marek Vasut; +Cc: u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
This series adds USB host support for the SpacemiT K1: a driver for
the K1's USB 2.0 (UTMI) PHY, and a flat-node entry for the SoC's DWC3
controller in dwc3-generic, which already handles clocks, resets, PHYs
and the host child for other flat-node SoCs. No K1-specific glue is
needed. USB 3 additionally needs the posted combo PHY series [1].
The patches apply to next at bd2f5794 and to current next
(ed869863c7e2), after the posted combo PHY series [1].
They also apply with the pending DWC3 resync [2], which does not
change dwc3-generic.c. The existing DWC3 flat-node users keep their
original rk_ops entries.
[1] https://lists.u-boot-project.org/pipermail/u-boot/2026-October/633775.html
[2] https://lists.u-boot-project.org/pipermail/u-boot/2026-October/633722.html
A targeted RISC-V build on current next (ed869863c7e2), with the
posted combo PHY prerequisites and these two patches, compiles the K1
USB2 PHY and generic DWC3 objects without compiler warnings. The
configuration checks pass.
Complete R2S and RV2 firmware builds on current next (ed869863c7e2),
with the maintained K1 prerequisites and these two patches, also pass,
and the compiled generic DWC3 objects retain rk_ops.
With that firmware on both boards, seven 64 MiB raw/FAT read pairs
pass SHA-256 and byte comparison at 5 Gb/s, including reads after each
of three USB resets and after a stop/start cycle. Automatic USB EFI
selection and boot of the USB-loaded FreeBSD kernel with the board's
native root also pass. Cold-boot, full USB-root and sustained testing
remain open.
Changes in v2:
- Drop the rk_ops rename from patch 2/2, as requested by Marek Vasut.
Add only the spacemit,k1-dwc3 compatible entry using the existing rk_ops.
- Patch 1/2 is unchanged.
Dave Klotz (2):
phy: spacemit: add K1 USB 2.0 PHY driver
usb: dwc3: generic: add SpacemiT K1 support
MAINTAINERS | 1 +
drivers/phy/spacemit/Kconfig | 9 ++
drivers/phy/spacemit/Makefile | 1 +
drivers/phy/spacemit/phy-k1-usb2.c | 173 +++++++++++++++++++++++++++++
drivers/usb/dwc3/dwc3-generic.c | 1 +
5 files changed, 185 insertions(+)
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 1/2] phy: spacemit: add K1 USB 2.0 PHY driver
2026-10-06 12:31 ` [PATCH v2 0/2] usb: add K1 USB2 PHY and generic DWC3 support Dave Klotz
@ 2026-10-06 12:32 ` Dave Klotz
2026-10-12 9:04 ` Yixun Lan
2026-10-12 9:37 ` Yixun Lan
2026-10-06 12:32 ` [PATCH v2 2/2] usb: dwc3: generic: add SpacemiT K1 support Dave Klotz
1 sibling, 2 replies; 12+ messages in thread
From: Dave Klotz @ 2026-10-06 12:32 UTC (permalink / raw)
To: Yixun Lan, Marek Vasut; +Cc: u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
The UTMI PHY at c0a30000 ("spacemit,k1-usb2-phy") feeds the K1's DWC3
USB 3 controller. Port the Linux driver: enable the PHY clock, program
the PLL divider for the 24 MHz reference, wait for the PLL, then release
the PHY's resets and enable its clocks, the HS TX clock and the
automatic host-disconnect clear.
The divider has to be written before the PLL is polled. On the OrangePi
R2S under FreeBSD, a driver that polled first and never wrote it left
the PLL stopped: the clock enables did not latch (0x60ef read back as
0x60e9), the PHY gave the controller no UTMI clock and the xHCI reset
(USBCMD.HCRST) never completed. Warn if the enables do not latch.
Also apply the vendor's HS DAC current setting (+15 %), which the
FreeBSD driver that runs the R2S port does.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
---
MAINTAINERS | 1 +
drivers/phy/spacemit/Kconfig | 9 ++
drivers/phy/spacemit/Makefile | 1 +
drivers/phy/spacemit/phy-k1-usb2.c | 173 +++++++++++++++++++++++++++++
4 files changed, 184 insertions(+)
create mode 100644 drivers/phy/spacemit/phy-k1-usb2.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 9e09f9506c..0af42acfbc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1517,6 +1517,7 @@ M: Yixun Lan <dlan@kernel.org>
S: Maintained
T: git https://git.u-boot-project.org/u-boot/custodians/u-boot-spacemit.git
F: arch/riscv/dts/k1-*-u-boot.dtsi
+F: drivers/phy/spacemit/phy-k1-usb2.c
N: spacemit
K: spacemit
diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig
index 3c47601c1f..7146965d92 100644
--- a/drivers/phy/spacemit/Kconfig
+++ b/drivers/phy/spacemit/Kconfig
@@ -9,3 +9,12 @@ config PHY_SPACEMIT_K1_PCIE
ports B and C. The combo PHY must be enabled even if port A
is not used for PCIe, because it provides calibration values
required by the other ports.
+
+config PHY_SPACEMIT_K1_USB2
+ bool "SpacemiT K1 USB 2.0 PHY driver"
+ depends on PHY && CLK
+ help
+ Enable this to support the USB 2.0 (UTMI) PHY of the SpacemiT K1
+ SoC, used by its DWC3 USB 3 controller. The driver configures the
+ PLL for the 24 MHz reference clock, releases the internal resets
+ and enables the PHY clocks before the controller is started.
diff --git a/drivers/phy/spacemit/Makefile b/drivers/phy/spacemit/Makefile
index 3496c099cd..cad47d11bf 100644
--- a/drivers/phy/spacemit/Makefile
+++ b/drivers/phy/spacemit/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_PHY_SPACEMIT_K1_PCIE) += phy-k1-pcie.o
+obj-$(CONFIG_PHY_SPACEMIT_K1_USB2) += phy-k1-usb2.o
diff --git a/drivers/phy/spacemit/phy-k1-usb2.c b/drivers/phy/spacemit/phy-k1-usb2.c
new file mode 100644
index 0000000000..c4b438219b
--- /dev/null
+++ b/drivers/phy/spacemit/phy-k1-usb2.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SpacemiT K1 USB 2.0 (UTMI) PHY driver
+ *
+ * Ported from the Linux SpacemiT K1 USB 2.0 PHY driver:
+ * Copyright (C) 2025 SpacemiT (Hangzhou) Technology Co. Ltd
+ * Copyright (C) 2025 Ze Huang <huang.ze@linux.dev>
+ *
+ * The HS DAC current setting and the clock-enable check follow the FreeBSD
+ * spacemit_usb2phy driver (BSD-2-Clause), which brought USB up on the
+ * OrangePi R2S:
+ * Copyright (c) 2026 Daniel Shue <dgshue@gmail.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+
+#define PHY_RST_MODE_CTRL 0x04
+#define PHY_PLL_RDY BIT(0)
+#define PHY_CLK_CDR_EN BIT(1)
+#define PHY_CLK_PLL_EN BIT(2)
+#define PHY_CLK_MAC_EN BIT(3)
+#define PHY_MAC_RSTN BIT(5)
+#define PHY_CDR_RSTN BIT(6)
+#define PHY_PLL_RSTN BIT(7)
+#define PHY_HS_LINE_TX_MODE BIT(13)
+#define PHY_FS_LINE_TX_MODE BIT(14)
+
+#define PHY_INIT_MODE_BITS (PHY_FS_LINE_TX_MODE | PHY_HS_LINE_TX_MODE)
+#define PHY_CLK_ENABLE_BITS (PHY_CLK_PLL_EN | PHY_CLK_CDR_EN | \
+ PHY_CLK_MAC_EN)
+#define PHY_DEASSERT_RST_BITS (PHY_PLL_RSTN | PHY_CDR_RSTN | \
+ PHY_MAC_RSTN)
+
+#define PHY_TX_HOST_CTRL 0x10
+#define PHY_HST_DISC_AUTO_CLR BIT(2)
+
+#define PHY_HSTXP_HW_CTRL 0x34
+#define PHY_HSTXP_RSTN BIT(2)
+#define PHY_CLK_HSTXP_EN BIT(3)
+#define PHY_HSTXP_MODE BIT(4)
+
+#define PHY_PLL_DIV_CFG 0x98
+#define PHY_FDIV_FRACT_8_15 GENMASK(7, 0)
+#define PHY_FDIV_FRACT_16_19 GENMASK(11, 8)
+#define PHY_FDIV_FRACT_20_21 BIT(12)
+#define PHY_FDIV_FRACT_0_1 GENMASK(14, 13)
+#define PHY_DIV_LOCAL_EN BIT(15)
+
+#define PHY_SEL_FREQ_24MHZ 0x01
+#define FDIV_REG_MASK (PHY_FDIV_FRACT_20_21 | PHY_FDIV_FRACT_16_19 | \
+ PHY_FDIV_FRACT_8_15)
+#define FDIV_REG_VAL 0x1ec4
+
+/* Vendor HS DAC current setting: +15 % drive, current regulator on */
+#define PHY_ANALOG_REG14_13 0xa4
+#define PHY_HSDAC_ISEL GENMASK(3, 0)
+#define PHY_HSDAC_ISEL_15_INC 0xc
+#define PHY_HSDAC_IREG_EN BIT(4)
+
+#define K1_USB2PHY_PLL_TIMEOUT_US 50000
+
+struct spacemit_usb2phy {
+ void __iomem *base;
+ struct clk clk;
+};
+
+static int spacemit_usb2phy_init(struct phy *phy)
+{
+ struct spacemit_usb2phy *sphy = dev_get_priv(phy->dev);
+ void __iomem *base = sphy->base;
+ u32 val;
+ int ret;
+
+ ret = clk_enable(&sphy->clk);
+ if (ret) {
+ dev_err(phy->dev, "failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ /* Let any controller reset settle before touching the PHY */
+ udelay(200);
+
+ /*
+ * Program the PLL divider for the 24 MHz reference first. Until it is
+ * written the PLL does not run, the clock enables below do not latch
+ * and the PHY gives the DWC3 no UTMI clock, so the xHCI reset
+ * (USBCMD.HCRST) never completes. Found on the OrangePi R2S under
+ * FreeBSD, whose earlier driver polled for the PLL before this write.
+ */
+ val = FIELD_PREP(FDIV_REG_MASK, FDIV_REG_VAL) |
+ FIELD_PREP(PHY_FDIV_FRACT_0_1, PHY_SEL_FREQ_24MHZ) |
+ PHY_DIV_LOCAL_EN;
+ writel(val, base + PHY_PLL_DIV_CFG);
+
+ ret = readl_poll_timeout(base + PHY_RST_MODE_CTRL, val,
+ val & PHY_PLL_RDY, K1_USB2PHY_PLL_TIMEOUT_US);
+ if (ret) {
+ dev_err(phy->dev, "PLL lock timeout\n");
+ clk_disable(&sphy->clk);
+ return ret;
+ }
+
+ /* Release the PHY's internal resets and enable its clocks */
+ writel(PHY_INIT_MODE_BITS | PHY_CLK_ENABLE_BITS | PHY_DEASSERT_RST_BITS,
+ base + PHY_RST_MODE_CTRL);
+ val = readl(base + PHY_RST_MODE_CTRL);
+ if ((val & PHY_CLK_ENABLE_BITS) != PHY_CLK_ENABLE_BITS)
+ dev_warn(phy->dev, "clock enables did not latch (%#x)\n", val);
+
+ writel(PHY_HSTXP_RSTN | PHY_CLK_HSTXP_EN | PHY_HSTXP_MODE,
+ base + PHY_HSTXP_HW_CTRL);
+
+ clrsetbits_le32(base + PHY_ANALOG_REG14_13, PHY_HSDAC_ISEL,
+ FIELD_PREP(PHY_HSDAC_ISEL, PHY_HSDAC_ISEL_15_INC) |
+ PHY_HSDAC_IREG_EN);
+
+ /* Auto-clear the HS host disconnect state on reconnect */
+ setbits_le32(base + PHY_TX_HOST_CTRL, PHY_HST_DISC_AUTO_CLR);
+
+ return 0;
+}
+
+static int spacemit_usb2phy_exit(struct phy *phy)
+{
+ struct spacemit_usb2phy *sphy = dev_get_priv(phy->dev);
+
+ return clk_disable(&sphy->clk);
+}
+
+static const struct phy_ops spacemit_usb2phy_ops = {
+ .init = spacemit_usb2phy_init,
+ .exit = spacemit_usb2phy_exit,
+};
+
+static int spacemit_usb2phy_probe(struct udevice *dev)
+{
+ struct spacemit_usb2phy *sphy = dev_get_priv(dev);
+ int ret;
+
+ sphy->base = dev_read_addr_ptr(dev);
+ if (!sphy->base)
+ return -EINVAL;
+
+ ret = clk_get_by_index(dev, 0, &sphy->clk);
+ if (ret) {
+ dev_err(dev, "failed to get clock: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id spacemit_usb2phy_ids[] = {
+ { .compatible = "spacemit,k1-usb2-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(spacemit_k1_usb2_phy) = {
+ .name = "spacemit_k1_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = spacemit_usb2phy_ids,
+ .probe = spacemit_usb2phy_probe,
+ .ops = &spacemit_usb2phy_ops,
+ .priv_auto = sizeof(struct spacemit_usb2phy),
+};
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 2/2] usb: dwc3: generic: add SpacemiT K1 support
2026-10-06 12:31 ` [PATCH v2 0/2] usb: add K1 USB2 PHY and generic DWC3 support Dave Klotz
2026-10-06 12:32 ` [PATCH v2 1/2] phy: spacemit: add K1 USB 2.0 PHY driver Dave Klotz
@ 2026-10-06 12:32 ` Dave Klotz
2026-10-12 9:38 ` Marek Vasut
2026-10-12 12:27 ` Yixun Lan
1 sibling, 2 replies; 12+ messages in thread
From: Dave Klotz @ 2026-10-06 12:32 UTC (permalink / raw)
To: Yixun Lan, Marek Vasut; +Cc: u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
The K1 describes its DWC3 controller as one flat device-tree node with
the controller registers, clocks, resets and PHYs. It has no separate
wrapper registers or controller subnode.
Use the existing flat-node callback through rk_ops so that the generic
wrapper binds its host or peripheral child to the same node.
The generic glue handles the K1 controller clocks, resets and USB 3 PHY,
while the child uses the existing generic DWC3 host/peripheral path.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
---
drivers/usb/dwc3/dwc3-generic.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 2356b3bc0a..cae627b587 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -724,6 +724,7 @@ static const struct udevice_id dwc3_glue_ids[] = {
{ .compatible = "rockchip,rk3568-dwc3", .data = (ulong)&rk_ops },
{ .compatible = "rockchip,rk3576-dwc3", .data = (ulong)&rk_ops },
{ .compatible = "rockchip,rk3588-dwc3", .data = (ulong)&rk_ops },
+ { .compatible = "spacemit,k1-dwc3", .data = (ulong)&rk_ops },
{ .compatible = "qcom,dwc3", .data = (ulong)&qcom_ops },
{ .compatible = "qcom,snps-dwc3", .data = (ulong)&qcom_flat_dt_ops },
{ .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops },
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/2] phy: spacemit: add K1 USB 2.0 PHY driver
2026-10-06 12:32 ` [PATCH v2 1/2] phy: spacemit: add K1 USB 2.0 PHY driver Dave Klotz
@ 2026-10-12 9:04 ` Yixun Lan
2026-10-12 12:17 ` Yixun Lan
2026-10-12 9:37 ` Yixun Lan
1 sibling, 1 reply; 12+ messages in thread
From: Yixun Lan @ 2026-10-12 9:04 UTC (permalink / raw)
To: Dave Klotz; +Cc: Marek Vasut, u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
Hi Dave,
On 12:32 Tue 06 Oct , Dave Klotz wrote:
> The UTMI PHY at c0a30000 ("spacemit,k1-usb2-phy") feeds the K1's DWC3
> USB 3 controller. Port the Linux driver: enable the PHY clock, program
> the PLL divider for the 24 MHz reference, wait for the PLL, then release
> the PHY's resets and enable its clocks, the HS TX clock and the
> automatic host-disconnect clear.
>
..
> The divider has to be written before the PLL is polled. On the OrangePi
Right, the upstream kernel driver also did this way
> R2S under FreeBSD, a driver that polled first and never wrote it left
> the PLL stopped: the clock enables did not latch (0x60ef read back as
Sorry, I've not fully understood here, "polled first and never write"..
Could you elaborate more on this?
> 0x60e9), the PHY gave the controller no UTMI clock and the xHCI reset
> (USBCMD.HCRST) never completed. Warn if the enables do not latch.
Will comment at code below
>
> Also apply the vendor's HS DAC current setting (+15 %), which the
> FreeBSD driver that runs the R2S port does.
>
Any actual problem without above settings? I'm just curious,
as upstream code miss this part
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
> ---
> MAINTAINERS | 1 +
> drivers/phy/spacemit/Kconfig | 9 ++
> drivers/phy/spacemit/Makefile | 1 +
> drivers/phy/spacemit/phy-k1-usb2.c | 173 +++++++++++++++++++++++++++++
> 4 files changed, 184 insertions(+)
> create mode 100644 drivers/phy/spacemit/phy-k1-usb2.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9e09f9506c..0af42acfbc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1517,6 +1517,7 @@ M: Yixun Lan <dlan@kernel.org>
> S: Maintained
> T: git https://git.u-boot-project.org/u-boot/custodians/u-boot-spacemit.git
> F: arch/riscv/dts/k1-*-u-boot.dtsi
> +F: drivers/phy/spacemit/phy-k1-usb2.c
> N: spacemit
> K: spacemit
>
> diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig
> index 3c47601c1f..7146965d92 100644
> --- a/drivers/phy/spacemit/Kconfig
> +++ b/drivers/phy/spacemit/Kconfig
> @@ -9,3 +9,12 @@ config PHY_SPACEMIT_K1_PCIE
> ports B and C. The combo PHY must be enabled even if port A
> is not used for PCIe, because it provides calibration values
> required by the other ports.
> +
> +config PHY_SPACEMIT_K1_USB2
> + bool "SpacemiT K1 USB 2.0 PHY driver"
> + depends on PHY && CLK
> + help
> + Enable this to support the USB 2.0 (UTMI) PHY of the SpacemiT K1
> + SoC, used by its DWC3 USB 3 controller. The driver configures the
> + PLL for the 24 MHz reference clock, releases the internal resets
> + and enables the PHY clocks before the controller is started.
> diff --git a/drivers/phy/spacemit/Makefile b/drivers/phy/spacemit/Makefile
> index 3496c099cd..cad47d11bf 100644
> --- a/drivers/phy/spacemit/Makefile
> +++ b/drivers/phy/spacemit/Makefile
> @@ -1 +1,2 @@
> obj-$(CONFIG_PHY_SPACEMIT_K1_PCIE) += phy-k1-pcie.o
> +obj-$(CONFIG_PHY_SPACEMIT_K1_USB2) += phy-k1-usb2.o
> diff --git a/drivers/phy/spacemit/phy-k1-usb2.c b/drivers/phy/spacemit/phy-k1-usb2.c
> new file mode 100644
> index 0000000000..c4b438219b
> --- /dev/null
> +++ b/drivers/phy/spacemit/phy-k1-usb2.c
> @@ -0,0 +1,173 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * SpacemiT K1 USB 2.0 (UTMI) PHY driver
> + *
> + * Ported from the Linux SpacemiT K1 USB 2.0 PHY driver:
> + * Copyright (C) 2025 SpacemiT (Hangzhou) Technology Co. Ltd
> + * Copyright (C) 2025 Ze Huang <huang.ze@linux.dev>
> + *
> + * The HS DAC current setting and the clock-enable check follow the FreeBSD
> + * spacemit_usb2phy driver (BSD-2-Clause), which brought USB up on the
> + * OrangePi R2S:
> + * Copyright (c) 2026 Daniel Shue <dgshue@gmail.com>
> + */
> +
> +#include <clk.h>
> +#include <dm.h>
> +#include <generic-phy.h>
> +#include <asm/io.h>
> +#include <dm/device_compat.h>
> +#include <linux/bitfield.h>
> +#include <linux/bitops.h>
> +#include <linux/delay.h>
> +#include <linux/iopoll.h>
> +
> +#define PHY_RST_MODE_CTRL 0x04
> +#define PHY_PLL_RDY BIT(0)
> +#define PHY_CLK_CDR_EN BIT(1)
> +#define PHY_CLK_PLL_EN BIT(2)
> +#define PHY_CLK_MAC_EN BIT(3)
> +#define PHY_MAC_RSTN BIT(5)
> +#define PHY_CDR_RSTN BIT(6)
> +#define PHY_PLL_RSTN BIT(7)
> +#define PHY_HS_LINE_TX_MODE BIT(13)
> +#define PHY_FS_LINE_TX_MODE BIT(14)
> +
> +#define PHY_INIT_MODE_BITS (PHY_FS_LINE_TX_MODE | PHY_HS_LINE_TX_MODE)
> +#define PHY_CLK_ENABLE_BITS (PHY_CLK_PLL_EN | PHY_CLK_CDR_EN | \
> + PHY_CLK_MAC_EN)
> +#define PHY_DEASSERT_RST_BITS (PHY_PLL_RSTN | PHY_CDR_RSTN | \
> + PHY_MAC_RSTN)
> +
> +#define PHY_TX_HOST_CTRL 0x10
> +#define PHY_HST_DISC_AUTO_CLR BIT(2)
> +
> +#define PHY_HSTXP_HW_CTRL 0x34
> +#define PHY_HSTXP_RSTN BIT(2)
> +#define PHY_CLK_HSTXP_EN BIT(3)
> +#define PHY_HSTXP_MODE BIT(4)
> +
> +#define PHY_PLL_DIV_CFG 0x98
> +#define PHY_FDIV_FRACT_8_15 GENMASK(7, 0)
> +#define PHY_FDIV_FRACT_16_19 GENMASK(11, 8)
> +#define PHY_FDIV_FRACT_20_21 BIT(12)
> +#define PHY_FDIV_FRACT_0_1 GENMASK(14, 13)
> +#define PHY_DIV_LOCAL_EN BIT(15)
> +
> +#define PHY_SEL_FREQ_24MHZ 0x01
> +#define FDIV_REG_MASK (PHY_FDIV_FRACT_20_21 | PHY_FDIV_FRACT_16_19 | \
> + PHY_FDIV_FRACT_8_15)
> +#define FDIV_REG_VAL 0x1ec4
> +
> +/* Vendor HS DAC current setting: +15 % drive, current regulator on */
> +#define PHY_ANALOG_REG14_13 0xa4
> +#define PHY_HSDAC_ISEL GENMASK(3, 0)
> +#define PHY_HSDAC_ISEL_15_INC 0xc
> +#define PHY_HSDAC_IREG_EN BIT(4)
> +
> +#define K1_USB2PHY_PLL_TIMEOUT_US 50000
> +
> +struct spacemit_usb2phy {
> + void __iomem *base;
> + struct clk clk;
> +};
> +
> +static int spacemit_usb2phy_init(struct phy *phy)
> +{
> + struct spacemit_usb2phy *sphy = dev_get_priv(phy->dev);
> + void __iomem *base = sphy->base;
> + u32 val;
> + int ret;
> +
> + ret = clk_enable(&sphy->clk);
> + if (ret) {
> + dev_err(phy->dev, "failed to enable clock: %d\n", ret);
> + return ret;
> + }
> +
> + /* Let any controller reset settle before touching the PHY */
> + udelay(200);
> +
> + /*
> + * Program the PLL divider for the 24 MHz reference first. Until it is
> + * written the PLL does not run, the clock enables below do not latch
> + * and the PHY gives the DWC3 no UTMI clock, so the xHCI reset
> + * (USBCMD.HCRST) never completes. Found on the OrangePi R2S under
> + * FreeBSD, whose earlier driver polled for the PLL before this write.
> + */
> + val = FIELD_PREP(FDIV_REG_MASK, FDIV_REG_VAL) |
> + FIELD_PREP(PHY_FDIV_FRACT_0_1, PHY_SEL_FREQ_24MHZ) |
> + PHY_DIV_LOCAL_EN;
> + writel(val, base + PHY_PLL_DIV_CFG);
> +
> + ret = readl_poll_timeout(base + PHY_RST_MODE_CTRL, val,
> + val & PHY_PLL_RDY, K1_USB2PHY_PLL_TIMEOUT_US);
> + if (ret) {
> + dev_err(phy->dev, "PLL lock timeout\n");
> + clk_disable(&sphy->clk);
> + return ret;
> + }
> +
> + /* Release the PHY's internal resets and enable its clocks */
> + writel(PHY_INIT_MODE_BITS | PHY_CLK_ENABLE_BITS | PHY_DEASSERT_RST_BITS,
> + base + PHY_RST_MODE_CTRL);
..
> + val = readl(base + PHY_RST_MODE_CTRL);
> + if ((val & PHY_CLK_ENABLE_BITS) != PHY_CLK_ENABLE_BITS)
> + dev_warn(phy->dev, "clock enables did not latch (%#x)\n", val);
So read back and check.. if this situation is happening, a warning
message won't save life.
But, I need to check if the "enable bits" actually reflect the clock
enabling status from the hardware perspective.. but even leave that alone,
I think using a poll() instead of a readl() is a more proper way to go?
usually it will take few time for the hardware to settle down..
> +
> + writel(PHY_HSTXP_RSTN | PHY_CLK_HSTXP_EN | PHY_HSTXP_MODE,
> + base + PHY_HSTXP_HW_CTRL);
> +
> + clrsetbits_le32(base + PHY_ANALOG_REG14_13, PHY_HSDAC_ISEL,
> + FIELD_PREP(PHY_HSDAC_ISEL, PHY_HSDAC_ISEL_15_INC) |
> + PHY_HSDAC_IREG_EN);
> +
> + /* Auto-clear the HS host disconnect state on reconnect */
> + setbits_le32(base + PHY_TX_HOST_CTRL, PHY_HST_DISC_AUTO_CLR);
> +
> + return 0;
> +}
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/2] phy: spacemit: add K1 USB 2.0 PHY driver
2026-10-06 12:32 ` [PATCH v2 1/2] phy: spacemit: add K1 USB 2.0 PHY driver Dave Klotz
2026-10-12 9:04 ` Yixun Lan
@ 2026-10-12 9:37 ` Yixun Lan
1 sibling, 0 replies; 12+ messages in thread
From: Yixun Lan @ 2026-10-12 9:37 UTC (permalink / raw)
To: Dave Klotz; +Cc: Marek Vasut, u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
Hi Dave,
On 12:32 Tue 06 Oct , Dave Klotz wrote:
> The UTMI PHY at c0a30000 ("spacemit,k1-usb2-phy") feeds the K1's DWC3
> USB 3 controller. Port the Linux driver: enable the PHY clock, program
> the PLL divider for the 24 MHz reference, wait for the PLL, then release
> the PHY's resets and enable its clocks, the HS TX clock and the
> automatic host-disconnect clear.
>
> The divider has to be written before the PLL is polled. On the OrangePi
> R2S under FreeBSD, a driver that polled first and never wrote it left
> the PLL stopped: the clock enables did not latch (0x60ef read back as
> 0x60e9), the PHY gave the controller no UTMI clock and the xHCI reset
> (USBCMD.HCRST) never completed. Warn if the enables do not latch.
>
> Also apply the vendor's HS DAC current setting (+15 %), which the
> FreeBSD driver that runs the R2S port does.
>
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
> ---
> MAINTAINERS | 1 +
> drivers/phy/spacemit/Kconfig | 9 ++
> drivers/phy/spacemit/Makefile | 1 +
> drivers/phy/spacemit/phy-k1-usb2.c | 173 +++++++++++++++++++++++++++++
> 4 files changed, 184 insertions(+)
> create mode 100644 drivers/phy/spacemit/phy-k1-usb2.c
>
..
> +
> +static const struct udevice_id spacemit_usb2phy_ids[] = {
> + { .compatible = "spacemit,k1-usb2-phy" },
Since K3 SoC share this IP with minor difference which we don't
care in U-Boot, and also I've tested, it works fine on K3 SoC,
so please add in next version, thanks
{ .compatible = "spacemit,k3-usb2-phy" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(spacemit_k1_usb2_phy) = {
> + .name = "spacemit_k1_usb2_phy",
> + .id = UCLASS_PHY,
> + .of_match = spacemit_usb2phy_ids,
> + .probe = spacemit_usb2phy_probe,
> + .ops = &spacemit_usb2phy_ops,
> + .priv_auto = sizeof(struct spacemit_usb2phy),
> +};
>
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 2/2] usb: dwc3: generic: add SpacemiT K1 support
2026-10-06 12:32 ` [PATCH v2 2/2] usb: dwc3: generic: add SpacemiT K1 support Dave Klotz
@ 2026-10-12 9:38 ` Marek Vasut
2026-10-12 12:27 ` Yixun Lan
1 sibling, 0 replies; 12+ messages in thread
From: Marek Vasut @ 2026-10-12 9:38 UTC (permalink / raw)
To: Dave Klotz, Yixun Lan; +Cc: u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
On 10/6/26 2:32 PM, Dave Klotz wrote:
> The K1 describes its DWC3 controller as one flat device-tree node with
> the controller registers, clocks, resets and PHYs. It has no separate
> wrapper registers or controller subnode.
>
> Use the existing flat-node callback through rk_ops so that the generic
> wrapper binds its host or peripheral child to the same node.
>
> The generic glue handles the K1 controller clocks, resets and USB 3 PHY,
> while the child uses the existing generic DWC3 host/peripheral path.
>
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
Reviewed-by: Marek Vasut <marek.vasut+usb@mailbox.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/2] phy: spacemit: add K1 USB 2.0 PHY driver
2026-10-12 9:04 ` Yixun Lan
@ 2026-10-12 12:17 ` Yixun Lan
0 siblings, 0 replies; 12+ messages in thread
From: Yixun Lan @ 2026-10-12 12:17 UTC (permalink / raw)
To: Dave Klotz; +Cc: Marek Vasut, u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
Hi Dave,
On 09:04 Mon 12 Oct , Yixun Lan wrote:
> Hi Dave,
>
> On 12:32 Tue 06 Oct , Dave Klotz wrote:
> > The UTMI PHY at c0a30000 ("spacemit,k1-usb2-phy") feeds the K1's DWC3
> > USB 3 controller. Port the Linux driver: enable the PHY clock, program
> > the PLL divider for the 24 MHz reference, wait for the PLL, then release
> > the PHY's resets and enable its clocks, the HS TX clock and the
> > automatic host-disconnect clear.
> >
> ..
> > The divider has to be written before the PLL is polled. On the OrangePi
> Right, the upstream kernel driver also did this way
>
> > R2S under FreeBSD, a driver that polled first and never wrote it left
> > the PLL stopped: the clock enables did not latch (0x60ef read back as
> Sorry, I've not fully understood here, "polled first and never write"..
> Could you elaborate more on this?
>
> > 0x60e9), the PHY gave the controller no UTMI clock and the xHCI reset
> > (USBCMD.HCRST) never completed. Warn if the enables do not latch.
> Will comment at code below
>
> >
> > Also apply the vendor's HS DAC current setting (+15 %), which the
> > FreeBSD driver that runs the R2S port does.
> >
> Any actual problem without above settings? I'm just curious,
> as upstream code miss this part
>
> > Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
> > ---
> > MAINTAINERS | 1 +
> > drivers/phy/spacemit/Kconfig | 9 ++
> > drivers/phy/spacemit/Makefile | 1 +
> > drivers/phy/spacemit/phy-k1-usb2.c | 173 +++++++++++++++++++++++++++++
> > 4 files changed, 184 insertions(+)
> > create mode 100644 drivers/phy/spacemit/phy-k1-usb2.c
> >
> > +
..
> > + /* Release the PHY's internal resets and enable its clocks */
> > + writel(PHY_INIT_MODE_BITS | PHY_CLK_ENABLE_BITS | PHY_DEASSERT_RST_BITS,
> > + base + PHY_RST_MODE_CTRL);
> ..
> > + val = readl(base + PHY_RST_MODE_CTRL);
> > + if ((val & PHY_CLK_ENABLE_BITS) != PHY_CLK_ENABLE_BITS)
> > + dev_warn(phy->dev, "clock enables did not latch (%#x)\n", val);
> So read back and check.. if this situation is happening, a warning
> message won't save life.
>
> But, I need to check if the "enable bits" actually reflect the clock
> enabling status from the hardware perspective.. but even leave that alone,
> I think using a poll() instead of a readl() is a more proper way to go?
> usually it will take few time for the hardware to settle down..
>
I've asked SpacemiT internal to check, and got this info:
Setting "enable bits" will take effect immediately, it doesn't reflect
the clock status, so this "readl() & check" isn't useful, drop it
If you still see problem, then probably need investigate other way..
> > +
> > + writel(PHY_HSTXP_RSTN | PHY_CLK_HSTXP_EN | PHY_HSTXP_MODE,
> > + base + PHY_HSTXP_HW_CTRL);
> > +
> > + clrsetbits_le32(base + PHY_ANALOG_REG14_13, PHY_HSDAC_ISEL,
> > + FIELD_PREP(PHY_HSDAC_ISEL, PHY_HSDAC_ISEL_15_INC) |
> > + PHY_HSDAC_IREG_EN);
> > +
> > + /* Auto-clear the HS host disconnect state on reconnect */
> > + setbits_le32(base + PHY_TX_HOST_CTRL, PHY_HST_DISC_AUTO_CLR);
> > +
> > + return 0;
> > +}
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 2/2] usb: dwc3: generic: add SpacemiT K1 support
2026-10-06 12:32 ` [PATCH v2 2/2] usb: dwc3: generic: add SpacemiT K1 support Dave Klotz
2026-10-12 9:38 ` Marek Vasut
@ 2026-10-12 12:27 ` Yixun Lan
1 sibling, 0 replies; 12+ messages in thread
From: Yixun Lan @ 2026-10-12 12:27 UTC (permalink / raw)
To: Dave Klotz; +Cc: Marek Vasut, u-boot, Quentin Schulz, Tom Rini, u-boot-spacemit
Hi Dave,
On 12:32 Tue 06 Oct , Dave Klotz wrote:
> The K1 describes its DWC3 controller as one flat device-tree node with
> the controller registers, clocks, resets and PHYs. It has no separate
> wrapper registers or controller subnode.
>
> Use the existing flat-node callback through rk_ops so that the generic
> wrapper binds its host or peripheral child to the same node.
>
> The generic glue handles the K1 controller clocks, resets and USB 3 PHY,
> while the child uses the existing generic DWC3 host/peripheral path.
>
https://github.com/torvalds/linux/commit/764c2e6e60bf17910d84e7179fee14129e053b96
"usb: dwc3: Add optional VBUS regulator support to SpacemiT K1"
Can you check above (for board OrangePi R2S), see if need to implement
similar support in U-Boot? I'd accept this patch if the regulator is
enabled by default, can leave us to improve later..
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
> ---
> drivers/usb/dwc3/dwc3-generic.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
> index 2356b3bc0a..cae627b587 100644
> --- a/drivers/usb/dwc3/dwc3-generic.c
> +++ b/drivers/usb/dwc3/dwc3-generic.c
> @@ -724,6 +724,7 @@ static const struct udevice_id dwc3_glue_ids[] = {
> { .compatible = "rockchip,rk3568-dwc3", .data = (ulong)&rk_ops },
> { .compatible = "rockchip,rk3576-dwc3", .data = (ulong)&rk_ops },
> { .compatible = "rockchip,rk3588-dwc3", .data = (ulong)&rk_ops },
> + { .compatible = "spacemit,k1-dwc3", .data = (ulong)&rk_ops },
> { .compatible = "qcom,dwc3", .data = (ulong)&qcom_ops },
> { .compatible = "qcom,snps-dwc3", .data = (ulong)&qcom_flat_dt_ops },
> { .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops },
>
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-10-12 12:27 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-06 4:28 [PATCH 0/2] usb: add K1 USB2 PHY and generic DWC3 support Dave Klotz
2026-10-06 4:28 ` [PATCH 1/2] phy: spacemit: add K1 USB 2.0 PHY driver Dave Klotz
2026-10-06 4:28 ` [PATCH 2/2] usb: dwc3: generic: add SpacemiT K1 support Dave Klotz
2026-10-06 5:15 ` Marek Vasut
2026-10-06 12:31 ` [PATCH v2 0/2] usb: add K1 USB2 PHY and generic DWC3 support Dave Klotz
2026-10-06 12:32 ` [PATCH v2 1/2] phy: spacemit: add K1 USB 2.0 PHY driver Dave Klotz
2026-10-12 9:04 ` Yixun Lan
2026-10-12 12:17 ` Yixun Lan
2026-10-12 9:37 ` Yixun Lan
2026-10-06 12:32 ` [PATCH v2 2/2] usb: dwc3: generic: add SpacemiT K1 support Dave Klotz
2026-10-12 9:38 ` Marek Vasut
2026-10-12 12:27 ` Yixun Lan
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.