All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.