[PATCH 08/17] mmc: zynq_sdhci: support Renesas RZ/N1

Ralph Siemsen <[email protected]> Fri, 31 Jul 2026 12:33:37 -0400
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <[email protected]>
The Renesas RZ/N1 SoC contains a MMC controller using the Arasan IP.
It is supported by the exisitng driver, with the following changes:

1) Multiple clocks need to be enabled. This is handled using
   clk_get_bulk() and clock_enable_bulk().

2) It is necessary to defer the sdhci_probe(), similar to what is
   done in drivers/mmc/am654_sdhci.c

Signed-off-by: Ralph Siemsen <[email protected]>
---
 drivers/mmc/Kconfig      |  2 +-
 drivers/mmc/zynq_sdhci.c | 39 ++++++++++++++++++++++++++++++++-------
 2 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index f9f7aa5cf97..7649fc8f53f 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -778,7 +778,7 @@ config TEGRA124_MMC_DISABLE_EXT_LOOPBACK
 config MMC_SDHCI_ZYNQ
 	bool "Arasan SDHCI controller support"
 	depends on OF_CONTROL
-	depends on ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2 || ARCH_ZYNQ || ARCH_ZYNQMP
+	depends on ARCH_RENESAS || ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2 || ARCH_ZYNQ || ARCH_ZYNQMP
 	depends on MMC_SDHCI
 	help
 	  Support for Arasan SDHCI host controller on Zynq/ZynqMP ARM SoCs platform
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index eda95b72f49..351e7d56569 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -1012,6 +1012,31 @@ static const struct sdhci_ops arasan_ops = {
 	.config_dll = &arasan_sdhci_config_dll,
 #endif
 };
+
+#elif defined(CONFIG_ARCH_RENESAS)
+/*
+ * It is unknown whether the IP in RZ/N1 supports these clock phase
+ * adjustments. The devicetree does not include these properties.
+ * So this is a no-op for now.
+ */
+static void arasan_dt_parse_clk_phases(struct udevice *dev)
+{
+}
+
+/*
+ * Renesas RZ/N1 needs deferred sdhci_probe(), otherwise the
+ * first CMD_00 fails with "Timeout for status update"
+ */
+static int arasan_sdhci_deferred_probe(struct sdhci_host *host)
+{
+	struct udevice *dev = host->mmc->dev;
+
+	return sdhci_probe(dev);
+}
+
+static const struct sdhci_ops arasan_ops = {
+	.deferred_probe = arasan_sdhci_deferred_probe,
+};
 #endif
 
 #if defined(CONFIG_ARCH_ZYNQMP) && defined(CONFIG_ZYNQMP_FIRMWARE)
@@ -1110,7 +1135,7 @@ static int arasan_sdhci_probe(struct udevice *dev)
 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
 	struct arasan_sdhci_priv *priv = dev_get_priv(dev);
 	struct sdhci_host *host;
-	struct clk clk;
+	struct clk_bulk clks;
 	unsigned long clock;
 	int ret;
 
@@ -1152,13 +1177,13 @@ static int arasan_sdhci_probe(struct udevice *dev)
 		}
 	}
 
-	ret = clk_get_by_index(dev, 0, &clk);
+	ret = clk_get_bulk(dev, &clks);
 	if (ret < 0) {
-		dev_err(dev, "failed to get clock\n");
+		dev_err(dev, "failed to get clock(s)\n");
 		return ret;
 	}
 
-	clock = clk_get_rate(&clk);
+	clock = clk_get_rate(&clks.clks[0]);
 	if (IS_ERR_VALUE(clock)) {
 		dev_err(dev, "failed to get rate\n");
 		return clock;
@@ -1166,9 +1191,9 @@ static int arasan_sdhci_probe(struct udevice *dev)
 
 	dev_dbg(dev, "%s: CLK %ld\n", __func__, clock);
 
-	ret = clk_enable(&clk);
+	ret = clk_enable_bulk(&clks);
 	if (ret) {
-		dev_err(dev, "failed to enable clock\n");
+		dev_err(dev, "failed to enable clock(s)\n");
 		return ret;
 	}
 
@@ -1239,7 +1264,7 @@ static int arasan_sdhci_of_to_plat(struct udevice *dev)
 	priv->host->name = dev->name;
 
 #if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL_NET) || \
-    defined(CONFIG_ARCH_VERSAL2)
+    defined(CONFIG_ARCH_VERSAL2) || defined(CONFIG_ARCH_RENESAS)
 	priv->host->ops = &arasan_ops;
 	arasan_dt_parse_clk_phases(dev);
 #endif

-- 
2.55.0