devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC
@ 2026-08-06  2:56 Yixun Lan
  2026-08-06  2:56 ` [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for " Yixun Lan
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Yixun Lan @ 2026-08-06  2:56 UTC (permalink / raw)
  To: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, James E.J. Bottomley,
	Martin K. Petersen, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti
  Cc: Anirudh Srinivasan, Aurelien Jarno, Jennifer Berringer,
	linux-scsi, devicetree, linux-riscv, spacemit, linux-kernel,
	Yixun Lan

This series try to add UFS support for SpacemiT K3 SoC, the controller
components consists of System Bus Interface Unit, UFS Host Controller
Interface, UFS Transport Protocol Layer, UFS Host Registers, Device
Management Entity (DME), Transport Layer, Network Layer, Data Link
Layer, PHY Adapter Layer, and M-PHY Interface. A more detail functional
block diagram can be found in SpacemiT website, chapter 9.7.3 [1]

Please note, in order to test this driver, the UFS clock driver[2] here
should be applied first as a prerequisite patch.

One known issue is that the device will occasionally raise BKOPS interrupt
when doing some high load test, log from dmesg shows

[  806.710763] ufshcd-spacemit c0e00000.ufshc: ufshcd_bkops_exception_event_handler: device raised urgent BKOPS exception for bkops status 1

Link: https://spacemit.com/community/document/info?nodepath=hardware/key_stone/k3/k3_docs/k3_usermanual/09_memory_storage.md&lang=en [1]
Link: https://lore.kernel.org/all/20260630-06-clk-ufs-support-v1-0-cf7521d1d0fe@kernel.org/ [2]
Signed-off-by: Yixun Lan <dlan@kernel.org>
---
Changes in v3:
- fix dt-binding warning reported-by sashiko
- fix low freq in opp-2 table
- fix err checking in check_hibern8()
- propagate err code in link_startup_notify()
- update documents for event_notify()
- Link to v2: https://patch.msgid.link/20260725-08-k3-ufs-support-v2-0-45036a2a2418@kernel.org

Changes in v2:
- fix missing interrupts property
- move ufs node to k3-com260.dtsi
- convert freq-table-hz to operating-points-v2
- rework reset_control, fix header and drop global variable
- drop dump_host_regs() debug interface
- converge and refactor dme_set() operations
- massive reduce of busy delay() loops
- drop vendor specific hce_enable_notify(), fallback to default
- drop unused member from struct ufs_spacemit_host
- add COMPILE_TEST support to Kconfig
- comment style fix
- Link to v1: https://patch.msgid.link/20260702-08-k3-ufs-support-v1-0-1a64a3ab128f@kernel.org

---
Yixun Lan (3):
      scsi: ufs: spacemit: dt-bindings: Add UFS controller for K3 SoC
      scsi: ufs: spacemit: k3: Add UFS Host Controller driver
      riscv: dts: spacemit: k3: Add UFS support

 .../devicetree/bindings/ufs/spacemit,k3-ufshc.yaml |  56 ++
 arch/riscv/boot/dts/spacemit/k3-com260.dtsi        |   4 +
 arch/riscv/boot/dts/spacemit/k3-pico-itx.dts       |   4 +
 arch/riscv/boot/dts/spacemit/k3.dtsi               |  22 +
 drivers/ufs/host/Kconfig                           |  12 +
 drivers/ufs/host/Makefile                          |   1 +
 drivers/ufs/host/ufs-spacemit.c                    | 687 +++++++++++++++++++++
 drivers/ufs/host/ufs-spacemit.h                    |  79 +++
 8 files changed, 865 insertions(+)
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260605-08-k3-ufs-support-c8b308e415e2

Best regards,
--  
Yixun Lan <dlan@kernel.org>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for K3 SoC
  2026-08-06  2:56 [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC Yixun Lan
@ 2026-08-06  2:56 ` Yixun Lan
  2026-08-06  4:39   ` Rob Herring (Arm)
  2026-08-06  7:05   ` Krzysztof Kozlowski
  2026-08-06  2:56 ` [PATCH v3 2/3] scsi: ufs: spacemit: k3: Add UFS Host Controller driver Yixun Lan
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 11+ messages in thread
From: Yixun Lan @ 2026-08-06  2:56 UTC (permalink / raw)
  To: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, James E.J. Bottomley,
	Martin K. Petersen, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti
  Cc: Anirudh Srinivasan, Aurelien Jarno, Jennifer Berringer,
	linux-scsi, devicetree, linux-riscv, spacemit, linux-kernel,
	Yixun Lan

Document the compatible for UFS (Universal Flash Storage) Host Controller
which found in SpacemiT K3 SoC chip. Its features are listed below:

- Compliant with MIPI UniPro v1.61 specification.
- Compliant with M-PHY v3.0 specification.
- Compliant with UFS HCI v2.1 specification.
- Supports up to 2 Tx and 2 Rx lanes, up to HS-GEAR3 5.8 Gbps per lane.
- Supports standard low-power hibernate to reduce power consumption.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
 .../devicetree/bindings/ufs/spacemit,k3-ufshc.yaml | 56 ++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/Documentation/devicetree/bindings/ufs/spacemit,k3-ufshc.yaml b/Documentation/devicetree/bindings/ufs/spacemit,k3-ufshc.yaml
new file mode 100644
index 000000000000..dda533c852e8
--- /dev/null
+++ b/Documentation/devicetree/bindings/ufs/spacemit,k3-ufshc.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/ufs/spacemit,k3-ufshc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SpacemiT K3 SoC UFS Host Controller
+
+maintainers:
+  - Yixun Lan <dlan@kernel.org>
+
+properties:
+  compatible:
+    const: spacemit,k3-ufshc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: aclk
+      - const: ref_clk
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+
+allOf:
+  - $ref: ufs-common.yaml
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/spacemit,k3-clocks.h>
+    #include <dt-bindings/reset/spacemit,k3-resets.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    ufs@c0e00000 {
+        compatible = "spacemit,k3-ufshc";
+        reg = <0xc0e00000 0x40000>;
+        clocks = <&syscon_apmu CLK_APMU_UFS_ACLK>,
+                 <&syscon_apmu CLK_APMU_UFS_REFCLK>;
+        clock-names = "aclk", "ref_clk";
+        resets = <&syscon_apmu RESET_APMU_UFS_ACLK>;
+        interrupts = <135 IRQ_TYPE_LEVEL_HIGH>;
+        lanes-per-direction = <2>;
+    };

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 2/3] scsi: ufs: spacemit: k3: Add UFS Host Controller driver
  2026-08-06  2:56 [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC Yixun Lan
  2026-08-06  2:56 ` [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for " Yixun Lan
@ 2026-08-06  2:56 ` Yixun Lan
  2026-08-06  3:10   ` sashiko-bot
  2026-08-06  2:56 ` [PATCH v3 3/3] riscv: dts: spacemit: k3: Add UFS support Yixun Lan
  2026-08-06 14:51 ` [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC Aurelien Jarno
  3 siblings, 1 reply; 11+ messages in thread
From: Yixun Lan @ 2026-08-06  2:56 UTC (permalink / raw)
  To: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, James E.J. Bottomley,
	Martin K. Petersen, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti
  Cc: Anirudh Srinivasan, Aurelien Jarno, Jennifer Berringer,
	linux-scsi, devicetree, linux-riscv, spacemit, linux-kernel,
	Yixun Lan

SpacemiT K3 SoC consist of UFS (Universal Flash Storage) Host Controller
which has features compatible with JEDEC UFS 2.2, MIPI UniPro v1.61 and
M-PHY v3.0 standard.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
 drivers/ufs/host/Kconfig        |  12 +
 drivers/ufs/host/Makefile       |   1 +
 drivers/ufs/host/ufs-spacemit.c | 687 ++++++++++++++++++++++++++++++++++++++++
 drivers/ufs/host/ufs-spacemit.h |  79 +++++
 4 files changed, 779 insertions(+)

diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig
index ff170c0b6da0..6146872fcecc 100644
--- a/drivers/ufs/host/Kconfig
+++ b/drivers/ufs/host/Kconfig
@@ -132,6 +132,18 @@ config SCSI_UFS_VARIABLE_SG_ENTRY_SIZE
 	bool
 	default y if SCSI_UFS_EXYNOS && SCSI_UFS_CRYPTO
 
+config SCSI_UFS_SPACEMIT
+	tristate "SpacemiT UFS controller driver"
+	depends on SCSI_UFSHCD_PLATFORM && (ARCH_SPACEMIT || COMPILE_TEST)
+	help
+	  This selects the SpacemiT specific additions to UFSHCD platform driver.
+	  UFS host on SpacemiT needs some vendor specific configuration before
+	  accessing the hardware which includes PHY configuration and vendor
+	  specific registers.
+
+	  Select this if you have UFS controller on SpacemiT chipset.
+	  If unsure, say N.
+
 config SCSI_UFS_SPRD
 	tristate "Unisoc specific hooks to UFS controller platform driver"
 	depends on SCSI_UFSHCD_PLATFORM && (ARCH_SPRD || COMPILE_TEST)
diff --git a/drivers/ufs/host/Makefile b/drivers/ufs/host/Makefile
index 65d8bb23ab7b..151bf43dfba7 100644
--- a/drivers/ufs/host/Makefile
+++ b/drivers/ufs/host/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o
 obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o
 obj-$(CONFIG_SCSI_UFS_RENESAS) += ufs-renesas.o
 obj-$(CONFIG_SCSI_UFS_ROCKCHIP) += ufs-rockchip.o
+obj-$(CONFIG_SCSI_UFS_SPACEMIT) += ufs-spacemit.o
 obj-$(CONFIG_SCSI_UFS_SPRD) += ufs-sprd.o
 obj-$(CONFIG_SCSI_UFS_TI_J721E) += ti-j721e-ufs.o
 obj-$(CONFIG_SCSI_UFS_AMD_VERSAL2) += ufs-amd-versal2.o ufshcd-dwc.o
diff --git a/drivers/ufs/host/ufs-spacemit.c b/drivers/ufs/host/ufs-spacemit.c
new file mode 100644
index 000000000000..94942ea27fb7
--- /dev/null
+++ b/drivers/ufs/host/ufs-spacemit.c
@@ -0,0 +1,687 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2026 SpacemiT (Hangzhou) Technology Co. Ltd
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#include <ufs/ufshcd.h>
+#include <ufs/ufshci.h>
+#include <ufs/ufs_quirks.h>
+#include <ufs/unipro.h>
+
+#include "ufshcd-pltfrm.h"
+#include "ufs-spacemit.h"
+
+/* PA Layer Gettable and settable M-PHY Specific Attributes */
+#define PA_TXHSG1SYNCLENGTH		0x1552
+#define PA_TXHSG1PREPARELENGTH		0x1553
+#define PA_TXHSG2SYNCLENGTH		0x1554
+#define PA_TXHSG2PREPARELENGTH		0x1555
+#define PA_TXHSG3SYNCLENGTH		0x1556
+#define PA_TXHSG3PREPARELENGTH		0x1557
+#define PA_TXMK2EXTENSION		0x155A
+#define PA_PEERSCRAMBLING		0x155B
+#define PA_TXSKIP			0x155C
+#define PA_TXSKIPPERIOD			0x155D
+#define PA_PEER_TX_LCC_ENABLE		0x155F
+
+#define PA_SCRAMBLING			0x1585
+#define PA_MK2EXTENSIONGUARDBAND	0x15AB
+
+/* Special TX/RX Configuration Attributes */
+#define RX_LS_PRE_LEN_CAP		0x008D
+#define RX_LANE_HB8_BKDOOR_ATTR		0x00F4
+#define RX_PWRM_CLOSURE_LEN_CAP		0x008E
+#define RX_MIN_STALL_CAP		0x0088
+#define RX_LANE_SOF_BKDOOR_ATT		0x00F2
+#define RX_GARBAGE_COUNT_OFFSET		0x00F2
+
+/* Special analog register */
+#define ANA_EQ_CTRL_REG_ATTR		0x00CD
+#define ANA_HSGEAR_CTRL_ATTR		0x00C1
+
+/*
+ * Keep UFS ACLK at a lower parent rate (409.6MHz) for stable init.
+ * This mirrors the "ufs-low-aclk-freq" change from the other environment.
+ */
+#define UFS_ACLK_LOW_FREQ_HZ		409600000UL
+
+/* PHY register magic values */
+#define MPHY_PU_ALL			0x87f
+#define MPHY_PU_WITH_HB8_RESET		0xb7f
+#define MPHY_DEVICE_RESET_DEASSERT	0x101
+#define MPHY_DEVICE_RESET_ASSERT	0x001
+#define MPHY_PLL_LOCK_BIT		BIT(31)
+#define MPHY_PLL_LOCK_TIMEOUT_US	10000
+
+/* FSM states */
+#define FSM_STATE_HIBERN8		0x1
+#define FSM_STATE_ACTIVE		0x3
+#define FSM_STATE_LS_BURST		0x5
+
+#define VENDOR_DUMP_BUF_SIZE		2048
+#define VENDOR_MAX_OFFSET		0xE0
+
+/* M-PHY FSM states */
+#define MPHY_RX_FSM_STATE	0xC1
+#define MPHY_TX_FSM_STATE	0x41
+
+static int ufs_spacemit_dme_set(struct ufs_hba *hba,
+				const struct ufshcd_dme_attr_val *v, int n)
+{
+	int ret = 0;
+	int attr_node = 0;
+
+	for (attr_node = 0; attr_node < n; attr_node++) {
+		ret = ufshcd_dme_set(hba, v[attr_node].attr_sel,
+				     v[attr_node].mib_val);
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ufs_spacemit_check_hibern8(struct ufs_hba *hba)
+{
+	u32 tx_fsm_val_0 = 0;
+	u32 tx_fsm_val_1 = 0;
+	int retries = DIV_ROUND_UP(HBRN8_POLL_TOUT_MS * 1000, 100);
+	int err = 0;
+
+	do {
+		err = ufshcd_dme_get(hba,
+				     UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
+						     UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+				     &tx_fsm_val_0);
+		if (err)
+			break;
+
+		err = ufshcd_dme_get(hba,
+				     UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
+						     UIC_ARG_MPHY_TX_GEN_SEL_INDEX(1)),
+				     &tx_fsm_val_1);
+		if (err || (tx_fsm_val_0 == TX_FSM_HIBERN8 &&
+			    tx_fsm_val_1 == TX_FSM_HIBERN8))
+			break;
+
+		usleep_range(100, 200);
+	} while (--retries > 0);
+
+	if (err) {
+		dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n",
+			__func__, err);
+	} else if (tx_fsm_val_0 != TX_FSM_HIBERN8 ||
+		   tx_fsm_val_1 != TX_FSM_HIBERN8) {
+		err = -ETIMEDOUT;
+		dev_err(hba->dev,
+			"%s: invalid TX_FSM_STATE, lane0 = %u, lane1 = %u\n",
+			__func__, tx_fsm_val_0, tx_fsm_val_1);
+	}
+
+	return err;
+}
+
+static int ufs_spacemit_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
+{
+	int err;
+
+	err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), tx_lanes);
+	if (err)
+		dev_err(hba->dev, "%s: couldn't read PA_CONNECTEDTXDATALANES %d\n", __func__, err);
+
+	return err;
+}
+
+static u32 ufs_spacemit_get_sys1clk_1us(struct ufs_hba *hba)
+{
+	struct ufs_clk_info *clki, *ufs_aclk = NULL;
+	struct list_head *head = &hba->clk_list_head;
+	unsigned long rate_hz = 0;
+
+	if (!list_empty(head)) {
+		list_for_each_entry(clki, head, list) {
+			if (clki->name && !strcmp(clki->name, "aclk") && clki->clk) {
+				ufs_aclk = clki;
+				break;
+			}
+		}
+	}
+
+	if (ufs_aclk && ufs_aclk->clk)
+		rate_hz = clk_get_rate(ufs_aclk->clk);
+
+	if (!rate_hz)
+		return 0;
+
+	return DIV_ROUND_CLOSEST(rate_hz, 1000000);
+}
+
+static int ufs_spacemit_wait_mphy_pll_lock(struct ufs_hba *hba)
+{
+	u32 val;
+	int err;
+
+	err = read_poll_timeout(ufshcd_readl, val, val & MPHY_PLL_LOCK_BIT,
+				10, MPHY_PLL_LOCK_TIMEOUT_US, false, hba,
+				UFS_PHY_MNG_BASE + UFS_MPHY_PU_CTRL);
+
+	if (err)
+		dev_err(hba->dev, "M-PHY PLL lock timeout\n");
+
+	return err;
+}
+
+/**
+ * ufs_spacemit_mphy_init
+ * @hba: host controller instance
+ */
+static int ufs_spacemit_mphy_init(struct ufs_hba *hba)
+{
+	int ret;
+
+	/* reset all mphy logical */
+	ufshcd_writel(hba, 0x003, UFS_PHY_MNG_BASE + 0x0);
+
+	/* power up all */
+	ufshcd_writel(hba, MPHY_PU_ALL, UFS_PHY_MNG_BASE + 0x4);
+
+	/* asserted ana_rx_hb8_reset */
+	ufshcd_writel(hba, 0xb7f, UFS_PHY_MNG_BASE + 0x4);
+	fsleep(500);
+
+	/* deasserted ana_rx_hb8_reset */
+	ufshcd_writel(hba, MPHY_PU_ALL, UFS_PHY_MNG_BASE + 0x4);
+
+	/* deasserted ufs device reset & refer clk output enable */
+	ufshcd_writel(hba, 0x101, UFS_PHY_MNG_BASE + 0xC);
+	fsleep(1000);
+
+	ret = ufs_spacemit_wait_mphy_pll_lock(hba);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(hba->dev, "M-PHY PLL locked successfully\n");
+
+	ufshcd_writel(hba, 0x1, UFS_PHY_MNG_BASE + 0x08);
+
+	ufshcd_writel(hba, 0x40, UFS_ATOP_BASE + (0xC2 << 2));
+
+	ufshcd_writel(hba, 0x0, UFS_PHY_MNG_BASE + 0x08);
+
+	fsleep(2000);
+
+	dev_dbg(hba->dev, "M-PHY init completed\n");
+
+	return 0;
+}
+
+static int ufs_spacemit_uniprov1p6_init(struct ufs_hba *hba)
+{
+	static const struct ufshcd_dme_attr_val setup_attrs[] = {
+		{ UIC_ARG_MIB(0x1552), 0x4f }, /* PA_TXHSG1SYNCLENGTH */
+		{ UIC_ARG_MIB(0x1553), 0xf }, /* PA_TXHSG1PREPARELENGTH */
+		{ UIC_ARG_MIB(0x1554), 0x4f }, /* PA_TXHSG2SYNCLENGTH */
+		{ UIC_ARG_MIB(0x1555), 0xf }, /* PA_TXHSG2PREPARELENGTH */
+		{ UIC_ARG_MIB(0x1556), 0x4f }, /* PA_TXHSG3SYNCLENGTH */
+		{ UIC_ARG_MIB(0x1557), 0xf }, /* PA_TXHSG3PREPARELENGTH */
+		{ UIC_ARG_MIB(0x155A), 0x0 }, /* PA_TXMK2EXTENSION */
+		{ UIC_ARG_MIB(0x155B), 0x1}, /* PA_PEERSCRAMBLING */
+		{ UIC_ARG_MIB(0x155C), 0x1 }, /* PA_TXSKIP */
+		{ UIC_ARG_MIB(0x155D), 250 }, /* PA_TXSKIPPERIOD */
+		{ UIC_ARG_MIB(0x155E), 0x0 }, /* PA_LOCAL_TX_LCC_ENABLE */
+		{ UIC_ARG_MIB(0x155F), 0x0 }, /* PA_PEER_TX_LCC_ENABLE */
+		{ UIC_ARG_MIB(0x1585), 0x1 }, /* PA_SCRAMBLING */
+		{ UIC_ARG_MIB(0x15AA), 0x1 }, /* PA_GRANULARITY */
+		{ UIC_ARG_MIB(0x15AB), 0x0 }, /* PA_MK2EXTENSIONGUARDBAND */
+		{ UIC_ARG_MIB(0x15A3), 15 }, /* PA_STALLNOCONFIGTIME */
+		{ UIC_ARG_MIB(0x15A8), 0x64 }, /* PA_TACTIVATE */
+		{ UIC_ARG_MIB(0x1564), 0x64 },	/* PA_TXTRAILINGCLOCKS */
+		{ UIC_ARG_MIB_SEL(0x008D, 4), 0x0B }, /* RX_LS_PREPARELEN_TIME RX0 */
+		{ UIC_ARG_MIB_SEL(0x008D, 5), 0x0B }, /* RX_LS_PREPARELEN_TIME RX1 */
+
+		/* RX_HIBERNATE_BKEN RX0 */
+		{ UIC_ARG_MIB_SEL(0x00F4, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x9F },
+		/* RX_HIBERNATE_BKEN RX1 */
+		{ UIC_ARG_MIB_SEL(0x00F4, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x9F },
+		/* PWM_BURST_closure_length */
+		{ UIC_ARG_MIB_SEL(0x008E, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),   15 },
+		{ UIC_ARG_MIB_SEL(0x008E, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)),   15 },
+		/* min_stall_not_config_time */
+		{ UIC_ARG_MIB_SEL(0x0088, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0xFF },
+		{ UIC_ARG_MIB_SEL(0x0088, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0xFF },
+		/* TX HB8_TIME CAP */
+		{ UIC_ARG_MIB_SEL(0x000F, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0x64 },
+		{ UIC_ARG_MIB_SEL(0x000F, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(1)), 0x64 },
+		/* RX HB8_TIME CAP */
+		{ UIC_ARG_MIB_SEL(0x0092, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x64 },
+		{ UIC_ARG_MIB_SEL(0x0092, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x64 },
+		/* TX EQ 3DB */
+		{ UIC_ARG_MIB_SEL(0x00CD, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),  0x5 },
+		/* RX garbage cnt = 32 SI */
+		{ UIC_ARG_MIB_SEL(0x00F2, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x9F },
+		{ UIC_ARG_MIB_SEL(0x00F2, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x9F },
+	};
+
+	return ufs_spacemit_dme_set(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
+}
+
+static void ufs_spacemit_set_dev_cap(struct ufs_host_params *host_params, u32 pwr_hs)
+{
+	if (!host_params)
+		return;
+
+	memset(host_params, 0, sizeof(struct ufs_host_params));
+	host_params->tx_lanes = UFS_SPACEMIT_K3_LIMIT_NUM_LANES_TX;
+	host_params->rx_lanes = UFS_SPACEMIT_K3_LIMIT_NUM_LANES_RX;
+	host_params->hs_rx_gear = UFS_SPACEMIT_K3_LIMIT_HSGEAR_RX;
+	host_params->hs_tx_gear = UFS_SPACEMIT_K3_LIMIT_HSGEAR_TX;
+	host_params->pwm_rx_gear = UFS_SPACEMIT_K3_LIMIT_PWMGEAR_RX;
+	host_params->pwm_tx_gear = UFS_SPACEMIT_K3_LIMIT_PWMGEAR_TX;
+	host_params->rx_pwr_pwm = UFS_SPACEMIT_K3_LIMIT_RX_PWR_PWM;
+	host_params->tx_pwr_pwm = UFS_SPACEMIT_K3_LIMIT_TX_PWR_PWM;
+	host_params->rx_pwr_hs = pwr_hs;
+	host_params->tx_pwr_hs = pwr_hs;
+	host_params->hs_rate = UFS_SPACEMIT_K3_LIMIT_HS_RATE;
+	host_params->desired_working_mode = UFS_HS_MODE;
+}
+
+static int ufs_spacemit_link_startup_pre_change(struct ufs_hba *hba)
+{
+	u32 value, sys1clk_1us;
+	int err;
+
+	err = ufs_spacemit_mphy_init(hba);
+	if (err < 0)
+		return err;
+
+	err = ufs_spacemit_uniprov1p6_init(hba);
+	if (err < 0)
+		return err;
+
+	/* config sysclk and tx symbol clk before link startup */
+	value = UFS_MAX_LINKSTARTUP_TIMER;
+
+	/* clear bit0~bit3, select b0 design */
+	value &= ~0xf;
+
+	ufshcd_writel(hba, value, UFS_PA_LINK_STARTUP_TIMER);
+
+	sys1clk_1us = ufs_spacemit_get_sys1clk_1us(hba);
+	if (!sys1clk_1us)
+		sys1clk_1us = DIV_ROUND_CLOSEST(UFS_ACLK_LOW_FREQ_HZ, 1000000);
+	ufshcd_writel(hba, sys1clk_1us, UFS_SYS1CLK_1US);
+	ufshcd_writel(hba, UFS_TX_SYMBO_CLK, UFS_TX_SYMBOL_CLK_NS_US);
+
+	dev_dbg(hba->dev, "REG_UFS_SYS1CLK_1US: 0x%x\n",
+		ufshcd_readl(hba, UFS_SYS1CLK_1US));
+	dev_dbg(hba->dev, "REG_UFS_TX_SYMBOL_CLK_NS_US: 0x%x\n",
+		ufshcd_readl(hba, UFS_TX_SYMBOL_CLK_NS_US));
+
+	return 0;
+}
+
+static int ufs_spacemit_link_startup_post_change(struct ufs_hba *hba)
+{
+	/* Add 0xe8 make UFS2.1 run GEAR3 + 2Lane@409M */
+	static const struct ufshcd_dme_attr_val setup_attrs[] = {
+		{ UIC_ARG_MIB_SEL(0xe8, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0x97 },
+		{ UIC_ARG_MIB_SEL(0xe8, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0xd7 },
+		{ UIC_ARG_MIB_SEL(0xe8, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0x17 },
+		{ UIC_ARG_MIB(DL_AFC0REQTIMEOUTVAL), UFS_DL_AFC0REQTIMEOUTVAL_MAX },
+	};
+	u32 tx_lanes;
+	int err;
+
+	err = ufs_spacemit_dme_set(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
+	if (err < 0)
+		return err;
+
+	return ufs_spacemit_get_connected_tx_lanes(hba, &tx_lanes);
+}
+
+static int ufs_spacemit_link_startup_notify(struct ufs_hba *hba,
+					    enum ufs_notify_change_status status)
+{
+	int err = 0;
+
+	switch (status) {
+	case PRE_CHANGE:
+		err = ufs_spacemit_link_startup_pre_change(hba);
+		break;
+	case POST_CHANGE:
+		err = ufs_spacemit_link_startup_post_change(hba);
+		break;
+	default:
+		break;
+	}
+
+	return err;
+}
+
+static int ufs_spacemit_negotiate_pwr_mode(struct ufs_hba *hba,
+					   const struct ufs_pa_layer_attr *dev_max_params,
+					   struct ufs_pa_layer_attr *dev_req_params)
+{
+	struct ufs_host_params host_params;
+	int ret;
+
+	ufs_spacemit_set_dev_cap(&host_params, FAST_MODE);
+	ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params,
+					  dev_req_params);
+	if (ret) {
+		dev_err(hba->dev, "Failed to negotiate power params: %d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(hba->dev,
+		"Power mode config - gear_rx:%d, gear_tx:%d, lane_rx:%d, lane_tx:%d, pwr_rx:%d, pwr_tx:%d, hs_rate:%d\n",
+		dev_req_params->gear_rx, dev_req_params->gear_tx, dev_req_params->lane_rx,
+		dev_req_params->lane_tx, dev_req_params->pwr_rx, dev_req_params->pwr_tx,
+		dev_req_params->hs_rate);
+
+	return ret;
+}
+
+static int ufs_spacemit_pwr_change_notify(struct ufs_hba *hba,
+					  enum ufs_notify_change_status status,
+					  struct ufs_pa_layer_attr *dev_req_params)
+{
+	struct ufs_spacemit_host *host = ufshcd_get_variant(hba);
+	int ret = 0;
+
+	if (!dev_req_params) {
+		dev_err(hba->dev, "Invalid Parameters\n");
+		return -EINVAL;
+	}
+
+	switch (status) {
+	case PRE_CHANGE:
+		break;
+	case POST_CHANGE:
+		/* Cache the power mode parameters to use internally */
+		memcpy(&host->dev_req_params, dev_req_params, sizeof(*dev_req_params));
+		ret = ufs_spacemit_wait_mphy_pll_lock(hba);
+		if (ret < 0)
+			return ret;
+
+		dev_dbg(hba->dev, "M-PHY PLL locked after power mode change\n");
+		/* Set ANA_HSGEAR_CTRL_ATTR back to default value */
+		ufshcd_dme_set(hba, UIC_ARG_MIB(ANA_HSGEAR_CTRL_ATTR), 0x00);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int ufs_spacemit_quirk_host_pa_saveconfigtime(struct ufs_hba *hba)
+{
+	int err;
+	u32 pa_vs_config_reg1;
+
+	err = ufshcd_dme_get(hba, UIC_ARG_MIB(UFS_PA_VS_CONFIG_REG1), &pa_vs_config_reg1);
+	if (err)
+		return err;
+
+	/* Allow extension of MSB bits of PA_SaveConfigTime attribute */
+	return ufshcd_dme_set(hba, UIC_ARG_MIB(UFS_PA_VS_CONFIG_REG1),
+			      (pa_vs_config_reg1 | (1 << 12)));
+}
+
+static int ufs_spacemit_apply_dev_quirks(struct ufs_hba *hba)
+{
+	static const struct ufshcd_dme_attr_val setup_attrs[] = {
+		/* LCC_DISABLE */
+		{ UIC_ARG_MIB_SEL(TX_LCC_ENABLE, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0 },
+		{ UIC_ARG_MIB_SEL(TX_LCC_ENABLE, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(1)), 0 },
+		/* TX_Min_ActivateTime */
+		{ UIC_ARG_MIB_SEL(TX_MIN_ACTIVATETIME, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0x0 },
+		{ UIC_ARG_MIB_SEL(TX_MIN_ACTIVATETIME, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(1)), 0x0 },
+		{ UIC_ARG_MIB(ANA_HSGEAR_CTRL_ATTR), 0x25 },
+	};
+
+	if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME)
+		ufs_spacemit_quirk_host_pa_saveconfigtime(hba);
+
+	if (hba->dev_info.wmanufacturerid == UFS_VENDOR_WDC)
+		hba->dev_quirks |= UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE;
+
+	ufs_spacemit_dme_set(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
+
+	return ufs_spacemit_wait_mphy_pll_lock(hba);
+}
+
+/**
+ * ufs_spacemit_advertise_quirks - advertise the known Spacemit UFS controller quirks
+ * @hba: host controller instance
+ *
+ * Spacemit UFS host controller might have some non standard behaviours (quirks)
+ * than what is specified by UFSHCI specification. Advertise all such
+ * quirks to standard UFS host controller driver so standard takes them into
+ * account.
+ */
+static void ufs_spacemit_advertise_quirks(struct ufs_hba *hba)
+{
+	hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8;
+}
+
+/**
+ * ufs_spacemit_init - init phy and prepare clk
+ * @hba: host controller instance
+ */
+static int ufs_spacemit_init(struct ufs_hba *hba)
+{
+	int err = 0;
+	struct device *dev = hba->dev;
+	struct ufs_spacemit_host *host;
+	struct reset_control *rst;
+
+	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	rst = devm_reset_control_get_exclusive_deasserted(dev, NULL);
+	if (IS_ERR(rst))
+		return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset control\n");
+
+	host->hba = hba;
+	ufshcd_set_variant(hba, host);
+	ufs_spacemit_advertise_quirks(hba);
+
+	err = ufshcd_vops_phy_initialization(host->hba);
+	return err;
+}
+
+/**
+ * ufs_spacemit_device_reset - Toggle device reset line
+ * @hba: per-adapter instance
+ *
+ * Toggles the reset line to reset the attached UFS device.
+ *
+ * Returns: 0 on success
+ */
+static int ufs_spacemit_device_reset(struct ufs_hba *hba)
+{
+	/* Stop device ref_clk & asserted ufs device reset */
+	ufshcd_writel(hba, 0x000, UFS_PHY_MNG_BASE + UFS_DEVICE_IO_CTRL);
+	usleep_range(10, 15);
+
+	/* Enable device ref_clk & de-asserted ufs device reset */
+	ufshcd_writel(hba, MPHY_DEVICE_RESET_DEASSERT, UFS_PHY_MNG_BASE + UFS_DEVICE_IO_CTRL);
+	usleep_range(10, 15);
+
+	return 0;
+}
+
+/**
+ * ufs_spacemit_event_notify - Handle UFS error events
+ * @hba: host controller instance
+ * @evt: event type
+ * @data: event-specific data
+ *
+ * Handles error events from UFS core, print warning messages
+ */
+static void ufs_spacemit_event_notify(struct ufs_hba *hba, enum ufs_event_type evt, void *data)
+{
+	switch (evt) {
+	case UFS_EVT_PA_ERR:
+		if (data)
+			dev_warn(hba->dev, "PA error event, INT errors:0x%x, PA_ERR_CODE:0x%x\n",
+				 hba->errors, *(u32 *)data);
+
+		break;
+	case UFS_EVT_DL_ERR:
+		if (data)
+			dev_warn(hba->dev, "DL error event, INT errors:0x%x, DL_ERR:0x%x\n",
+				 hba->errors, *(u32 *)data);
+
+		break;
+	case UFS_EVT_ABORT:
+		dev_warn(hba->dev, "Abort event, INT errors:0x%x\n", hba->errors);
+		break;
+	default:
+		break;
+	}
+}
+
+static void ufs_spacemit_pre_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd)
+{
+	static const struct ufshcd_dme_attr_val setup_attrs[] = {
+		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x84 },
+		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x84 },
+		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x85 },
+		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x85 },
+	};
+	int ret;
+
+	if (cmd == UIC_CMD_DME_HIBER_EXIT) {
+		/* Enable reference clock */
+		ufshcd_writel(hba, MPHY_DEVICE_RESET_DEASSERT,
+			      UFS_PHY_MNG_BASE + UFS_DEVICE_IO_CTRL);
+
+		/* Power up all */
+		ufshcd_writel(hba, MPHY_PU_ALL, UFS_PHY_MNG_BASE + UFS_MPHY_PU_CTRL);
+
+		/* Assert ana_rx_hb8_reset */
+		ufshcd_writel(hba, MPHY_PU_WITH_HB8_RESET,
+			      UFS_PHY_MNG_BASE + UFS_MPHY_PU_CTRL);
+		fsleep(500);
+
+		/* Deassert ana_rx_hb8_reset */
+		ufshcd_writel(hba, MPHY_PU_ALL, UFS_PHY_MNG_BASE + UFS_MPHY_PU_CTRL);
+
+		ret = ufs_spacemit_wait_mphy_pll_lock(hba);
+		if (ret < 0)
+			return;
+
+		ufshcd_dme_set(hba, UIC_ARG_MIB(0xdd), 0x57);
+		ufshcd_dme_set(hba, UIC_ARG_MIB(0xe8), 0x57);
+	}
+
+	if (cmd == UIC_CMD_DME_HIBER_ENTER)
+		ufs_spacemit_dme_set(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
+}
+
+static void ufs_spacemit_post_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd)
+{
+	static const struct ufshcd_dme_attr_val setup_attrs[] = {
+		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x84 },
+		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x84 },
+		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x80 },
+		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x80 },
+		{ UIC_ARG_MIB(0xdd), 0x57 },
+		{ UIC_ARG_MIB(0xdd), 0xd7 },
+		{ UIC_ARG_MIB(0xe8), 0x57 },
+		{ UIC_ARG_MIB(0xe8), 0xd7 },
+	};
+
+	if (cmd == UIC_CMD_DME_HIBER_ENTER) {
+		ufs_spacemit_check_hibern8(hba);
+
+		ufs_spacemit_dme_set(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
+
+		/* Power down M-PHY */
+		ufshcd_writel(hba, 0x0, UFS_PHY_MNG_BASE + UFS_MPHY_PU_CTRL);
+
+		/* Keep reference clock enabled, assert device reset */
+		ufshcd_writel(hba, MPHY_DEVICE_RESET_ASSERT,
+			      UFS_PHY_MNG_BASE + UFS_DEVICE_IO_CTRL);
+	}
+}
+
+/**
+ * ufs_spacemit_hibern8_notify - Handle hibernate enter/exit
+ * @hba: host controller instance
+ * @cmd: UIC command (HIBER_ENTER or HIBER_EXIT)
+ * @status: notification status
+ *
+ * Manages M-PHY power state during hibernate transitions.
+ */
+static void ufs_spacemit_hibern8_notify(struct ufs_hba *hba, enum uic_cmd_dme cmd,
+					enum ufs_notify_change_status status)
+{
+	if (status == PRE_CHANGE)
+		ufs_spacemit_pre_hibern8(hba, cmd);
+
+	if (status == POST_CHANGE)
+		ufs_spacemit_post_hibern8(hba, cmd);
+}
+
+/**
+ * struct ufs_hba_spacemit_vops - UFS Spacemit specific variant operations
+ *
+ * The variant operations configure the necessary controller and PHY
+ * handshake during initialization.
+ */
+static const struct ufs_hba_variant_ops ufs_hba_spacemit_vops = {
+	.name = "ufshcd-spacemit",
+	.init = ufs_spacemit_init,
+	.link_startup_notify = ufs_spacemit_link_startup_notify,
+	.negotiate_pwr_mode = ufs_spacemit_negotiate_pwr_mode,
+	.pwr_change_notify = ufs_spacemit_pwr_change_notify,
+	.device_reset = ufs_spacemit_device_reset,
+	.event_notify = ufs_spacemit_event_notify,
+	.apply_dev_quirks = ufs_spacemit_apply_dev_quirks,
+	.hibern8_notify = ufs_spacemit_hibern8_notify,
+};
+
+static const struct of_device_id ufs_spacemit_of_match[] = {
+	{ .compatible = "spacemit,k3-ufshc" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ufs_spacemit_of_match);
+
+static int ufs_spacemit_probe(struct platform_device *pdev)
+{
+	return ufshcd_pltfrm_init(pdev, &ufs_hba_spacemit_vops);
+}
+
+static void ufs_spacemit_remove(struct platform_device *pdev)
+{
+	ufshcd_pltfrm_remove(pdev);
+}
+
+static struct platform_driver ufs_spacemit_pltform = {
+	.probe	= ufs_spacemit_probe,
+	.remove	= ufs_spacemit_remove,
+	.driver	= {
+		.name	= "ufshcd-spacemit",
+		.of_match_table = of_match_ptr(ufs_spacemit_of_match),
+	},
+};
+module_platform_driver(ufs_spacemit_pltform);
+
+MODULE_DESCRIPTION("SpacemiT UFS Host Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ufs/host/ufs-spacemit.h b/drivers/ufs/host/ufs-spacemit.h
new file mode 100644
index 000000000000..5e459f6ba243
--- /dev/null
+++ b/drivers/ufs/host/ufs-spacemit.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * SpacemiT UFS Host Controller driver
+ *
+ * Copyright (c) 2026 SpacemiT (Hangzhou) Technology Co. Ltd
+ */
+
+#ifndef _UFS_SPACEMIT_H_
+#define _UFS_SPACEMIT_H_
+
+#include <linux/regulator/consumer.h>
+#include <linux/pm_qos.h>
+#include <linux/workqueue.h>
+
+/* Spacemit K3 UFS host controller vendor specific registers */
+#define UFS_SYS1CLK_1US			0xC0
+#define UFS_TX_SYMBOL_CLK_NS_US		0xC4
+#define UFS_LOCAL_PORT_ID_REG		0xC8
+#define UFS_PA_ERR_CODE			0xCC
+#define UFS_RETRY_TIMER_REG		0xD0
+#define UFS_PA_LINK_STARTUP_TIMER	0xD8
+#define UFS_CFG1			0xDC
+
+/* MPHY control registers */
+#define UFS_PHY_MNG_BASE		0x1B00
+#define UFS_MPHY_RST_CTRL		0x0
+#define UFS_MPHY_PU_CTRL		0x4
+#define UFS_MPHY_BKDR_CTRL		0x8
+#define UFS_DEVICE_IO_CTRL		0xC
+
+/* ATOP base*/
+#define UFS_ATOP_BASE			0x1C00
+
+#define UFS_SYSCLK			499
+#define UFS_TX_SYMBO_CLK		0x800
+#define UFS_MAX_LINKSTARTUP_TIMER	0xFFFFFFFF
+#define UFS_DL_AFC0REQTIMEOUTVAL_MAX	0xFFFF
+
+#define MPHY_TX_FSM_STATE		0x41
+#define TX_FSM_HIBERN8			0x1
+#define HBRN8_POLL_TOUT_MS		100
+#define DEFAULT_CLK_RATE_HZ		1000000
+#define BUS_VECTOR_NAME_LEN		32
+
+#define UFS_HW_VER_MAJOR_SHFT		28
+#define UFS_HW_VER_MAJOR_MASK		(0x000F << UFS_HW_VER_MAJOR_SHFT)
+#define UFS_HW_VER_MINOR_SHFT		16
+#define UFS_HW_VER_MINOR_MASK		(0x0FFF << UFS_HW_VER_MINOR_SHFT)
+#define UFS_HW_VER_STEP_SHFT		0
+#define UFS_HW_VER_STEP_MASK		(0xFFFF << UFS_HW_VER_STEP_SHFT)
+
+#define UFS_SPACEMIT_K3_LIMIT_NUM_LANES_RX	2
+#define UFS_SPACEMIT_K3_LIMIT_NUM_LANES_TX	2
+#define UFS_SPACEMIT_K3_LIMIT_HSGEAR_RX		UFS_HS_G3
+#define UFS_SPACEMIT_K3_LIMIT_HSGEAR_TX		UFS_HS_G3
+#define UFS_SPACEMIT_K3_LIMIT_PWMGEAR_RX	UFS_PWM_G4
+#define UFS_SPACEMIT_K3_LIMIT_PWMGEAR_TX	UFS_PWM_G4
+#define UFS_SPACEMIT_K3_LIMIT_RX_PWR_PWM	SLOW_MODE
+#define UFS_SPACEMIT_K3_LIMIT_TX_PWR_PWM	SLOW_MODE
+#define UFS_SPACEMIT_K3_LIMIT_RX_PWR_HS		FAST_MODE
+#define UFS_SPACEMIT_K3_LIMIT_TX_PWR_HS		FAST_MODE
+#define UFS_SPACEMIT_K3_LIMIT_HS_RATE		PA_HS_MODE_B
+#define UFS_SPACEMIT_K3_LIMIT_DESIRED_MODE	2
+
+#define UFS_PA_VS_CONFIG_REG1			0x9000
+#define UFS_DME_VS_CORE_CLK_CTRL		0xD002
+
+#define UFS_HCLKDIV_REG 0xFC
+
+struct ufs_spacemit_host {
+	struct ufs_hba *hba;
+	struct ufs_pa_layer_attr dev_req_params;
+};
+
+struct ufshcd_dme_attr_val {
+	u32 attr_sel;
+	u32 mib_val;
+};
+#endif /* _UFS_SPACEMIT_H_ */

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 3/3] riscv: dts: spacemit: k3: Add UFS support
  2026-08-06  2:56 [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC Yixun Lan
  2026-08-06  2:56 ` [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for " Yixun Lan
  2026-08-06  2:56 ` [PATCH v3 2/3] scsi: ufs: spacemit: k3: Add UFS Host Controller driver Yixun Lan
@ 2026-08-06  2:56 ` Yixun Lan
  2026-08-06  3:12   ` sashiko-bot
  2026-08-06 14:51 ` [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC Aurelien Jarno
  3 siblings, 1 reply; 11+ messages in thread
From: Yixun Lan @ 2026-08-06  2:56 UTC (permalink / raw)
  To: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, James E.J. Bottomley,
	Martin K. Petersen, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti
  Cc: Anirudh Srinivasan, Aurelien Jarno, Jennifer Berringer,
	linux-scsi, devicetree, linux-riscv, spacemit, linux-kernel,
	Yixun Lan

Add UFS Host Controller support for SpacemiT K3 SoC, and enable
it both on Pico-ITX and CoM260-IFX boards.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
 arch/riscv/boot/dts/spacemit/k3-com260.dtsi  |  4 ++++
 arch/riscv/boot/dts/spacemit/k3-pico-itx.dts |  4 ++++
 arch/riscv/boot/dts/spacemit/k3.dtsi         | 22 ++++++++++++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/arch/riscv/boot/dts/spacemit/k3-com260.dtsi b/arch/riscv/boot/dts/spacemit/k3-com260.dtsi
index a38d7b738258..a68a55c8e73d 100644
--- a/arch/riscv/boot/dts/spacemit/k3-com260.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k3-com260.dtsi
@@ -188,3 +188,7 @@ &uart0 {
 	pinctrl-0 = <&uart0_0_cfg>;
 	status = "okay";
 };
+
+&ufshc {
+	status = "okay";
+};
diff --git a/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts b/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts
index b89c1521e664..eab8c430f2d1 100644
--- a/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts
+++ b/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts
@@ -206,6 +206,10 @@ &uart0 {
 	status = "okay";
 };
 
+&ufshc {
+	status = "okay";
+};
+
 &usb2_host {
 	#address-cells = <1>;
 	#size-cells = <0>;
diff --git a/arch/riscv/boot/dts/spacemit/k3.dtsi b/arch/riscv/boot/dts/spacemit/k3.dtsi
index 19fc9b49668e..cee1569608ea 100644
--- a/arch/riscv/boot/dts/spacemit/k3.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k3.dtsi
@@ -469,6 +469,28 @@ usb2_phy: phy@c0a20000 {
 			status = "disabled";
 		};
 
+		ufshc: ufshc@c0e00000 {
+			compatible = "spacemit,k3-ufshc";
+			reg = <0x0 0xc0e00000 0x0 0x40000>;
+			clocks = <&syscon_apmu CLK_APMU_UFS_ACLK>,
+				 <&syscon_apmu CLK_APMU_UFS_REFCLK>;
+			clock-names = "aclk", "ref_clk";
+			resets = <&syscon_apmu RESET_APMU_UFS_ACLK>;
+			interrupts = <135 IRQ_TYPE_LEVEL_HIGH>;
+			lanes-per-direction = <2>;
+			operating-points-v2 = <&ufs_opp_table>;
+			status = "disabled";
+
+			ufs_opp_table: opp-table {
+				compatible = "operating-points-v2";
+
+				opp-1 {
+					opp-hz = /bits/ 64 <491520000>,
+						 /bits/ 64 <19200000>;
+				};
+			};
+		};
+
 		eth0: ethernet@cac80000 {
 			compatible = "spacemit,k3-dwmac", "snps,dwmac-5.40a";
 			reg = <0x0 0xcac80000 0x0 0x2000>;

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 2/3] scsi: ufs: spacemit: k3: Add UFS Host Controller driver
  2026-08-06  2:56 ` [PATCH v3 2/3] scsi: ufs: spacemit: k3: Add UFS Host Controller driver Yixun Lan
@ 2026-08-06  3:10   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-06  3:10 UTC (permalink / raw)
  To: Yixun Lan; +Cc: linux-scsi, robh, devicetree, conor+dt

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Vendor M-PHY TX attributes are only configured for TX Lane 0, neglecting Lane 1 in a 2-lane setup.
- [High] Hardcoded dual-lane check in `ufs_spacemit_check_hibern8` will fail and timeout on 1-lane UFS devices.
- [High] The UFS hardware reset pulse width is too short, violating the JEDEC UFS specification.
- [Medium] Misleading macro names and comments for device reset contradict hardware behavior.
- [Medium] Silently ignoring DME configuration errors.
- [Low] Usage of `of_match_ptr` causes build warnings when `CONFIG_OF` is disabled.
--

--- Patch [2]: [PATCH v3 2/3] scsi: ufs: spacemit: k3: Add UFS Host Controller driver ---
commit a6bb8f511d306cddb9d21e41123fafdbcd63a6c9
Author: Yixun Lan <dlan@kernel.org>
Subject: scsi: ufs: spacemit: k3: Add UFS Host Controller driver

SpacemiT K3 SoC consist of UFS (Universal Flash Storage) Host Controller
which has features compatible with JEDEC UFS 2.2, MIPI UniPro v1.61 and
M-PHY v3.0 standard.

> diff --git a/drivers/ufs/host/ufs-spacemit.c b/drivers/ufs/host/ufs-spacemit.c
> new file mode 100644
> index 0000000000000..94942ea27fb7d
> --- /dev/null
> +++ b/drivers/ufs/host/ufs-spacemit.c

[ ... ]

> +/* PHY register magic values */
> +#define MPHY_PU_ALL			0x87f
> +#define MPHY_PU_WITH_HB8_RESET		0xb7f
> +#define MPHY_DEVICE_RESET_DEASSERT	0x101
> +#define MPHY_DEVICE_RESET_ASSERT	0x001

[Severity: Medium]
Is this macro name misleading? Looking at ufs_spacemit_device_reset(), it
uses 0x000 to assert the reset and 0x101 to de-assert it. This means 0x001
actually disables the reference clock while keeping the reset de-asserted.

[ ... ]

> +static int ufs_spacemit_check_hibern8(struct ufs_hba *hba)
> +{
> +	u32 tx_fsm_val_0 = 0;
> +	u32 tx_fsm_val_1 = 0;
> +	int retries = DIV_ROUND_UP(HBRN8_POLL_TOUT_MS * 1000, 100);
> +	int err = 0;
> +
> +	do {
> +		err = ufshcd_dme_get(hba,
> +				     UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
> +						     UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
> +				     &tx_fsm_val_0);
> +		if (err)
> +			break;
> +
> +		err = ufshcd_dme_get(hba,
> +				     UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
> +						     UIC_ARG_MPHY_TX_GEN_SEL_INDEX(1)),
> +				     &tx_fsm_val_1);
> +		if (err || (tx_fsm_val_0 == TX_FSM_HIBERN8 &&
> +			    tx_fsm_val_1 == TX_FSM_HIBERN8))
> +			break;

[Severity: High]
Will this hardcoded dual-lane check timeout on single-lane UFS devices?

If a 1-lane memory chip is connected, Lane 1 is inactive. Querying its state
will either return a DME error or read a non-Hibern8 state, causing the loop
to timeout after 100ms and break power management.

Could this check be updated to use the dynamically negotiated lane count from
dev_req_params to know how many lanes to poll?

[ ... ]

> +static int ufs_spacemit_uniprov1p6_init(struct ufs_hba *hba)
> +{
> +	static const struct ufshcd_dme_attr_val setup_attrs[] = {
> +		{ UIC_ARG_MIB(0x1552), 0x4f }, /* PA_TXHSG1SYNCLENGTH */
[ ... ]
> +		/* RX HB8_TIME CAP */
> +		{ UIC_ARG_MIB_SEL(0x0092, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x64 },
> +		{ UIC_ARG_MIB_SEL(0x0092, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x64 },
> +		/* TX EQ 3DB */
> +		{ UIC_ARG_MIB_SEL(0x00CD, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),  0x5 },

[Severity: High]
Should this TX equalization be applied to Lane 1 as well?

The host controller is configured for 2 lanes, but this setup attribute only
targets UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0). Omitting tuning parameters for the
second lane could cause asymmetric lane configurations or link instability.

[ ... ]

> +static int ufs_spacemit_link_startup_post_change(struct ufs_hba *hba)
> +{
> +	/* Add 0xe8 make UFS2.1 run GEAR3 + 2Lane@409M */
> +	static const struct ufshcd_dme_attr_val setup_attrs[] = {
> +		{ UIC_ARG_MIB_SEL(0xe8, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0x97 },
> +		{ UIC_ARG_MIB_SEL(0xe8, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0xd7 },
> +		{ UIC_ARG_MIB_SEL(0xe8, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0x17 },

[Severity: High]
Does attribute 0xe8 need to be programmed for both lanes?

Similar to the TX equalization setup, this only programs Lane 0 despite the
driver specifying dual-lane support.

[ ... ]

> +static int ufs_spacemit_apply_dev_quirks(struct ufs_hba *hba)
> +{
> +	static const struct ufshcd_dme_attr_val setup_attrs[] = {
[ ... ]
> +	};
> +
> +	if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME)
> +		ufs_spacemit_quirk_host_pa_saveconfigtime(hba);
> +
> +	if (hba->dev_info.wmanufacturerid == UFS_VENDOR_WDC)
> +		hba->dev_quirks |= UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE;
> +
> +	ufs_spacemit_dme_set(hba, setup_attrs, ARRAY_SIZE(setup_attrs));

[Severity: Medium]
Is it safe to ignore the return values of these DME configuration functions?

If ufs_spacemit_quirk_host_pa_saveconfigtime() or ufs_spacemit_dme_set()
fail, the errors are not propagated. Could this allow initialization to proceed
with an incorrectly configured M-PHY?

[ ... ]

> +static int ufs_spacemit_device_reset(struct ufs_hba *hba)
> +{
> +	/* Stop device ref_clk & asserted ufs device reset */
> +	ufshcd_writel(hba, 0x000, UFS_PHY_MNG_BASE + UFS_DEVICE_IO_CTRL);
> +	usleep_range(10, 15);

[Severity: High]
Is this reset pulse width long enough?

The JEDEC UFS specification mandates that the host must maintain the RST_n
signal low for a minimum of 1 ms. A 10 to 15 microsecond delay might cause
the memory chip to fail to reset properly.

[ ... ]

> +static void ufs_spacemit_post_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd)
> +{
> +	static const struct ufshcd_dme_attr_val setup_attrs[] = {
> +		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x84 },
> +		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x84 },
> +		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x80 },
> +		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x80 },
> +		{ UIC_ARG_MIB(0xdd), 0x57 },
> +		{ UIC_ARG_MIB(0xdd), 0xd7 },
> +		{ UIC_ARG_MIB(0xe8), 0x57 },
> +		{ UIC_ARG_MIB(0xe8), 0xd7 },

[Severity: High]
Are these attributes defaulting to Lane 0?

Using UIC_ARG_MIB() defaults to Lane 0. If these need to be applied to Lane 1
as well during post-Hibern8 configuration, they are currently missing.

[ ... ]

> +	if (cmd == UIC_CMD_DME_HIBER_ENTER) {
> +		ufs_spacemit_check_hibern8(hba);
> +
> +		ufs_spacemit_dme_set(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
> +
> +		/* Power down M-PHY */
> +		ufshcd_writel(hba, 0x0, UFS_PHY_MNG_BASE + UFS_MPHY_PU_CTRL);
> +
> +		/* Keep reference clock enabled, assert device reset */
> +		ufshcd_writel(hba, MPHY_DEVICE_RESET_ASSERT,
> +			      UFS_PHY_MNG_BASE + UFS_DEVICE_IO_CTRL);

[Severity: Medium]
Does this operation contradict its comment?

The code writes MPHY_DEVICE_RESET_ASSERT (0x001), which disables the reference
clock but keeps the reset de-asserted. The comment says "Keep reference clock
enabled, assert device reset", which is the exact opposite.

While keeping reset de-asserted is the correct action for Hibern8 (asserting
reset would destroy the device's state), the comment and macro name suggest
incorrect hardware behavior.

[ ... ]

> +static struct platform_driver ufs_spacemit_pltform = {
> +	.probe	= ufs_spacemit_probe,
> +	.remove	= ufs_spacemit_remove,
> +	.driver	= {
> +		.name	= "ufshcd-spacemit",
> +		.of_match_table = of_match_ptr(ufs_spacemit_of_match),
> +	},
> +};

[Severity: Low]
Does the use of of_match_ptr() here cause a compiler warning?

Because ufs_spacemit_of_match is defined unconditionally, building with
CONFIG_OF disabled will evaluate of_match_ptr() to NULL, leaving the array
unused and triggering a -Wunused-variable warning.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260806-08-k3-ufs-support-v3-0-037fb322acdb@kernel.org?part=2

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 3/3] riscv: dts: spacemit: k3: Add UFS support
  2026-08-06  2:56 ` [PATCH v3 3/3] riscv: dts: spacemit: k3: Add UFS support Yixun Lan
@ 2026-08-06  3:12   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-06  3:12 UTC (permalink / raw)
  To: Yixun Lan; +Cc: conor+dt, linux-scsi, robh, devicetree

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Failure to enter HIBERN8 state is ignored before forcibly powering down the M-PHY.
- [High] Missing DME attributes configuration for TX lane 1 and inconsistent MIB selector usage.
- [Medium] The retrieved connected TX lanes value is silently discarded.
- [Low] Redundant and ineffective call to `ufshcd_vops_phy_initialization`.
- [Low] The device tree references an undefined clock macro `CLK_APMU_UFS_REFCLK`, which causes a Device Tree compilation failure.
--

--- Patch [3]: [PATCH v3 3/3] riscv: dts: spacemit: k3: Add UFS support ---
commit 7b2ecae3ba0ff920d65fce0475cce3fc5045f08d
Author: Yixun Lan <dlan@kernel.org>
Subject: riscv: dts: spacemit: k3: Add UFS support

Add UFS Host Controller support for SpacemiT K3 SoC, and enable
it both on Pico-ITX and CoM260-IFX boards.

> diff --git a/arch/riscv/boot/dts/spacemit/k3.dtsi b/arch/riscv/boot/dts/spacemit/k3.dtsi
> index 19fc9b49668ed..cee1569608ea2 100644
> --- a/arch/riscv/boot/dts/spacemit/k3.dtsi
> +++ b/arch/riscv/boot/dts/spacemit/k3.dtsi
> @@ -469,6 +469,28 @@ usb2_phy: phy@c0a20000 {
>  			status = "disabled";
>  		};
>  
> +		ufshc: ufshc@c0e00000 {
> +			compatible = "spacemit,k3-ufshc";
> +			reg = <0x0 0xc0e00000 0x0 0x40000>;
> +			clocks = <&syscon_apmu CLK_APMU_UFS_ACLK>,
> +				 <&syscon_apmu CLK_APMU_UFS_REFCLK>;

[Severity: Low]
Does this reference an undefined clock macro?

The device tree references CLK_APMU_UFS_REFCLK, but this macro appears to be
undefined. Will this cause a compilation failure when building the device tree?

[ ... ]

> diff --git a/drivers/ufs/host/ufs-spacemit.c b/drivers/ufs/host/ufs-spacemit.c
> new file mode 100644
> index 0000000000000..94942ea27fb7d
> --- /dev/null
> +++ b/drivers/ufs/host/ufs-spacemit.c
> @@ -0,0 +1,687 @@

[ ... ]

> +static int ufs_spacemit_uniprov1p6_init(struct ufs_hba *hba)
> +{
> +	static const struct ufshcd_dme_attr_val setup_attrs[] = {

[ ... ]

> +		/* TX HB8_TIME CAP */
> +		{ UIC_ARG_MIB_SEL(0x000F, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0x64 },
> +		{ UIC_ARG_MIB_SEL(0x000F, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(1)), 0x64 },
> +		/* RX HB8_TIME CAP */
> +		{ UIC_ARG_MIB_SEL(0x0092, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x64 },
> +		{ UIC_ARG_MIB_SEL(0x0092, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x64 },
> +		/* TX EQ 3DB */
> +		{ UIC_ARG_MIB_SEL(0x00CD, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),  0x5 },

[Severity: High]
Are we missing the TX EQ 3DB configuration for lane 1 here?

The device tree specifies lanes-per-direction = <2>, but this DME attribute
is only configured for TX lane 0. Could this leave lane 1 with undefined or
default parameters and prevent successful 2-lane initialization?

[ ... ]

> +static int ufs_spacemit_link_startup_post_change(struct ufs_hba *hba)
> +{
> +	/* Add 0xe8 make UFS2.1 run GEAR3 + 2Lane@409M */
> +	static const struct ufshcd_dme_attr_val setup_attrs[] = {
> +		{ UIC_ARG_MIB_SEL(0xe8, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0x97 },
> +		{ UIC_ARG_MIB_SEL(0xe8, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0xd7 },
> +		{ UIC_ARG_MIB_SEL(0xe8, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), 0x17 },

[Severity: High]
Is the DME configuration for TX lane 1 missing?

Similar to ufs_spacemit_uniprov1p6_init(), attribute 0xe8 is explicitly
targeting only lane 0. Does lane 1 also need to be configured for 2-lane mode?

> +		{ UIC_ARG_MIB(DL_AFC0REQTIMEOUTVAL), UFS_DL_AFC0REQTIMEOUTVAL_MAX },
> +	};
> +	u32 tx_lanes;
> +	int err;
> +
> +	err = ufs_spacemit_dme_set(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
> +	if (err < 0)
> +		return err;
> +
> +	return ufs_spacemit_get_connected_tx_lanes(hba, &tx_lanes);

[Severity: Medium]
Is the retrieved tx_lanes value meant to be used?

The value of tx_lanes is populated by ufs_spacemit_get_connected_tx_lanes()
but is then silently discarded when returning. Should this value be verified
against the configuration?

[ ... ]

> +static void ufs_spacemit_post_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd)
> +{
> +	static const struct ufshcd_dme_attr_val setup_attrs[] = {
> +		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x84 },
> +		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x84 },
> +		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x80 },
> +		{ UIC_ARG_MIB_SEL(0xf1, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x80 },
> +		{ UIC_ARG_MIB(0xdd), 0x57 },
> +		{ UIC_ARG_MIB(0xdd), 0xd7 },
> +		{ UIC_ARG_MIB(0xe8), 0x57 },
> +		{ UIC_ARG_MIB(0xe8), 0xd7 },
> +	};
> +
> +	if (cmd == UIC_CMD_DME_HIBER_ENTER) {
> +		ufs_spacemit_check_hibern8(hba);
> +
> +		ufs_spacemit_dme_set(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
> +
> +		/* Power down M-PHY */
> +		ufshcd_writel(hba, 0x0, UFS_PHY_MNG_BASE + UFS_MPHY_PU_CTRL);

[Severity: High]
Should we check the return value of ufs_spacemit_check_hibern8(hba) before
powering down the M-PHY?

If the HIBERN8 check times out and returns -ETIMEDOUT, the error is ignored
and the driver unconditionally powers down the PHY. Can this cause a bus lockup
or hardware error if the M-PHY isn't actually in the HIBERN8 state?

[ ... ]

> +static int ufs_spacemit_init(struct ufs_hba *hba)
> +{
> +	int err = 0;
> +	struct device *dev = hba->dev;
> +	struct ufs_spacemit_host *host;
> +	struct reset_control *rst;
> +
> +	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
> +	if (!host)
> +		return -ENOMEM;
> +
> +	rst = devm_reset_control_get_exclusive_deasserted(dev, NULL);
> +	if (IS_ERR(rst))
> +		return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset control\n");
> +
> +	host->hba = hba;
> +	ufshcd_set_variant(hba, host);
> +	ufs_spacemit_advertise_quirks(hba);
> +
> +	err = ufshcd_vops_phy_initialization(host->hba);
> +	return err;
> +}

[Severity: Low]
Is this call to ufshcd_vops_phy_initialization() effective?

ufs_hba_spacemit_vops does not define the phy_initialization callback, so
the wrapper function will silently return 0. Does this need to be called here,
or is it redundant since the real PHY initialization occurs in
ufs_spacemit_link_startup_pre_change()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260806-08-k3-ufs-support-v3-0-037fb322acdb@kernel.org?part=3

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for K3 SoC
  2026-08-06  2:56 ` [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for " Yixun Lan
@ 2026-08-06  4:39   ` Rob Herring (Arm)
  2026-08-06  7:05   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 11+ messages in thread
From: Rob Herring (Arm) @ 2026-08-06  4:39 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Alexandre Ghiti, Martin K. Petersen, Anirudh Srinivasan,
	linux-scsi, Avri Altman, spacemit, Palmer Dabbelt, linux-riscv,
	linux-kernel, Paul Walmsley, Aurelien Jarno, Albert Ou,
	Bart Van Assche, Alim Akhtar, Jennifer Berringer, devicetree,
	Krzysztof Kozlowski, Conor Dooley, James E.J. Bottomley,
	Philipp Zabel


On Thu, 06 Aug 2026 02:56:18 +0000, Yixun Lan wrote:
> Document the compatible for UFS (Universal Flash Storage) Host Controller
> which found in SpacemiT K3 SoC chip. Its features are listed below:
> 
> - Compliant with MIPI UniPro v1.61 specification.
> - Compliant with M-PHY v3.0 specification.
> - Compliant with UFS HCI v2.1 specification.
> - Supports up to 2 Tx and 2 Rx lanes, up to HS-GEAR3 5.8 Gbps per lane.
> - Supports standard low-power hibernate to reduce power consumption.
> 
> Signed-off-by: Yixun Lan <dlan@kernel.org>
> ---
>  .../devicetree/bindings/ufs/spacemit,k3-ufshc.yaml | 56 ++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Lexical error: Documentation/devicetree/bindings/ufs/spacemit,k3-ufshc.example.dts:31.36-55 Unexpected 'CLK_APMU_UFS_REFCLK'
FATAL ERROR: Syntax error parsing input tree
make[2]: *** [scripts/Makefile.dtbs:140: Documentation/devicetree/bindings/ufs/spacemit,k3-ufshc.example.dtb] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1669: dt_binding_check] Error 2
make: *** [Makefile:248: __sub-make] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20260806-08-k3-ufs-support-v3-1-037fb322acdb@kernel.org

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for K3 SoC
  2026-08-06  2:56 ` [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for " Yixun Lan
  2026-08-06  4:39   ` Rob Herring (Arm)
@ 2026-08-06  7:05   ` Krzysztof Kozlowski
  2026-08-06  7:46     ` Yixun Lan
  1 sibling, 1 reply; 11+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-06  7:05 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, James E.J. Bottomley,
	Martin K. Petersen, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Anirudh Srinivasan, Aurelien Jarno,
	Jennifer Berringer, linux-scsi, devicetree, linux-riscv, spacemit,
	linux-kernel

On Thu, Aug 06, 2026 at 02:56:18AM +0000, Yixun Lan wrote:
> Document the compatible for UFS (Universal Flash Storage) Host Controller
> which found in SpacemiT K3 SoC chip. Its features are listed below:
> 
> - Compliant with MIPI UniPro v1.61 specification.
> - Compliant with M-PHY v3.0 specification.
> - Compliant with UFS HCI v2.1 specification.
> - Supports up to 2 Tx and 2 Rx lanes, up to HS-GEAR3 5.8 Gbps per lane.
> - Supports standard low-power hibernate to reduce power consumption.
> 
> Signed-off-by: Yixun Lan <dlan@kernel.org>
> ---

You keep having the same failure for every version, no? Never responded to it...

I'll drop from Patchwork.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for K3 SoC
  2026-08-06  7:05   ` Krzysztof Kozlowski
@ 2026-08-06  7:46     ` Yixun Lan
  2026-08-06  7:57       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 11+ messages in thread
From: Yixun Lan @ 2026-08-06  7:46 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, James E.J. Bottomley,
	Martin K. Petersen, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Anirudh Srinivasan, Aurelien Jarno,
	Jennifer Berringer, linux-scsi, devicetree, linux-riscv, spacemit,
	linux-kernel


On 09:05 Thu 06 Aug     , Krzysztof Kozlowski wrote:
> On Thu, Aug 06, 2026 at 02:56:18AM +0000, Yixun Lan wrote:
> > Document the compatible for UFS (Universal Flash Storage) Host Controller
> > which found in SpacemiT K3 SoC chip. Its features are listed below:
> > 
> > - Compliant with MIPI UniPro v1.61 specification.
> > - Compliant with M-PHY v3.0 specification.
> > - Compliant with UFS HCI v2.1 specification.
> > - Supports up to 2 Tx and 2 Rx lanes, up to HS-GEAR3 5.8 Gbps per lane.
> > - Supports standard low-power hibernate to reduce power consumption.
> > 
> > Signed-off-by: Yixun Lan <dlan@kernel.org>
> > ---
> 
> You keep having the same failure for every version, no? Never responded to it...
> 
sorry, I should respond in previous series

for the Unexpected 'CLK_APMU_UFS_REFCLK' error, it depend on UFS clock patch[1],
also I've sent a PR to clock maintainer for inclusion to v7.3 [2], It should be
solved after v7.3-rc1 if all things goes well

Link: https://lore.kernel.org/all/20260630-06-clk-ufs-support-v1-2-cf7521d1d0fe@kernel.org/ [1] 
Link: https://lore.kernel.org/all/20260802014217-KYC2734409@kernel.org [2]
-- 
Yixun Lan (dlan)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for K3 SoC
  2026-08-06  7:46     ` Yixun Lan
@ 2026-08-06  7:57       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 11+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-06  7:57 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, James E.J. Bottomley,
	Martin K. Petersen, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Anirudh Srinivasan, Aurelien Jarno,
	Jennifer Berringer, linux-scsi, devicetree, linux-riscv, spacemit,
	linux-kernel

On 06/08/2026 09:46, Yixun Lan wrote:
> 
> On 09:05 Thu 06 Aug     , Krzysztof Kozlowski wrote:
>> On Thu, Aug 06, 2026 at 02:56:18AM +0000, Yixun Lan wrote:
>>> Document the compatible for UFS (Universal Flash Storage) Host Controller
>>> which found in SpacemiT K3 SoC chip. Its features are listed below:
>>>
>>> - Compliant with MIPI UniPro v1.61 specification.
>>> - Compliant with M-PHY v3.0 specification.
>>> - Compliant with UFS HCI v2.1 specification.
>>> - Supports up to 2 Tx and 2 Rx lanes, up to HS-GEAR3 5.8 Gbps per lane.
>>> - Supports standard low-power hibernate to reduce power consumption.
>>>
>>> Signed-off-by: Yixun Lan <dlan@kernel.org>
>>> ---
>>
>> You keep having the same failure for every version, no? Never responded to it...
>>
> sorry, I should respond in previous series
> 
> for the Unexpected 'CLK_APMU_UFS_REFCLK' error, it depend on UFS clock patch[1],
> also I've sent a PR to clock maintainer for inclusion to v7.3 [2], It should be
> solved after v7.3-rc1 if all things goes well

So this cannot be tested and applied via UFS tree. Please do not send
new versions before dependency hits mainline (or decouple dependencies
as usually we recommend in such case).

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC
  2026-08-06  2:56 [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC Yixun Lan
                   ` (2 preceding siblings ...)
  2026-08-06  2:56 ` [PATCH v3 3/3] riscv: dts: spacemit: k3: Add UFS support Yixun Lan
@ 2026-08-06 14:51 ` Aurelien Jarno
  3 siblings, 0 replies; 11+ messages in thread
From: Aurelien Jarno @ 2026-08-06 14:51 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, James E.J. Bottomley,
	Martin K. Petersen, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Anirudh Srinivasan,
	Jennifer Berringer, linux-scsi, devicetree, linux-riscv, spacemit,
	linux-kernel

On 2026-08-06 02:56, Yixun Lan wrote:
> This series try to add UFS support for SpacemiT K3 SoC, the controller
> components consists of System Bus Interface Unit, UFS Host Controller
> Interface, UFS Transport Protocol Layer, UFS Host Registers, Device
> Management Entity (DME), Transport Layer, Network Layer, Data Link
> Layer, PHY Adapter Layer, and M-PHY Interface. A more detail functional
> block diagram can be found in SpacemiT website, chapter 9.7.3 [1]
> 
> Please note, in order to test this driver, the UFS clock driver[2] here
> should be applied first as a prerequisite patch.
> 
> One known issue is that the device will occasionally raise BKOPS interrupt
> when doing some high load test, log from dmesg shows
> 
> [  806.710763] ufshcd-spacemit c0e00000.ufshc: ufshcd_bkops_exception_event_handler: device raised urgent BKOPS exception for bkops status 1
> 
> Link: https://spacemit.com/community/document/info?nodepath=hardware/key_stone/k3/k3_docs/k3_usermanual/09_memory_storage.md&lang=en [1]
> Link: https://lore.kernel.org/all/20260630-06-clk-ufs-support-v1-0-cf7521d1d0fe@kernel.org/ [2]
> Signed-off-by: Yixun Lan <dlan@kernel.org>
> ---
> Changes in v3:
> - fix dt-binding warning reported-by sashiko
> - fix low freq in opp-2 table
> - fix err checking in check_hibern8()
> - propagate err code in link_startup_notify()
> - update documents for event_notify()
> - Link to v2: https://patch.msgid.link/20260725-08-k3-ufs-support-v2-0-45036a2a2418@kernel.org
> 
> Changes in v2:
> - fix missing interrupts property
> - move ufs node to k3-com260.dtsi
> - convert freq-table-hz to operating-points-v2
> - rework reset_control, fix header and drop global variable
> - drop dump_host_regs() debug interface
> - converge and refactor dme_set() operations
> - massive reduce of busy delay() loops
> - drop vendor specific hce_enable_notify(), fallback to default
> - drop unused member from struct ufs_spacemit_host
> - add COMPILE_TEST support to Kconfig
> - comment style fix
> - Link to v1: https://patch.msgid.link/20260702-08-k3-ufs-support-v1-0-1a64a3ab128f@kernel.org
> 
> ---
> Yixun Lan (3):
>       scsi: ufs: spacemit: dt-bindings: Add UFS controller for K3 SoC
>       scsi: ufs: spacemit: k3: Add UFS Host Controller driver
>       riscv: dts: spacemit: k3: Add UFS support
> 
>  .../devicetree/bindings/ufs/spacemit,k3-ufshc.yaml |  56 ++
>  arch/riscv/boot/dts/spacemit/k3-com260.dtsi        |   4 +
>  arch/riscv/boot/dts/spacemit/k3-pico-itx.dts       |   4 +
>  arch/riscv/boot/dts/spacemit/k3.dtsi               |  22 +
>  drivers/ufs/host/Kconfig                           |  12 +
>  drivers/ufs/host/Makefile                          |   1 +
>  drivers/ufs/host/ufs-spacemit.c                    | 687 +++++++++++++++++++++
>  drivers/ufs/host/ufs-spacemit.h                    |  79 +++
>  8 files changed, 865 insertions(+)
> ---
> base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
> change-id: 20260605-08-k3-ufs-support-c8b308e415e2
> 

Thanks for this new version, and no worries about not adding the 
previous Tested-by tags. I have also tested this version, so patches 2 
and 3 are:

Tested-by: Aurelien Jarno <aurelien@aurel32.net>

Regards
Aurelien

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                     http://aurel32.net

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-08-06 15:24 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-06  2:56 [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC Yixun Lan
2026-08-06  2:56 ` [PATCH v3 1/3] scsi: ufs: spacemit: dt-bindings: Add UFS controller for " Yixun Lan
2026-08-06  4:39   ` Rob Herring (Arm)
2026-08-06  7:05   ` Krzysztof Kozlowski
2026-08-06  7:46     ` Yixun Lan
2026-08-06  7:57       ` Krzysztof Kozlowski
2026-08-06  2:56 ` [PATCH v3 2/3] scsi: ufs: spacemit: k3: Add UFS Host Controller driver Yixun Lan
2026-08-06  3:10   ` sashiko-bot
2026-08-06  2:56 ` [PATCH v3 3/3] riscv: dts: spacemit: k3: Add UFS support Yixun Lan
2026-08-06  3:12   ` sashiko-bot
2026-08-06 14:51 ` [PATCH v3 0/3] Add UFS Host driver support for SpacemiT K3 SoC Aurelien Jarno

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).