mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v2 0/6] mci: cadence: add v6 support
@ 2026-03-09 12:04 Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 1/6] mci: add data segment to mci_cmd Steffen Trumtrar
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2026-03-09 12:04 UTC (permalink / raw)
  To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar

The Agilex5 apperently has a cadence sdhci host controller in version 6.
Add support for this version, reworking the original driver
significantly.

Tested on Agilex5, sadly HS200-support is currently broken and doesn't
work yet with this driver.

Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
- sdhci_send_cmd: fix return value
- mci_cmd: add mci_data
- mci_cmd: setup mci_data in mci_core
- mci_cmd: remove mci_data from callers
- mci_cmd: split in separate patch
- cadence_sdhci: remove old driver before adding new one
- Link to v1: https://lore.barebox.org/20251215-v2025-11-0-topic-socfpga-agilex5-sdhci-v1-0-11eea1b2ef41@pengutronix.de

---
Steffen Trumtrar (6):
      mci: add data segment to mci_cmd
      mci: sdhci: add sdhci_send_cmd
      mci: sdhci: add set_uhs_signaling callback
      mci: cadence: remove driver
      mci: cadence: add support for version 6
      ARM: socfpga-agilex5_defconfig: enable cadencen-sdhci

 arch/arm/configs/socfpga-agilex5_defconfig |  11 +-
 drivers/mci/Kconfig                        |   2 +-
 drivers/mci/Makefile                       |   1 +
 drivers/mci/am654-sdhci.c                  |   4 +-
 drivers/mci/arasan-sdhci.c                 |   4 +-
 drivers/mci/atmel-sdhci.c                  |   5 +-
 drivers/mci/atmel_mci.c                    |   5 +-
 drivers/mci/atmel_mci_pbl.c                |   5 +-
 drivers/mci/bcm2835-sdhost.c               |   4 +-
 drivers/mci/cadence-sdhci.c                | 713 +++++++++++++----------------
 drivers/mci/cadence-sdhci.h                | 118 +++++
 drivers/mci/cadence-sdhci6.c               | 373 +++++++++++++++
 drivers/mci/dove-sdhci.c                   |   4 +-
 drivers/mci/dw_mmc.c                       |   3 +-
 drivers/mci/dwcmshc-sdhci.c                |   5 +-
 drivers/mci/imx-esdhc.c                    |   5 +-
 drivers/mci/imx.c                          |   4 +-
 drivers/mci/mci-bcm2835.c                  |   5 +-
 drivers/mci/mci-core.c                     | 187 ++++----
 drivers/mci/mci_spi.c                      |   3 +-
 drivers/mci/mmci.c                         |   6 +-
 drivers/mci/mxs.c                          |   7 +-
 drivers/mci/omap_hsmmc.c                   |   5 +-
 drivers/mci/pxamci.c                       |   4 +-
 drivers/mci/rockchip-dwcmshc-sdhci.c       |   4 +-
 drivers/mci/sdhci.c                        | 139 +++++-
 drivers/mci/sdhci.h                        |  22 +
 drivers/mci/stm32_sdmmc2.c                 |   4 +-
 drivers/mci/sunxi-mmc.c                    |   4 +-
 drivers/mci/tegra-sdmmc.c                  |   4 +-
 include/mci.h                              |   6 +-
 31 files changed, 1126 insertions(+), 540 deletions(-)
---
base-commit: 8c9d58cef2c65434e719ccbd3799b23014cb779d
change-id: 20251215-v2025-11-0-topic-socfpga-agilex5-sdhci-8d7de91edc30

Best regards,
-- 
Steffen Trumtrar <s.trumtrar@pengutronix.de>




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

* [PATCH v2 1/6] mci: add data segment to mci_cmd
  2026-03-09 12:04 [PATCH v2 0/6] mci: cadence: add v6 support Steffen Trumtrar
@ 2026-03-09 12:04 ` Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 2/6] mci: sdhci: add sdhci_send_cmd Steffen Trumtrar
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2026-03-09 12:04 UTC (permalink / raw)
  To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar

In Linux the struct mmc_command includes the mmc_data field and doesn't
hand it around in the function calls.

Do the same here and remove the mci_data parameter from the send_cmd
callback. The mci-core sets up the mci_cmd->data field and the drivers
can get the mmc_data from the mci_cmd struct.

A lot of the calls in mci-core don't use data in the mci_send_cmd call.
Explicitly initialize the mci_cmd struct with 0 (and therefore the
mci_data struct with NULL) on declaration.

When data is used and set up before mci_send_cmd is called the pointer
is xzalloc'd where it previously was setup on the stack.

Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
 drivers/mci/am654-sdhci.c            |   4 +-
 drivers/mci/arasan-sdhci.c           |   4 +-
 drivers/mci/atmel-sdhci.c            |   5 +-
 drivers/mci/atmel_mci.c              |   5 +-
 drivers/mci/atmel_mci_pbl.c          |   5 +-
 drivers/mci/bcm2835-sdhost.c         |   4 +-
 drivers/mci/dove-sdhci.c             |   4 +-
 drivers/mci/dw_mmc.c                 |   3 +-
 drivers/mci/dwcmshc-sdhci.c          |   5 +-
 drivers/mci/imx-esdhc.c              |   5 +-
 drivers/mci/imx.c                    |   4 +-
 drivers/mci/mci-bcm2835.c            |   5 +-
 drivers/mci/mci-core.c               | 187 ++++++++++++++++++-----------------
 drivers/mci/mci_spi.c                |   3 +-
 drivers/mci/mmci.c                   |   6 +-
 drivers/mci/mxs.c                    |   7 +-
 drivers/mci/omap_hsmmc.c             |   5 +-
 drivers/mci/pxamci.c                 |   4 +-
 drivers/mci/rockchip-dwcmshc-sdhci.c |   4 +-
 drivers/mci/sdhci.c                  |   4 +-
 drivers/mci/stm32_sdmmc2.c           |   4 +-
 drivers/mci/sunxi-mmc.c              |   4 +-
 drivers/mci/tegra-sdmmc.c            |   4 +-
 include/mci.h                        |   5 +-
 24 files changed, 147 insertions(+), 143 deletions(-)

diff --git a/drivers/mci/am654-sdhci.c b/drivers/mci/am654-sdhci.c
index 4ceea226f7..cea0451c1a 100644
--- a/drivers/mci/am654-sdhci.c
+++ b/drivers/mci/am654-sdhci.c
@@ -454,13 +454,13 @@ static void print_error(struct am654_sdhci_plat *host, int cmdidx)
 		sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS));
 }
 
-static int am654_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-				struct mci_data *data)
+static int am654_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct am654_sdhci_plat *host = container_of(mci, struct am654_sdhci_plat, mci);
 	u32 mask, command, xfer;
 	int ret;
 	dma_addr_t dma;
+	struct mci_data *data = cmd->data;
 
 	ret = sdhci_wait_idle(&host->sdhci, cmd, data);
 	if (ret)
diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 4adaaa243d..4e0e7b3793 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -244,13 +244,13 @@ static void print_error(struct arasan_sdhci_host *host, int cmdidx, int ret)
 		sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS));
 }
 
-static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-				 struct mci_data *data)
+static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
 	u32 mask, command, xfer;
 	dma_addr_t dma;
 	int ret;
+	struct mci_data *data = cmd->data;
 
 	ret = sdhci_wait_idle(&host->sdhci, cmd, data);
 	if (ret)
diff --git a/drivers/mci/atmel-sdhci.c b/drivers/mci/atmel-sdhci.c
index 7bf8004707..462cf21bc2 100644
--- a/drivers/mci/atmel-sdhci.c
+++ b/drivers/mci/atmel-sdhci.c
@@ -29,10 +29,9 @@ struct at91_sdhci_priv {
 
 #define to_priv(h) container_of(h, struct at91_sdhci_priv, mci)
 
-static int at91_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-				   struct mci_data *data)
+static int at91_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
-	return at91_sdhci_send_command(&to_priv(mci)->host, cmd, data);
+	return at91_sdhci_send_command(&to_priv(mci)->host, cmd, cmd->data);
 }
 
 static void at91_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
diff --git a/drivers/mci/atmel_mci.c b/drivers/mci/atmel_mci.c
index 1012feb6c2..65e53d7202 100644
--- a/drivers/mci/atmel_mci.c
+++ b/drivers/mci/atmel_mci.c
@@ -23,12 +23,11 @@ static void atmci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 	atmci_common_set_ios(host, ios);
 }
 
-static int atmci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-		  struct mci_data *data)
+static int atmci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct atmel_mci *host = to_mci_host(mci);
 
-	return atmci_common_request(host, cmd, data);
+	return atmci_common_request(host, cmd, cmd->data);
 }
 
 static void atmci_info(struct device *mci_dev)
diff --git a/drivers/mci/atmel_mci_pbl.c b/drivers/mci/atmel_mci_pbl.c
index 27727b2734..b70997a918 100644
--- a/drivers/mci/atmel_mci_pbl.c
+++ b/drivers/mci/atmel_mci_pbl.c
@@ -9,10 +9,9 @@
 #define SUPPORT_MAX_BLOCKS		16U
 
 static int pbl_atmci_common_request(struct pbl_mci *mci,
-				    struct mci_cmd *cmd,
-				    struct mci_data *data)
+				    struct mci_cmd *cmd)
 {
-	return atmci_common_request(mci->priv, cmd, data);
+	return atmci_common_request(mci->priv, cmd, cmd->data);
 }
 
 static struct atmel_mci atmci_host;
diff --git a/drivers/mci/bcm2835-sdhost.c b/drivers/mci/bcm2835-sdhost.c
index 9ed7cffb55..31c28ef3fb 100644
--- a/drivers/mci/bcm2835-sdhost.c
+++ b/drivers/mci/bcm2835-sdhost.c
@@ -521,10 +521,10 @@ static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock)
 	writel(clock / 2, host->regs + SDTOUT);
 }
 
-static int bcm2835_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-			    struct mci_data *data)
+static int bcm2835_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct bcm2835_host *host = to_bcm2835_host(mci);
+	struct mci_data *data = cmd->data;
 	u32 edm, fsm;
 	int ret = 0;
 
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
index 71045016a1..45b996cca8 100644
--- a/drivers/mci/dove-sdhci.c
+++ b/drivers/mci/dove-sdhci.c
@@ -54,13 +54,13 @@ static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask)
 	return 0;
 }
 
-static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-				struct mci_data *data)
+static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	u32 command, xfer;
 	int ret;
 	unsigned int num_bytes = 0;
 	struct dove_sdhci *host = priv_from_mci_host(mci);
+	struct mci_data *data = cmd->data;
 
 	ret = sdhci_wait_idle_data(&host->sdhci, cmd);
 	if (ret)
diff --git a/drivers/mci/dw_mmc.c b/drivers/mci/dw_mmc.c
index 30e5d56944..9944693d01 100644
--- a/drivers/mci/dw_mmc.c
+++ b/drivers/mci/dw_mmc.c
@@ -263,7 +263,7 @@ static int dwmci_write_data_pio(struct dwmci_host *host, struct mci_data *data)
 }
 
 static int
-dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
+dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct dwmci_host *host = to_dwmci_host(mci);
 	int flags = 0;
@@ -273,6 +273,7 @@ dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
 	int ret;
 	unsigned int num_bytes = 0;
 	dma_addr_t dma = 0;
+	struct mci_data *data = cmd->data;
 
 	start = get_time_ns();
 	while (1) {
diff --git a/drivers/mci/dwcmshc-sdhci.c b/drivers/mci/dwcmshc-sdhci.c
index 6fdbb61565..7f467e52b5 100644
--- a/drivers/mci/dwcmshc-sdhci.c
+++ b/drivers/mci/dwcmshc-sdhci.c
@@ -102,12 +102,11 @@ static int do_abort_sequence(struct mci_host *mci, struct mci_cmd *current_cmd)
 	return ret;
 }
 
-static int dwcmshc_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-				struct mci_data *data)
+static int dwcmshc_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
 		return do_abort_sequence(mci, cmd);
-	return do_send_cmd(mci, cmd, data);
+	return do_send_cmd(mci, cmd, cmd->data);
 }
 
 static int do_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 6dd3bef457..ba33daffc4 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -75,12 +75,11 @@
  * Sends a command out on the bus.  Takes the mci pointer,
  * a command pointer, and an optional data pointer.
  */
-static int
-esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
+static int esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
 
-	return  __esdhc_send_cmd(host, cmd, data);
+	return  __esdhc_send_cmd(host, cmd, cmd->data);
 }
 
 static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr)
diff --git a/drivers/mci/imx.c b/drivers/mci/imx.c
index d462cb8843..15f80697ba 100644
--- a/drivers/mci/imx.c
+++ b/drivers/mci/imx.c
@@ -378,10 +378,10 @@ static int mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
 	return ret;
 }
 
-static int mxcmci_request(struct mci_host *mci, struct mci_cmd *cmd,
-		struct mci_data *data)
+static int mxcmci_request(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct mxcmci_host *host = to_mxcmci(mci);
+	struct mci_data *data = cmd->data;
 	unsigned int cmdat = host->cmdat;
 	u32 stat;
 	int ret;
diff --git a/drivers/mci/mci-bcm2835.c b/drivers/mci/mci-bcm2835.c
index aad5ae0d9e..d33e54d2ab 100644
--- a/drivers/mci/mci-bcm2835.c
+++ b/drivers/mci/mci-bcm2835.c
@@ -114,11 +114,12 @@ static void bcm2835_mci_reset_emmc(struct bcm2835_mci_host *host, u32 reset,
  * @param data The data to handle in the command (can be NULL)
  * @return 0 on success, negative value else
  */
-static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd,
-		struct mci_data *data) {
+static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd)
+{
 	u32 command, block_data = 0, transfer_mode = 0;
 	int ret;
 	struct bcm2835_mci_host *host = to_bcm2835_host(mci);
+	struct mci_data *data = cmd->data;
 
 	sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, false,
 				&command, &transfer_mode);
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 37d864b3d0..69ae52a29a 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -72,11 +72,11 @@ static inline unsigned mci_caps(struct mci *mci)
  * @param data The data according to the command (can be NULL)
  * @return Driver's answer (0 on success)
  */
-int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd, struct mci_data *data)
+int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd)
 {
 	struct mci_host *host = mci->host;
 
-	return host->ops.send_cmd(mci->host, cmd, data);
+	return host->ops.send_cmd(mci->host, cmd);
 }
 
 /**
@@ -90,12 +90,12 @@ int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd, struct mci_data *data)
  * Return: 0 if ok, -ve on error
  */
 static int mci_send_cmd_retry(struct mci *mci, struct mci_cmd *cmd,
-			      struct mci_data *data, unsigned retries)
+			      unsigned int retries)
 {
 	int ret;
 
 	do
-		ret = mci_send_cmd(mci, cmd, data);
+		ret = mci_send_cmd(mci, cmd);
 	while (ret && retries--);
 
 	return ret;
@@ -108,11 +108,11 @@ static int mci_send_cmd_retry(struct mci *mci, struct mci_cmd *cmd,
  */
 static int mci_set_dsr(struct mci *mci)
 {
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 
 	mci_setup_cmd(&cmd, MMC_CMD_SET_DSR,
 			(mci->host->dsr_val >> 16) | 0xffff, MMC_RSP_NONE);
-	return mci_send_cmd(mci, &cmd, NULL);
+	return mci_send_cmd(mci, &cmd);
 }
 
 /**
@@ -123,13 +123,13 @@ static int mci_set_dsr(struct mci *mci)
  */
 static int mci_set_blocklen(struct mci *mci, unsigned len)
 {
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 
 	if (mci->host->ios.timing == MMC_TIMING_MMC_DDR52)
 		return 0;
 
 	mci_setup_cmd(&cmd, MMC_CMD_SET_BLOCKLEN, len, MMC_RSP_R1);
-	return mci_send_cmd_retry(mci, &cmd, NULL, 4);
+	return mci_send_cmd_retry(mci, &cmd, 4);
 }
 
 static void *sector_buf;
@@ -137,7 +137,7 @@ static void *sector_buf;
 static int mci_send_status(struct mci *mci, unsigned int *status)
 {
 	struct mci_host *host = mci->host;
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 	int ret;
 
 	/*
@@ -151,7 +151,7 @@ static int mci_send_status(struct mci *mci, unsigned int *status)
 	cmd.resp_type = MMC_RSP_R1;
 	cmd.cmdarg = mci->rca << 16;
 
-	ret = mci_send_cmd_retry(mci, &cmd, NULL, 4);
+	ret = mci_send_cmd_retry(mci, &cmd, 4);
 	if (!ret)
 		*status = cmd.response[0];
 
@@ -161,14 +161,13 @@ static int mci_send_status(struct mci *mci, unsigned int *status)
 static int mci_app_sd_status(struct mci *mci, __be32 *ssr)
 {
 	int err;
-	struct mci_cmd cmd = {};
-	struct mci_data data;
+	struct mci_cmd cmd = {0};
 
 	cmd.cmdidx = MMC_CMD_APP_CMD;
 	cmd.resp_type = MMC_RSP_R1;
 	cmd.cmdarg = mci->rca << 16;
 
-	err = mci_send_cmd_retry(mci, &cmd, NULL, 4);
+	err = mci_send_cmd_retry(mci, &cmd, 4);
 	if (err)
 		return err;
 
@@ -176,12 +175,14 @@ static int mci_app_sd_status(struct mci *mci, __be32 *ssr)
 	cmd.resp_type = MMC_RSP_R1;
 	cmd.cmdarg = 0;
 
-	data.dest = (u8 *)ssr;
-	data.blocksize = 64;
-	data.blocks = 1;
-	data.flags = MMC_DATA_READ;
+	cmd.data = xzalloc(sizeof(struct mci_data));
+
+	cmd.data->dest = (u8 *)ssr;
+	cmd.data->blocksize = 64;
+	cmd.data->blocks = 1;
+	cmd.data->flags = MMC_DATA_READ;
 
-	return mci_send_cmd_retry(mci, &cmd, &data, 3);
+	return mci_send_cmd_retry(mci, &cmd, 3);
 }
 
 static int mmc_switch_status_error(struct mci_host *host, u32 status)
@@ -262,7 +263,6 @@ static int mci_block_write(struct mci *mci, const void *src, int blocknum,
 			   int blocks)
 {
 	struct mci_cmd cmd = {};
-	struct mci_data data;
 	unsigned mmccmd;
 	int ret;
 
@@ -287,16 +287,19 @@ static int mci_block_write(struct mci *mci, const void *src, int blocknum,
 		mci->high_capacity != 0 ? blocknum : blocknum * mci->write_bl_len,
 		MMC_RSP_R1);
 
-	data.src = src;
-	data.blocks = blocks;
-	data.blocksize = mci->write_bl_len;
-	data.flags = MMC_DATA_WRITE;
+	cmd.data = xzalloc(sizeof(struct mci_data));
+
+	cmd.data->src = src;
+	cmd.data->blocks = blocks;
+	cmd.data->blocksize = mci->write_bl_len;
+	cmd.data->flags = MMC_DATA_WRITE;
 
-	ret = mci_send_cmd(mci, &cmd, &data);
+	ret = mci_send_cmd(mci, &cmd);
 
 	if (ret || blocks > 1) {
 		mci_setup_cmd(&cmd, MMC_CMD_STOP_TRANSMISSION, 0, MMC_RSP_R1b);
-		mci_send_cmd(mci, &cmd, NULL);
+		cmd.data = NULL;
+		mci_send_cmd(mci, &cmd);
         }
 
 	return ret;
@@ -313,7 +316,7 @@ static int mci_block_erase(struct mci *card, unsigned int from,
 			   unsigned int blkcnt, unsigned int arg)
 {
 	unsigned int to = from + blkcnt - 1;
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 	int err;
 
 	if (!card->high_capacity) {
@@ -324,7 +327,7 @@ static int mci_block_erase(struct mci *card, unsigned int from,
 	cmd.cmdidx = IS_SD(card) ? SD_ERASE_WR_BLK_START : MMC_ERASE_GROUP_START;
 	cmd.cmdarg = from;
 	cmd.resp_type = MMC_RSP_R1;
-	err = mci_send_cmd(card, &cmd, NULL);
+	err = mci_send_cmd(card, &cmd);
 	if (err)
 		goto err_out;
 
@@ -332,7 +335,7 @@ static int mci_block_erase(struct mci *card, unsigned int from,
 	cmd.cmdidx = IS_SD(card) ? SD_ERASE_WR_BLK_END : MMC_ERASE_GROUP_END;
 	cmd.cmdarg = to;
 	cmd.resp_type = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
-	err = mci_send_cmd(card, &cmd, NULL);
+	err = mci_send_cmd(card, &cmd);
 	if (err)
 		goto err_out;
 
@@ -340,8 +343,7 @@ static int mci_block_erase(struct mci *card, unsigned int from,
 	cmd.cmdidx = MMC_ERASE;
 	cmd.cmdarg = arg;
 	cmd.resp_type = MMC_RSP_R1b;
-
-	err = mci_send_cmd(card, &cmd, NULL);
+	err = mci_send_cmd(card, &cmd);
 	if (err)
 		goto err_out;
 
@@ -355,11 +357,11 @@ static int mci_block_erase(struct mci *card, unsigned int from,
 
 int mci_set_blockcount(struct mci *mci, unsigned int cmdarg)
 {
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 
 	mci_setup_cmd(&cmd, MMC_CMD_SET_BLOCK_COUNT, cmdarg, MMC_RSP_R1);
 
-	return mci_send_cmd(mci, &cmd, NULL);
+	return mci_send_cmd(mci, &cmd);
 }
 
 /**
@@ -373,7 +375,6 @@ static int mci_block_read(struct mci *mci, void *dst, int blocknum,
 			  int blocks)
 {
 	struct mci_cmd cmd = {};
-	struct mci_data data;
 	int ret;
 	unsigned mmccmd;
 
@@ -387,17 +388,20 @@ static int mci_block_read(struct mci *mci, void *dst, int blocknum,
 		mci->high_capacity != 0 ? blocknum : blocknum * mci->read_bl_len,
 		MMC_RSP_R1);
 
-	data.dest = dst;
-	data.blocks = blocks;
-	data.blocksize = mci->read_bl_len;
-	data.flags = MMC_DATA_READ;
+	cmd.data = xzalloc(sizeof(struct mci_data));
 
-	ret = mci_send_cmd(mci, &cmd, &data);
+	cmd.data->dest = dst;
+	cmd.data->blocks = blocks;
+	cmd.data->blocksize = mci->read_bl_len;
+	cmd.data->flags = MMC_DATA_READ;
+
+	ret = mci_send_cmd(mci, &cmd);
 
 	if (ret || blocks > 1) {
 		mci_setup_cmd(&cmd, MMC_CMD_STOP_TRANSMISSION, 0,
 			      IS_SD(mci) ? MMC_RSP_R1b : MMC_RSP_R1);
-		mci_send_cmd(mci, &cmd, NULL);
+		cmd.data = NULL;
+		mci_send_cmd(mci, &cmd);
 	}
 	return ret;
 }
@@ -409,13 +413,13 @@ static int mci_block_read(struct mci *mci, void *dst, int blocknum,
  */
 static int mci_go_idle(struct mci *mci)
 {
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 	int err;
 
 	udelay(1000);
 
 	mci_setup_cmd(&cmd, MMC_CMD_GO_IDLE_STATE, 0, MMC_RSP_NONE);
-	err = mci_send_cmd(mci, &cmd, NULL);
+	err = mci_send_cmd(mci, &cmd);
 
 	if (err) {
 		dev_dbg(&mci->dev, "Activating IDLE state failed: %d\n", err);
@@ -429,11 +433,11 @@ static int mci_go_idle(struct mci *mci)
 
 static int sdio_send_op_cond(struct mci *mci)
 {
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 
 	mci_setup_cmd(&cmd, SD_IO_SEND_OP_COND, 0, MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR);
 
-	return mci_send_cmd(mci, &cmd, NULL);
+	return mci_send_cmd(mci, &cmd);
 }
 
 /**
@@ -444,7 +448,7 @@ static int sdio_send_op_cond(struct mci *mci)
 static int sd_send_op_cond(struct mci *mci)
 {
 	struct mci_host *host = mci->host;
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 	int timeout = 1000;
 	int err;
 	unsigned voltages;
@@ -462,7 +466,7 @@ static int sd_send_op_cond(struct mci *mci)
 
 	do {
 		mci_setup_cmd(&cmd, MMC_CMD_APP_CMD, 0, MMC_RSP_R1);
-		err = mci_send_cmd(mci, &cmd, NULL);
+		err = mci_send_cmd(mci, &cmd);
 		if (err) {
 			dev_dbg(&mci->dev, "Preparing SD for operating conditions failed: %d\n", err);
 			return err;
@@ -474,7 +478,7 @@ static int sd_send_op_cond(struct mci *mci)
 			arg |= OCR_HCS;
 
 		mci_setup_cmd(&cmd, SD_CMD_APP_SEND_OP_COND, arg, MMC_RSP_R3);
-		err = mci_send_cmd(mci, &cmd, NULL);
+		err = mci_send_cmd(mci, &cmd);
 		if (err) {
 			dev_dbg(&mci->dev, "SD operation condition set failed: %d\n", err);
 			return err;
@@ -498,7 +502,7 @@ static int sd_send_op_cond(struct mci *mci)
 
 	if (mmc_host_is_spi(host)) { /* read OCR for spi */
 		mci_setup_cmd(&cmd, MMC_CMD_SPI_READ_OCR, 0, MMC_RSP_R3);
-		err = mci_send_cmd(mci, &cmd, NULL);
+		err = mci_send_cmd(mci, &cmd);
 		if (err)
 			return err;
 	}
@@ -519,7 +523,7 @@ static int sd_send_op_cond(struct mci *mci)
 static int mmc_send_op_cond(struct mci *mci)
 {
 	struct mci_host *host = mci->host;
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 	int timeout = 1000;
 	int err;
 
@@ -529,7 +533,7 @@ static int mmc_send_op_cond(struct mci *mci)
 	do {
 		mci_setup_cmd(&cmd, MMC_CMD_SEND_OP_COND, OCR_HCS |
 				host->voltages, MMC_RSP_R3);
-		err = mci_send_cmd(mci, &cmd, NULL);
+		err = mci_send_cmd(mci, &cmd);
 
 		if (err) {
 			dev_dbg(&mci->dev, "Preparing MMC for operating conditions failed: %d\n", err);
@@ -565,17 +569,18 @@ static int mmc_send_op_cond(struct mci *mci)
 int mci_send_ext_csd(struct mci *mci, char *ext_csd)
 {
 	struct mci_cmd cmd = {};
-	struct mci_data data;
 
 	/* Get the Card Status Register */
 	mci_setup_cmd(&cmd, MMC_CMD_SEND_EXT_CSD, 0, MMC_RSP_R1);
 
-	data.dest = ext_csd;
-	data.blocks = 1;
-	data.blocksize = 512;
-	data.flags = MMC_DATA_READ;
+	cmd.data = xzalloc(sizeof(struct mci_data));
+
+	cmd.data->dest = ext_csd;
+	cmd.data->blocks = 1;
+	cmd.data->blocksize = 512;
+	cmd.data->flags = MMC_DATA_READ;
 
-	return mci_send_cmd(mci, &cmd, &data);
+	return mci_send_cmd(mci, &cmd);
 }
 
 /**
@@ -593,7 +598,7 @@ int mci_send_ext_csd(struct mci *mci, char *ext_csd)
 int mci_switch(struct mci *mci, unsigned index, unsigned value)
 {
 	unsigned int status;
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 	int ret;
 
 	mci_setup_cmd(&cmd, MMC_CMD_SWITCH,
@@ -602,7 +607,7 @@ int mci_switch(struct mci *mci, unsigned index, unsigned value)
 		(value << 8),
 		 MMC_RSP_R1b);
 
-	ret = mci_send_cmd(mci, &cmd, NULL);
+	ret = mci_send_cmd(mci, &cmd);
 	if (ret)
 		return ret;
 
@@ -853,7 +858,6 @@ static int sd_switch(struct mci *mci, unsigned mode, unsigned group,
 			unsigned value, uint8_t *resp)
 {
 	struct mci_cmd cmd = {};
-	struct mci_data data;
 	unsigned arg;
 
 	arg = (mode << 31) | 0xffffff;
@@ -863,12 +867,13 @@ static int sd_switch(struct mci *mci, unsigned mode, unsigned group,
 	/* Switch the frequency */
 	mci_setup_cmd(&cmd, SD_CMD_SWITCH_FUNC, arg, MMC_RSP_R1);
 
-	data.dest = resp;
-	data.blocksize = 64;
-	data.blocks = 1;
-	data.flags = MMC_DATA_READ;
+	cmd.data = xzalloc(sizeof(struct mci_data));
+	cmd.data->dest = resp;
+	cmd.data->blocksize = 64;
+	cmd.data->blocks = 1;
+	cmd.data->flags = MMC_DATA_READ;
 
-	return mci_send_cmd(mci, &cmd, &data);
+	return mci_send_cmd(mci, &cmd);
 }
 
 static int sd_read_ssr(struct mci *mci)
@@ -921,8 +926,7 @@ static int sd_read_ssr(struct mci *mci)
  */
 static int sd_change_freq(struct mci *mci)
 {
-	struct mci_cmd cmd = {};
-	struct mci_data data;
+	struct mci_cmd cmd = {0};
 	struct mci_host *host = mci->host;
 	uint32_t *switch_status = sector_buf;
 	uint32_t *scr = sector_buf;
@@ -937,7 +941,7 @@ static int sd_change_freq(struct mci *mci)
 
 	/* Read the SCR to find out if this card supports higher speeds */
 	mci_setup_cmd(&cmd, MMC_CMD_APP_CMD, mci->rca << 16, MMC_RSP_R1);
-	err = mci_send_cmd(mci, &cmd, NULL);
+	err = mci_send_cmd(mci, &cmd);
 	if (err) {
 		dev_dbg(&mci->dev, "Query SD card capabilities failed: %d\n", err);
 		return err;
@@ -947,14 +951,17 @@ static int sd_change_freq(struct mci *mci)
 
 	timeout = 3;
 
+	cmd.data = xzalloc(sizeof(struct mci_data));
+
 retry_scr:
 	dev_dbg(&mci->dev, "Trying to read the SCR (try %d of %d)\n", 4 - timeout, 3);
-	data.dest = (char *)scr;
-	data.blocksize = 8;
-	data.blocks = 1;
-	data.flags = MMC_DATA_READ;
 
-	err = mci_send_cmd(mci, &cmd, &data);
+	cmd.data->dest = (char *)scr;
+	cmd.data->blocksize = 8;
+	cmd.data->blocks = 1;
+	cmd.data->flags = MMC_DATA_READ;
+
+	err = mci_send_cmd(mci, &cmd);
 	if (err) {
 		dev_dbg(&mci->dev, " Catch error (%d)", err);
 		if (timeout--) {
@@ -1449,7 +1456,8 @@ static int mci_startup_sd(struct mci *mci)
 	if (mci_caps(mci) & MMC_CAP_4_BIT_DATA) {
 		dev_dbg(&mci->dev, "Prepare for bus width change\n");
 		mci_setup_cmd(&cmd, MMC_CMD_APP_CMD, mci->rca << 16, MMC_RSP_R1);
-		err = mci_send_cmd(mci, &cmd, NULL);
+		cmd.data = NULL;
+		err = mci_send_cmd(mci, &cmd);
 		if (err) {
 			dev_dbg(&mci->dev, "Preparing SD for bus width change failed: %d\n", err);
 			return err;
@@ -1457,7 +1465,7 @@ static int mci_startup_sd(struct mci *mci)
 
 		dev_dbg(&mci->dev, "Set SD bus width to 4 bit\n");
 		mci_setup_cmd(&cmd, SD_CMD_APP_SET_BUS_WIDTH, 2, MMC_RSP_R1);
-		err = mci_send_cmd(mci, &cmd, NULL);
+		err = mci_send_cmd(mci, &cmd);
 		if (err) {
 			dev_warn(&mci->dev, "Changing SD bus width failed: %d\n", err);
 			/* TODO continue with 1 bit? */
@@ -1644,7 +1652,6 @@ static const u8 tuning_blk_pattern_8bit[] = {
 int mmc_send_tuning(struct mci *mci, u32 opcode)
 {
 	struct mci_cmd cmd = {};
-	struct mci_data data = {};
 	const u8 *tuning_block_pattern;
 	int size, err = 0;
 	u8 *data_buf;
@@ -1664,19 +1671,19 @@ int mmc_send_tuning(struct mci *mci, u32 opcode)
 
 	mci_setup_cmd(&cmd, opcode, 0, MMC_RSP_R1 | MMC_CMD_ADTC);
 
-
-	data.blocksize = size;
-	data.blocks = 1;
-	data.flags = MMC_DATA_READ;
+	cmd.data = xzalloc(sizeof(struct mci_data));
+	cmd.data->blocksize = size;
+	cmd.data->blocks = 1;
+	cmd.data->flags = MMC_DATA_READ;
 
 	/*
 	 * According to the tuning specs, Tuning process
 	 * is normally shorter 40 executions of CMD19,
 	 * and timeout value should be shorter than 150 ms
 	 */
-	data.timeout_ns = 150 * NSEC_PER_MSEC;
+	cmd.data->timeout_ns = 150 * NSEC_PER_MSEC;
 
-	err = mci_send_cmd(mci, &cmd, &data);
+	err = mci_send_cmd(mci, &cmd);
 	if (err)
 		goto out;
 
@@ -1691,7 +1698,7 @@ EXPORT_SYMBOL_GPL(mmc_send_tuning);
 
 int mci_send_abort_tuning(struct mci *mci, u32 opcode)
 {
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 
 	/*
 	 * eMMC specification specifies that CMD12 can be used to stop a tuning
@@ -1704,7 +1711,7 @@ int mci_send_abort_tuning(struct mci *mci, u32 opcode)
 	cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
 	cmd.resp_type = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 
-	return mci_send_cmd(mci, &cmd, NULL);
+	return mci_send_cmd(mci, &cmd);
 }
 EXPORT_SYMBOL_GPL(mci_send_abort_tuning);
 
@@ -2022,13 +2029,13 @@ static void mci_init_erase(struct mci *card)
 static int mci_startup(struct mci *mci)
 {
 	struct mci_host *host = mci->host;
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 	int err;
 
 	if (IS_ENABLED(CONFIG_MMC_SPI_CRC_ON) && mmc_host_is_spi(host)) { /* enable CRC check for spi */
 
 		mci_setup_cmd(&cmd, MMC_CMD_SPI_CRC_ON_OFF, 1, MMC_RSP_R1);
-		err = mci_send_cmd(mci, &cmd, NULL);
+		err = mci_send_cmd(mci, &cmd);
 
 		if (err) {
 			dev_dbg(&mci->dev, "Can't enable CRC check : %d\n", err);
@@ -2040,7 +2047,7 @@ static int mci_startup(struct mci *mci)
 
 	/* Put the Card in Identify Mode */
 	mci_setup_cmd(&cmd, mmc_host_is_spi(host) ? MMC_CMD_SEND_CID : MMC_CMD_ALL_SEND_CID, 0, MMC_RSP_R2);
-	err = mci_send_cmd(mci, &cmd, NULL);
+	err = mci_send_cmd(mci, &cmd);
 	if (err) {
 		dev_dbg(&mci->dev, "Can't bring card into identify mode: %d\n", err);
 		return err;
@@ -2059,7 +2066,7 @@ static int mci_startup(struct mci *mci)
 	if (!mmc_host_is_spi(host)) { /* cmd not supported in spi */
 		dev_dbg(&mci->dev, "Get/Set relative address\n");
 		mci_setup_cmd(&cmd, SD_CMD_SEND_RELATIVE_ADDR, mci->rca << 16, MMC_RSP_R6);
-		err = mci_send_cmd(mci, &cmd, NULL);
+		err = mci_send_cmd(mci, &cmd);
 		if (err) {
 			dev_dbg(&mci->dev, "Get/Set relative address failed: %d\n", err);
 			return err;
@@ -2072,7 +2079,7 @@ static int mci_startup(struct mci *mci)
 	dev_dbg(&mci->dev, "Get card's specific data\n");
 	/* Get the Card-Specific Data */
 	mci_setup_cmd(&cmd, MMC_CMD_SEND_CSD, mci->rca << 16, MMC_RSP_R2);
-	err = mci_send_cmd(mci, &cmd, NULL);
+	err = mci_send_cmd(mci, &cmd);
 	if (err) {
 		dev_dbg(&mci->dev, "Getting card's specific data failed: %d\n", err);
 		return err;
@@ -2111,7 +2118,7 @@ static int mci_startup(struct mci *mci)
 		dev_dbg(&mci->dev, "Select the card, and put it into Transfer Mode\n");
 		/* Select the card, and put it into Transfer Mode */
 		mci_setup_cmd(&cmd, MMC_CMD_SELECT_CARD, mci->rca << 16, MMC_RSP_R1b);
-		err = mci_send_cmd(mci, &cmd, NULL);
+		err = mci_send_cmd(mci, &cmd);
 		if (err) {
 			dev_dbg(&mci->dev, "Putting in transfer mode failed: %d\n", err);
 			return err;
@@ -2166,14 +2173,14 @@ static int mci_startup(struct mci *mci)
 static int sd_send_if_cond(struct mci *mci)
 {
 	struct mci_host *host = mci->host;
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 	int err;
 
 	mci_setup_cmd(&cmd, SD_CMD_SEND_IF_COND,
 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
 		((host->voltages & 0x00ff8000) != 0) << 8 | 0xaa,
 		MMC_RSP_R7);
-	err = mci_send_cmd(mci, &cmd, NULL);
+	err = mci_send_cmd(mci, &cmd);
 	if (err) {
 		dev_dbg(&mci->dev, "Query interface conditions failed: %d\n", err);
 		return err;
diff --git a/drivers/mci/mci_spi.c b/drivers/mci/mci_spi.c
index 3ab90d768f..06693a5811 100644
--- a/drivers/mci/mci_spi.c
+++ b/drivers/mci/mci_spi.c
@@ -235,9 +235,10 @@ static uint mmc_spi_writedata(struct mmc_spi_host *host, const void *xbuf,
 	return r1;
 }
 
-static int mmc_spi_request(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
+static int mmc_spi_request(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct mmc_spi_host	*host = to_spi_host(mci);
+	struct mci_data *data = cmd->data;
 	uint8_t r1;
 	int i;
 	int ret = 0;
diff --git a/drivers/mci/mmci.c b/drivers/mci/mmci.c
index 1a70776bb1..7e1b5e3f2c 100644
--- a/drivers/mci/mmci.c
+++ b/drivers/mci/mmci.c
@@ -421,12 +421,12 @@ static int do_data_transfer(struct mci_host *mci, struct mci_cmd *cmd, struct mc
 	return error;
 }
 
-static int mci_request(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
+static int mci_request(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	int result;
 
-	if (data)
-		result = do_data_transfer(mci, cmd, data);
+	if (cmd->data)
+		result = do_data_transfer(mci, cmd, cmd->data);
 	else
 		result = do_command(mci, cmd);
 
diff --git a/drivers/mci/mxs.c b/drivers/mci/mxs.c
index 63a4813ff4..b297a978aa 100644
--- a/drivers/mci/mxs.c
+++ b/drivers/mci/mxs.c
@@ -461,16 +461,15 @@ static int mxs_mci_initialize(struct mci_host *host, struct device *mci_dev)
  * @param data The data to handle in the command (can be NULL)
  * @return 0 on success, negative value else
  */
-static int mxs_mci_request(struct mci_host *host, struct mci_cmd *cmd,
-			struct mci_data *data)
+static int mxs_mci_request(struct mci_host *host, struct mci_cmd *cmd)
 {
 	struct mxs_mci_host *mxs_mci = to_mxs_mci(host);
 	int rc;
 
-	if ((cmd->resp_type == 0) || (data == NULL))
+	if ((cmd->resp_type == 0) || (cmd->data == NULL))
 		rc = mxs_mci_std_cmds(mxs_mci, cmd);
 	else
-		rc = mxs_mci_adtc(mxs_mci, cmd, data);	/* with response and data */
+		rc = mxs_mci_adtc(mxs_mci, cmd, cmd->data);	/* with response and data */
 
 	mxs_mci_finish_request(mxs_mci);	/* TODO */
 	return rc;
diff --git a/drivers/mci/omap_hsmmc.c b/drivers/mci/omap_hsmmc.c
index 03f71eb453..4bc3ea4092 100644
--- a/drivers/mci/omap_hsmmc.c
+++ b/drivers/mci/omap_hsmmc.c
@@ -53,12 +53,11 @@ static int mmc_init_setup(struct mci_host *mci, struct device *dev)
 	return omap_hsmmc_init(hsmmc);
 }
 
-static int mmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-		struct mci_data *data)
+static int mmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct omap_hsmmc *hsmmc = to_hsmmc(mci);
 
-	return omap_hsmmc_send_cmd(hsmmc, cmd, data);
+	return omap_hsmmc_send_cmd(hsmmc, cmd, cmd->data);
 }
 
 static void mmc_set_ios(struct mci_host *mci, struct mci_ios *ios)
diff --git a/drivers/mci/pxamci.c b/drivers/mci/pxamci.c
index 6b3e213be5..f337ea48ef 100644
--- a/drivers/mci/pxamci.c
+++ b/drivers/mci/pxamci.c
@@ -258,10 +258,10 @@ static int pxamci_mmccmd(struct pxamci_host *host, struct mci_cmd *cmd,
 	return ret;
 }
 
-static int pxamci_request(struct mci_host *mci, struct mci_cmd *cmd,
-			  struct mci_data *data)
+static int pxamci_request(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct pxamci_host *host = to_pxamci(mci);
+	struct mci_data *data = cmd->data;
 	unsigned int cmdat;
 	int ret;
 
diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c
index c4c03f703a..eb1c8760bf 100644
--- a/drivers/mci/rockchip-dwcmshc-sdhci.c
+++ b/drivers/mci/rockchip-dwcmshc-sdhci.c
@@ -241,10 +241,10 @@ static void print_error(struct rk_sdhci_host *host, int cmdidx)
 		sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS));
 }
 
-static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-				 struct mci_data *data)
+static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+	struct mci_data *data = cmd->data;
 	u32 command, xfer;
 	int ret;
 	dma_addr_t dma;
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 2d32a8b311..847c0dc516 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -62,7 +62,7 @@ static int sdhci_send_command_retry(struct sdhci *host, struct mci_cmd *cmd)
 		mdelay(1);
 	}
 
-	return host->mci->ops.send_cmd(host->mci, cmd, NULL);
+	return host->mci->ops.send_cmd(host->mci, cmd);
 }
 
 /*
@@ -74,7 +74,7 @@ static int sdhci_send_command_retry(struct sdhci *host, struct mci_cmd *cmd)
  */
 static int sdhci_send_tuning(struct sdhci *host, u32 opcode)
 {
-	struct mci_cmd cmd = {};
+	struct mci_cmd cmd = {0};
 	int ret;
 
 	cmd.cmdidx = opcode;
diff --git a/drivers/mci/stm32_sdmmc2.c b/drivers/mci/stm32_sdmmc2.c
index 8aeda6e988..36273ac270 100644
--- a/drivers/mci/stm32_sdmmc2.c
+++ b/drivers/mci/stm32_sdmmc2.c
@@ -476,10 +476,10 @@ static int stm32_sdmmc2_end_data(struct stm32_sdmmc2_priv *priv,
 	return 0;
 }
 
-static int stm32_sdmmc2_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-				 struct mci_data *data)
+static int stm32_sdmmc2_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct stm32_sdmmc2_priv *priv = to_mci_host(mci);
+	struct mci_data *data = cmd->data;
 	u32 cmdat = data ? SDMMC_CMD_CMDTRANS : 0;
 	dma_addr_t dma_addr = DMA_ERROR_CODE;
 	u32 data_length = 0;
diff --git a/drivers/mci/sunxi-mmc.c b/drivers/mci/sunxi-mmc.c
index 376ef2c0a9..297e053ac8 100644
--- a/drivers/mci/sunxi-mmc.c
+++ b/drivers/mci/sunxi-mmc.c
@@ -20,14 +20,14 @@
 #include "sunxi-mmc.h"
 #include "sunxi-mmc-common.c"
 
-static int sdxc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
+static int sdxc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct sunxi_mmc_host *host = to_sunxi_mmc_host(mci);
 	struct device *dev = mci->hw_dev;
 	const char *why = "";
 	int ret;
 
-	ret = sunxi_mmc_send_cmd(host, cmd, data, &why);
+	ret = sunxi_mmc_send_cmd(host, cmd, cmd->data, &why);
 	if (ret && ret != -ETIMEDOUT && ret != -EINVAL)
 		dev_err(dev, "error %s CMD%d (%d)\n", why, cmd->cmdidx, ret);
 	if (ret == -ETIMEDOUT)
diff --git a/drivers/mci/tegra-sdmmc.c b/drivers/mci/tegra-sdmmc.c
index ce868b48ce..bc6a7728db 100644
--- a/drivers/mci/tegra-sdmmc.c
+++ b/drivers/mci/tegra-sdmmc.c
@@ -96,10 +96,10 @@ static int tegra_sdmmc_wait_inhibit(struct tegra_sdmmc_host *host,
 	return 0;
 }
 
-static int tegra_sdmmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
-				struct mci_data *data)
+static int tegra_sdmmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd)
 {
 	struct tegra_sdmmc_host *host = to_tegra_sdmmc_host(mci);
+	struct mci_data *data = cmd->data;
 	unsigned int num_bytes = 0;
 	u32 val = 0, command, xfer;
 	int ret;
diff --git a/include/mci.h b/include/mci.h
index 50214aaae7..667829c489 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -489,6 +489,7 @@ struct mci_cmd {
 	unsigned cmdarg;	/**< Command's arguments */
 	unsigned busy_timeout;	/**< Busy timeout in ms */
 	unsigned response[4];	/**< card's response */
+	struct mci_data		*data;		/* data segment associated with cmd */
 };
 
 /**
@@ -575,7 +576,7 @@ struct mci_ops {
 	/** change host interface settings */
 	void (*set_ios)(struct mci_host*, struct mci_ios *);
 	/** handle a command */
-	int (*send_cmd)(struct mci_host*, struct mci_cmd*, struct mci_data*);
+	int (*send_cmd)(struct mci_host *host, struct mci_cmd *cmd);
 	/** check if a card is inserted */
 	int (*card_present)(struct mci_host *);
 	/** check if a card is write protected */
@@ -788,7 +789,7 @@ static inline int mci_send_abort_tuning(struct mci *mci, u32 opcode) { return -E
 int mmc_select_timing(struct mci *mci);
 int mci_set_blockcount(struct mci *mci, unsigned int cmdarg);
 int mci_blk_part_switch(struct mci_part *part);
-int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd, struct mci_data *data);
+int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd);
 struct mci *mci_get_rpmb_dev(unsigned int id);
 int mci_rpmb_route_frames(struct mci *mci, void *req, unsigned long reqlen,
 			  void *rsp, unsigned long rsplen);

-- 
2.52.0




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

* [PATCH v2 2/6] mci: sdhci: add sdhci_send_cmd
  2026-03-09 12:04 [PATCH v2 0/6] mci: cadence: add v6 support Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 1/6] mci: add data segment to mci_cmd Steffen Trumtrar
@ 2026-03-09 12:04 ` Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 3/6] mci: sdhci: add set_uhs_signaling callback Steffen Trumtrar
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2026-03-09 12:04 UTC (permalink / raw)
  To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar

Linux uses a generic sdhci_send_cmd function for most sdhci host
drivers. Port the v6.18-rc1 version and mix and match with the
arasan_sdhci_send_cmd function already in barebox.

Also add sdhci_dumpregs for debugging errors.

Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
 drivers/mci/sdhci.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mci/sdhci.h |  21 +++++++++
 2 files changed, 149 insertions(+)

diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 847c0dc516..371d3e4a4b 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -11,6 +11,8 @@
 
 #define MAX_TUNING_LOOP 40
 
+#define DRIVER_NAME "sdhci"
+
 enum sdhci_reset_reason {
 	SDHCI_RESET_FOR_INIT,
 	SDHCI_RESET_FOR_REQUEST_ERROR,
@@ -25,6 +27,69 @@ static inline struct device *sdhci_dev(struct sdhci *host)
 	return host->mci ? host->mci->hw_dev : NULL;
 }
 
+void sdhci_dumpregs(struct sdhci *sdhci)
+{
+	dev_err(sdhci_dev(sdhci), "============ SDHCI REGISTER DUMP ===========\n");
+
+	dev_err(sdhci_dev(sdhci), "Sys addr:  0x%08x | Version:  0x%08x\n",
+		   sdhci_read32(sdhci, SDHCI_DMA_ADDRESS),
+		   sdhci_read16(sdhci, SDHCI_HOST_VERSION));
+	dev_err(sdhci_dev(sdhci), "Blk size:  0x%08x | Blk cnt:  0x%08x\n",
+		   sdhci_read16(sdhci, SDHCI_BLOCK_SIZE),
+		   sdhci_read16(sdhci, SDHCI_BLOCK_COUNT));
+	dev_err(sdhci_dev(sdhci), "Argument:  0x%08x | Trn mode: 0x%08x\n",
+		   sdhci_read32(sdhci, SDHCI_ARGUMENT),
+		   sdhci_read16(sdhci, SDHCI_TRANSFER_MODE));
+	dev_err(sdhci_dev(sdhci), "Present:   0x%08x | Host ctl: 0x%08x\n",
+		   sdhci_read32(sdhci, SDHCI_PRESENT_STATE),
+		   sdhci_read8(sdhci, SDHCI_HOST_CONTROL));
+	dev_err(sdhci_dev(sdhci), "Power:     0x%08x | Blk gap:  0x%08x\n",
+		   sdhci_read8(sdhci, SDHCI_POWER_CONTROL),
+		   sdhci_read8(sdhci, SDHCI_BLOCK_GAP_CONTROL));
+	dev_err(sdhci_dev(sdhci), "Wake-up:   0x%08x | Clock:    0x%08x\n",
+		   sdhci_read8(sdhci, SDHCI_WAKE_UP_CONTROL),
+		   sdhci_read16(sdhci, SDHCI_CLOCK_CONTROL));
+	dev_err(sdhci_dev(sdhci), "Timeout:   0x%08x | Int stat: 0x%08x\n",
+		   sdhci_read8(sdhci, SDHCI_TIMEOUT_CONTROL),
+		   sdhci_read32(sdhci, SDHCI_INT_STATUS));
+	dev_err(sdhci_dev(sdhci), "Int enab:  0x%08x | Sig enab: 0x%08x\n",
+		   sdhci_read32(sdhci, SDHCI_INT_ENABLE),
+		   sdhci_read32(sdhci, SDHCI_SIGNAL_ENABLE));
+	dev_err(sdhci_dev(sdhci), "ACmd stat: 0x%08x | Slot int: 0x%08x\n",
+		   sdhci_read16(sdhci, SDHCI_ACMD12_ERR__HOST_CONTROL2),
+		   sdhci_read16(sdhci, SDHCI_SLOT_INT_STATUS));
+	dev_err(sdhci_dev(sdhci), "Caps:      0x%08x | Caps_1:   0x%08x\n",
+		   sdhci_read32(sdhci, SDHCI_CAPABILITIES),
+		   sdhci_read32(sdhci, SDHCI_CAPABILITIES_1));
+	dev_err(sdhci_dev(sdhci), "Cmd:       0x%08x | Max curr: 0x%08x\n",
+		   sdhci_read16(sdhci, SDHCI_COMMAND),
+		   sdhci_read32(sdhci, SDHCI_MAX_CURRENT));
+	dev_err(sdhci_dev(sdhci), "Resp[0]:   0x%08x | Resp[1]:  0x%08x\n",
+		   sdhci_read32(sdhci, SDHCI_RESPONSE_0),
+		   sdhci_read32(sdhci, SDHCI_RESPONSE_1));
+	dev_err(sdhci_dev(sdhci), "Resp[2]:   0x%08x | Resp[3]:  0x%08x\n",
+		   sdhci_read32(sdhci, SDHCI_RESPONSE_2),
+		   sdhci_read32(sdhci, SDHCI_RESPONSE_3));
+	dev_err(sdhci_dev(sdhci), "Host ctl2: 0x%08x\n",
+		   sdhci_read16(sdhci, SDHCI_HOST_CONTROL2));
+
+	if (sdhci->flags & SDHCI_USE_ADMA) {
+		if (sdhci->flags & SDHCI_USE_64_BIT_DMA) {
+			dev_err(sdhci_dev(sdhci), "ADMA Err:  0x%08x | ADMA Ptr: 0x%08x%08x\n",
+				   sdhci_read32(sdhci, SDHCI_ADMA_ERROR),
+				   sdhci_read32(sdhci, SDHCI_ADMA_ADDRESS_HI),
+				   sdhci_read32(sdhci, SDHCI_ADMA_ADDRESS));
+		} else {
+			dev_err(sdhci_dev(sdhci), "ADMA Err:  0x%08x | ADMA Ptr: 0x%08x\n",
+				   sdhci_read32(sdhci, SDHCI_ADMA_ERROR),
+				   sdhci_read32(sdhci, SDHCI_ADMA_ADDRESS));
+		}
+	}
+
+	dev_err(sdhci_dev(sdhci), "============================================\n");
+}
+EXPORT_SYMBOL_GPL(sdhci_dumpregs);
+
 static void sdhci_reset_for_reason(struct sdhci *host, enum sdhci_reset_reason reason)
 {
 	if (host->quirks2 & SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER) {
@@ -51,6 +116,69 @@ static void sdhci_reset_for_reason(struct sdhci *host, enum sdhci_reset_reason r
 
 #define sdhci_reset_for(h, r) sdhci_reset_for_reason((h), SDHCI_RESET_FOR_##r)
 
+int sdhci_send_command(struct sdhci *host, struct mci_cmd *cmd)
+{
+	u32 mask, command, xfer;
+	dma_addr_t dma;
+	int ret;
+
+	ret = sdhci_wait_idle(host, cmd, cmd->data);
+	if (ret)
+		return ret;
+
+	sdhci_write32(host, SDHCI_INT_STATUS, ~0);
+
+	mask = SDHCI_INT_CMD_COMPLETE;
+	if (cmd->resp_type & MMC_RSP_BUSY)
+		mask |= SDHCI_INT_XFER_COMPLETE;
+
+	sdhci_setup_data_dma(host, cmd->data, &dma);
+
+	sdhci_set_cmd_xfer_mode(host, cmd, cmd->data,
+				dma == SDHCI_NO_DMA ? false : true,
+				&command, &xfer);
+
+	sdhci_write8(host, SDHCI_TIMEOUT_CONTROL, 0xf);
+	if (xfer)
+		sdhci_write16(host, SDHCI_TRANSFER_MODE, xfer);
+	if (cmd->data) {
+		sdhci_write16(host, SDHCI_BLOCK_SIZE,
+			      SDHCI_DMA_BOUNDARY_512K |
+			      SDHCI_TRANSFER_BLOCK_SIZE(cmd->data->blocksize));
+		sdhci_write16(host, SDHCI_BLOCK_COUNT, cmd->data->blocks);
+	}
+	sdhci_write32(host, SDHCI_ARGUMENT, cmd->cmdarg);
+	sdhci_write16(host, SDHCI_COMMAND, command);
+
+	/* CMD19/21 generate _only_ Buffer Read Ready interrupt */
+	if (mmc_op_tuning(cmd->cmdidx))
+		mask = SDHCI_INT_DATA_AVAIL;
+
+	ret = sdhci_wait_for_done(host, mask);
+	if (ret) {
+		sdhci_teardown_data(host, cmd->data, dma);
+		sdhci_dumpregs(host);
+		goto error;
+	}
+
+	sdhci_read_response(host, cmd);
+	sdhci_write32(host, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
+
+	if (cmd->data)
+		ret = sdhci_transfer_data_dma(host, cmd, cmd->data, dma);
+
+	return ret;
+
+error:
+	if (ret) {
+		sdhci_reset(host, SDHCI_RESET_CMD);
+		sdhci_reset(host, SDHCI_RESET_DATA);
+	}
+
+	sdhci_write32(host, SDHCI_INT_STATUS, ~0);
+	return ret;
+}
+
 static int sdhci_send_command_retry(struct sdhci *host, struct mci_cmd *cmd)
 {
 	int timeout = 10;
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index ec82b1b8ff..e7c56d59f4 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -85,6 +85,11 @@
 #define  SDHCI_BUS_VOLTAGE_330			SDHCI_BUS_VOLTAGE(7)
 #define  SDHCI_BUS_VOLTAGE(v)			((v) << 1)
 #define  SDHCI_BUS_POWER_EN			BIT(0)
+#define SDHCI_BLOCK_GAP_CONTROL			0x2A
+#define SDHCI_WAKE_UP_CONTROL			0x2B
+#define  SDHCI_WAKE_ON_INT			0x01
+#define  SDHCI_WAKE_ON_INSERT			0x02
+#define  SDHCI_WAKE_ON_REMOVE			0x04
 #define SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET	0x2c
 #define SDHCI_CLOCK_CONTROL					0x2C
 #define  SDHCI_DIVIDER_SHIFT			8
@@ -177,6 +182,17 @@
 #define  SDHCI_CAN_DO_ADMA3			0x08000000
 #define  SDHCI_SUPPORT_HS400			0x80000000 /* Non-standard */
 
+#define SDHCI_MAX_CURRENT		0x48
+#define  SDHCI_MAX_CURRENT_LIMIT	GENMASK(7, 0)
+#define  SDHCI_MAX_CURRENT_330_MASK	GENMASK(7, 0)
+#define  SDHCI_MAX_CURRENT_300_MASK	GENMASK(15, 8)
+#define  SDHCI_MAX_CURRENT_180_MASK	GENMASK(23, 16)
+#define SDHCI_MAX_CURRENT_1		0x4C
+#define  SDHCI_MAX_CURRENT_VDD2_180_MASK	GENMASK(7, 0) /* UHS2 */
+#define   SDHCI_MAX_CURRENT_MULTIPLIER	4
+
+#define SDHCI_ADMA_ERROR	0x54
+
 #define SDHCI_PRESET_FOR_SDR12	0x66
 #define SDHCI_PRESET_FOR_SDR25	0x68
 #define SDHCI_PRESET_FOR_SDR50	0x6A
@@ -207,6 +223,8 @@
 
 #define SDHCI_MMC_BOOT						0xC4
 
+#define SDHCI_SLOT_INT_STATUS	0xFC
+
 #define SDHCI_MAX_DIV_SPEC_200	256
 #define SDHCI_MAX_DIV_SPEC_300	2046
 
@@ -357,6 +375,9 @@ static inline void sdhci_read_caps(struct sdhci *host)
 {
 	__sdhci_read_caps(host, NULL, NULL, NULL);
 }
+
+void sdhci_dumpregs(struct sdhci *host);
+int sdhci_send_command(struct sdhci *host, struct mci_cmd *cmd);
 void sdhci_set_bus_width(struct sdhci *host, int width);
 
 #define sdhci_read8_poll_timeout(sdhci, reg, val, cond, timeout_us) \

-- 
2.52.0




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

* [PATCH v2 3/6] mci: sdhci: add set_uhs_signaling callback
  2026-03-09 12:04 [PATCH v2 0/6] mci: cadence: add v6 support Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 1/6] mci: add data segment to mci_cmd Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 2/6] mci: sdhci: add sdhci_send_cmd Steffen Trumtrar
@ 2026-03-09 12:04 ` Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 4/6] mci: cadence: remove driver Steffen Trumtrar
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2026-03-09 12:04 UTC (permalink / raw)
  To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar

Allow adding a set_uhs_signaling callback in a host driver.

If the callback is not provided, just call the generic
sdhci_set_uhs_signaling function as before.

Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
 drivers/mci/sdhci.c | 7 +++++--
 drivers/mci/sdhci.h | 1 +
 include/mci.h       | 1 +
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 371d3e4a4b..f7172347e1 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -471,7 +471,7 @@ void sdhci_set_bus_width(struct sdhci *host, int width)
 	sdhci_write8(host, SDHCI_HOST_CONTROL, ctrl);
 }
 
-static void sdhci_set_uhs_signaling(struct sdhci *host, unsigned timing)
+void sdhci_set_uhs_signaling(struct sdhci *host, unsigned int timing)
 {
 	u16 ctrl_2;
 
@@ -997,7 +997,10 @@ void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_
 
 	host->mci->ios.clock = 0;
 
-	sdhci_set_uhs_signaling(host, host->mci->ios.timing);
+	if (host->mci->ops.set_uhs_signaling)
+		host->mci->ops.set_uhs_signaling(host->mci, host->mci->ios.timing);
+	else
+		sdhci_set_uhs_signaling(host, host->mci->ios.timing);
 
 	sdhci_wait_idle_data(host, NULL);
 
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index e7c56d59f4..8d21febd7a 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -344,6 +344,7 @@ static inline void sdhci_write8(struct sdhci *host, int reg, u32 val)
 }
 
 #define SDHCI_NO_DMA DMA_ERROR_CODE
+void sdhci_set_uhs_signaling(struct sdhci *host, unsigned int timing);
 int sdhci_execute_tuning(struct sdhci *sdhci, u32 opcode);
 int sdhci_wait_idle_data(struct sdhci *host, struct mci_cmd *cmd);
 int sdhci_wait_idle(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *data);
diff --git a/include/mci.h b/include/mci.h
index 667829c489..7d903dec05 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -583,6 +583,7 @@ struct mci_ops {
 	int (*card_write_protected)(struct mci_host *);
 	/* The tuning command opcode value is different for SD and eMMC cards */
 	int (*execute_tuning)(struct mci_host *, u32);
+	void (*set_uhs_signaling)(struct mci_host *host, unsigned int timing);
 };
 
 /** host information */

-- 
2.52.0




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

* [PATCH v2 4/6] mci: cadence: remove driver
  2026-03-09 12:04 [PATCH v2 0/6] mci: cadence: add v6 support Steffen Trumtrar
                   ` (2 preceding siblings ...)
  2026-03-09 12:04 ` [PATCH v2 3/6] mci: sdhci: add set_uhs_signaling callback Steffen Trumtrar
@ 2026-03-09 12:04 ` Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 5/6] mci: cadence: add support for version 6 Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 6/6] ARM: socfpga-agilex5_defconfig: enable cadencen-sdhci Steffen Trumtrar
  5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2026-03-09 12:04 UTC (permalink / raw)
  To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar

There are no users of the current driver in barebox.
Remove the driver in preparation for an updated driver for the cadence
SDHCI core in the next patch.

As the rework is pretty exhausting, it is easier to remove the old one
and add the new driver in an extra patch. This way the patch is easier
to read than having an enormous diff between an old and a new driver.

Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
 drivers/mci/Kconfig         |   7 -
 drivers/mci/cadence-sdhci.c | 602 --------------------------------------------
 2 files changed, 609 deletions(-)

diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 6736e7421c..c99f29a6db 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -259,13 +259,6 @@ config MCI_STM32_SDMMC2
 	  If you have a board based on such a SoC and with a SD/MMC slot,
 	  say Y or M here.
 
-config MMC_CADENCE_SDHCI
-	tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
-	select MCI_SDHCI
-	help
-	  This selects the Cadence SD/SDIO/eMMC driver.
-	  If you have a controller with this interface, say Y or M here.
-
 endif
 
 config MCI_IMX_ESDHC_PBL
diff --git a/drivers/mci/cadence-sdhci.c b/drivers/mci/cadence-sdhci.c
deleted file mode 100644
index d59ee04665..0000000000
--- a/drivers/mci/cadence-sdhci.c
+++ /dev/null
@@ -1,602 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Socionext Inc.
- *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
- */
-
-#include <clock.h>
-#include <common.h>
-#include <driver.h>
-#include <init.h>
-#include <linux/clk.h>
-#include <mci.h>
-#include <linux/bitfield.h>
-#include <linux/bits.h>
-#include <linux/iopoll.h>
-#include <linux/reset.h>
-
-#include "sdhci.h"
-
-/* HRS - Host Register Set (specific to Cadence) */
-#define SDHCI_CDNS_HRS04		0x10		/* PHY access port */
-#define SDHCI_CDNS_HRS05        0x14        /* PHY data access port */
-#define   SDHCI_CDNS_HRS04_ACK			BIT(26)
-#define   SDHCI_CDNS_HRS04_RD			BIT(25)
-#define   SDHCI_CDNS_HRS04_WR			BIT(24)
-#define   SDHCI_CDNS_HRS04_RDATA		GENMASK(23, 16)
-#define   SDHCI_CDNS_HRS04_WDATA		GENMASK(15, 8)
-#define   SDHCI_CDNS_HRS04_ADDR			GENMASK(5, 0)
-
-#define SDHCI_CDNS_HRS06		0x18		/* eMMC control */
-#define   SDHCI_CDNS_HRS06_TUNE_UP		BIT(15)
-#define   SDHCI_CDNS_HRS06_TUNE			GENMASK(13, 8)
-#define   SDHCI_CDNS_HRS06_MODE			GENMASK(2, 0)
-#define   SDHCI_CDNS_HRS06_MODE_SD		0x0
-#define   SDHCI_CDNS_HRS06_MODE_MMC_SDR		0x2
-#define   SDHCI_CDNS_HRS06_MODE_MMC_DDR		0x3
-#define   SDHCI_CDNS_HRS06_MODE_MMC_HS200	0x4
-#define   SDHCI_CDNS_HRS06_MODE_MMC_HS400	0x5
-#define   SDHCI_CDNS_HRS06_MODE_MMC_HS400ES	0x6
-
-/* PHY specific register */
-/* HRS register to set after SDMMC reset */
-#define SDHCI_CDNS_HRS00	0x0
-#define SDHCI_CDNS_HRS07	0x1C        /* IO_DELAY_INFO_REG */
-#define SDHCI_CDNS_HRS07_RW_COMPENSATE  GENMASK(20, 16) /* RW_COMPENSATE */
-#define SDHCI_CDNS_HRS07_IDELAY_VAL     GENMASK(4, 0)   /* IDELAY_VAL */
-/* TODO: check DV dfi_init val=9 */
-#define SDHCI_CDNS_HRS07_RW_COMPENSATE_DATA 0x9
-/* TODO: check DV dfi_init val=8 ; DDR Mode */
-#define SDHCI_CDNS_HRS07_RW_COMPENSATE_DATA_DDR 0x8
-#define SDHCI_CDNS_HRS07_IDELAY_VAL_DATA    0x0
-
-#define SDHCI_CDNS_HRS09	0x024
-#define SDHCI_CDNS_HRS09_PHY_SW_RESET       BIT(0)  /* PHY_SW_RESET */
-#define SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE  BIT(1)  /* PHY_INIT_COMPLETE */
-#define SDHCI_CDNS_HRS09_RDDATA_EN  BIT(16) /* RDDATA_EN */
-#define SDHCI_CDNS_HRS09_RDCMD_EN   BIT(15) /* RDCMD_EN */
-#define SDHCI_CDNS_HRS09_EXTENDED_WR_MODE   BIT(3)  /* EXTENDED_WR_MODE */
-#define SDHCI_CDNS_HRS09_EXTENDED_RD_MODE   BIT(2)  /* EXTENDED_RD_MODE */
-
-#define SDHCI_CDNS_HRS10        0x28        /* PHY reset port */
-#define SDHCI_CDNS_HRS10_HCSDCLKADJ     GENMASK(19, 16) /* HCSDCLKADJ */
-#define SDHCI_CDNS_HRS10_HCSDCLKADJ_DATA    0x0         /* HCSDCLKADJ DATA */
-/* HCSDCLKADJ DATA; DDR Mode */
-#define SDHCI_CDNS_HRS10_HCSDCLKADJ_DATA_DDR    0x2
-#define SDHCI_CDNS_HRS16        0x40        /* CMD_DATA_OUTPUT */
-
-/* SRS - Slot Register Set (SDHCI-compatible) */
-#define SDHCI_CDNS_SRS_BASE	0x200
-#define SDHCI_CDNS_SRS09	0x224
-#define SDHCI_CDNS_SRS10	0x228
-#define SDHCI_CDNS_SRS11	0x22c
-#define SDHCI_CDNS_SRS12	0x230
-#define SDHCI_CDNS_SRS13	0x234
-#define SDHCI_CDNS_SRS09_CI	BIT(16)
-#define SDHCI_CDNS_SRS13_DATA	0xffffffff
-#define SD_HOST_CLK 200000000
-
-/* PHY */
-#define SDHCI_CDNS_PHY_DLY_SD_HS	0x00
-#define SDHCI_CDNS_PHY_DLY_SD_DEFAULT	0x01
-#define SDHCI_CDNS_PHY_DLY_UHS_SDR12	0x02
-#define SDHCI_CDNS_PHY_DLY_UHS_SDR25	0x03
-#define SDHCI_CDNS_PHY_DLY_UHS_SDR50	0x04
-#define SDHCI_CDNS_PHY_DLY_UHS_DDR50	0x05
-#define SDHCI_CDNS_PHY_DLY_EMMC_LEGACY	0x06
-#define SDHCI_CDNS_PHY_DLY_EMMC_SDR	0x07
-#define SDHCI_CDNS_PHY_DLY_EMMC_DDR	0x08
-#define SDHCI_CDNS_PHY_DLY_SDCLK	0x0b
-#define SDHCI_CDNS_PHY_DLY_HSMMC	0x0c
-#define SDHCI_CDNS_PHY_DLY_STROBE	0x0d
-/* PHY register values */
-#define PHY_DQ_TIMING_REG			0x2000
-#define PHY_DQS_TIMING_REG			0x2004
-#define PHY_GATE_LPBK_CTRL_REG			0x2008
-#define PHY_DLL_MASTER_CTRL_REG			0x200C
-#define PHY_DLL_SLAVE_CTRL_REG			0x2010
-#define PHY_CTRL_REG				0x2080
-#define USE_EXT_LPBK_DQS			BIT(22)
-#define USE_LPBK_DQS				BIT(21)
-#define USE_PHONY_DQS				BIT(20)
-#define USE_PHONY_DQS_CMD			BIT(19)
-#define SYNC_METHOD				BIT(31)
-#define SW_HALF_CYCLE_SHIFT			BIT(28)
-#define RD_DEL_SEL				GENMASK(24, 19)
-#define RD_DEL_SEL_DATA				0x34
-#define GATE_CFG_ALWAYS_ON			BIT(6)
-#define UNDERRUN_SUPPRESS			BIT(18)
-#define PARAM_DLL_BYPASS_MODE			BIT(23)
-#define PARAM_PHASE_DETECT_SEL			GENMASK(22, 20)
-#define PARAM_DLL_START_POINT			GENMASK(7, 0)
-#define PARAM_PHASE_DETECT_SEL_DATA		0x2
-#define PARAM_DLL_START_POINT_DATA		0x4
-#define PARAM_DLL_START_POINT_DATA_SDR50	254
-
-#define READ_DQS_CMD_DELAY		GENMASK(31, 24)
-#define CLK_WRDQS_DELAY			GENMASK(23, 16)
-#define CLK_WR_DELAY			GENMASK(15, 8)
-#define READ_DQS_DELAY			GENMASK(7, 0)
-#define READ_DQS_CMD_DELAY_DATA		0x0
-#define CLK_WRDQS_DELAY_DATA		0x0
-#define CLK_WR_DELAY_DATA		0x0
-#define READ_DQS_DELAY_DATA		0x0
-
-#define PHONY_DQS_TIMING		GENMASK(9, 4)
-#define PHONY_DQS_TIMING_DATA		0x0
-
-#define IO_MASK_ALWAYS_ON		BIT(31)
-#define IO_MASK_END			GENMASK(29, 27)
-#define IO_MASK_START			GENMASK(26, 24)
-#define DATA_SELECT_OE_END		GENMASK(2, 0)
-#define IO_MASK_END_DATA		0x5
-/* DDR Mode */
-#define IO_MASK_END_DATA_DDR		0x2
-#define IO_MASK_START_DATA		0x0
-#define DATA_SELECT_OE_END_DATA 	0x1
-
-/*
- * The tuned val register is 6 bit-wide, but not the whole of the range is
- * available.  The range 0-42 seems to be available (then 43 wraps around to 0)
- * but I am not quite sure if it is official.  Use only 0 to 39 for safety.
- */
-#define SDHCI_CDNS_MAX_TUNING_LOOP	40
-
-struct sdhci_cdns_phy_param {
-	u32 addr;
-	u32 data;
-	u32 offset;
-};
-
-struct sdhci_cdns_priv {
-	struct mci_host mci;
-	struct sdhci sdhci;
-	void __iomem *hrs_addr;
-	bool enhanced_strobe;
-	unsigned int nr_phy_params;
-	struct sdhci_cdns_phy_param phy_params[];
-};
-
-struct sdhci_cdns_phy_cfg {
-	const char *property;
-	u32 addr;
-	u32 offset;
-};
-
-static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = {
-	{ "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, },
-	{ "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, },
-	{ "cdns,phy-input-delay-sd-uhs-sdr12", SDHCI_CDNS_PHY_DLY_UHS_SDR12, },
-	{ "cdns,phy-input-delay-sd-uhs-sdr25", SDHCI_CDNS_PHY_DLY_UHS_SDR25, },
-	{ "cdns,phy-input-delay-sd-uhs-sdr50", SDHCI_CDNS_PHY_DLY_UHS_SDR50, },
-	{ "cdns,phy-input-delay-sd-uhs-ddr50", SDHCI_CDNS_PHY_DLY_UHS_DDR50, },
-	{ "cdns,phy-input-delay-mmc-highspeed", SDHCI_CDNS_PHY_DLY_EMMC_SDR, },
-	{ "cdns,phy-input-delay-mmc-ddr", SDHCI_CDNS_PHY_DLY_EMMC_DDR, },
-	{ "cdns,phy-dll-delay-sdclk", SDHCI_CDNS_PHY_DLY_SDCLK, },
-	{ "cdns,phy-dll-delay-sdclk-hsmmc", SDHCI_CDNS_PHY_DLY_HSMMC, },
-	{ "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, },
-	{ "cdns,phy-use-ext-lpbk-dqs", PHY_DQS_TIMING_REG, 22,},
-	{ "cdns,phy-use-lpbk-dqs", PHY_DQS_TIMING_REG, 21,},
-	{ "cdns,phy-use-phony-dqs", PHY_DQS_TIMING_REG, 20,},
-	{ "cdns,phy-use-phony-dqs-cmd", PHY_DQS_TIMING_REG, 19,},
-	{ "cdns,phy-io-mask-always-on", PHY_DQ_TIMING_REG, 31,},
-	{ "cdns,phy-io-mask-end", PHY_DQ_TIMING_REG, 27,},
-	{ "cdns,phy-io-mask-start", PHY_DQ_TIMING_REG, 24,},
-	{ "cdns,phy-data-select-oe-end", PHY_DQ_TIMING_REG, 0,},
-	{ "cdns,phy-sync-method", PHY_GATE_LPBK_CTRL_REG, 31,},
-	{ "cdns,phy-sw-half-cycle-shift", PHY_GATE_LPBK_CTRL_REG, 28,},
-	{ "cdns,phy-rd-del-sel", PHY_GATE_LPBK_CTRL_REG, 19,},
-	{ "cdns,phy-underrun-suppress", PHY_GATE_LPBK_CTRL_REG, 18,},
-	{ "cdns,phy-gate-cfg-always-on", PHY_GATE_LPBK_CTRL_REG, 6,},
-	{ "cdns,phy-param-dll-bypass-mode", PHY_DLL_MASTER_CTRL_REG, 23,},
-	{ "cdns,phy-param-phase-detect-sel", PHY_DLL_MASTER_CTRL_REG, 20,},
-	{ "cdns,phy-param-dll-start-point", PHY_DLL_MASTER_CTRL_REG, 0,},
-	{ "cdns,phy-read-dqs-cmd-delay", PHY_DLL_SLAVE_CTRL_REG, 24,},
-	{ "cdns,phy-clk-wrdqs-delay", PHY_DLL_SLAVE_CTRL_REG, 16,},
-	{ "cdns,phy-clk-wr-delay", PHY_DLL_SLAVE_CTRL_REG, 8,},
-	{ "cdns,phy-read-dqs-delay", PHY_DLL_SLAVE_CTRL_REG, 0,},
-	{ "cdns,phy-phony-dqs-timing", PHY_CTRL_REG, 4,},
-	{ "cdns,hrs09-rddata-en", SDHCI_CDNS_HRS09, 16,},
-	{ "cdns,hrs09-rdcmd-en", SDHCI_CDNS_HRS09, 15,},
-	{ "cdns,hrs09-extended-wr-mode", SDHCI_CDNS_HRS09, 3,},
-	{ "cdns,hrs09-extended-rd-mode", SDHCI_CDNS_HRS09, 2,},
-	{ "cdns,hrs10-hcsdclkadj", SDHCI_CDNS_HRS10, 16,},
-	{ "cdns,hrs16-wrdata1-sdclk-dly", SDHCI_CDNS_HRS16, 28,},
-	{ "cdns,hrs16-wrdata0-sdclk-dly", SDHCI_CDNS_HRS16, 24,},
-	{ "cdns,hrs16-wrcmd1-sdclk-dly", SDHCI_CDNS_HRS16, 20,},
-	{ "cdns,hrs16-wrcmd0-sdclk-dly", SDHCI_CDNS_HRS16, 16,},
-	{ "cdns,hrs16-wrdata1-dly", SDHCI_CDNS_HRS16, 12,},
-	{ "cdns,hrs16-wrdata0-dly", SDHCI_CDNS_HRS16, 8,},
-	{ "cdns,hrs16-wrcmd1-dly", SDHCI_CDNS_HRS16, 4,},
-	{ "cdns,hrs16-wrcmd0-dly", SDHCI_CDNS_HRS16, 0,},
-	{ "cdns,hrs07-rw-compensate", SDHCI_CDNS_HRS07, 16,},
-	{ "cdns,hrs07-idelay-val", SDHCI_CDNS_HRS07, 0,},
-};
-
-static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv,
-				    u8 addr, u8 data)
-{
-	void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS04;
-	u32 tmp;
-	int ret;
-
-	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK), 10);
-	if (ret)
-		return ret;
-
-	tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
-	      FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
-	writel(tmp, reg);
-
-	tmp |= SDHCI_CDNS_HRS04_WR;
-	writel(tmp, reg);
-
-	ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 10);
-	if (ret)
-		return ret;
-
-	tmp &= ~SDHCI_CDNS_HRS04_WR;
-	writel(tmp, reg);
-
-	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK), 10);
-
-	return ret;
-}
-
-static int sdhci_cdns_write_phy_reg_mask(struct sdhci_cdns_priv *priv,
-			u32 addr, u32 data, u32 mask)
-{
-	u32 tmp;
-
-	tmp = addr;
-
-	/* get PHY address */
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS04);
-
-	/* read current PHY register value, before write */
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS05);
-
-	tmp &= ~mask;
-	tmp |= data;
-
-	/* write operation */
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS05);
-
-	/* re-read PHY address */
-	writel(addr, priv->hrs_addr + SDHCI_CDNS_HRS04);
-
-	/* re-read current PHY register value, check */
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS05);
-
-	return 0;
-}
-
-static u32 sdhci_cdns_read_phy_reg(struct sdhci_cdns_priv *priv,
-			u32 addr)
-{
-	u32 tmp;
-
-	tmp = addr;
-
-	/* get PHY address */
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS04);
-
-	/* read current PHY register value, before write */
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS05);
-
-	return tmp;
-}
-
-static int sdhci_cdns_dfi_phy_val(struct sdhci_cdns_priv *priv, u32 reg)
-{
-	int i;
-	u32 tmp;
-
-	tmp = 0;
-
-	for (i = 0; i < priv->nr_phy_params; i++) {
-		if (priv->phy_params[i].addr == reg)
-			tmp |= priv->phy_params[i].data << priv->phy_params[i].offset;
-	}
-
-	return tmp;
-}
-
-static int sdhci_cdns_combophy_init_sd_dfi_init(struct sdhci_cdns_priv *priv)
-{
-	int ret = 0;
-	u32 mask = 0x0;
-	u32 tmp = 0;
-
-	writel(0x0, priv->hrs_addr + SDHCI_CDNS_SRS11);
-	writel(1<<0, priv->hrs_addr + SDHCI_CDNS_HRS00);
-	while ((readl(priv->hrs_addr + SDHCI_CDNS_HRS00) & 1<<0) == 1)
-
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS09) & ~1;
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS09);
-
-	tmp = (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19);
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_DQS_TIMING_REG, tmp, tmp);
-
-	tmp = (1 << 31) | (0 << 28) | (52 << 19) | (1 << 18) | (1 << 6);
-	mask = SYNC_METHOD | SW_HALF_CYCLE_SHIFT | RD_DEL_SEL | UNDERRUN_SUPPRESS |
-			GATE_CFG_ALWAYS_ON;
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_GATE_LPBK_CTRL_REG, tmp,
-			mask);
-
-	tmp = (1 << 23) | (2 << 20) | (4 << 0);
-	mask = PARAM_DLL_BYPASS_MODE | PARAM_PHASE_DETECT_SEL |
-			PARAM_DLL_START_POINT;
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_DLL_MASTER_CTRL_REG, tmp,
-			mask);
-
-	tmp = (0 << 24) | (0 << 16) | (0 << 8) | (0 << 0);
-	mask = READ_DQS_CMD_DELAY | CLK_WRDQS_DELAY | CLK_WR_DELAY | READ_DQS_DELAY;
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_DLL_SLAVE_CTRL_REG, tmp,
-			mask);
-
-	writel(0x2080, priv->hrs_addr + SDHCI_CDNS_HRS04);
-	tmp &= ~(0x3f << 4);
-	mask = PHONY_DQS_TIMING;
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_CTRL_REG, tmp, mask);
-
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS09) | 1;
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS09);
-
-	while (~readl(priv->hrs_addr + SDHCI_CDNS_HRS09) & (1 << 1))
-
-	tmp = sdhci_cdns_read_phy_reg(priv, PHY_DQ_TIMING_REG) & 0x07FFFF8;
-	tmp |= (0 << 31) | (0 << 27) | (0 << 24) | (1 << 0);
-	mask = IO_MASK_ALWAYS_ON | IO_MASK_END | IO_MASK_START | DATA_SELECT_OE_END;
-
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_DQ_TIMING_REG, tmp, mask);
-
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS09) & 0xFFFE7FF3;
-
-	tmp |= (1 << 16) | (1 << 15) | (1 << 3) | (1 << 2);
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS09);
-
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS10) & 0xFFF0FFFF;
-
-	tmp |= (0 << 16);
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS10);
-
-	tmp = (0 << 28) | (0 << 24) | (0 << 20) | (0 << 16) | (0 << 12) | (1 << 8) |
-			(0 << 4) | (1 << 0);
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS16);
-
-	tmp = (9 << 16) | (0 << 0);
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS07);
-
-	return ret;
-}
-
-static int sdhci_cdns_combophy_init_sd_gen(struct sdhci_cdns_priv *priv)
-{
-	u32 tmp;
-	int ret = 0;
-	u32 mask = 0x0;
-
-	/* step 1, switch on DLL_RESET */
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS09) & ~1;
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS09);
-
-	/* step 2, program PHY_DQS_TIMING_REG */
-	tmp = sdhci_cdns_dfi_phy_val(priv, PHY_DQS_TIMING_REG);
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_DQS_TIMING_REG, tmp, tmp);
-
-	/* step 3, program PHY_GATE_LPBK_CTRL_REG */
-	tmp = sdhci_cdns_dfi_phy_val(priv, PHY_GATE_LPBK_CTRL_REG);
-	mask = SYNC_METHOD | SW_HALF_CYCLE_SHIFT | RD_DEL_SEL | UNDERRUN_SUPPRESS |
-	GATE_CFG_ALWAYS_ON;
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_GATE_LPBK_CTRL_REG, tmp,
-	mask);
-
-	/* step 4, program PHY_DLL_MASTER_CTRL_REG */
-	tmp = sdhci_cdns_dfi_phy_val(priv, PHY_DLL_MASTER_CTRL_REG);
-	mask = PARAM_DLL_BYPASS_MODE | PARAM_PHASE_DETECT_SEL |
-	PARAM_DLL_START_POINT;
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_DLL_MASTER_CTRL_REG, tmp,
-	mask);
-
-	/* step 5, program PHY_DLL_SLAVE_CTRL_REG */
-	tmp = sdhci_cdns_dfi_phy_val(priv, PHY_DLL_SLAVE_CTRL_REG);
-	mask = READ_DQS_CMD_DELAY | CLK_WRDQS_DELAY | CLK_WR_DELAY | READ_DQS_DELAY;
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_DLL_SLAVE_CTRL_REG, tmp,
-	mask);
-
-	/* step 7, switch off DLL_RESET */
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS09) | 1;
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS09);
-
-	/* step 8, polling PHY_INIT_COMPLETE */
-	while (~readl(priv->hrs_addr + SDHCI_CDNS_HRS09) & (1 << 1))
-	/* polling for PHY_INIT_COMPLETE bit */
-
-	/* step 9, program PHY_DQ_TIMING_REG */
-	tmp = sdhci_cdns_read_phy_reg(priv, PHY_DQ_TIMING_REG) & 0x07FFFF8;
-	tmp |= sdhci_cdns_dfi_phy_val(priv, PHY_DQ_TIMING_REG);
-	mask = IO_MASK_ALWAYS_ON | IO_MASK_END | IO_MASK_START | DATA_SELECT_OE_END;
-	ret = sdhci_cdns_write_phy_reg_mask(priv, PHY_DQ_TIMING_REG, tmp, mask);
-
-	/* step 10, program HRS09, register 42 */
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS09) & 0xFFFE7FF3;
-
-	tmp |= sdhci_cdns_dfi_phy_val(priv, SDHCI_CDNS_HRS09);
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS09);
-
-	/* step 11, program HRS10, register 43 */
-	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS10) & 0xFFF0FFFF;
-	tmp |= sdhci_cdns_dfi_phy_val(priv, SDHCI_CDNS_HRS10);
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS10);
-
-	/* step 12, program HRS16, register 48 */
-	tmp = sdhci_cdns_dfi_phy_val(priv, SDHCI_CDNS_HRS16);
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS16);
-
-	/* step 13, program HRS07, register 40 */
-	tmp = sdhci_cdns_dfi_phy_val(priv, SDHCI_CDNS_HRS07);
-	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS07);
-	/* end of combophy init */
-
-	return ret;
-}
-
-
-static unsigned int sdhci_cdns_phy_param_count(struct device_node *np)
-{
-	unsigned int count = 0;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++)
-		if (of_property_read_bool(np, sdhci_cdns_phy_cfgs[i].property))
-			count++;
-
-	return count;
-}
-
-static void sdhci_cdns_phy_param_parse(struct device_node *np,
-				       struct sdhci_cdns_priv *priv)
-{
-	struct sdhci_cdns_phy_param *p = priv->phy_params;
-	u32 val;
-	int ret, i;
-
-	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++) {
-		ret = of_property_read_u32(np, sdhci_cdns_phy_cfgs[i].property,
-					   &val);
-		if (ret)
-			continue;
-
-		p->addr = sdhci_cdns_phy_cfgs[i].addr;
-		p->data = val;
-		p->offset = sdhci_cdns_phy_cfgs[i].offset;
-		p++;
-	}
-}
-
-static int sdhci_cdns_phy_init(struct sdhci_cdns_priv *priv)
-{
-	int ret, i;
-
-	for (i = 0; i < priv->nr_phy_params; i++) {
-		if (priv->phy_params[i].offset)
-			break;
-		ret = sdhci_cdns_write_phy_reg(priv, priv->phy_params[i].addr,
-					       priv->phy_params[i].data);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-static void sdhci_cdns_set_clock(struct mci_host *host, unsigned int clock)
-{
-	struct sdhci_cdns_priv *priv = host->hw_dev->priv;
-	int ret;
-
-	ret = sdhci_cdns_combophy_init_sd_gen(priv);
-
-	sdhci_set_clock(&priv->sdhci, clock, host->f_max);
-}
-
-static void sdhci_cdns_set_ios(struct mci_host *host, struct mci_ios *ios)
-{
-	struct sdhci_cdns_priv *priv = host->hw_dev->priv;
-
-	if (ios->clock)
-		sdhci_cdns_set_clock(host, ios->clock);
-
-	sdhci_set_bus_width(&priv->sdhci, ios->bus_width);
-}
-
-static const struct mci_ops sdhci_cdns_ops = {
-	.set_ios = sdhci_cdns_set_ios,
-};
-
-static int sdhci_cdns_probe(struct device *dev)
-{
-	struct sdhci_cdns_priv *priv;
-	struct mci_host *mci;
-	struct clk *clk;
-	struct resource *iores;
-	struct reset_control *rst;
-	unsigned int nr_phy_params;
-	int ret;
-
-	priv = xzalloc(sizeof(*priv));
-	mci = &priv->mci;
-
-	clk = clk_get(dev, "biu");
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	iores = dev_request_mem_resource(dev, 0);
-	if (IS_ERR(iores))
-		return PTR_ERR(iores);
-
-	rst = reset_control_get(dev, "reset");
-	if (IS_ERR(rst)) {
-		dev_err(dev, "Invalid reset line 'reset'.\n");
-		return PTR_ERR(rst);
-	}
-	reset_control_deassert(rst);
-	ret = clk_prepare_enable(clk);
-	if (ret)
-		return ret;
-
-	mci->ops = sdhci_cdns_ops;
-	mci->hw_dev = dev;
-
-	nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
-
-	priv->nr_phy_params = nr_phy_params;
-	priv->hrs_addr = IOMEM(iores->start);
-	priv->enhanced_strobe = false;
-	priv->sdhci.base = IOMEM(iores->start + SDHCI_CDNS_SRS_BASE);
-	priv->sdhci.quirks2 = SDHCI_QUIRK2_40_BIT_DMA_MASK;
-	priv->sdhci.mci = mci;
-
-	mci_of_parse(mci);
-
-	sdhci_cdns_phy_param_parse(dev->of_node, priv);
-
-	ret = sdhci_cdns_phy_init(priv);
-	if (ret)
-		goto disable_clk;
-
-	ret = sdhci_cdns_combophy_init_sd_dfi_init(priv);
-	if (ret)
-		goto disable_clk;
-
-	dev->priv = priv;
-
-	ret = sdhci_setup_host(&priv->sdhci);
-	if (ret)
-		goto disable_clk;
-
-	return 0;
-
-disable_clk:
-	clk_disable_unprepare(clk);
-
-	return ret;
-}
-
-static __maybe_unused struct of_device_id sdhci_cdns_match[] = {
-	{
-		.compatible = "cdns,sd4hc"
-	},
-	{
-		.compatible = "intel,agilex5-sd4hc",
-	},
-	{ /* sentinel */ }
-};
-
-static struct driver sdhci_cdns_driver = {
-	.name = "sdhci-cdns",
-	.of_compatible = DRV_OF_COMPAT(sdhci_cdns_match),
-	.probe = sdhci_cdns_probe,
-};
-device_platform_driver(sdhci_cdns_driver);

-- 
2.52.0




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

* [PATCH v2 5/6] mci: cadence: add support for version 6
  2026-03-09 12:04 [PATCH v2 0/6] mci: cadence: add v6 support Steffen Trumtrar
                   ` (3 preceding siblings ...)
  2026-03-09 12:04 ` [PATCH v2 4/6] mci: cadence: remove driver Steffen Trumtrar
@ 2026-03-09 12:04 ` Steffen Trumtrar
  2026-03-09 12:04 ` [PATCH v2 6/6] ARM: socfpga-agilex5_defconfig: enable cadencen-sdhci Steffen Trumtrar
  5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2026-03-09 12:04 UTC (permalink / raw)
  To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar

There is a v4 and a v6 of the Cadence SDHCI. The Agilex actually has the
v6 version on the SoC.

Port the driver from Alteras Linux tree [1]

[1]: https://github.com/altera-fpga/linux-socfpga.git socfpga-6.12.33-lts

Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
 drivers/mci/Kconfig          |   7 +
 drivers/mci/Makefile         |   1 +
 drivers/mci/cadence-sdhci.c  | 537 +++++++++++++++++++++++++++++++++++++++++++
 drivers/mci/cadence-sdhci.h  | 118 ++++++++++
 drivers/mci/cadence-sdhci6.c | 373 ++++++++++++++++++++++++++++++
 5 files changed, 1036 insertions(+)

diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index c99f29a6db..e7b8afb3b4 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -259,6 +259,13 @@ config MCI_STM32_SDMMC2
 	  If you have a board based on such a SoC and with a SD/MMC slot,
 	  say Y or M here.
 
+config MCI_CADENCE_SDHCI
+	tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
+	select MCI_SDHCI
+	help
+	  This selects the Cadence SD/SDIO/eMMC driver.
+	  If you have a controller with this interface, say Y or M here.
+
 endif
 
 config MCI_IMX_ESDHC_PBL
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index f76059e7b5..f82e31320e 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_MCI_ATMEL)		+= atmel_mci.o atmel_mci_common.o
 obj-$(CONFIG_MCI_ATMEL_SDHCI)	+= atmel-sdhci.o atmel-sdhci-common.o
 obj-$(CONFIG_MCI_BCM283X)	+= mci-bcm2835.o
 obj-$(CONFIG_MCI_BCM283X_SDHOST)	+= bcm2835-sdhost.o
+obj-$(CONFIG_MCI_CADENCE_SDHCI) += cadence-sdhci.o cadence-sdhci6.o
 obj-$(CONFIG_MCI_DOVE)		+= dove-sdhci.o
 pbl-$(CONFIG_MCI_ATMEL_PBL)	+= atmel_mci_pbl.o atmel_mci_common.o
 pbl-$(CONFIG_MCI_ATMEL_SDHCI_PBL)	+= atmel-sdhci-pbl.o atmel-sdhci-common.o
diff --git a/drivers/mci/cadence-sdhci.c b/drivers/mci/cadence-sdhci.c
new file mode 100644
index 0000000000..ccd0f36cb0
--- /dev/null
+++ b/drivers/mci/cadence-sdhci.c
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <clock.h>
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <mci.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/iopoll.h>
+#include <linux/reset.h>
+
+#include "cadence-sdhci.h"
+#include "sdhci.h"
+
+/* HRS - Host Register Set (specific to Cadence) */
+#define   SDHCI_CDNS_HRS04_ACK			BIT(26)
+#define   SDHCI_CDNS_HRS04_RD			BIT(25)
+#define   SDHCI_CDNS_HRS04_WR			BIT(24)
+#define   SDHCI_CDNS_HRS04_RDATA		GENMASK(23, 16)
+#define   SDHCI_CDNS_HRS04_WDATA		GENMASK(15, 8)
+#define   SDHCI_CDNS_HRS04_ADDR			GENMASK(5, 0)
+
+#define SDHCI_CDNS_HRS06			0x18		/* eMMC control */
+#define   SDHCI_CDNS_HRS06_TUNE_UP		BIT(15)
+#define   SDHCI_CDNS_HRS06_TUNE			GENMASK(13, 8)
+#define   SDHCI_CDNS_HRS06_MODE			GENMASK(2, 0)
+#define   SDHCI_CDNS_HRS06_MODE_SD		0x0
+#define   SDHCI_CDNS_HRS06_MODE_MMC_SDR		0x2
+#define   SDHCI_CDNS_HRS06_MODE_MMC_DDR		0x3
+#define   SDHCI_CDNS_HRS06_MODE_MMC_HS200	0x4
+#define   SDHCI_CDNS_HRS06_MODE_MMC_HS400	0x5
+#define   SDHCI_CDNS_HRS06_MODE_MMC_HS400ES	0x6
+
+/* SRS - Slot Register Set (SDHCI-compatible) */
+#define SDHCI_CDNS_SRS_BASE			0x200
+
+/* PHY */
+#define SDHCI_CDNS_PHY_DLY_SD_HS		0x00
+#define SDHCI_CDNS_PHY_DLY_SD_DEFAULT		0x01
+#define SDHCI_CDNS_PHY_DLY_UHS_SDR12		0x02
+#define SDHCI_CDNS_PHY_DLY_UHS_SDR25		0x03
+#define SDHCI_CDNS_PHY_DLY_UHS_SDR50		0x04
+#define SDHCI_CDNS_PHY_DLY_UHS_DDR50		0x05
+#define SDHCI_CDNS_PHY_DLY_EMMC_LEGACY		0x06
+#define SDHCI_CDNS_PHY_DLY_EMMC_SDR		0x07
+#define SDHCI_CDNS_PHY_DLY_EMMC_DDR		0x08
+#define SDHCI_CDNS_PHY_DLY_SDCLK		0x0b
+#define SDHCI_CDNS_PHY_DLY_HSMMC		0x0c
+#define SDHCI_CDNS_PHY_DLY_STROBE		0x0d
+
+#define MAIN_CLOCK_INDEX			0
+#define SD_MASTER_CLOCK_INDEX			1
+
+struct sdhci_cdns_phy_cfg {
+	const char *property;
+	u8 addr;
+};
+
+static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = {
+	{ "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, },
+	{ "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, },
+	{ "cdns,phy-input-delay-sd-uhs-sdr12", SDHCI_CDNS_PHY_DLY_UHS_SDR12, },
+	{ "cdns,phy-input-delay-sd-uhs-sdr25", SDHCI_CDNS_PHY_DLY_UHS_SDR25, },
+	{ "cdns,phy-input-delay-sd-uhs-sdr50", SDHCI_CDNS_PHY_DLY_UHS_SDR50, },
+	{ "cdns,phy-input-delay-sd-uhs-ddr50", SDHCI_CDNS_PHY_DLY_UHS_DDR50, },
+	{ "cdns,phy-input-delay-mmc-highspeed", SDHCI_CDNS_PHY_DLY_EMMC_SDR, },
+	{ "cdns,phy-input-delay-mmc-ddr", SDHCI_CDNS_PHY_DLY_EMMC_DDR, },
+	{ "cdns,phy-dll-delay-sdclk", SDHCI_CDNS_PHY_DLY_SDCLK, },
+	{ "cdns,phy-dll-delay-sdclk-hsmmc", SDHCI_CDNS_PHY_DLY_HSMMC, },
+	{ "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, },
+};
+
+static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv,
+				    u8 addr, u8 data)
+{
+	void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS04;
+	u32 tmp;
+	int ret;
+
+	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK), 10);
+	if (ret)
+		return ret;
+
+	tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
+	      FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
+	writel(tmp, reg);
+
+	tmp |= SDHCI_CDNS_HRS04_WR;
+	writel(tmp, reg);
+
+	ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 10);
+	if (ret)
+		return ret;
+
+	tmp &= ~SDHCI_CDNS_HRS04_WR;
+	writel(tmp, reg);
+
+	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK), 10);
+
+	return ret;
+}
+
+static unsigned int sdhci_cdns_phy_param_count(struct device_node *np)
+{
+	unsigned int count = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++)
+		if (of_property_read_bool(np, sdhci_cdns_phy_cfgs[i].property))
+			count++;
+
+	return count;
+}
+
+static void sdhci_cdns_phy_param_parse(struct device_node *np,
+				       struct sdhci_cdns_priv *priv)
+{
+	struct sdhci_cdns4_phy_param *p = priv->phy_params;
+	u32 val;
+	int ret, i;
+
+	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++) {
+		ret = of_property_read_u32(np, sdhci_cdns_phy_cfgs[i].property,
+					   &val);
+		if (ret)
+			continue;
+
+		p->addr = sdhci_cdns_phy_cfgs[i].addr;
+		p->data = val;
+		p++;
+	}
+}
+
+static int sdhci_cdns_phy_init(struct sdhci_cdns_priv *priv)
+{
+	int ret, i;
+
+	for (i = 0; i < priv->nr_phy_params; i++) {
+		ret = sdhci_cdns_write_phy_reg(priv, priv->phy_params[i].addr,
+					       priv->phy_params[i].data);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode)
+{
+	u32 tmp;
+
+	/* The speed mode for eMMC is selected by HRS06 register */
+	tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06);
+	tmp &= ~SDHCI_CDNS_HRS06_MODE;
+	tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode);
+	writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS06);
+}
+
+static int sdhci_cdns_init(struct mci_host *host, struct device *dev)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	int ret;
+
+	ret = sdhci_reset(&priv->sdhci, SDHCI_RESET_ALL);
+	if (ret)
+		return ret;
+
+	sdhci_write8(&priv->sdhci, SDHCI_POWER_CONTROL,
+		     SDHCI_BUS_VOLTAGE_330 | SDHCI_BUS_POWER_EN);
+	udelay(400);
+
+	sdhci_write32(&priv->sdhci, SDHCI_INT_ENABLE, SDHCI_INT_CMD_COMPLETE |
+			SDHCI_INT_XFER_COMPLETE | SDHCI_INT_CARD_INT |
+			SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_END_BIT |
+			SDHCI_INT_INDEX | SDHCI_INT_DATA_TIMEOUT |
+			SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DMA);
+	sdhci_write32(&priv->sdhci, SDHCI_SIGNAL_ENABLE, 0);
+
+	sdhci_enable_v4_mode(&priv->sdhci);
+
+	return 0;
+}
+
+static void sdhci_cdns_set_ios(struct mci_host *host, struct mci_ios *ios)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	u16 val;
+
+	debug("%s: clock = %u, f_max = %u, bus-width = %d, timing = %02x\n", __func__,
+	      ios->clock, host->f_max, ios->bus_width, ios->timing);
+
+	if (ios->clock)
+		sdhci_set_clock(&priv->sdhci, ios->clock, priv->sdhci.max_clk);
+
+	sdhci_set_bus_width(&priv->sdhci, ios->bus_width);
+
+	val = sdhci_read8(&priv->sdhci, SDHCI_HOST_CONTROL);
+
+	if (ios->clock > 26000000)
+		val |= SDHCI_CTRL_HISPD;
+	else
+		val &= ~SDHCI_CTRL_HISPD;
+
+	sdhci_write8(&priv->sdhci, SDHCI_HOST_CONTROL, val);
+}
+
+static int sdhci_cdns_send_cmd(struct mci_host *host, struct mci_cmd *cmd)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	int timeout = 10; /* Approx. 10 ms */
+
+	while (sdhci_send_command(&priv->sdhci, cmd) != 0) {
+		if (!timeout--) {
+			sdhci_dumpregs(&priv->sdhci);
+			return -EIO;
+		}
+
+		mdelay(1);
+	}
+	return 0;
+}
+
+static int sdhci_cdns_set_tune_val(struct mci_host *host, unsigned int val)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
+	u32 tmp;
+	int i, ret;
+
+	if (priv->sdhci.version >= SDHCI_SPEC_420)
+		return sdhci_cdns6_set_tune_val(host, val);
+
+	if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
+		return -EINVAL;
+
+	tmp = readl(reg);
+	tmp &= ~SDHCI_CDNS_HRS06_TUNE;
+	tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
+
+	/*
+	 * Workaround for IP errata:
+	 * The IP6116 SD/eMMC PHY design has a timing issue on receive data
+	 * path. Send tune request twice.
+	 */
+	for (i = 0; i < 2; i++) {
+		tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
+		writel(tmp, reg);
+
+		ret = readl_poll_timeout(reg, tmp,
+					 !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), 0);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * In SD mode, software must not use the hardware tuning and instead perform
+ * an almost identical procedure to eMMC.
+ */
+static int sdhci_cdns_execute_tuning(struct mci_host *host, u32 opcode)
+{
+	int cur_streak = 0;
+	int max_streak = 0;
+	int end_of_streak = 0;
+	int i;
+	int ret;
+
+	/*
+	 * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
+	 * The delay is set by probe, based on the DT properties.
+	 */
+	if (host->ios.timing != MMC_TIMING_MMC_HS200 &&
+	    host->ios.timing != MMC_TIMING_UHS_SDR104) {
+		dev_dbg(host->hw_dev, "Tuning skipped (timing: %d)\n",
+			host->ios.timing);
+		return 0;
+	}
+
+	for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
+		if (sdhci_cdns_set_tune_val(host, i) ||
+		    mmc_send_tuning(host->mci, opcode)) { /* bad */
+			cur_streak = 0;
+		} else { /* good */
+			cur_streak++;
+			if (cur_streak > max_streak) {
+				max_streak = cur_streak;
+				end_of_streak = i;
+			}
+		}
+	}
+
+	if (!max_streak) {
+		dev_err(host->hw_dev, "no tuning point found\n");
+		return -EIO;
+	}
+
+	ret = sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void sdhci_cdns_set_uhs_signaling(struct mci_host *host,
+					 unsigned int timing)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	u32 mode;
+
+	switch (timing) {
+	case MMC_TIMING_MMC_HS:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
+		break;
+	case MMC_TIMING_MMC_DDR52:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
+		break;
+	case MMC_TIMING_MMC_HS200:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
+		break;
+	case MMC_TIMING_MMC_HS400:
+		if (priv->enhanced_strobe)
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
+		else
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
+		break;
+	default:
+		mode = SDHCI_CDNS_HRS06_MODE_SD;
+		break;
+	}
+
+	sdhci_cdns_set_emmc_mode(priv, mode);
+
+	/* For SD, fall back to the default handler */
+	if (mode == SDHCI_CDNS_HRS06_MODE_SD)
+		sdhci_set_uhs_signaling(&priv->sdhci, timing);
+
+	/* For host controller V6, set SDHCI and PHY registers for UHS signaling */
+	if (priv->sdhci.version >= SDHCI_SPEC_420)
+		sdhci_cdns6_phy_adj(host, timing);
+}
+
+static const struct mci_ops sdhci_cdns_ops = {
+	.set_ios = sdhci_cdns_set_ios,
+	.init = sdhci_cdns_init,
+	.send_cmd = sdhci_cdns_send_cmd,
+	.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
+};
+
+static const struct sdhci_cdns_drv_data sdhci_cdns6_agilex5_drv_data = {
+	.ops = &sdhci_cdns_ops,
+};
+
+static const struct sdhci_cdns_drv_data sdhci_cdns4_drv_data = {
+	.ops = &sdhci_cdns_ops,
+};
+
+static int sdhci_cdns4_phy_probe(struct device *dev,
+				 struct sdhci_cdns_priv *priv)
+{
+	sdhci_cdns_phy_param_parse(dev->of_node, priv);
+
+	return sdhci_cdns_phy_init(priv);
+}
+
+static struct clk **sdhci_cdns_enable_clocks(struct device *dev, bool is_sd4hc)
+{
+	struct clk **clks = NULL;
+
+	if (is_sd4hc) {
+		/* For SDHCI V4 controllers, enable only the default clock */
+		clks = xzalloc(sizeof(struct clk *));
+		clks[MAIN_CLOCK_INDEX] = clk_get_enabled(dev, NULL);
+		if (IS_ERR(clks[MAIN_CLOCK_INDEX])) {
+			dev_err(dev, "Failed to get/enable clock\n");
+			return ERR_CAST(clks[MAIN_CLOCK_INDEX]);
+		}
+	} else {
+		clks = xzalloc(sizeof(struct clk *) * 2);
+
+		/* Enable main clock ("biu") */
+		clks[MAIN_CLOCK_INDEX] = clk_get_enabled(dev, "biu");
+		if (IS_ERR(clks[MAIN_CLOCK_INDEX])) {
+			dev_err(dev, "%s: request of Main clock failed (%ld)\n",
+				__func__, PTR_ERR(clks[MAIN_CLOCK_INDEX]));
+			return ERR_CAST(clks[MAIN_CLOCK_INDEX]);
+		}
+
+		/* Enable SD master clock ("ciu") */
+		clks[SD_MASTER_CLOCK_INDEX] = clk_get_enabled(dev, "ciu");
+		if (IS_ERR(clks[SD_MASTER_CLOCK_INDEX])) {
+			dev_err(dev,
+				"%s: request of SD master clock failed (%ld)\n",
+				__func__, PTR_ERR(clks[SD_MASTER_CLOCK_INDEX]));
+			return ERR_CAST(clks[SD_MASTER_CLOCK_INDEX]);
+		}
+	}
+	return clks;
+}
+
+static int sdhci_cdns_probe(struct device *dev)
+{
+	struct sdhci_cdns_priv *priv;
+	struct mci_host *mci;
+	struct clk **clks;
+	struct resource *iores;
+	unsigned int nr_phy_params;
+	int ret;
+	bool is_sd4hc = of_device_is_compatible(dev->device_node, "cdns,sd4hc");
+
+	priv = xzalloc(sizeof(*priv));
+	mci = &priv->mci;
+
+	priv->rst = reset_control_get(dev, "sdhc-reset");
+	if (IS_ERR(priv->rst)) {
+		dev_err(dev, "Invalid reset line 'sdhc-reset'.\n");
+		return PTR_ERR(priv->rst);
+	}
+
+	priv->softphy_rst = reset_control_get(dev, "softphy-reset");
+	if (IS_ERR(priv->softphy_rst)) {
+		dev_err(dev, "Invalid reset line 'softphy-reset'.\n");
+		return PTR_ERR(priv->softphy_rst);
+	}
+
+	priv->sdmmc_ocp_rst = reset_control_get(dev, "sdmmc-ocp");
+	if (IS_ERR(priv->sdmmc_ocp_rst)) {
+		dev_err(dev, "Invalid reset line 'sdmmc-ocp-reset'.\n");
+		return PTR_ERR(priv->sdmmc_ocp_rst);
+	}
+	reset_control_assert(priv->rst);
+	reset_control_deassert(priv->rst);
+
+	reset_control_assert(priv->softphy_rst);
+	reset_control_deassert(priv->softphy_rst);
+
+	reset_control_assert(priv->sdmmc_ocp_rst);
+	reset_control_deassert(priv->sdmmc_ocp_rst);
+
+	clks = sdhci_cdns_enable_clocks(dev, is_sd4hc);
+	if (IS_ERR(clks)) {
+		dev_err(dev, "Failed to enable controller clocks: %ld\n", PTR_ERR(clks));
+		return PTR_ERR(clks);
+	}
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	mci->ops = sdhci_cdns_ops;
+	mci->hw_dev = dev;
+
+	nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
+
+	priv->biu_clk = clks[MAIN_CLOCK_INDEX];
+
+	priv->nr_phy_params = nr_phy_params;
+	priv->hrs_addr = IOMEM(iores->start);
+	priv->enhanced_strobe = false;
+	priv->sdhci.base = IOMEM(iores->start + SDHCI_CDNS_SRS_BASE);
+	priv->sdhci.mci = mci;
+	priv->sdhci.max_clk = clk_get_rate(priv->biu_clk);
+	priv->sdhci.quirks2 = SDHCI_QUIRK2_BROKEN_HS200;
+
+	dev->priv = priv;
+
+	priv->mci.f_max = clk_get_rate(priv->biu_clk);
+	mci_of_parse(mci);
+	priv->mci.f_min = priv->mci.f_max / SDHCI_MAX_DIV_SPEC_300;
+
+	priv->mci.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+	priv->mci.host_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+	priv->mci.host_caps |= MMC_CAP_MMC_HIGHSPEED_52MHZ;
+	if (is_sd4hc) {
+		ret = sdhci_cdns4_phy_probe(dev, priv);
+	} else {
+		priv->ciu_clk = clks[SD_MASTER_CLOCK_INDEX];
+		ret = sdhci_cdns6_phy_probe(mci);
+	}
+	if (ret)
+		goto disable_clk;
+
+	if (IS_ENABLED(CONFIG_MCI_TUNING))
+		mci->ops.execute_tuning = sdhci_cdns_execute_tuning;
+
+	ret = sdhci_setup_host(&priv->sdhci);
+	if (ret)
+		goto disable_clk;
+
+	if (priv->sdhci.caps & SDHCI_CAN_64BIT_V4) {
+		dma_set_mask(dev, DMA_BIT_MASK(40));
+		dev_dbg(priv->mci.hw_dev, "set DMA mask to 40-bit\n");
+	} else {
+		dma_set_mask(dev, DMA_BIT_MASK(32));
+		dev_dbg(priv->mci.hw_dev, "set DMA mask to 32-bit\n");
+	}
+
+	dev_dbg(priv->mci.hw_dev, "host controller version: %u\n",
+		priv->sdhci.version);
+
+	ret = mci_register(priv->sdhci.mci);
+	if (ret)
+		return ret;
+
+	return 0;
+
+disable_clk:
+	clk_disable_unprepare(priv->biu_clk);
+
+	return ret;
+}
+
+static __maybe_unused struct of_device_id sdhci_cdns_match[] = {
+	{
+		.compatible = "cdns,sd4hc",
+		.data = &sdhci_cdns4_drv_data,
+	},
+	{
+		.compatible = "altr,agilex5-sd6hc",
+		.data = &sdhci_cdns6_agilex5_drv_data,
+	},
+	{ /* sentinel */ }
+};
+
+static struct driver sdhci_cdns_driver = {
+	.name = "sdhci-cdns",
+	.of_compatible = DRV_OF_COMPAT(sdhci_cdns_match),
+	.probe = sdhci_cdns_probe,
+};
+device_platform_driver(sdhci_cdns_driver);
diff --git a/drivers/mci/cadence-sdhci.h b/drivers/mci/cadence-sdhci.h
new file mode 100644
index 0000000000..0352dc0be2
--- /dev/null
+++ b/drivers/mci/cadence-sdhci.h
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#ifndef SDHCI_CADENCE_H_
+#define SDHCI_CADENCE_H_
+
+#include <common.h>
+#include <clock.h>
+#include <linux/clk.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/iopoll.h>
+#include <linux/reset.h>
+
+#include "sdhci.h"
+
+/* HRS - Host Register Set (specific to Cadence) */
+#define SDHCI_CDNS_HRS04	0x10		/* PHY access port */
+#define SDHCI_CDNS_HRS05        0x14		/* PHY data access port */
+
+/*
+ * The tuned val register is 6 bit-wide, but not the whole of the range is
+ * available. The range 0-42 seems to be available (then 43 wraps around to 0)
+ * but I am not quite sure if it is official.  Use only 0 to 39 for safety.
+ */
+#define SDHCI_CDNS_MAX_TUNING_LOOP	40
+
+struct sdhci_cdns_drv_data {
+	const struct mci_ops *ops;
+	unsigned int quirks;
+	unsigned int quirks2;
+};
+
+/**
+ * struct sdhci_cdns4_phy_param - PHY parameter/address pair
+ * @addr: PHY register address.
+ * @data: Value to write to the PHY register.
+ *
+ * Used for passing a list of PHY configuration parameters to the
+ * Cadence SDHCI V4 controller.
+ */
+struct sdhci_cdns4_phy_param {
+	u8 addr;
+	u8 data;
+};
+
+/**
+ * struct sdhci_cdns_priv - Cadence SDHCI private controller data
+ * @hrs_addr: Base address of Cadence Host Register Set (HRS) registers.
+ * @ctl_addr: Base address for write control registers.
+ *            Used only for "amd,pensando-elba-sd4hc" compatible controllers
+ *            to enable byte-lane writes.
+ * @wrlock: Spinlock for protecting register writes (Elba only).
+ * @enhanced_strobe: Flag indicating if Enhanced Strobe (HS400ES) is enabled.
+ * @priv_writel: Optional SoC-specific write function for register access.
+ *               Used for Elba to ensure correct byte-lane enable.
+ * @rst_hw: Hardware reset control for the controller.
+ * @ciu_clk: Card Interface Unit (CIU) clock handle.
+ *           Used only for V6 (SDHCI spec >= 4.20) controllers.
+ * @nr_phy_params: Number of PHY parameter entries parsed from DT (V4 only).
+ * @phy_params: Array of PHY parameter/address pairs for PHY initialization (V4 only).
+ */
+struct sdhci_cdns_priv {
+	struct mci_host mci;
+	struct sdhci sdhci;
+	struct reset_control *rst;
+	struct reset_control *softphy_rst;
+	struct reset_control *sdmmc_ocp_rst;
+	void __iomem *hrs_addr;
+	void __iomem *ctl_addr; /* write control */
+	bool enhanced_strobe;
+	struct clk *biu_clk; /* Card Interface Unit clock */
+	struct clk *ciu_clk; /* Card Interface Unit clock */
+	unsigned int nr_phy_params;
+	struct sdhci_cdns4_phy_param phy_params[];
+};
+
+/*
+ * sdhci_cdns_priv - Helper to retrieve Cadence private data from sdhci_host
+ * @host: Pointer to struct sdhci_host.
+ *
+ * Returns: Pointer to struct sdhci_cdns_priv.
+ */
+static inline void *sdhci_cdns_priv(struct mci_host *host)
+{
+	return host->hw_dev->priv;
+}
+
+/**
+ * sdhci_cdns6_phy_probe - Initialize the Cadence PHY using device tree.
+ * @host: Pointer to struct sdhci_host.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int sdhci_cdns6_phy_probe(struct mci_host *host);
+
+/**
+ * sdhci_cdns6_phy_adj - Program PHY registers for a specific timing mode.
+ * @host: Pointer to struct sdhci_host.
+ * @timing: MMC timing mode (MMC_TIMING_*).
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int sdhci_cdns6_phy_adj(struct mci_host *host, unsigned char timing);
+
+/**
+ * sdhci_cdns6_set_tune_val - Set the PHY tuning value.
+ * @host: Pointer to struct sdhci_host.
+ * @val: Tuning value to program.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int sdhci_cdns6_set_tune_val(struct mci_host *host, unsigned int val);
+
+#endif // SDHCI_CADENCE_H_
diff --git a/drivers/mci/cadence-sdhci6.c b/drivers/mci/cadence-sdhci6.c
new file mode 100644
index 0000000000..031c589f78
--- /dev/null
+++ b/drivers/mci/cadence-sdhci6.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * PHY support for Cadence version 6 SDHCI
+ *
+ * Copyright (C) 2025 Altera Corporation
+ *   Author: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
+ */
+
+#include "cadence-sdhci.h"
+
+/* IO Delay Information */
+#define SDHCI_CDNS_HRS07			0X1C
+
+/* PHY Control and Status */
+#define SDHCI_CDNS_HRS09			0x24
+#define   SDHCI_CDNS_HRS09_RDDATA_EN		BIT(16)
+#define   SDHCI_CDNS_HRS09_RDCMD_EN		BIT(15)
+#define   SDHCI_CDNS_HRS09_EXTENDED_WR_MODE	BIT(3)
+#define   SDHCI_CDNS_HRS09_EXTENDED_RD_MODE	BIT(2)
+#define   SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE	BIT(1)
+#define   SDHCI_CDNS_HRS09_PHY_SW_RESET		BIT(0)
+
+/* SDCLK start point adjustment */
+#define SDHCI_CDNS_HRS10			0x28
+
+/* eMMC Control */
+#define SDHCI_CDNS_HRS11			0x2C
+#define   SDHCI_CDNS_HRS11_EMMC_RST		BIT(0)	/* eMMC reset */
+
+/* CMD/DAT output delay */
+#define SDHCI_CDNS_HRS16			0x40
+
+/* PHY Special Function Registers */
+/* DQ timing */
+#define PHY_DQ_TIMING_REG_ADDR			0x2000
+
+/* DQS timing */
+#define PHY_DQS_TIMING_REG_ADDR			0x2004
+
+/* Gate and loopback control */
+#define PHY_GATE_LPBK_CTRL_REG_ADDR		0x2008
+
+/* Master DLL logic */
+#define PHY_DLL_MASTER_CTRL_REG_ADDR		0x200C
+
+/* Slave DLL logic */
+#define PHY_DLL_SLAVE_CTRL_REG_ADDR			0x2010
+#define   PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY	GENMASK(31, 24)
+#define   PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY		GENMASK(7, 0)
+
+/* Global control settings */
+#define PHY_CTRL_REG_ADDR			0x2080
+
+/*
+ * Supports MMC_TIMING_LEGACY to MMC_TIMING_MMC_HS400 and additionally
+ * MMC_TIMING_MMC_HS400ES, as defined in include/linux/mmc/host.h.
+ */
+#define MAX_TIMING_MODES			12
+
+/* Index register configuration arrays for Cadence SDHCI V6 controller and PHY setup */
+enum sdhci_cdns6_reg_index {
+	REG_CFG_HRS07 = 0,
+	REG_CFG_HRS09,
+	REG_CFG_HRS10,
+	REG_CFG_HRS16,
+	REG_CFG_PHY_DQS,
+	REG_CFG_PHY_GATE_LPBK_CTRL,
+	REG_CFG_PHY_DLL_MASTER_CTRL,
+	REG_CFG_PHY_DLL_SLAVE_CTRL,
+	REG_CFG_PHY_DQ,
+	REG_CFG_MAX
+};
+
+/**
+ * struct sdhci_cdns6_ctrl_cfg - Controller/PHY register property and value pair
+ * @property: Device tree property name for the register configuration
+ * @value: Value to be programmed into the register
+ *
+ * Store register configuration values parsed from the device tree
+ * for Cadence SDHCI V6 controller and PHY initialization.
+ */
+struct sdhci_cdns6_ctrl_cfg {
+	const char *property;
+	u32 value;
+};
+
+static const struct sdhci_cdns6_ctrl_cfg reg_cfg[REG_CFG_MAX][MAX_TIMING_MODES] = {
+	/* [0] SD Host Controller: HRS07 */
+	{
+		{ "cdns,ctrl-hrs07-timing-delay-default", 0x00090000 }, // MMC legacy or SD default
+		{ "cdns,ctrl-hrs07-timing-delay-mmc-hs", 0x00090000 }, // MMC High Speed
+		{ "cdns,ctrl-hrs07-timing-delay-sd-hs", 0x000A0001 }, // SD High Speed
+		{ "cdns,ctrl-hrs07-timing-delay-sd-sdr12", 0x000A0001 }, // SD UHS1 SDR12
+		{ "cdns,ctrl-hrs07-timing-delay-sd-sdr25", 0x000A0001 }, // SD UHS1 SDR25
+		{ "cdns,ctrl-hrs07-timing-delay-sd-sdr50", 0x00090005 }, // SD UHS1 SDR50
+		{ "cdns,ctrl-hrs07-timing-delay-sd-sdr104", 0x00090005 }, // SD UHS1 SDR104
+		{ "cdns,ctrl-hrs07-timing-delay-sd-ddr50", 0x00090001 }, // SD UHS1 DDR50
+		{ "cdns,ctrl-hrs07-timing-delay-mmc-ddr52", 0x00090001 }, // MMC DDR52
+		{ "cdns,ctrl-hrs07-timing-delay-mmc-hs200", 0x00090000 }, // MMC HS200
+		{ "cdns,ctrl-hrs07-timing-delay-mmc-hs400", 0x00090001 }, // MMC HS400
+		{ "cdns,ctrl-hrs07-timing-delay-mmc-hs400es", 0x00090001 }, // MMC HS400ES
+	},
+	/* [1] SD Host Controller: HRS09 */
+	{
+		{ "cdns,ctrl-hrs09-timing-delay-default", 0x0001800C },
+		{ "cdns,ctrl-hrs09-timing-delay-mmc-hs", 0x0001800C },
+		{ "cdns,ctrl-hrs09-timing-delay-sd-hs", 0x0001800C },
+		{ "cdns,ctrl-hrs09-timing-delay-sd-sdr12", 0x0001800C },
+		{ "cdns,ctrl-hrs09-timing-delay-sd-sdr25", 0x0001800C },
+		{ "cdns,ctrl-hrs09-timing-delay-sd-sdr50", 0xf1c1800c },
+		{ "cdns,ctrl-hrs09-timing-delay-sd-sdr104", 0xf1c18000 },
+		{ "cdns,ctrl-hrs09-timing-delay-sd-ddr50", 0x0001800C },
+		{ "cdns,ctrl-hrs09-timing-delay-mmc-ddr52", 0x0001800C },
+		{ "cdns,ctrl-hrs09-timing-delay-mmc-hs200", 0xf1c18000 },
+		{ "cdns,ctrl-hrs09-timing-delay-mmc-hs400", 0xf1c18000 },
+		{ "cdns,ctrl-hrs09-timing-delay-mmc-hs400es", 0xf1c18000 },
+	},
+	/* [2] SD Host Controller: HRS10 */
+	{
+		{ "cdns,ctrl-hrs10-timing-delay-default", 0x00020000 },
+		{ "cdns,ctrl-hrs10-timing-delay-mmc-hs", 0x00020000 },
+		{ "cdns,ctrl-hrs10-timing-delay-sd-hs", 0x00030000 },
+		{ "cdns,ctrl-hrs10-timing-delay-sd-sdr12", 0x00030000 },
+		{ "cdns,ctrl-hrs10-timing-delay-sd-sdr25", 0x00030000 },
+		{ "cdns,ctrl-hrs10-timing-delay-sd-sdr50", 0x00020000 },
+		{ "cdns,ctrl-hrs10-timing-delay-sd-sdr104", 0x00090000 },
+		{ "cdns,ctrl-hrs10-timing-delay-sd-ddr50", 0x00020000 },
+		{ "cdns,ctrl-hrs10-timing-delay-mmc-ddr52", 0x00020000 },
+		{ "cdns,ctrl-hrs10-timing-delay-mmc-hs200", 0x00090000 },
+		{ "cdns,ctrl-hrs10-timing-delay-mmc-hs400", 0x00080000 },
+		{ "cdns,ctrl-hrs10-timing-delay-mmc-hs400es", 0x00080000 },
+	},
+	/* [3] SD Host Controller: HRS16 */
+	{
+		{ "cdns,ctrl-hrs16-timing-delay-default", 0x00000000 },
+		{ "cdns,ctrl-hrs16-timing-delay-mmc-hs", 0x0000010a },
+		{ "cdns,ctrl-hrs16-timing-delay-sd-hs", 0x00000101 },
+		{ "cdns,ctrl-hrs16-timing-delay-sd-sdr12", 0x00000000 },
+		{ "cdns,ctrl-hrs16-timing-delay-sd-sdr25", 0x00000101 },
+		{ "cdns,ctrl-hrs16-timing-delay-sd-sdr50", 0x00000101 },
+		{ "cdns,ctrl-hrs16-timing-delay-sd-sdr104", 0x00000101 },
+		{ "cdns,ctrl-hrs16-timing-delay-sd-ddr50", 0x11000000 },
+		{ "cdns,ctrl-hrs16-timing-delay-mmc-ddr52", 0x11000001 },
+		{ "cdns,ctrl-hrs16-timing-delay-mmc-hs200", 0x00007777 },
+		{ "cdns,ctrl-hrs16-timing-delay-mmc-hs400", 0x11000001 },
+		{ "cdns,ctrl-hrs16-timing-delay-mmc-hs400es", 0x11000001 },
+	},
+	/* [4] ComboPHY: DQS timing */
+	{
+		{ "cdns,phy-dqs-timing-delay-default", 0x00780000 },
+		{ "cdns,phy-dqs-timing-delay-mmc-hs", 0x00780000 },
+		{ "cdns,phy-dqs-timing-delay-sd-hs", 0x00780001 },
+		{ "cdns,phy-dqs-timing-delay-sd-sdr12", 0x00780000 },
+		{ "cdns,phy-dqs-timing-delay-sd-sdr25", 0x00780001 },
+		{ "cdns,phy-dqs-timing-delay-sd-sdr50", 0x00780004 },
+		{ "cdns,phy-dqs-timing-delay-sd-sdr104", 0x00780004 },
+		{ "cdns,phy-dqs-timing-delay-sd-ddr50", 0x00780004 },
+		{ "cdns,phy-dqs-timing-delay-mmc-ddr52", 0x00780001 },
+		{ "cdns,phy-dqs-timing-delay-mmc-hs200", 0x00780004 },
+		{ "cdns,phy-dqs-timing-delay-mmc-hs400", 0x00680004 },
+		{ "cdns,phy-dqs-timing-delay-mmc-hs400es", 0x00680004 },
+	},
+	/* [5] ComboPHY: PHY Gate Loopback Control */
+	{
+		{ "cdns,phy-gate-lpbk-ctrl-delay-default", 0x81a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-mmc-hs", 0x81a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-sd-hs", 0x81a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-sd-sdr12", 0x81a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-sd-sdr25", 0x81a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-sd-sdr50", 0x80a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-sd-sdr104", 0x81a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-sd-ddr50", 0x80a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-mmc-ddr52", 0x81a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-mmc-hs200", 0x81a40040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-mmc-hs400", 0x81fc0040 },
+		{ "cdns,phy-gate-lpbk-ctrl-delay-mmc-hs400es", 0x81fc0040 },
+	},
+	/* [6] ComboPHY: PHY DLL Master Control */
+	{
+		{ "cdns,phy-dll-master-ctrl-default", 0x00800004 },
+		{ "cdns,phy-dll-master-ctrl-mmc-hs", 0x00800004 },
+		{ "cdns,phy-dll-master-ctrl-sd-hs", 0x00800004 },
+		{ "cdns,phy-dll-master-ctrl-sd-sdr12", 0x00800004 },
+		{ "cdns,phy-dll-master-ctrl-sd-sdr25", 0x00800004 },
+		{ "cdns,phy-dll-master-ctrl-sd-sdr50", 0x00800004 },
+		{ "cdns,phy-dll-master-ctrl-sd-sdr104", 0x00204d00 },
+		{ "cdns,phy-dll-master-ctrl-sd-ddr50", 0x00800000 },
+		{ "cdns,phy-dll-master-ctrl-mmc-ddr52", 0x00800000 },
+		{ "cdns,phy-dll-master-ctrl-mmc-hs200", 0x00000004 },
+		{ "cdns,phy-dll-master-ctrl-mmc-hs400", 0x00000004 },
+		{ "cdns,phy-dll-master-ctrl-mmc-hs400es", 0x00000004 },
+	},
+	/* [7] ComboPHY: PHY DLL Slave Control */
+	{
+		{ "cdns,phy-dll-slave-ctrl-default", 0x00000000 },
+		{ "cdns,phy-dll-slave-ctrl-mmc-hs", 0x00000000 },
+		{ "cdns,phy-dll-slave-ctrl-sd-hs", 0x00000000 },
+		{ "cdns,phy-dll-slave-ctrl-sd-sdr12", 0x00000000 },
+		{ "cdns,phy-dll-slave-ctrl-sd-sdr25", 0x00000000 },
+		{ "cdns,phy-dll-slave-ctrl-sd-sdr50", 0x04000004 },
+		{ "cdns,phy-dll-slave-ctrl-sd-sdr104", 0x04000004 },
+		{ "cdns,phy-dll-slave-ctrl-sd-ddr50", 0x00000000 },
+		{ "cdns,phy-dll-slave-ctrl-mmc-ddr52", 0x00000000 },
+		{ "cdns,phy-dll-slave-ctrl-mmc-hs200", 0x004d4d00 },
+		{ "cdns,phy-dll-slave-ctrl-mmc-hs400", 0x004d4b40 },
+		{ "cdns,phy-dll-slave-ctrl-mmc-hs400es", 0x004d4b40 },
+	},
+	/* [8] ComboPHY: DQ timing delay */
+	{
+		{ "cdns,phy-dq-timing-delay-default", 0x28000001 },
+		{ "cdns,phy-dq-timing-delay-mmc-hs", 0x00000001 },
+		{ "cdns,phy-dq-timing-delay-sd-hs", 0x10000001 },
+		{ "cdns,phy-dq-timing-delay-sd-sdr12", 0x28000001 },
+		{ "cdns,phy-dq-timing-delay-sd-sdr25", 0x10000001 },
+		{ "cdns,phy-dq-timing-delay-sd-sdr50", 0x38000001 },
+		{ "cdns,phy-dq-timing-delay-sd-sdr104", 0x38000001 },
+		{ "cdns,phy-dq-timing-delay-sd-ddr50", 0x38000001 },
+		{ "cdns,phy-dq-timing-delay-mmc-ddr52", 0x10000001 },
+		{ "cdns,phy-dq-timing-delay-mmc-hs200", 0x10000001 },
+		{ "cdns,phy-dq-timing-delay-mmc-hs400", 0x10000001 },
+		{ "cdns,phy-dq-timing-delay-mmc-hs400es", 0x10000001 },
+	}
+};
+
+static unsigned int sdhci_cdns6_read_phy_reg(struct sdhci_cdns_priv *priv,
+					     const u32 address)
+{
+	writel(address, priv->hrs_addr + SDHCI_CDNS_HRS04);
+	return readl(priv->hrs_addr + SDHCI_CDNS_HRS05);
+}
+
+static void sdhci_cdns6_write_phy_reg(struct sdhci_cdns_priv *priv,
+				      const u32 address, const u32 value)
+{
+	writel(address, priv->hrs_addr + SDHCI_CDNS_HRS04);
+	writel(value, priv->hrs_addr + SDHCI_CDNS_HRS05);
+}
+
+static int sdhci_cdns6_reset_phy_dll(struct mci_host *host, unsigned int reset)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS09;
+	u32 tmp;
+	int ret = 0;
+
+	tmp = readl(reg);
+	/* Switch On DLL Reset */
+	tmp &= ~SDHCI_CDNS_HRS09_PHY_SW_RESET;
+
+	if (!reset)
+		/* Switch Off DLL Reset */
+		tmp |= SDHCI_CDNS_HRS09_PHY_SW_RESET;
+
+	writel(tmp, reg);
+
+	/* After reset, wait until HRS09.PHY_INIT_COMPLETE is set to 1 within 3000us*/
+	if (!reset) {
+		ret = readl_poll_timeout(
+			reg, tmp, (tmp & SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE),
+			3000);
+	}
+
+	return ret;
+}
+
+int sdhci_cdns6_phy_adj(struct mci_host *host, unsigned char timing)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	struct device_node *np = host->hw_dev->of_node;
+	struct sdhci_cdns6_ctrl_cfg timing_cfg[REG_CFG_MAX];
+	u32 dt_value;
+	void __iomem *reg;
+	u32 tmp;
+	int i;
+
+	if (timing >= MAX_TIMING_MODES) {
+		pr_err("Invalid timing mode: %d\n", timing);
+		return -EINVAL;
+	}
+
+	/* Override values from device tree */
+	for (i = 0; i < REG_CFG_MAX; i++) {
+		const char *prop = reg_cfg[i][timing].property;
+
+		if (!of_property_read_u32(np, prop, &dt_value)) {
+			timing_cfg[i].value = dt_value;
+			pr_debug("Overriding %s to 0x%08x from DT\n", prop,
+				 dt_value);
+		} else {
+			timing_cfg[i].value = reg_cfg[i][timing].value;
+		}
+	}
+
+	/* Switch On the DLL Reset */
+	sdhci_cdns6_reset_phy_dll(host, true);
+
+	sdhci_cdns6_write_phy_reg(priv, PHY_DQS_TIMING_REG_ADDR,
+				  timing_cfg[REG_CFG_PHY_DQS].value);
+	sdhci_cdns6_write_phy_reg(priv, PHY_GATE_LPBK_CTRL_REG_ADDR,
+				  timing_cfg[REG_CFG_PHY_GATE_LPBK_CTRL].value);
+	sdhci_cdns6_write_phy_reg(
+		priv, PHY_DLL_MASTER_CTRL_REG_ADDR,
+		timing_cfg[REG_CFG_PHY_DLL_MASTER_CTRL].value);
+	sdhci_cdns6_write_phy_reg(priv, PHY_DLL_SLAVE_CTRL_REG_ADDR,
+				  timing_cfg[REG_CFG_PHY_DLL_SLAVE_CTRL].value);
+
+	/* Switch Off the DLL Reset */
+	sdhci_cdns6_reset_phy_dll(host, false);
+
+	/* Set PHY DQ TIMING control register */
+	sdhci_cdns6_write_phy_reg(priv, PHY_DQ_TIMING_REG_ADDR,
+				  timing_cfg[REG_CFG_PHY_DQ].value);
+
+	/* Set HRS09 register */
+	reg = priv->hrs_addr + SDHCI_CDNS_HRS09;
+	tmp = readl(reg);
+	tmp &= ~(SDHCI_CDNS_HRS09_EXTENDED_WR_MODE |
+		 SDHCI_CDNS_HRS09_EXTENDED_RD_MODE |
+		 SDHCI_CDNS_HRS09_RDDATA_EN | SDHCI_CDNS_HRS09_RDCMD_EN);
+	tmp |= timing_cfg[REG_CFG_HRS09].value;
+	writel(tmp, reg);
+
+	/* Set HRS10 register */
+	writel(timing_cfg[REG_CFG_HRS10].value,
+	       priv->hrs_addr + SDHCI_CDNS_HRS10);
+
+	/* Set HRS16 register */
+	writel(timing_cfg[REG_CFG_HRS16].value,
+	       priv->hrs_addr + SDHCI_CDNS_HRS16);
+
+	/* Set HRS07 register */
+	writel(timing_cfg[REG_CFG_HRS07].value,
+	       priv->hrs_addr + SDHCI_CDNS_HRS07);
+
+	return 0;
+}
+
+int sdhci_cdns6_set_tune_val(struct mci_host *host, unsigned int val)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	u32 tmp, tuneval;
+
+	/**
+	 * Scale the tuning tap (0..39) to the 8-bit PHY DLL delay field (0..255),
+	 * as required by the read_dqs_cmd_delay and read_dqs_delay fields.
+	 * This ensures each tuning step maps linearly to the hardware delay range.
+	 */
+#define SDHCI_CDNS6_PHY_DLL_FIELD_SIZE 256
+
+	tuneval = (val * SDHCI_CDNS6_PHY_DLL_FIELD_SIZE) /
+		  SDHCI_CDNS_MAX_TUNING_LOOP;
+
+	tmp = sdhci_cdns6_read_phy_reg(priv, PHY_DLL_SLAVE_CTRL_REG_ADDR);
+	tmp &= ~(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY |
+		 PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY);
+	tmp |= FIELD_PREP(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY, tuneval) |
+	       FIELD_PREP(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY, tuneval);
+
+	/* Switch On the DLL Reset */
+	sdhci_cdns6_reset_phy_dll(host, true);
+
+	sdhci_cdns6_write_phy_reg(priv, PHY_DLL_SLAVE_CTRL_REG_ADDR, tmp);
+
+	/* Switch Off the DLL Reset */
+	sdhci_cdns6_reset_phy_dll(host, false);
+
+	return 0;
+}
+
+int sdhci_cdns6_phy_probe(struct mci_host *host)
+{
+	return sdhci_cdns6_phy_adj(host, MMC_TIMING_LEGACY);
+}

-- 
2.52.0




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

* [PATCH v2 6/6] ARM: socfpga-agilex5_defconfig: enable cadencen-sdhci
  2026-03-09 12:04 [PATCH v2 0/6] mci: cadence: add v6 support Steffen Trumtrar
                   ` (4 preceding siblings ...)
  2026-03-09 12:04 ` [PATCH v2 5/6] mci: cadence: add support for version 6 Steffen Trumtrar
@ 2026-03-09 12:04 ` Steffen Trumtrar
  5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2026-03-09 12:04 UTC (permalink / raw)
  To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar

Regenerate the defconfig and enable the Cadence SDHCI driver for the
SoCFPGA Agilex5 platform.

Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
 arch/arm/configs/socfpga-agilex5_defconfig | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/arch/arm/configs/socfpga-agilex5_defconfig b/arch/arm/configs/socfpga-agilex5_defconfig
index ce3954a6e7..2cfeef3ec3 100644
--- a/arch/arm/configs/socfpga-agilex5_defconfig
+++ b/arch/arm/configs/socfpga-agilex5_defconfig
@@ -1,5 +1,4 @@
 CONFIG_ARCH_SOCFPGA=y
-CONFIG_64BIT=y
 CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE=y
 CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
 CONFIG_MMU=y
@@ -12,7 +11,6 @@ CONFIG_AUTO_COMPLETE=y
 CONFIG_BOOTM_SHOW_TYPE=y
 CONFIG_BOOTM_VERBOSE=y
 CONFIG_BOOTM_INITRD=y
-CONFIG_BOOTM_OFTREE=y
 CONFIG_BOOTM_OFTREE_UIMAGE=y
 CONFIG_BOOTM_AIMAGE=y
 CONFIG_SYSTEM_PARTITIONS=y
@@ -42,8 +40,6 @@ CONFIG_CMD_SLEEP=y
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_ECHO_E=y
 CONFIG_CMD_EDIT=y
-CONFIG_CMD_LOGIN=y
-CONFIG_CMD_PASSWD=y
 CONFIG_CMD_READLINE=y
 CONFIG_CMD_TIMEOUT=y
 CONFIG_CMD_CRC=y
@@ -52,6 +48,8 @@ CONFIG_CMD_MEMTEST=y
 CONFIG_CMD_MM=y
 CONFIG_CMD_CLK=y
 CONFIG_CMD_DETECT=y
+CONFIG_CMD_LOGIN=y
+CONFIG_CMD_PASSWD=y
 CONFIG_CMD_BAREBOX_UPDATE=y
 CONFIG_CMD_OF_DIFF=y
 CONFIG_CMD_OF_NODE=y
@@ -70,13 +68,16 @@ CONFIG_DRIVER_NET_DESIGNWARE_XGMAC_SOCFPGA=y
 CONFIG_ADIN_PHY=y
 # CONFIG_SPI is not set
 CONFIG_MCI=y
+CONFIG_MCI_CADENCE_SDHCI=y
 # CONFIG_PINCTRL is not set
+# CONFIG_RESET_SCMI is not set
+CONFIG_RESET_SOCFPGA32=y
 CONFIG_ARM_SCMI_PROTOCOL=y
 # CONFIG_VIRTIO_MENU is not set
 CONFIG_MAILBOX=y
 CONFIG_FS_TFTP=y
+CONFIG_DIGEST_SHA256_GENERIC=y
 CONFIG_ZLIB=y
 CONFIG_CRC_CCITT=y
 CONFIG_NLS=y
-CONFIG_DIGEST_SHA256_GENERIC=y
 # CONFIG_MISSING_FIRMWARE_ERROR is not set

-- 
2.52.0




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

end of thread, other threads:[~2026-03-09 12:05 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-09 12:04 [PATCH v2 0/6] mci: cadence: add v6 support Steffen Trumtrar
2026-03-09 12:04 ` [PATCH v2 1/6] mci: add data segment to mci_cmd Steffen Trumtrar
2026-03-09 12:04 ` [PATCH v2 2/6] mci: sdhci: add sdhci_send_cmd Steffen Trumtrar
2026-03-09 12:04 ` [PATCH v2 3/6] mci: sdhci: add set_uhs_signaling callback Steffen Trumtrar
2026-03-09 12:04 ` [PATCH v2 4/6] mci: cadence: remove driver Steffen Trumtrar
2026-03-09 12:04 ` [PATCH v2 5/6] mci: cadence: add support for version 6 Steffen Trumtrar
2026-03-09 12:04 ` [PATCH v2 6/6] ARM: socfpga-agilex5_defconfig: enable cadencen-sdhci Steffen Trumtrar

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