public inbox for devicetree@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/3] Add SDHCI support for Canaan K230 SoC
@ 2026-03-15  5:44 Jiayu Du
  2026-03-15  5:44 ` [PATCH v4 1/3] dt-bindings: mmc: Add sdhci support for Canaan k230 Jiayu Du
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Jiayu Du @ 2026-03-15  5:44 UTC (permalink / raw)
  To: krzk, ulf.hansson, adrian.hunter, robh, krzk+dt, conor+dt
  Cc: pjw, palmer, aou, linux-mmc, devicetree, linux-riscv,
	linux-kernel, gaohan, me, Jiayu Du

This series is based on the k230 usbphy series[1].

This patch series adds SDHCI support for the Canaan K230 SoC,
which uses Synopsys DWCMSHC SDHCI controllers, include MMC0 and MMC1.
The hardware designs of these two controllers are different.
The MMC0 supports eMMC, while MMC1 only supports SDIO. Detailed
information can be found in the vendor's manual[2].

From the vendor's K230 manual:
 - MMC0 supports eMMC5.0 and SDIO3.0, usually for eMMC chips.
 - MMC1 only does SDIO3.0 in 4/1-bit mode up to SDR104, and the manual
   clearly says it can't handle eMMC because of pin count and limits.

Therefore, there are two separate compatibles and the driver treats them
differently.

Link: https://lore.kernel.org/all/20260121145526.14672-1-jiayu.riscv@isrc.iscas.ac.cn/ [1]
Link: https://github.com/kendryte/k230_docs/blob/main/en/00_hardware/K230_Hardware_Design_Guide.md#mmc-circuit [2]

Changes in v4:
- Drop the unnecessary line wrapping.
- Drop the extra match_data pointer that was added in v3.
- Add struct k230_pltfm_data which embeds struct dwcmshc_pltfm_data.
- Use container_of() to get k230_pltfm_data.
- Link to v3: https://lore.kernel.org/all/20260310064513.140093-1-jiayu.riscv@isrc.iscas.ac.cn/

Changes in v3:
- Drop the clock maxItems.
- Add a const void *match_data to the struct dwcmshc_priv
- Copy the match_data pointer to dwcmshc_priv in the common dwcmshc_probe
- Link to v2: https://lore.kernel.org/all/20260226115923.75670-1-jiayu.riscv@isrc.iscas.ac.cn/

Changes in v2:
- Change the clock minItems to 5.
- Add comments to explain the reason for setting SDHCI_PROG_CLOCK_MODE.
- Write the power selection logic in the phy init cleaner.
- Replace manual delay loop with read_poll_timeout.
- Drop unnecessarily braces where a single statement will do.
- Add the match_data pointer to dwcmshc_pltfm_data.
- Add dwcmshc_k230_match_data struct to separate eMMC/SDIO config data
- Split K230 into individual emmc/sdio platform data instances instead of
  sharing one.
- Remove redundant have_phy member in k230_priv.
- Replace of_find_compatible_node with of_parse_phandle to get USB PHY
  from DT phandle.
- Link to v1: https://lore.kernel.org/all/20260204082908.27501-1-jiayu.riscv@isrc.iscas.ac.cn/

Jiayu Du (3):
  dt-bindings: mmc: Add sdhci support for Canaan k230
  mmc: sdhci-dwcmshc: Add Canaan K230 DWCMSHC controller support
  riscv: dts: canaan: Add mmc nodes for K230

 .../bindings/mmc/snps,dwcmshc-sdhci.yaml      |  28 ++
 .../boot/dts/canaan/k230-canmv-dshanpi.dts    |  56 ++++
 .../dts/canaan/k230-canmv-module-dshanpi.dtsi |   7 +
 arch/riscv/boot/dts/canaan/k230.dtsi          |  28 ++
 drivers/mmc/host/sdhci-of-dwcmshc.c           | 277 ++++++++++++++++++
 5 files changed, 396 insertions(+)

-- 
2.53.0


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

* [PATCH v4 1/3] dt-bindings: mmc: Add sdhci support for Canaan k230
  2026-03-15  5:44 [PATCH v4 0/3] Add SDHCI support for Canaan K230 SoC Jiayu Du
@ 2026-03-15  5:44 ` Jiayu Du
  2026-03-15  5:44 ` [PATCH v4 2/3] mmc: sdhci-dwcmshc: Add Canaan K230 DWCMSHC controller support Jiayu Du
  2026-03-15  5:44 ` [PATCH v4 3/3] riscv: dts: canaan: Add mmc nodes for K230 Jiayu Du
  2 siblings, 0 replies; 8+ messages in thread
From: Jiayu Du @ 2026-03-15  5:44 UTC (permalink / raw)
  To: krzk, ulf.hansson, adrian.hunter, robh, krzk+dt, conor+dt
  Cc: pjw, palmer, aou, linux-mmc, devicetree, linux-riscv,
	linux-kernel, gaohan, me, Jiayu Du, Conor Dooley

The Canaan k230 uses the SDHCI from Synopsys. Add compatible strings
to the k230. The k230 has two controllers. MMC0 supports eMMC, while
MMC1 supports SDIO.

Signed-off-by: Jiayu Du <jiayu.riscv@isrc.iscas.ac.cn>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
---
 .../bindings/mmc/snps,dwcmshc-sdhci.yaml      | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
index 5cebe5eb1efb..2e3ac1053065 100644
--- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
@@ -23,6 +23,8 @@ properties:
           - const: sophgo,sg2044-dwcmshc
           - const: sophgo,sg2042-dwcmshc
       - enum:
+          - canaan,k230-emmc
+          - canaan,k230-sdio
           - rockchip,rk3568-dwcmshc
           - rockchip,rk3588-dwcmshc
           - snps,dwcmshc-sdhci
@@ -57,6 +59,11 @@ properties:
     minItems: 4
     maxItems: 5
 
+  canaan,usb-phy:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Phandle to the Canaan K230 USB PHY node required for
+                 k230-emmc/sdio.
+
   rockchip,txclk-tapnum:
     description: Specify the number of delay for tx sampling.
     $ref: /schemas/types.yaml#/definitions/uint8
@@ -89,6 +96,27 @@ required:
 allOf:
   - $ref: mmc-controller.yaml#
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - canaan,k230-emmc
+              - canaan,k230-sdio
+    then:
+      properties:
+        clocks:
+          minItems: 5
+        clock-names:
+          items:
+            - const: core
+            - const: bus
+            - const: axi
+            - const: block
+            - const: timer
+      required:
+        - canaan,usb-phy
+
   - if:
       properties:
         compatible:
-- 
2.53.0


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

* [PATCH v4 2/3] mmc: sdhci-dwcmshc: Add Canaan K230 DWCMSHC controller support
  2026-03-15  5:44 [PATCH v4 0/3] Add SDHCI support for Canaan K230 SoC Jiayu Du
  2026-03-15  5:44 ` [PATCH v4 1/3] dt-bindings: mmc: Add sdhci support for Canaan k230 Jiayu Du
@ 2026-03-15  5:44 ` Jiayu Du
  2026-03-16 12:33   ` Adrian Hunter
  2026-03-15  5:44 ` [PATCH v4 3/3] riscv: dts: canaan: Add mmc nodes for K230 Jiayu Du
  2 siblings, 1 reply; 8+ messages in thread
From: Jiayu Du @ 2026-03-15  5:44 UTC (permalink / raw)
  To: krzk, ulf.hansson, adrian.hunter, robh, krzk+dt, conor+dt
  Cc: pjw, palmer, aou, linux-mmc, devicetree, linux-riscv,
	linux-kernel, gaohan, me, Jiayu Du

Add SDHCI controller driver for Canaan k230 SoC. Implement custom
sdhci_ops for set_clock, phy init, init and reset.

Signed-off-by: Jiayu Du <jiayu.riscv@isrc.iscas.ac.cn>
---
 drivers/mmc/host/sdhci-of-dwcmshc.c | 277 ++++++++++++++++++++++++++++
 1 file changed, 277 insertions(+)

diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
index 2b75a36c096b..489274c39141 100644
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -128,9 +128,11 @@
 #define PHY_CNFG_PHY_PWRGOOD_MASK	BIT_MASK(1) /* bit [1] */
 #define PHY_CNFG_PAD_SP_MASK		GENMASK(19, 16) /* bits [19:16] */
 #define PHY_CNFG_PAD_SP			0x0c /* PMOS TX drive strength */
+#define PHY_CNFG_PAD_SP_k230		0x09 /* PMOS TX drive strength for k230 */
 #define PHY_CNFG_PAD_SP_SG2042		0x09 /* PMOS TX drive strength for SG2042 */
 #define PHY_CNFG_PAD_SN_MASK		GENMASK(23, 20) /* bits [23:20] */
 #define PHY_CNFG_PAD_SN			0x0c /* NMOS TX drive strength */
+#define PHY_CNFG_PAD_SN_k230		0x08 /* NMOS TX drive strength for k230 */
 #define PHY_CNFG_PAD_SN_SG2042		0x08 /* NMOS TX drive strength for SG2042 */
 
 /* PHY command/response pad settings */
@@ -153,14 +155,22 @@
 #define PHY_PAD_RXSEL_3V3		0x2 /* Receiver type select for 3.3V */
 
 #define PHY_PAD_WEAKPULL_MASK		GENMASK(4, 3) /* bits [4:3] */
+#define PHY_PAD_WEAKPULL_DISABLED	0x0 /* Weak pull up and pull down disabled */
 #define PHY_PAD_WEAKPULL_PULLUP		0x1 /* Weak pull up enabled */
 #define PHY_PAD_WEAKPULL_PULLDOWN	0x2 /* Weak pull down enabled */
 
 #define PHY_PAD_TXSLEW_CTRL_P_MASK	GENMASK(8, 5) /* bits [8:5] */
 #define PHY_PAD_TXSLEW_CTRL_P		0x3 /* Slew control for P-Type pad TX */
+#define PHY_PAD_TXSLEW_CTRL_P_k230_VAL2	0x2 /* Slew control for P-Type pad TX for k230 */
 #define PHY_PAD_TXSLEW_CTRL_N_MASK	GENMASK(12, 9) /* bits [12:9] */
 #define PHY_PAD_TXSLEW_CTRL_N		0x3 /* Slew control for N-Type pad TX */
 #define PHY_PAD_TXSLEW_CTRL_N_SG2042	0x2 /* Slew control for N-Type pad TX for SG2042 */
+#define PHY_PAD_TXSLEW_CTRL_N_k230_VAL2	0x2 /* Slew control for N-Type pad TX for k230 */
+#define PHY_PAD_TXSLEW_CTRL_N_k230_VAL1	0x1 /* Slew control for N-Type pad TX for k230 */
+
+/* PHY Common DelayLine config settings */
+#define PHY_COMMDL_CNFG			(DWC_MSHC_PTR_PHY_R + 0x1c)
+#define PHY_COMMDL_CNFG_DLSTEP_SEL	BIT(0) /* DelayLine outputs on PAD enabled */
 
 /* PHY CLK delay line settings */
 #define PHY_SDCLKDL_CNFG_R		(DWC_MSHC_PTR_PHY_R + 0x1d)
@@ -174,7 +184,10 @@
 #define PHY_SDCLKDL_DC_HS400		0x18 /* delay code for HS400 mode */
 
 #define PHY_SMPLDL_CNFG_R		(DWC_MSHC_PTR_PHY_R + 0x20)
+#define PHY_SMPLDL_CNFG_EXTDLY_EN	BIT(0)
 #define PHY_SMPLDL_CNFG_BYPASS_EN	BIT(1)
+#define PHY_SMPLDL_CNFG_INPSEL_MASK	GENMASK(3, 2) /* bits [3:2] */
+#define PHY_SMPLDL_CNFG_INPSEL		0x3 /* delay line input source */
 
 /* PHY drift_cclk_rx delay line configuration setting */
 #define PHY_ATDL_CNFG_R			(DWC_MSHC_PTR_PHY_R + 0x21)
@@ -227,6 +240,14 @@
 /* SMC call for BlueField-3 eMMC RST_N */
 #define BLUEFIELD_SMC_SET_EMMC_RST_N	0x82000007
 
+/* Canaan specific Registers */
+#define SD0_CTRL			0x00
+#define SD0_HOST_REG_VOL_STABLE		BIT(4)
+#define SD0_CARD_WRITE_PROT		BIT(6)
+#define SD1_CTRL			0x08
+#define SD1_HOST_REG_VOL_STABLE		BIT(0)
+#define SD1_CARD_WRITE_PROT		BIT(2)
+
 /* Eswin specific Registers */
 #define EIC7700_CARD_CLK_STABLE		BIT(28)
 #define EIC7700_INT_BCLK_STABLE		BIT(16)
@@ -268,6 +289,12 @@ struct eic7700_priv {
 	unsigned int drive_impedance;
 };
 
+struct k230_priv  {
+	/* Kendryte k230 specific */
+	struct regmap *hi_sys_regmap;
+	const struct k230_pltfm_data *k230_pdata;
+};
+
 #define DWCMSHC_MAX_OTHER_CLKS 3
 
 struct dwcmshc_priv {
@@ -278,6 +305,7 @@ struct dwcmshc_priv {
 	int num_other_clks;
 	struct clk_bulk_data other_clks[DWCMSHC_MAX_OTHER_CLKS];
 
+	const struct dwcmshc_pltfm_data *dwcmshc_pdata;
 	void *priv; /* pointer to SoC private stuff */
 	u16 delay_line;
 	u16 flags;
@@ -290,6 +318,14 @@ struct dwcmshc_pltfm_data {
 	void (*postinit)(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv);
 };
 
+struct k230_pltfm_data {
+	struct dwcmshc_pltfm_data dwcmshc_pdata;
+	bool is_emmc;
+	u32 ctrl_reg;
+	u32 vol_stable_bit;
+	u32 write_prot_bit;
+};
+
 static void dwcmshc_enable_card_clk(struct sdhci_host *host)
 {
 	u16 ctrl;
@@ -1656,6 +1692,199 @@ static int eic7700_init(struct device *dev, struct sdhci_host *host, struct dwcm
 	return 0;
 }
 
+static void dwcmshc_k230_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	u16 clk;
+
+	sdhci_set_clock(host, clock);
+
+	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+	/*
+	 * It is necessary to enable SDHCI_PROG_CLOCK_MODE. This is a
+	 * vendor-specific quirk. If this is not done, the eMMC will be
+	 * unable to read or write.
+	 */
+	clk |= SDHCI_PROG_CLOCK_MODE;
+	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+}
+
+static void sdhci_k230_config_phy_delay(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
+	u32 val;
+
+	sdhci_writeb(host, PHY_COMMDL_CNFG_DLSTEP_SEL, PHY_COMMDL_CNFG);
+	sdhci_writeb(host, 0x0, PHY_SDCLKDL_CNFG_R);
+	sdhci_writeb(host, PHY_SDCLKDL_DC_INITIAL, PHY_SDCLKDL_DC_R);
+
+	val = PHY_SMPLDL_CNFG_EXTDLY_EN;
+	val |= FIELD_PREP(PHY_SMPLDL_CNFG_INPSEL_MASK, PHY_SMPLDL_CNFG_INPSEL);
+	sdhci_writeb(host, val, PHY_SMPLDL_CNFG_R);
+
+	sdhci_writeb(host, FIELD_PREP(PHY_ATDL_CNFG_INPSEL_MASK, PHY_ATDL_CNFG_INPSEL),
+		     PHY_ATDL_CNFG_R);
+
+	val = sdhci_readl(host, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
+	val |= AT_CTRL_TUNE_CLK_STOP_EN;
+	val |= FIELD_PREP(AT_CTRL_PRE_CHANGE_DLY_MASK, AT_CTRL_PRE_CHANGE_DLY);
+	val |= FIELD_PREP(AT_CTRL_POST_CHANGE_DLY_MASK, AT_CTRL_POST_CHANGE_DLY);
+	sdhci_writel(host, val, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
+	sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_AT_STAT);
+}
+
+static int dwcmshc_k230_phy_init(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
+	u32 rxsel;
+	u32 val;
+	u32 reg;
+	int ret;
+
+	/* reset phy */
+	sdhci_writew(host, 0, PHY_CNFG_R);
+
+	/* Disable the clock */
+	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+	rxsel = priv->flags & FLAG_IO_FIXED_1V8 ?
+			PHY_PAD_RXSEL_1V8 : PHY_PAD_RXSEL_3V3;
+
+	val = rxsel;
+	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P_k230_VAL2);
+	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N_k230_VAL2);
+	val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP);
+
+	sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
+	sdhci_writew(host, val, PHY_DATAPAD_CNFG_R);
+	sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R);
+
+	val = rxsel;
+	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P_k230_VAL2);
+	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N_k230_VAL2);
+	sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
+
+	val = rxsel;
+	val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN);
+	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P_k230_VAL2);
+	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N_k230_VAL2);
+	sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
+
+	sdhci_k230_config_phy_delay(host);
+
+	/* Wait max 150 ms */
+	ret = read_poll_timeout(sdhci_readl, reg,
+				(reg & FIELD_PREP(PHY_CNFG_PHY_PWRGOOD_MASK, 1)),
+				10, 150000, false, host, PHY_CNFG_R);
+	if (ret) {
+		dev_err(mmc_dev(host->mmc),
+			"READ PHY PWRGOOD timeout!\n");
+		return -ETIMEDOUT;
+	}
+
+	reg = FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN_k230) |
+	      FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP_k230);
+	sdhci_writel(host, reg, PHY_CNFG_R);
+
+	/* de-assert the phy */
+	reg |= PHY_CNFG_RSTN_DEASSERT;
+	sdhci_writel(host, reg, PHY_CNFG_R);
+
+	return 0;
+}
+
+static void dwcmshc_k230_sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
+	struct k230_priv *k230_priv = dwc_priv->priv;
+	u8 emmc_ctrl;
+
+	dwcmshc_reset(host, mask);
+
+	if (mask != SDHCI_RESET_ALL)
+		return;
+
+	emmc_ctrl = sdhci_readw(host,
+				dwc_priv->vendor_specific_area1 +
+				DWCMSHC_EMMC_CONTROL);
+	sdhci_writeb(host, emmc_ctrl,
+		     dwc_priv->vendor_specific_area1 +
+		     DWCMSHC_EMMC_CONTROL);
+
+	if (k230_priv->k230_pdata->is_emmc)
+		dwcmshc_k230_phy_init(host);
+	else
+		sdhci_writel(host, 0x0,
+			     dwc_priv->vendor_specific_area1 +
+			     DWCMSHC_HOST_CTRL3);
+}
+
+static int dwcmshc_k230_init(struct device *dev, struct sdhci_host *host,
+			     struct dwcmshc_priv *dwc_priv)
+{
+	static const char * const clk_ids[] = {"block", "timer", "axi"};
+	const struct k230_pltfm_data *k230_pdata;
+	struct device_node *usb_phy_node;
+	struct k230_priv *k230_priv;
+	u32 data;
+	int ret;
+
+	k230_pdata = container_of(dwc_priv->dwcmshc_pdata,
+				  struct k230_pltfm_data, dwcmshc_pdata);
+	if (!k230_pdata) {
+		dev_err(dev, "No vendor data found for K230\n");
+		return -EINVAL;
+	}
+
+	k230_priv = devm_kzalloc(dev, sizeof(struct k230_priv), GFP_KERNEL);
+	if (!k230_priv)
+		return -ENOMEM;
+
+	k230_priv->k230_pdata = k230_pdata;
+	dwc_priv->priv = k230_priv;
+
+	usb_phy_node = of_parse_phandle(dev->of_node, "canaan,usb-phy", 0);
+	if (!usb_phy_node)
+		return dev_err_probe(dev, -ENODEV,
+				     "Failed to find canaan,usb-phy phandle\n");
+
+	k230_priv->hi_sys_regmap = device_node_to_regmap(usb_phy_node);
+	of_node_put(usb_phy_node);
+
+	if (IS_ERR(k230_priv->hi_sys_regmap))
+		return dev_err_probe(dev, PTR_ERR(k230_priv->hi_sys_regmap),
+				     "Failed to get k230-usb-phy regmap\n");
+
+	ret = dwcmshc_get_enable_other_clks(mmc_dev(host->mmc), dwc_priv,
+					    ARRAY_SIZE(clk_ids), clk_ids);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to get/enable k230 mmc other clocks\n");
+
+	if (k230_pdata->is_emmc) {
+		host->flags &= ~SDHCI_SIGNALING_330;
+		dwc_priv->flags |= FLAG_IO_FIXED_1V8;
+	} else {
+		host->mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+		host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+	}
+
+	ret = regmap_read(k230_priv->hi_sys_regmap, k230_pdata->ctrl_reg, &data);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to read control reg 0x%x\n",
+				     k230_pdata->ctrl_reg);
+
+	data |= k230_pdata->write_prot_bit | k230_pdata->vol_stable_bit;
+	ret = regmap_write(k230_priv->hi_sys_regmap, k230_pdata->ctrl_reg, data);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to write control reg 0x%x\n",
+				     k230_pdata->ctrl_reg);
+
+	return 0;
+}
+
 static const struct sdhci_ops sdhci_dwcmshc_ops = {
 	.set_clock		= sdhci_set_clock,
 	.set_bus_width		= sdhci_set_bus_width,
@@ -1743,6 +1972,15 @@ static const struct sdhci_ops sdhci_dwcmshc_eic7700_ops = {
 	.platform_execute_tuning = sdhci_eic7700_executing_tuning,
 };
 
+static const struct sdhci_ops sdhci_dwcmshc_k230_ops = {
+	.set_clock = dwcmshc_k230_sdhci_set_clock,
+	.set_bus_width = sdhci_set_bus_width,
+	.set_uhs_signaling = dwcmshc_set_uhs_signaling,
+	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
+	.reset = dwcmshc_k230_sdhci_reset,
+	.adma_write_desc = dwcmshc_adma_write_desc,
+};
+
 static const struct dwcmshc_pltfm_data sdhci_dwcmshc_pdata = {
 	.pdata = {
 		.ops = &sdhci_dwcmshc_ops,
@@ -1834,6 +2072,36 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_eic7700_pdata = {
 	.init = eic7700_init,
 };
 
+static const struct k230_pltfm_data k230_emmc_data = {
+	.dwcmshc_pdata = {
+		.pdata = {
+			.ops = &sdhci_dwcmshc_k230_ops,
+			.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
+				  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+		},
+		.init = dwcmshc_k230_init,
+	},
+	.is_emmc = true,
+	.ctrl_reg = SD0_CTRL,
+	.vol_stable_bit = SD0_HOST_REG_VOL_STABLE,
+	.write_prot_bit = SD0_CARD_WRITE_PROT,
+};
+
+static const struct k230_pltfm_data k230_sdio_data = {
+	.dwcmshc_pdata = {
+		.pdata = {
+		.ops = &sdhci_dwcmshc_k230_ops,
+		.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
+			  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+		},
+		.init = dwcmshc_k230_init,
+	},
+	.is_emmc = false,
+	.ctrl_reg = SD1_CTRL,
+	.vol_stable_bit = SD1_HOST_REG_VOL_STABLE,
+	.write_prot_bit = SD1_CARD_WRITE_PROT,
+};
+
 static const struct cqhci_host_ops dwcmshc_cqhci_ops = {
 	.enable		= dwcmshc_sdhci_cqe_enable,
 	.disable	= sdhci_cqe_disable,
@@ -1906,6 +2174,14 @@ static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *
 }
 
 static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
+	{
+		.compatible = "canaan,k230-emmc",
+		.data = &k230_emmc_data.dwcmshc_pdata,
+	},
+	{
+		.compatible = "canaan,k230-sdio",
+		.data = &k230_sdio_data.dwcmshc_pdata,
+	},
 	{
 		.compatible = "rockchip,rk3588-dwcmshc",
 		.data = &sdhci_dwcmshc_rk35xx_pdata,
@@ -1988,6 +2264,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
 
 	pltfm_host = sdhci_priv(host);
 	priv = sdhci_pltfm_priv(pltfm_host);
+	priv->dwcmshc_pdata = pltfm_data;
 
 	if (dev->of_node) {
 		pltfm_host->clk = devm_clk_get(dev, "core");
-- 
2.53.0


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

* [PATCH v4 3/3] riscv: dts: canaan: Add mmc nodes for K230
  2026-03-15  5:44 [PATCH v4 0/3] Add SDHCI support for Canaan K230 SoC Jiayu Du
  2026-03-15  5:44 ` [PATCH v4 1/3] dt-bindings: mmc: Add sdhci support for Canaan k230 Jiayu Du
  2026-03-15  5:44 ` [PATCH v4 2/3] mmc: sdhci-dwcmshc: Add Canaan K230 DWCMSHC controller support Jiayu Du
@ 2026-03-15  5:44 ` Jiayu Du
  2026-03-16 14:15   ` Junhui Liu
  2 siblings, 1 reply; 8+ messages in thread
From: Jiayu Du @ 2026-03-15  5:44 UTC (permalink / raw)
  To: krzk, ulf.hansson, adrian.hunter, robh, krzk+dt, conor+dt
  Cc: pjw, palmer, aou, linux-mmc, devicetree, linux-riscv,
	linux-kernel, gaohan, me, Jiayu Du

Add MMC nodes to K230, including eMMC and SDIO. Enable HS200 eMMC
on the SoM and SDIO high-speed on the board.

Signed-off-by: Jiayu Du <jiayu.riscv@isrc.iscas.ac.cn>
---
 .../boot/dts/canaan/k230-canmv-dshanpi.dts    | 56 +++++++++++++++++++
 .../dts/canaan/k230-canmv-module-dshanpi.dtsi |  7 +++
 arch/riscv/boot/dts/canaan/k230.dtsi          | 28 ++++++++++
 3 files changed, 91 insertions(+)

diff --git a/arch/riscv/boot/dts/canaan/k230-canmv-dshanpi.dts b/arch/riscv/boot/dts/canaan/k230-canmv-dshanpi.dts
index 55197cfc25b4..1877b2049409 100644
--- a/arch/riscv/boot/dts/canaan/k230-canmv-dshanpi.dts
+++ b/arch/riscv/boot/dts/canaan/k230-canmv-dshanpi.dts
@@ -15,6 +15,8 @@ / {
 
 	aliases {
 		serial0 = &uart0;
+		mmc0 = &emmc;
+		mmc1 = &sdio;
 	};
 
 	chosen {
@@ -73,6 +75,60 @@ uart0-rxd-cfg {
 			input-schmitt-enable;
 		};
 	};
+
+	mmc1_pins: mmc1-pins {
+		mmc1-cmd-cfg {
+			pinmux = <K230_PINMUX(54, 2)>;
+			slew-rate = <0>;
+			drive-strength = <7>;
+			power-source = <K230_MSC_3V3>;
+			input-enable;
+			output-enable;
+			bias-pull-up;
+			input-schmitt-enable;
+		};
+
+		mmc1-clk-cfg {
+			pinmux = <K230_PINMUX(55, 2)>;
+			slew-rate = <0>;
+			drive-strength = <7>;
+			power-source = <K230_MSC_3V3>;
+			output-enable;
+			bias-disable;
+			input-schmitt-enable;
+		};
+
+		mmc1-data-cfg {
+			pinmux = <K230_PINMUX(56, 2)>, /* mmc1 data0 */
+				 <K230_PINMUX(57, 2)>, /* mmc1 data1 */
+				 <K230_PINMUX(58, 2)>, /* mmc1 data2 */
+				 <K230_PINMUX(59, 2)>; /* mmc1 data3 */
+			slew-rate = <0>;
+			drive-strength = <7>;
+			power-source = <K230_MSC_3V3>;
+			input-enable;
+			output-enable;
+			bias-pull-up;
+			input-schmitt-enable;
+		};
+	};
+};
+
+&emmc {
+	vmmc-supply = <&vdd_3v3>;
+	vqmmc-supply = <&vdd_1v8>;
+};
+
+&sdio {
+	bus-width = <4>;
+	max-frequency = <50000000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins>;
+	vmmc-supply = <&vdd_3v3>;
+	vqmmc-supply = <&vdd_3v3>;
+	cap-sd-highspeed;
+	no-1-8-v;
+	status = "okay";
 };
 
 &uart0 {
diff --git a/arch/riscv/boot/dts/canaan/k230-canmv-module-dshanpi.dtsi b/arch/riscv/boot/dts/canaan/k230-canmv-module-dshanpi.dtsi
index 566665d39239..1db7569253fe 100644
--- a/arch/riscv/boot/dts/canaan/k230-canmv-module-dshanpi.dtsi
+++ b/arch/riscv/boot/dts/canaan/k230-canmv-module-dshanpi.dtsi
@@ -24,3 +24,10 @@ &sysclk {
 	clocks = <&osc24m>, <&timerx_pulse_in>;
 	clock-names = "osc24m", "timer-pulse-in";
 };
+
+&emmc {
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	mmc-hs200-1_8v;
+	status = "okay";
+};
diff --git a/arch/riscv/boot/dts/canaan/k230.dtsi b/arch/riscv/boot/dts/canaan/k230.dtsi
index e1ec3e1f40a7..e3c6926dbadc 100644
--- a/arch/riscv/boot/dts/canaan/k230.dtsi
+++ b/arch/riscv/boot/dts/canaan/k230.dtsi
@@ -192,6 +192,34 @@ usb1: usb@91540000 {
 			status = "disabled";
 		};
 
+		emmc: mmc@91580000 {
+			compatible = "canaan,k230-emmc";
+			reg = <0x0 0x91580000 0x0 0x1000>;
+			clocks = <&sysclk K230_HS_SD0_CARD_GATE>,
+				 <&sysclk K230_HS_SD0_AHB_GATE>,
+				 <&sysclk K230_HS_SD0_AXI_GATE>,
+				 <&sysclk K230_HS_SD0_BASE_GATE>,
+				 <&sysclk K230_HS_SD0_TIMER_GATE>;
+			clock-names = "core", "bus", "axi", "block", "timer";
+			interrupts = <142 IRQ_TYPE_LEVEL_HIGH>;
+			canaan,usb-phy = <&usbphy>;
+			status = "disabled";
+		};
+
+		sdio: mmc@91581000 {
+			compatible = "canaan,k230-sdio";
+			reg = <0x0 0x91581000 0x0 0x1000>;
+			clocks = <&sysclk K230_HS_SD1_CARD_GATE>,
+				 <&sysclk K230_HS_SD1_AHB_GATE>,
+				 <&sysclk K230_HS_SD1_AXI_GATE>,
+				 <&sysclk K230_HS_SD1_BASE_GATE>,
+				 <&sysclk K230_HS_SD1_TIMER_GATE>;
+			clock-names = "core", "bus", "axi", "block", "timer";
+			interrupts = <144 IRQ_TYPE_LEVEL_HIGH>;
+			canaan,usb-phy = <&usbphy>;
+			status = "disabled";
+		};
+
 		usbphy: usb-phy@91585000 {
 			compatible = "canaan,k230-usb-phy";
 			reg = <0x0 0x91585000 0x0 0x400>;
-- 
2.53.0


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

* Re: [PATCH v4 2/3] mmc: sdhci-dwcmshc: Add Canaan K230 DWCMSHC controller support
  2026-03-15  5:44 ` [PATCH v4 2/3] mmc: sdhci-dwcmshc: Add Canaan K230 DWCMSHC controller support Jiayu Du
@ 2026-03-16 12:33   ` Adrian Hunter
  0 siblings, 0 replies; 8+ messages in thread
From: Adrian Hunter @ 2026-03-16 12:33 UTC (permalink / raw)
  To: Jiayu Du, krzk, ulf.hansson, robh, krzk+dt, conor+dt
  Cc: pjw, palmer, aou, linux-mmc, devicetree, linux-riscv,
	linux-kernel, gaohan, me

On 15/03/2026 07:44, Jiayu Du wrote:
> Add SDHCI controller driver for Canaan k230 SoC. Implement custom
> sdhci_ops for set_clock, phy init, init and reset.
> 
> Signed-off-by: Jiayu Du <jiayu.riscv@isrc.iscas.ac.cn>

Still a few little things.  See comments below.

> ---
>  drivers/mmc/host/sdhci-of-dwcmshc.c | 277 ++++++++++++++++++++++++++++
>  1 file changed, 277 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
> index 2b75a36c096b..489274c39141 100644
> --- a/drivers/mmc/host/sdhci-of-dwcmshc.c
> +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
> @@ -128,9 +128,11 @@
>  #define PHY_CNFG_PHY_PWRGOOD_MASK	BIT_MASK(1) /* bit [1] */
>  #define PHY_CNFG_PAD_SP_MASK		GENMASK(19, 16) /* bits [19:16] */
>  #define PHY_CNFG_PAD_SP			0x0c /* PMOS TX drive strength */
> +#define PHY_CNFG_PAD_SP_k230		0x09 /* PMOS TX drive strength for k230 */
>  #define PHY_CNFG_PAD_SP_SG2042		0x09 /* PMOS TX drive strength for SG2042 */
>  #define PHY_CNFG_PAD_SN_MASK		GENMASK(23, 20) /* bits [23:20] */
>  #define PHY_CNFG_PAD_SN			0x0c /* NMOS TX drive strength */
> +#define PHY_CNFG_PAD_SN_k230		0x08 /* NMOS TX drive strength for k230 */
>  #define PHY_CNFG_PAD_SN_SG2042		0x08 /* NMOS TX drive strength for SG2042 */
>  
>  /* PHY command/response pad settings */
> @@ -153,14 +155,22 @@
>  #define PHY_PAD_RXSEL_3V3		0x2 /* Receiver type select for 3.3V */
>  
>  #define PHY_PAD_WEAKPULL_MASK		GENMASK(4, 3) /* bits [4:3] */
> +#define PHY_PAD_WEAKPULL_DISABLED	0x0 /* Weak pull up and pull down disabled */
>  #define PHY_PAD_WEAKPULL_PULLUP		0x1 /* Weak pull up enabled */
>  #define PHY_PAD_WEAKPULL_PULLDOWN	0x2 /* Weak pull down enabled */
>  
>  #define PHY_PAD_TXSLEW_CTRL_P_MASK	GENMASK(8, 5) /* bits [8:5] */
>  #define PHY_PAD_TXSLEW_CTRL_P		0x3 /* Slew control for P-Type pad TX */
> +#define PHY_PAD_TXSLEW_CTRL_P_k230_VAL2	0x2 /* Slew control for P-Type pad TX for k230 */
>  #define PHY_PAD_TXSLEW_CTRL_N_MASK	GENMASK(12, 9) /* bits [12:9] */
>  #define PHY_PAD_TXSLEW_CTRL_N		0x3 /* Slew control for N-Type pad TX */
>  #define PHY_PAD_TXSLEW_CTRL_N_SG2042	0x2 /* Slew control for N-Type pad TX for SG2042 */
> +#define PHY_PAD_TXSLEW_CTRL_N_k230_VAL2	0x2 /* Slew control for N-Type pad TX for k230 */
> +#define PHY_PAD_TXSLEW_CTRL_N_k230_VAL1	0x1 /* Slew control for N-Type pad TX for k230 */
> +
> +/* PHY Common DelayLine config settings */
> +#define PHY_COMMDL_CNFG			(DWC_MSHC_PTR_PHY_R + 0x1c)
> +#define PHY_COMMDL_CNFG_DLSTEP_SEL	BIT(0) /* DelayLine outputs on PAD enabled */
>  
>  /* PHY CLK delay line settings */
>  #define PHY_SDCLKDL_CNFG_R		(DWC_MSHC_PTR_PHY_R + 0x1d)
> @@ -174,7 +184,10 @@
>  #define PHY_SDCLKDL_DC_HS400		0x18 /* delay code for HS400 mode */
>  
>  #define PHY_SMPLDL_CNFG_R		(DWC_MSHC_PTR_PHY_R + 0x20)
> +#define PHY_SMPLDL_CNFG_EXTDLY_EN	BIT(0)
>  #define PHY_SMPLDL_CNFG_BYPASS_EN	BIT(1)
> +#define PHY_SMPLDL_CNFG_INPSEL_MASK	GENMASK(3, 2) /* bits [3:2] */
> +#define PHY_SMPLDL_CNFG_INPSEL		0x3 /* delay line input source */
>  
>  /* PHY drift_cclk_rx delay line configuration setting */
>  #define PHY_ATDL_CNFG_R			(DWC_MSHC_PTR_PHY_R + 0x21)
> @@ -227,6 +240,14 @@
>  /* SMC call for BlueField-3 eMMC RST_N */
>  #define BLUEFIELD_SMC_SET_EMMC_RST_N	0x82000007
>  
> +/* Canaan specific Registers */
> +#define SD0_CTRL			0x00
> +#define SD0_HOST_REG_VOL_STABLE		BIT(4)
> +#define SD0_CARD_WRITE_PROT		BIT(6)
> +#define SD1_CTRL			0x08
> +#define SD1_HOST_REG_VOL_STABLE		BIT(0)
> +#define SD1_CARD_WRITE_PROT		BIT(2)
> +
>  /* Eswin specific Registers */
>  #define EIC7700_CARD_CLK_STABLE		BIT(28)
>  #define EIC7700_INT_BCLK_STABLE		BIT(16)
> @@ -268,6 +289,12 @@ struct eic7700_priv {
>  	unsigned int drive_impedance;
>  };
>  
> +struct k230_priv  {
> +	/* Kendryte k230 specific */
> +	struct regmap *hi_sys_regmap;
> +	const struct k230_pltfm_data *k230_pdata;

I'd prefer to drop k230_pdata here and make a macro that anyone could use:

#define to_pltfm_data(priv, name) \
	container_of((priv)->dwcmshc_pdata, struct name##_pltfm_data, dwcmshc_pdata);

> +};
> +
>  #define DWCMSHC_MAX_OTHER_CLKS 3
>  
>  struct dwcmshc_priv {
> @@ -278,6 +305,7 @@ struct dwcmshc_priv {
>  	int num_other_clks;
>  	struct clk_bulk_data other_clks[DWCMSHC_MAX_OTHER_CLKS];
>  
> +	const struct dwcmshc_pltfm_data *dwcmshc_pdata;
>  	void *priv; /* pointer to SoC private stuff */
>  	u16 delay_line;
>  	u16 flags;
> @@ -290,6 +318,14 @@ struct dwcmshc_pltfm_data {
>  	void (*postinit)(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv);
>  };
>  
> +struct k230_pltfm_data {
> +	struct dwcmshc_pltfm_data dwcmshc_pdata;
> +	bool is_emmc;
> +	u32 ctrl_reg;
> +	u32 vol_stable_bit;
> +	u32 write_prot_bit;
> +};
> +
>  static void dwcmshc_enable_card_clk(struct sdhci_host *host)
>  {
>  	u16 ctrl;
> @@ -1656,6 +1692,199 @@ static int eic7700_init(struct device *dev, struct sdhci_host *host, struct dwcm
>  	return 0;
>  }
>  
> +static void dwcmshc_k230_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
> +{
> +	u16 clk;
> +
> +	sdhci_set_clock(host, clock);
> +
> +	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> +	/*
> +	 * It is necessary to enable SDHCI_PROG_CLOCK_MODE. This is a
> +	 * vendor-specific quirk. If this is not done, the eMMC will be
> +	 * unable to read or write.
> +	 */
> +	clk |= SDHCI_PROG_CLOCK_MODE;
> +	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> +}
> +
> +static void sdhci_k230_config_phy_delay(struct sdhci_host *host)
> +{
> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +	struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
> +	u32 val;
> +
> +	sdhci_writeb(host, PHY_COMMDL_CNFG_DLSTEP_SEL, PHY_COMMDL_CNFG);
> +	sdhci_writeb(host, 0x0, PHY_SDCLKDL_CNFG_R);
> +	sdhci_writeb(host, PHY_SDCLKDL_DC_INITIAL, PHY_SDCLKDL_DC_R);
> +
> +	val = PHY_SMPLDL_CNFG_EXTDLY_EN;
> +	val |= FIELD_PREP(PHY_SMPLDL_CNFG_INPSEL_MASK, PHY_SMPLDL_CNFG_INPSEL);
> +	sdhci_writeb(host, val, PHY_SMPLDL_CNFG_R);
> +
> +	sdhci_writeb(host, FIELD_PREP(PHY_ATDL_CNFG_INPSEL_MASK, PHY_ATDL_CNFG_INPSEL),
> +		     PHY_ATDL_CNFG_R);
> +
> +	val = sdhci_readl(host, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
> +	val |= AT_CTRL_TUNE_CLK_STOP_EN;
> +	val |= FIELD_PREP(AT_CTRL_PRE_CHANGE_DLY_MASK, AT_CTRL_PRE_CHANGE_DLY);
> +	val |= FIELD_PREP(AT_CTRL_POST_CHANGE_DLY_MASK, AT_CTRL_POST_CHANGE_DLY);
> +	sdhci_writel(host, val, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
> +	sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_AT_STAT);
> +}
> +
> +static int dwcmshc_k230_phy_init(struct sdhci_host *host)
> +{
> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +	struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
> +	u32 rxsel;
> +	u32 val;
> +	u32 reg;
> +	int ret;
> +
> +	/* reset phy */
> +	sdhci_writew(host, 0, PHY_CNFG_R);
> +
> +	/* Disable the clock */
> +	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
> +
> +	rxsel = priv->flags & FLAG_IO_FIXED_1V8 ?
> +			PHY_PAD_RXSEL_1V8 : PHY_PAD_RXSEL_3V3;

Line wrapping not needed

> +
> +	val = rxsel;
> +	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P_k230_VAL2);
> +	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N_k230_VAL2);
> +	val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP);
> +
> +	sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
> +	sdhci_writew(host, val, PHY_DATAPAD_CNFG_R);
> +	sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R);
> +
> +	val = rxsel;
> +	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P_k230_VAL2);
> +	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N_k230_VAL2);
> +	sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
> +
> +	val = rxsel;
> +	val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN);
> +	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P_k230_VAL2);
> +	val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N_k230_VAL2);
> +	sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
> +
> +	sdhci_k230_config_phy_delay(host);
> +
> +	/* Wait max 150 ms */
> +	ret = read_poll_timeout(sdhci_readl, reg,
> +				(reg & FIELD_PREP(PHY_CNFG_PHY_PWRGOOD_MASK, 1)),
> +				10, 150000, false, host, PHY_CNFG_R);
> +	if (ret) {
> +		dev_err(mmc_dev(host->mmc),
> +			"READ PHY PWRGOOD timeout!\n");

Line wrapping not needed

> +		return -ETIMEDOUT;
> +	}
> +
> +	reg = FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN_k230) |
> +	      FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP_k230);
> +	sdhci_writel(host, reg, PHY_CNFG_R);
> +
> +	/* de-assert the phy */
> +	reg |= PHY_CNFG_RSTN_DEASSERT;
> +	sdhci_writel(host, reg, PHY_CNFG_R);
> +
> +	return 0;
> +}
> +
> +static void dwcmshc_k230_sdhci_reset(struct sdhci_host *host, u8 mask)
> +{
> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +	struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
> +	struct k230_priv *k230_priv = dwc_priv->priv;

	const struct k230_pltfm_data *k230_pdata = to_pltfm_data(dwc_priv, k230);

> +	u8 emmc_ctrl;
> +
> +	dwcmshc_reset(host, mask);
> +
> +	if (mask != SDHCI_RESET_ALL)
> +		return;
> +
> +	emmc_ctrl = sdhci_readw(host,
> +				dwc_priv->vendor_specific_area1 +
> +				DWCMSHC_EMMC_CONTROL);
> +	sdhci_writeb(host, emmc_ctrl,
> +		     dwc_priv->vendor_specific_area1 +
> +		     DWCMSHC_EMMC_CONTROL);
> +
> +	if (k230_priv->k230_pdata->is_emmc)
> +		dwcmshc_k230_phy_init(host);
> +	else
> +		sdhci_writel(host, 0x0,
> +			     dwc_priv->vendor_specific_area1 +
> +			     DWCMSHC_HOST_CTRL3);

Line wrapping is not needed in this function:

	emmc_ctrl = sdhci_readw(host, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
	sdhci_writeb(host, emmc_ctrl, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);

	if (k230_pdata->is_emmc)
		dwcmshc_k230_phy_init(host);
	else
		sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3);

> +}
> +
> +static int dwcmshc_k230_init(struct device *dev, struct sdhci_host *host,
> +			     struct dwcmshc_priv *dwc_priv)
> +{

	const struct k230_pltfm_data *k230_pdata = to_pltfm_data(dwc_priv, k230);

> +	static const char * const clk_ids[] = {"block", "timer", "axi"};
> +	const struct k230_pltfm_data *k230_pdata;
> +	struct device_node *usb_phy_node;
> +	struct k230_priv *k230_priv;
> +	u32 data;
> +	int ret;
> +
> +	k230_pdata = container_of(dwc_priv->dwcmshc_pdata,
> +				  struct k230_pltfm_data, dwcmshc_pdata);
> +	if (!k230_pdata) {

Not possible, so not needed (also assumes the container
offset is zero which is a bit fragile)

> +		dev_err(dev, "No vendor data found for K230\n");
> +		return -EINVAL;
> +	}
> +
> +	k230_priv = devm_kzalloc(dev, sizeof(struct k230_priv), GFP_KERNEL);
> +	if (!k230_priv)
> +		return -ENOMEM;
> +
> +	k230_priv->k230_pdata = k230_pdata;

Suggest dropping k230_priv->k230_pdata

> +	dwc_priv->priv = k230_priv;
> +
> +	usb_phy_node = of_parse_phandle(dev->of_node, "canaan,usb-phy", 0);
> +	if (!usb_phy_node)
> +		return dev_err_probe(dev, -ENODEV,
> +				     "Failed to find canaan,usb-phy phandle\n");

If it fits in 100 columns, just put it all on one line

> +
> +	k230_priv->hi_sys_regmap = device_node_to_regmap(usb_phy_node);
> +	of_node_put(usb_phy_node);
> +
> +	if (IS_ERR(k230_priv->hi_sys_regmap))
> +		return dev_err_probe(dev, PTR_ERR(k230_priv->hi_sys_regmap),
> +				     "Failed to get k230-usb-phy regmap\n");
> +
> +	ret = dwcmshc_get_enable_other_clks(mmc_dev(host->mmc), dwc_priv,
> +					    ARRAY_SIZE(clk_ids), clk_ids);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to get/enable k230 mmc other clocks\n");

If it fits in 100 columns, just put it all on one line

> +
> +	if (k230_pdata->is_emmc) {
> +		host->flags &= ~SDHCI_SIGNALING_330;
> +		dwc_priv->flags |= FLAG_IO_FIXED_1V8;
> +	} else {
> +		host->mmc->caps |= MMC_CAP_SD_HIGHSPEED;
> +		host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
> +	}
> +
> +	ret = regmap_read(k230_priv->hi_sys_regmap, k230_pdata->ctrl_reg, &data);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to read control reg 0x%x\n",
> +				     k230_pdata->ctrl_reg);
> +
> +	data |= k230_pdata->write_prot_bit | k230_pdata->vol_stable_bit;
> +	ret = regmap_write(k230_priv->hi_sys_regmap, k230_pdata->ctrl_reg, data);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to write control reg 0x%x\n",
> +				     k230_pdata->ctrl_reg);
> +
> +	return 0;
> +}
> +
>  static const struct sdhci_ops sdhci_dwcmshc_ops = {
>  	.set_clock		= sdhci_set_clock,
>  	.set_bus_width		= sdhci_set_bus_width,
> @@ -1743,6 +1972,15 @@ static const struct sdhci_ops sdhci_dwcmshc_eic7700_ops = {
>  	.platform_execute_tuning = sdhci_eic7700_executing_tuning,
>  };
>  
> +static const struct sdhci_ops sdhci_dwcmshc_k230_ops = {
> +	.set_clock = dwcmshc_k230_sdhci_set_clock,
> +	.set_bus_width = sdhci_set_bus_width,
> +	.set_uhs_signaling = dwcmshc_set_uhs_signaling,
> +	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
> +	.reset = dwcmshc_k230_sdhci_reset,
> +	.adma_write_desc = dwcmshc_adma_write_desc,
> +};
> +
>  static const struct dwcmshc_pltfm_data sdhci_dwcmshc_pdata = {
>  	.pdata = {
>  		.ops = &sdhci_dwcmshc_ops,
> @@ -1834,6 +2072,36 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_eic7700_pdata = {
>  	.init = eic7700_init,
>  };
>  
> +static const struct k230_pltfm_data k230_emmc_data = {
> +	.dwcmshc_pdata = {
> +		.pdata = {
> +			.ops = &sdhci_dwcmshc_k230_ops,
> +			.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
> +				  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
> +		},
> +		.init = dwcmshc_k230_init,
> +	},
> +	.is_emmc = true,
> +	.ctrl_reg = SD0_CTRL,
> +	.vol_stable_bit = SD0_HOST_REG_VOL_STABLE,
> +	.write_prot_bit = SD0_CARD_WRITE_PROT,
> +};
> +
> +static const struct k230_pltfm_data k230_sdio_data = {
> +	.dwcmshc_pdata = {
> +		.pdata = {
> +		.ops = &sdhci_dwcmshc_k230_ops,
> +		.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
> +			  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
> +		},
> +		.init = dwcmshc_k230_init,
> +	},
> +	.is_emmc = false,
> +	.ctrl_reg = SD1_CTRL,
> +	.vol_stable_bit = SD1_HOST_REG_VOL_STABLE,
> +	.write_prot_bit = SD1_CARD_WRITE_PROT,
> +};
> +
>  static const struct cqhci_host_ops dwcmshc_cqhci_ops = {
>  	.enable		= dwcmshc_sdhci_cqe_enable,
>  	.disable	= sdhci_cqe_disable,
> @@ -1906,6 +2174,14 @@ static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *
>  }
>  
>  static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
> +	{
> +		.compatible = "canaan,k230-emmc",
> +		.data = &k230_emmc_data.dwcmshc_pdata,
> +	},
> +	{
> +		.compatible = "canaan,k230-sdio",
> +		.data = &k230_sdio_data.dwcmshc_pdata,
> +	},
>  	{
>  		.compatible = "rockchip,rk3588-dwcmshc",
>  		.data = &sdhci_dwcmshc_rk35xx_pdata,
> @@ -1988,6 +2264,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
>  
>  	pltfm_host = sdhci_priv(host);
>  	priv = sdhci_pltfm_priv(pltfm_host);
> +	priv->dwcmshc_pdata = pltfm_data;
>  
>  	if (dev->of_node) {
>  		pltfm_host->clk = devm_clk_get(dev, "core");


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

* Re: [PATCH v4 3/3] riscv: dts: canaan: Add mmc nodes for K230
  2026-03-15  5:44 ` [PATCH v4 3/3] riscv: dts: canaan: Add mmc nodes for K230 Jiayu Du
@ 2026-03-16 14:15   ` Junhui Liu
  2026-03-16 16:03     ` Jiayu Du
  0 siblings, 1 reply; 8+ messages in thread
From: Junhui Liu @ 2026-03-16 14:15 UTC (permalink / raw)
  To: Jiayu Du, krzk, ulf.hansson, adrian.hunter, robh, krzk+dt,
	conor+dt
  Cc: pjw, palmer, aou, linux-mmc, devicetree, linux-riscv,
	linux-kernel, gaohan, me, linux-riscv

Hi Jiayu,
Thanks for the new version. Just a friendly reminder.

On Sun Mar 15, 2026 at 1:44 PM CST, Jiayu Du wrote:
> Add MMC nodes to K230, including eMMC and SDIO. Enable HS200 eMMC
> on the SoM and SDIO high-speed on the board.
>
> Signed-off-by: Jiayu Du <jiayu.riscv@isrc.iscas.ac.cn>
> ---
>  .../boot/dts/canaan/k230-canmv-dshanpi.dts    | 56 +++++++++++++++++++
>  .../dts/canaan/k230-canmv-module-dshanpi.dtsi |  7 +++
>  arch/riscv/boot/dts/canaan/k230.dtsi          | 28 ++++++++++
>  3 files changed, 91 insertions(+)

[...]

> +
> +&sdio {
> +	bus-width = <4>;
> +	max-frequency = <50000000>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&mmc1_pins>;
> +	vmmc-supply = <&vdd_3v3>;
> +	vqmmc-supply = <&vdd_3v3>;
> +	cap-sd-highspeed;
> +	no-1-8-v;
> +	status = "okay";
>  };
>  

It seems the broken-cd property we discussed in the previous version is
not added, and also my Tested-by tag (for the whole series). Was this
intentional or just an oversight?

-- 
Best regards,
Junhui Liu


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

* Re: [PATCH v4 3/3] riscv: dts: canaan: Add mmc nodes for K230
  2026-03-16 14:15   ` Junhui Liu
@ 2026-03-16 16:03     ` Jiayu Du
  2026-03-17  6:52       ` Junhui Liu
  0 siblings, 1 reply; 8+ messages in thread
From: Jiayu Du @ 2026-03-16 16:03 UTC (permalink / raw)
  To: Junhui Liu
  Cc: pjw, palmer, aou, linux-mmc, devicetree, linux-riscv,
	linux-kernel, gaohan, me, linux-riscv

On Mon, Mar 16, 2026 at 10:15:27PM +0800, Junhui Liu wrote:
> Hi Jiayu,
> Thanks for the new version. Just a friendly reminder.
> 
> On Sun Mar 15, 2026 at 1:44 PM CST, Jiayu Du wrote:
> > Add MMC nodes to K230, including eMMC and SDIO. Enable HS200 eMMC
> > on the SoM and SDIO high-speed on the board.
> >
> > Signed-off-by: Jiayu Du <jiayu.riscv@isrc.iscas.ac.cn>
> > ---
> >  .../boot/dts/canaan/k230-canmv-dshanpi.dts    | 56 +++++++++++++++++++
> >  .../dts/canaan/k230-canmv-module-dshanpi.dtsi |  7 +++
> >  arch/riscv/boot/dts/canaan/k230.dtsi          | 28 ++++++++++
> >  3 files changed, 91 insertions(+)
> 
> [...]
> 
> > +
> > +&sdio {
> > +	bus-width = <4>;
> > +	max-frequency = <50000000>;
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&mmc1_pins>;
> > +	vmmc-supply = <&vdd_3v3>;
> > +	vqmmc-supply = <&vdd_3v3>;
> > +	cap-sd-highspeed;
> > +	no-1-8-v;
> > +	status = "okay";
> >  };
> >  
> 
> It seems the broken-cd property we discussed in the previous version is
> not added, and also my Tested-by tag (for the whole series). Was this
> intentional or just an oversight?
> 

Sorry for that, It was a oversight. I will fix both.

And I will only add your Tested-by tags to patch [2/3] and [3/3].
Is this correct?

Kind regards,
Jiayu Du

> -- 
> Best regards,
> Junhui Liu
> 


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

* Re: [PATCH v4 3/3] riscv: dts: canaan: Add mmc nodes for K230
  2026-03-16 16:03     ` Jiayu Du
@ 2026-03-17  6:52       ` Junhui Liu
  0 siblings, 0 replies; 8+ messages in thread
From: Junhui Liu @ 2026-03-17  6:52 UTC (permalink / raw)
  To: Jiayu Du, Junhui Liu
  Cc: pjw, palmer, aou, linux-mmc, devicetree, linux-riscv,
	linux-kernel, gaohan, me, linux-riscv

On Tue Mar 17, 2026 at 12:03 AM CST, Jiayu Du wrote:
> On Mon, Mar 16, 2026 at 10:15:27PM +0800, Junhui Liu wrote:
>> Hi Jiayu,
>> Thanks for the new version. Just a friendly reminder.
>> 
>> On Sun Mar 15, 2026 at 1:44 PM CST, Jiayu Du wrote:
>> > Add MMC nodes to K230, including eMMC and SDIO. Enable HS200 eMMC
>> > on the SoM and SDIO high-speed on the board.
>> >
>> > Signed-off-by: Jiayu Du <jiayu.riscv@isrc.iscas.ac.cn>
>> > ---
>> >  .../boot/dts/canaan/k230-canmv-dshanpi.dts    | 56 +++++++++++++++++++
>> >  .../dts/canaan/k230-canmv-module-dshanpi.dtsi |  7 +++
>> >  arch/riscv/boot/dts/canaan/k230.dtsi          | 28 ++++++++++
>> >  3 files changed, 91 insertions(+)
>> 
>> [...]
>> 
>> > +
>> > +&sdio {
>> > +	bus-width = <4>;
>> > +	max-frequency = <50000000>;
>> > +	pinctrl-names = "default";
>> > +	pinctrl-0 = <&mmc1_pins>;
>> > +	vmmc-supply = <&vdd_3v3>;
>> > +	vqmmc-supply = <&vdd_3v3>;
>> > +	cap-sd-highspeed;
>> > +	no-1-8-v;
>> > +	status = "okay";
>> >  };
>> >  
>> 
>> It seems the broken-cd property we discussed in the previous version is
>> not added, and also my Tested-by tag (for the whole series). Was this
>> intentional or just an oversight?
>> 
>
> Sorry for that, It was a oversight. I will fix both.
>
> And I will only add your Tested-by tags to patch [2/3] and [3/3].
> Is this correct?

That's fine, Thanks.

-- 
Best regards,
Junhui Liu


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

end of thread, other threads:[~2026-03-17  6:53 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-15  5:44 [PATCH v4 0/3] Add SDHCI support for Canaan K230 SoC Jiayu Du
2026-03-15  5:44 ` [PATCH v4 1/3] dt-bindings: mmc: Add sdhci support for Canaan k230 Jiayu Du
2026-03-15  5:44 ` [PATCH v4 2/3] mmc: sdhci-dwcmshc: Add Canaan K230 DWCMSHC controller support Jiayu Du
2026-03-16 12:33   ` Adrian Hunter
2026-03-15  5:44 ` [PATCH v4 3/3] riscv: dts: canaan: Add mmc nodes for K230 Jiayu Du
2026-03-16 14:15   ` Junhui Liu
2026-03-16 16:03     ` Jiayu Du
2026-03-17  6:52       ` Junhui Liu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox