* [PATCH v2 00/30] mci: imx-esdhc: add HS200 support
@ 2025-05-07 8:21 Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 01/30] mci: sdhci: fix SDHCI_TRNS_AUTO_CMD12 definition Ahmad Fatoum
` (30 more replies)
0 siblings, 31 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox
On my i.MX8MP board this increases sequential read nearly from
72 MiB/s to 131 MiB/s.
I also got HS400ES running, but it gives me occasional CRC errors, so
this series only concerns itself with HS200 for now.
v1 -> v2:
- use correct speed comparison in commit message. v1 had KASAN
and DMA_API_DEBUG enabled..
- define and use new sdhci_compute_timeout helper (Sascha)
- remove superfluous comment about clearing bits (Sascha)
- always populate delay settings in boarddata (Sascha)
- reduce number of Linux SDHCI quirks mentioned in commit
message to 51 (Sascha)
Ahmad Fatoum (30):
mci: sdhci: fix SDHCI_TRNS_AUTO_CMD12 definition
mci: move most recent I/O settings into mci_host::ios
mci: use struct mci_host::ios inside mci_set_ios
mci: tuning: fix fallback to DDR52
mci: sdhci: unmap DMA buffers on timeout
mci: add MMC_CAP_UHS constants
mci: rename MMC_CAP_MMC_x_yV_DDR to MMC_CAP_x_yV_DDR as in Linux
mci: compare host and card caps for supported speeds
mci: print HS200 capabilities in devinfo
mci: respect no-1-8-v OF property
mci: sdhci: add support for struct mci_data::timeout_ns
mci: imx-esdhc: use unsigned types where appropriate
mci: imx-esdhc: implement esdhc_poll using sdhci_read32_poll_timeout
mci: imx-esdhc: drop one extra read of SDHCI_INT_STATUS
mci: sdhci: add cmd parameter to sdhci_transfer_*
mci: arasan: introduce mmc_op_tuning helper
mci: imx-esdhc: flesh out register description
mci: imx-esdhc: add support for delay/tuning properties in DT
mci: add mci_set_timing helper
mci: imx-esdhc: add support for setting drive strength
mci: sdhci: move SDHCI_MAKE_BLKSZ definition to header
mci: imx-esdhc: select different pinctrl state depending on frequency
mci: core: retry MMC_CMD_SET_BLOCKLEN up to 4 times
mci: imx-esdhc: don't reconfigure clock unless required
mci: sdhci: fix sdhci_transfer_data MMC_SEND_TUNING compatibility
mci: core: implement mmc_send_tuning
mci: imx-esdhc: set burst_length_enable
mci: imx-esdhc: fixup quirks in standard SDHCI registers
mci: sdhci: support Linux SDHCI_QUIRK2_BROKEN_HS200 flag
mci: imx-esdhc: implement HS200 support
drivers/mci/am654-sdhci.c | 15 +-
drivers/mci/arasan-sdhci.c | 26 ++-
drivers/mci/atmel-sdhci-common.c | 2 +-
drivers/mci/atmel_mci.c | 4 +-
drivers/mci/dwcmshc-sdhci.c | 8 +-
drivers/mci/imx-esdhc-common.c | 334 +++++++++++++++++++++-----
drivers/mci/imx-esdhc.c | 335 +++++++++++++++++++++++++--
drivers/mci/imx-esdhc.h | 96 +++++++-
drivers/mci/mci-bcm2835.c | 2 +-
drivers/mci/mci-core.c | 331 +++++++++++++++++++-------
drivers/mci/mmci.c | 18 +-
drivers/mci/rockchip-dwcmshc-sdhci.c | 11 +-
drivers/mci/sdhci.c | 151 +++++++++---
drivers/mci/sdhci.h | 49 +++-
drivers/mci/stm32_sdmmc2.c | 16 +-
include/mci.h | 47 +++-
16 files changed, 1187 insertions(+), 258 deletions(-)
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 01/30] mci: sdhci: fix SDHCI_TRNS_AUTO_CMD12 definition
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 02/30] mci: move most recent I/O settings into mci_host::ios Ahmad Fatoum
` (29 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
BIT(3) in the SDHCI_TRANSFER_MODE register is not
SDHCI_TRNS_AUTO_CMD12, but SDHCI_TRNS_AUTO_CMD23.
Fix this in preparation for later use of SDHCI_TRNS_AUTO_CMD23.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/sdhci.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 2a8456545d70..841e39af05ee 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -28,7 +28,8 @@
#define SDHCI_TRANSFER_MODE 0x0c
#define SDHCI_MULTIPLE_BLOCKS BIT(5)
#define SDHCI_DATA_TO_HOST BIT(4)
-#define SDHCI_TRNS_AUTO_CMD12 BIT(3)
+#define SDHCI_TRNS_AUTO_CMD23 BIT(3)
+#define SDHCI_TRNS_AUTO_CMD12 BIT(2)
#define SDHCI_BLOCK_COUNT_EN BIT(1)
#define SDHCI_DMA_EN BIT(0)
#define SDHCI_COMMAND 0x0e
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 02/30] mci: move most recent I/O settings into mci_host::ios
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 01/30] mci: sdhci: fix SDHCI_TRNS_AUTO_CMD12 definition Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 03/30] mci: use struct mci_host::ios inside mci_set_ios Ahmad Fatoum
` (28 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We already keep around mci_host::{clock,bus_width,timing}, which hold
the last configured I/O settings.
Before duplicating yet another member in struct mci_host, let's do as
Linux does and embed the active struct mmc_ios directly directly into
the MCI object.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/arasan-sdhci.c | 14 ++++----
drivers/mci/atmel_mci.c | 4 +--
drivers/mci/mci-core.c | 48 ++++++++++++++--------------
drivers/mci/mmci.c | 18 +++++------
drivers/mci/rockchip-dwcmshc-sdhci.c | 2 +-
drivers/mci/sdhci.c | 10 +++---
drivers/mci/stm32_sdmmc2.c | 12 +++----
include/mci.h | 10 +++---
8 files changed, 58 insertions(+), 60 deletions(-)
diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index e987ff654862..0ec4cb57ab76 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -155,7 +155,7 @@ static int arasan_zynqmp_execute_tuning(struct mci_host *mci, u32 opcode)
int err;
/* ZynqMP SD controller does not perform auto tuning in DDR50 mode */
- if (mci->timing == MMC_TIMING_UHS_DDR50)
+ if (mci->ios.timing == MMC_TIMING_UHS_DDR50)
return 0;
arasan_zynqmp_dll_reset(host, device_id);
@@ -205,9 +205,9 @@ static void arasan_sdhci_set_clock(struct mci_host *mci, unsigned int clock)
}
clk_set_phase(clk_data->sampleclk,
- clk_data->clk_phase_in[mci->mci->host->timing]);
+ clk_data->clk_phase_in[mci->mci->host->ios.timing]);
clk_set_phase(clk_data->sdcardclk,
- clk_data->clk_phase_out[mci->mci->host->timing]);
+ clk_data->clk_phase_out[mci->mci->host->ios.timing]);
sdhci_set_clock(&host->sdhci, clock, mci->f_max);
}
@@ -312,9 +312,9 @@ static void sdhci_arasan_set_clk_delays(struct sdhci *host)
struct sdhci_arasan_clk_data *clk_data = &arasan_sdhci->clk_data;
clk_set_phase(clk_data->sampleclk,
- clk_data->clk_phase_in[mci->timing]);
+ clk_data->clk_phase_in[mci->ios.timing]);
clk_set_phase(clk_data->sdcardclk,
- clk_data->clk_phase_out[mci->timing]);
+ clk_data->clk_phase_out[mci->ios.timing]);
}
static void arasan_dt_read_clk_phase(struct device *dev,
@@ -372,7 +372,7 @@ static int arasan_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees)
/* Assert DLL Reset */
zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT);
- switch (host->timing) {
+ switch (host->ios.timing) {
case MMC_TIMING_MMC_HS:
case MMC_TIMING_SD_HS:
case MMC_TIMING_UHS_DDR50:
@@ -441,7 +441,7 @@ static int arasan_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
if (sdhci_arasan->sdhci.version < SDHCI_SPEC_300)
return 0;
- switch (host->timing) {
+ switch (host->ios.timing) {
case MMC_TIMING_MMC_HS:
case MMC_TIMING_SD_HS:
case MMC_TIMING_UHS_DDR50:
diff --git a/drivers/mci/atmel_mci.c b/drivers/mci/atmel_mci.c
index 18d623f20823..1012feb6c226 100644
--- a/drivers/mci/atmel_mci.c
+++ b/drivers/mci/atmel_mci.c
@@ -35,9 +35,9 @@ static void atmci_info(struct device *mci_dev)
{
struct atmel_mci *host = mci_dev->priv;
- printf(" Bus data width: %d bit\n", host->mci.bus_width);
+ printf(" Bus data width: %d bit\n", host->mci.ios.bus_width);
- printf(" Bus frequency: %u Hz\n", host->mci.clock);
+ printf(" Bus frequency: %u Hz\n", host->mci.ios.clock);
printf(" Frequency limits: ");
if (host->mci.f_min == 0)
printf("no lower limit ");
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index abcda497646d..262535d63006 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -121,7 +121,7 @@ static int mci_set_blocklen(struct mci *mci, unsigned len)
{
struct mci_cmd cmd = {};
- if (mci->host->timing == MMC_TIMING_MMC_DDR52)
+ if (mci->host->ios.timing == MMC_TIMING_MMC_DDR52)
return 0;
mci_setup_cmd(&cmd, MMC_CMD_SET_BLOCKLEN, len, MMC_RSP_R1);
@@ -1032,14 +1032,14 @@ static void mci_set_ios(struct mci *mci)
{
struct mci_host *host = mci->host;
struct mci_ios ios = {
- .bus_width = host->bus_width,
- .clock = host->clock,
- .timing = host->timing,
+ .bus_width = host->ios.bus_width,
+ .clock = host->ios.clock,
+ .timing = host->ios.timing,
};
host->ops.set_ios(host, &ios);
- host->actual_clock = host->clock;
+ host->actual_clock = host->ios.clock;
}
/**
@@ -1058,7 +1058,7 @@ static void mci_set_clock(struct mci *mci, unsigned clock)
if (clock < host->f_min)
clock = host->f_min;
- host->clock = clock; /* the new target frequency */
+ host->ios.clock = clock; /* the new target frequency */
mci_set_ios(mci);
}
@@ -1071,7 +1071,7 @@ static void mci_set_bus_width(struct mci *mci, enum mci_bus_width width)
{
struct mci_host *host = mci->host;
- host->bus_width = width; /* the new target bus width */
+ host->ios.bus_width = width; /* the new target bus width */
mci_set_ios(mci);
}
@@ -1432,7 +1432,7 @@ static int mci_startup_sd(struct mci *mci)
}
if (mci->tran_speed > 25000000)
- mci->host->timing = MMC_TIMING_SD_HS;
+ mci->host->ios.timing = MMC_TIMING_SD_HS;
mci_set_clock(mci, mci->tran_speed);
@@ -1471,7 +1471,7 @@ static int mci_mmc_try_bus_width(struct mci *mci, enum mci_bus_width bus_width,
if (err < 0)
goto out;
- mci->host->timing = timing;
+ mci->host->ios.timing = timing;
mci_set_bus_width(mci, bus_width);
switch (bus_width) {
@@ -1526,7 +1526,7 @@ static int mci_mmc_select_bus_width(struct mci *mci)
* 4bit transfer mode. On success set the corresponding
* bus width on the host.
*/
- ret = mci_mmc_try_bus_width(mci, bus_widths[idx], host->timing);
+ ret = mci_mmc_try_bus_width(mci, bus_widths[idx], host->ios.timing);
if (ret > 0)
break;
}
@@ -1548,9 +1548,9 @@ static int mci_mmc_select_hs_ddr(struct mci *mci)
if (!(mci_caps(mci) & (MMC_CAP_MMC_1_8V_DDR | MMC_CAP_MMC_3_3V_DDR)))
return 0;
- ret = mci_mmc_try_bus_width(mci, host->bus_width, MMC_TIMING_MMC_DDR52);
+ ret = mci_mmc_try_bus_width(mci, host->ios.bus_width, MMC_TIMING_MMC_DDR52);
if (ret < 0)
- return mci_mmc_try_bus_width(mci, host->bus_width, MMC_TIMING_MMC_HS);
+ return mci_mmc_try_bus_width(mci, host->ios.bus_width, MMC_TIMING_MMC_HS);
/* Block length is fixed to 512 bytes while in DDR mode */
mci->read_bl_len = SECTOR_SIZE;
@@ -1666,10 +1666,10 @@ static int mmc_select_hs200(struct mci *mci)
* NB: We can't move to full (HS200) speeds until after we've
* successfully switched over.
*/
- old_timing = mci->host->timing;
- old_clock = mci->host->clock;
+ old_timing = mci->host->ios.timing;
+ old_clock = mci->host->ios.clock;
- mci->host->timing = MMC_TIMING_MMC_HS200;
+ mci->host->ios.timing = MMC_TIMING_MMC_HS200;
mci_set_ios(mci);
mci_set_clock(mci, mci->host->hs_max_dtr);
@@ -1680,8 +1680,8 @@ static int mmc_select_hs200(struct mci *mci)
* it is a switch error.
*/
if (err == -EBADMSG) {
- mci->host->clock = old_clock;
- mci->host->timing = old_timing;
+ mci->host->ios.clock = old_clock;
+ mci->host->ios.timing = old_timing;
mci_set_ios(mci);
}
}
@@ -1759,7 +1759,7 @@ static int mci_startup_mmc(struct mci *mci)
else
mci->tran_speed = 26000000;
- host->timing = MMC_TIMING_MMC_HS;
+ host->ios.timing = MMC_TIMING_MMC_HS;
}
if (IS_ENABLED(CONFIG_MCI_TUNING)) {
@@ -1774,7 +1774,7 @@ static int mci_startup_mmc(struct mci *mci)
ret = mmc_hs200_tuning(mci);
if (ret) {
- host->timing = MMC_TIMING_MMC_HS;
+ host->ios.timing = MMC_TIMING_MMC_HS;
mci_switch(mci, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
}
}
@@ -2448,17 +2448,17 @@ static void mci_info(struct device *dev)
}
printf("Host information:\n");
- printf(" current clock: %d\n", host->clock);
+ printf(" current clock: %d\n", host->ios.clock);
- if (host->bus_width == MMC_BUS_WIDTH_8)
+ if (host->ios.bus_width == MMC_BUS_WIDTH_8)
bw = 8;
- else if (host->bus_width == MMC_BUS_WIDTH_4)
+ else if (host->ios.bus_width == MMC_BUS_WIDTH_4)
bw = 4;
else
bw = 1;
printf(" current buswidth: %d\n", bw);
- printf(" current timing: %s\n", mci_timing_tostr(host->timing));
+ printf(" current timing: %s\n", mci_timing_tostr(host->ios.timing));
mci_print_caps(host->host_caps);
printf("Card information:\n");
@@ -2845,7 +2845,7 @@ static int mci_card_probe(struct mci *mci)
on_error:
if (rc != 0) {
- host->clock = 0; /* disable the MCI clock */
+ host->ios.clock = 0; /* disable the MCI clock */
mci_set_ios(mci);
regulator_disable(host->supply);
mci->nr_parts = 0;
diff --git a/drivers/mci/mmci.c b/drivers/mci/mmci.c
index c811d3980f98..1a70776bb125 100644
--- a/drivers/mci/mmci.c
+++ b/drivers/mci/mmci.c
@@ -472,35 +472,35 @@ static void mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
sdi_clkcr = mmci_readl(host, MMCICLOCK);
/* Ramp up the clock rate */
- if (mci->clock) {
+ if (mci->ios.clock) {
u32 clkdiv = 0;
u32 tmp_clock;
dev_dbg(host->hw_dev, "setting clock and bus width in the host:");
- if (mci->clock >= mci->f_max) {
+ if (mci->ios.clock >= mci->f_max) {
clkdiv = 0;
- mci->clock = mci->f_max;
+ mci->ios.clock = mci->f_max;
} else {
- clkdiv = (host->mclk / mci->clock) - 2;
+ clkdiv = (host->mclk / mci->ios.clock) - 2;
}
tmp_clock = host->mclk / (clkdiv + 2);
- while (tmp_clock > mci->clock) {
+ while (tmp_clock > mci->ios.clock) {
clkdiv++;
tmp_clock = host->mclk / (clkdiv + 2);
}
if (clkdiv > MCI_CLK_CLKDIV_MASK)
clkdiv = MCI_CLK_CLKDIV_MASK;
tmp_clock = host->mclk / (clkdiv + 2);
- mci->clock = tmp_clock;
+ mci->ios.clock = tmp_clock;
sdi_clkcr &= ~(MCI_CLK_CLKDIV_MASK);
sdi_clkcr |= clkdiv;
}
/* Set the bus width */
- if (mci->bus_width) {
+ if (mci->ios.bus_width) {
u32 buswidth = 0;
- switch (mci->bus_width) {
+ switch (mci->ios.bus_width) {
case MMC_BUS_WIDTH_1:
buswidth |= MCI_1BIT_BUS;
break;
@@ -511,7 +511,7 @@ static void mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
buswidth |= MCI_ST_8BIT_BUS;
break;
default:
- dev_err(host->hw_dev, "Invalid bus width (%d)\n", mci->bus_width);
+ dev_err(host->hw_dev, "Invalid bus width (%d)\n", mci->ios.bus_width);
break;
}
sdi_clkcr &= ~(MCI_xBIT_BUS_MASK);
diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c
index ff4ba3125873..6f3795465765 100644
--- a/drivers/mci/rockchip-dwcmshc-sdhci.c
+++ b/drivers/mci/rockchip-dwcmshc-sdhci.c
@@ -130,7 +130,7 @@ static void rk_sdhci_set_clock(struct rk_sdhci_host *host, unsigned int clock)
u32 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, extra;
int err;
- host->mci.clock = 0;
+ host->mci.ios.clock = 0;
/* DO NOT TOUCH THIS SETTING */
extra = DWCMSHC_EMMC_DLL_DLYENA |
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 2c12f00ab967..f54cc6d58b2c 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -87,7 +87,7 @@ static int sdhci_send_tuning(struct sdhci *host, u32 opcode)
* to 64 here.
*/
if (cmd.cmdidx == MMC_SEND_TUNING_BLOCK_HS200 &&
- host->mci->bus_width == MMC_BUS_WIDTH_8) {
+ host->mci->ios.bus_width == MMC_BUS_WIDTH_8) {
sdhci_write16(host, SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, 128));
} else {
sdhci_write16(host, SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, 64));
@@ -196,7 +196,7 @@ int sdhci_execute_tuning(struct sdhci *sdhci, u32 opcode)
* If the Host Controller supports the HS200 mode then the
* tuning function has to be executed.
*/
- switch (host->timing) {
+ switch (host->ios.timing) {
/* HS400 tuning is done in HS200 mode */
case MMC_TIMING_MMC_HS400:
err = -EINVAL;
@@ -859,9 +859,9 @@ void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_
BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
- host->mci->clock = 0;
+ host->mci->ios.clock = 0;
- sdhci_set_uhs_signaling(host, host->mci->timing);
+ sdhci_set_uhs_signaling(host, host->mci->ios.timing);
sdhci_wait_idle_data(host, NULL);
@@ -870,7 +870,7 @@ void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_
if (clock == 0)
return;
- clk = sdhci_calc_clk(host, clock, &host->mci->clock, input_clock);
+ clk = sdhci_calc_clk(host, clock, &host->mci->ios.clock, input_clock);
sdhci_enable_clk(host, clk);
}
diff --git a/drivers/mci/stm32_sdmmc2.c b/drivers/mci/stm32_sdmmc2.c
index 30745ea7c6c0..b517ab7964e2 100644
--- a/drivers/mci/stm32_sdmmc2.c
+++ b/drivers/mci/stm32_sdmmc2.c
@@ -254,7 +254,7 @@ static void stm32_sdmmc2_pwron(struct stm32_sdmmc2_priv *priv)
priv->base + SDMMC_POWER);
/* during the first 74 SDMMC_CK cycles the SDMMC is still disabled. */
- udelay(DIV_ROUND_UP(74 * USEC_PER_SEC, priv->mci.clock));
+ udelay(DIV_ROUND_UP(74 * USEC_PER_SEC, priv->mci.ios.clock));
}
static dma_addr_t stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv,
@@ -539,17 +539,17 @@ static int stm32_sdmmc2_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
static void stm32_sdmmc2_set_ios(struct mci_host *mci, struct mci_ios *ios)
{
struct stm32_sdmmc2_priv *priv = to_mci_host(mci);
- u32 desired = mci->clock;
+ u32 desired = mci->ios.clock;
u32 sys_clock = clk_get_rate(priv->clk);
u32 clk = 0, ddr = 0;
dev_dbg(priv->dev, "%s: bus_width = %d, clock = %d\n", __func__,
- mci->bus_width, mci->clock);
+ mci->ios.bus_width, mci->ios.clock);
if (mci_timing_is_ddr(ios->timing))
ddr = SDMMC_CLKCR_DDR;
- if (mci->clock)
+ if (mci->ios.clock)
stm32_sdmmc2_pwron(priv);
else
stm32_sdmmc2_pwrcycle(priv);
@@ -570,9 +570,9 @@ static void stm32_sdmmc2_set_ios(struct mci_host *mci, struct mci_ios *ios)
clk |= ddr;
- if (mci->bus_width == MMC_BUS_WIDTH_4)
+ if (mci->ios.bus_width == MMC_BUS_WIDTH_4)
clk |= SDMMC_CLKCR_WIDBUS_4;
- if (mci->bus_width == MMC_BUS_WIDTH_8)
+ if (mci->ios.bus_width == MMC_BUS_WIDTH_8)
clk |= SDMMC_CLKCR_WIDBUS_8;
writel(clk | priv->clk_reg_msk | SDMMC_CLKCR_HWFC_EN,
diff --git a/include/mci.h b/include/mci.h
index 10bba878a8f9..7ee2e4faa90c 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -606,10 +606,8 @@ struct mci_host {
#define MMC_CAP2_CRYPTO 0
unsigned f_min; /**< host interface lower limit */
unsigned f_max; /**< host interface upper limit */
- unsigned clock; /**< Current clock used to talk to the card */
unsigned actual_clock;
- enum mci_bus_width bus_width; /**< used data bus width to the card */
- enum mci_timing timing; /**< used timing specification to the card */
+ struct mci_ios ios; /* current io bus settings */
unsigned hs_max_dtr;
unsigned hs200_max_dtr;
unsigned max_req_size;
@@ -739,8 +737,8 @@ static inline struct mci *mci_get_device_by_devpath(const char *devpath)
static inline int mmc_card_hs(struct mci *mci)
{
- return mci->host->timing == MMC_TIMING_SD_HS ||
- mci->host->timing == MMC_TIMING_MMC_HS;
+ return mci->host->ios.timing == MMC_TIMING_SD_HS ||
+ mci->host->ios.timing == MMC_TIMING_MMC_HS;
}
/*
@@ -760,7 +758,7 @@ int mci_rpmb_route_frames(struct mci *mci, void *req, unsigned long reqlen,
static inline bool mmc_card_hs200(struct mci *mci)
{
- return mci->host->timing == MMC_TIMING_MMC_HS200;
+ return mci->host->ios.timing == MMC_TIMING_MMC_HS200;
}
#endif /* _MCI_H_ */
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 03/30] mci: use struct mci_host::ios inside mci_set_ios
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 01/30] mci: sdhci: fix SDHCI_TRNS_AUTO_CMD12 definition Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 02/30] mci: move most recent I/O settings into mci_host::ios Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 04/30] mci: tuning: fix fallback to DDR52 Ahmad Fatoum
` (27 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Now that we have a struct mci_ios inside struct mci_host, let's make use
of it directly in mci_set_ios instead of copying out the struct members
one by one.
While at it, let's also add a debug print describing the configuration
being applied.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-core.c | 48 +++++++++++++++++++++---------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 262535d63006..7b33b4c8df88 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1024,6 +1024,24 @@ static int sd_change_freq(struct mci *mci)
return 0;
}
+static const char *mci_timing_tostr(unsigned timing)
+{
+ switch (timing) {
+ case MMC_TIMING_LEGACY:
+ return "legacy";
+ case MMC_TIMING_MMC_HS:
+ return "MMC HS";
+ case MMC_TIMING_SD_HS:
+ return "SD HS";
+ case MMC_TIMING_MMC_DDR52:
+ return "MMC DDR52";
+ case MMC_TIMING_MMC_HS200:
+ return "HS200";
+ default:
+ return "unknown"; /* shouldn't happen */
+ }
+}
+
/**
* Setup host's interface bus width and transfer frequency
* @param mci MCI instance
@@ -1031,13 +1049,13 @@ static int sd_change_freq(struct mci *mci)
static void mci_set_ios(struct mci *mci)
{
struct mci_host *host = mci->host;
- struct mci_ios ios = {
- .bus_width = host->ios.bus_width,
- .clock = host->ios.clock,
- .timing = host->ios.timing,
- };
+ struct mci_ios *ios = &host->ios;
- host->ops.set_ios(host, &ios);
+ dev_dbg(&mci->dev, "clock %u.%uMHz width %u timing %s\n",
+ ios->clock / 1000000, ios->clock % 1000000,
+ 1 << ios->bus_width, mci_timing_tostr(ios->timing));
+
+ host->ops.set_ios(host, ios);
host->actual_clock = host->ios.clock;
}
@@ -2313,24 +2331,6 @@ static int mci_sd_read(struct block_device *blk, void *buffer, sector_t block,
/* ------------------ attach to the device API --------------------------- */
-static const char *mci_timing_tostr(unsigned timing)
-{
- switch (timing) {
- case MMC_TIMING_LEGACY:
- return "legacy";
- case MMC_TIMING_MMC_HS:
- return "MMC HS";
- case MMC_TIMING_SD_HS:
- return "SD HS";
- case MMC_TIMING_MMC_DDR52:
- return "MMC DDR52";
- case MMC_TIMING_MMC_HS200:
- return "HS200";
- default:
- return "unknown"; /* shouldn't happen */
- }
-}
-
static void mci_print_caps(unsigned caps)
{
printf(" capabilities: %s%s%s%s%s%s%s%s\n",
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 04/30] mci: tuning: fix fallback to DDR52
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (2 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 03/30] mci: use struct mci_host::ios inside mci_set_ios Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 05/30] mci: sdhci: unmap DMA buffers on timeout Ahmad Fatoum
` (26 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
When CONFIG_MCI_TUNING is enabled, but a card mmc_card_hs200 return
false, the fallback currently puts the card into high speed mode instead
of DDR52, which would've been the next best thing.
Rework the code to fix this.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-core.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 7b33b4c8df88..5a3bb9d1ad13 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1781,34 +1781,35 @@ static int mci_startup_mmc(struct mci *mci)
}
if (IS_ENABLED(CONFIG_MCI_TUNING)) {
- /*
- * Select timing interface
- */
+ dev_dbg(&mci->dev, "select timing %s\n", mci_timing_tostr(host->ios.timing));
+
ret = mmc_select_timing(mci);
if (ret)
return ret;
- if (mmc_card_hs200(mci))
+ if (mmc_card_hs200(mci)) {
ret = mmc_hs200_tuning(mci);
+ if (!ret) {
+ dev_dbg(&mci->dev, "HS200 tuning succeeded\n");
+ return 0;
+ }
+
+ dev_dbg(&mci->dev, "HS200 tuning failed, falling back to HS\n");
- if (ret) {
host->ios.timing = MMC_TIMING_MMC_HS;
mci_switch(mci, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
}
}
- if (ret || !IS_ENABLED(CONFIG_MCI_TUNING)) {
- mci_set_clock(mci, mci->tran_speed);
+ mci_set_clock(mci, mci->tran_speed);
- /* find out maximum bus width and then try DDR if supported */
- ret = mci_mmc_select_bus_width(mci);
- if (ret > MMC_BUS_WIDTH_1 && mci->tran_speed == 52000000)
- ret = mci_mmc_select_hs_ddr(mci);
+ /* find out maximum bus width and then try DDR if supported */
+ ret = mci_mmc_select_bus_width(mci);
+ if (ret > MMC_BUS_WIDTH_1 && mci->tran_speed == 52000000)
+ ret = mci_mmc_select_hs_ddr(mci);
- if (ret < 0) {
- dev_warn(&mci->dev, "Changing MMC bus width failed: %d\n", ret);
- }
- }
+ if (ret < 0)
+ dev_warn(&mci->dev, "Changing MMC bus width failed: %d\n", ret);
return ret >= MMC_BUS_WIDTH_1 ? 0 : ret;
}
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 05/30] mci: sdhci: unmap DMA buffers on timeout
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (3 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 04/30] mci: tuning: fix fallback to DDR52 Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 06/30] mci: add MMC_CAP_UHS constants Ahmad Fatoum
` (25 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We map DMA buffers during sdhci_setup_data_dma and unmap them inside
sdhci_transfer_data_dma, but if an error happens between these two
functions, DMA buffers are never unmapped.
Fix this to silence CONFIG_DMA_API_DEBUG observed during a timeout on an
i.MX8M.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/am654-sdhci.c | 4 +++-
drivers/mci/arasan-sdhci.c | 4 +++-
drivers/mci/dwcmshc-sdhci.c | 4 +++-
drivers/mci/imx-esdhc-common.c | 19 +++++++++++++------
drivers/mci/rockchip-dwcmshc-sdhci.c | 4 +++-
drivers/mci/sdhci.c | 22 ++++++++++++++++++----
drivers/mci/sdhci.h | 1 +
7 files changed, 44 insertions(+), 14 deletions(-)
diff --git a/drivers/mci/am654-sdhci.c b/drivers/mci/am654-sdhci.c
index 2c1fa5d80451..a378e3d53c91 100644
--- a/drivers/mci/am654-sdhci.c
+++ b/drivers/mci/am654-sdhci.c
@@ -488,8 +488,10 @@ static int am654_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
ret = sdhci_wait_for_done(&host->sdhci, SDHCI_INT_CMD_COMPLETE);
- if (ret)
+ if (ret) {
+ sdhci_teardown_data(&host->sdhci, data, dma);
goto error;
+ }
sdhci_read_response(&host->sdhci, cmd);
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 0ec4cb57ab76..f98f7eb3d10b 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -284,8 +284,10 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
mask = SDHCI_INT_DATA_AVAIL;
ret = sdhci_wait_for_done(&host->sdhci, mask);
- if (ret)
+ if (ret) {
+ sdhci_teardown_data(&host->sdhci, data, dma);
goto error;
+ }
sdhci_read_response(&host->sdhci, cmd);
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
diff --git a/drivers/mci/dwcmshc-sdhci.c b/drivers/mci/dwcmshc-sdhci.c
index 8398889a703c..f6d559e393d4 100644
--- a/drivers/mci/dwcmshc-sdhci.c
+++ b/drivers/mci/dwcmshc-sdhci.c
@@ -153,8 +153,10 @@ static int do_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
ret = sdhci_wait_for_done(&host->sdhci, SDHCI_INT_CMD_COMPLETE);
- if (ret)
+ if (ret) {
+ sdhci_teardown_data(&host->sdhci, data, dma);
goto error;
+ }
sdhci_read_response(&host->sdhci, cmd);
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index a51e38734cb3..7673220fe8d4 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -164,16 +164,20 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
100 * MSECOND);
if (ret) {
dev_dbg(host->dev, "timeout 1\n");
- return -ETIMEDOUT;
+ goto undo_setup_data;
}
irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
- if (irqstat & CMD_ERR)
- return -EIO;
+ if (irqstat & CMD_ERR) {
+ ret = -EIO;
+ goto undo_setup_data;
+ }
- if (irqstat & SDHCI_INT_TIMEOUT)
- return -ETIMEDOUT;
+ if (irqstat & SDHCI_INT_TIMEOUT) {
+ ret = -ETIMEDOUT;
+ goto undo_setup_data;
+ }
/* Workaround for ESDHC errata ENGcm03648 / ENGcm12360 */
if (!data && (cmd->resp_type & MMC_RSP_BUSY)) {
@@ -186,7 +190,7 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
2500 * MSECOND);
if (ret) {
dev_err(host->dev, "timeout PRSSTAT_DAT0\n");
- return -ETIMEDOUT;
+ goto undo_setup_data;
}
}
@@ -223,5 +227,8 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
}
return 0;
+undo_setup_data:
+ sdhci_teardown_data(&host->sdhci, data, dma);
+ return ret;
}
diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c
index 6f3795465765..a7da64f4d7db 100644
--- a/drivers/mci/rockchip-dwcmshc-sdhci.c
+++ b/drivers/mci/rockchip-dwcmshc-sdhci.c
@@ -269,8 +269,10 @@ static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
ret = sdhci_wait_for_done(&host->sdhci, SDHCI_INT_CMD_COMPLETE);
- if (ret)
+ if (ret) {
+ sdhci_teardown_data(&host->sdhci, data, dma);
goto error;
+ }
sdhci_read_response(&host->sdhci, cmd);
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index f54cc6d58b2c..d0caee22f2f7 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -507,6 +507,23 @@ void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data,
sdhci_set_sdma_addr(sdhci, *dma);
}
+void sdhci_teardown_data(struct sdhci *sdhci,
+ struct mci_data *data, dma_addr_t dma)
+{
+ struct device *dev = sdhci_dev(sdhci);
+ unsigned nbytes;
+
+ if (IN_PBL || !data || dma_mapping_error(dev, dma))
+ return;
+
+ nbytes = data->blocks * data->blocksize;
+
+ if (data->flags & MMC_DATA_READ)
+ dma_unmap_single(dev, dma, nbytes, DMA_FROM_DEVICE);
+ else
+ dma_unmap_single(dev, dma, nbytes, DMA_TO_DEVICE);
+}
+
int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
dma_addr_t dma)
{
@@ -572,10 +589,7 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
ret = 0;
out:
- if (data->flags & MMC_DATA_READ)
- dma_unmap_single(dev, dma, nbytes, DMA_FROM_DEVICE);
- else
- dma_unmap_single(dev, dma, nbytes, DMA_TO_DEVICE);
+ sdhci_teardown_data(sdhci, data, dma);
return ret;
}
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 841e39af05ee..d3b681153134 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -323,6 +323,7 @@ void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd,
u32 *xfer);
void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data);
void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data, dma_addr_t *dma);
+void sdhci_teardown_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma);
int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma);
int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data);
int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 06/30] mci: add MMC_CAP_UHS constants
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (4 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 05/30] mci: sdhci: unmap DMA buffers on timeout Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 07/30] mci: rename MMC_CAP_MMC_x_yV_DDR to MMC_CAP_x_yV_DDR as in Linux Ahmad Fatoum
` (24 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We currently support higher speed modes only for eMMC, not SD, but to
simplify porting drivers, let's add the capability bits into the header.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/am654-sdhci.c | 6 ------
include/mci.h | 8 ++++++++
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/mci/am654-sdhci.c b/drivers/mci/am654-sdhci.c
index a378e3d53c91..20dd03b83a9a 100644
--- a/drivers/mci/am654-sdhci.c
+++ b/drivers/mci/am654-sdhci.c
@@ -83,12 +83,6 @@
#define AM654_SDHCI_MIN_FREQ 400000
#define CLOCK_TOO_SLOW_HZ 50000000
-#define MMC_CAP_UHS_SDR104 0
-#define MMC_CAP_UHS_SDR12 0
-#define MMC_CAP_UHS_DDR50 0
-#define MMC_CAP_UHS_SDR25 0
-#define MMC_CAP_UHS_SDR50 0
-
struct timing_data {
const char *otap_binding;
const char *itap_binding;
diff --git a/include/mci.h b/include/mci.h
index 7ee2e4faa90c..bb168ca2225f 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -58,6 +58,14 @@
#define MMC_CAP_MMC_1_2V_DDR (1 << 9) /* Host supports eMMC DDR 1.2V */
#define MMC_CAP_DDR (MMC_CAP_MMC_3_3V_DDR | MMC_CAP_MMC_1_8V_DDR | \
MMC_CAP_MMC_1_2V_DDR)
+#define MMC_CAP_UHS_SDR12 (1 << 16) /* Host supports UHS SDR12 mode */
+#define MMC_CAP_UHS_SDR25 (1 << 17) /* Host supports UHS SDR25 mode */
+#define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */
+#define MMC_CAP_UHS_SDR104 (1 << 19) /* Host supports UHS SDR104 mode */
+#define MMC_CAP_UHS_DDR50 (1 << 20) /* Host supports UHS DDR50 mode */
+#define MMC_CAP_UHS (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | \
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | \
+ MMC_CAP_UHS_DDR50)
/* Mask of all caps for bus width */
#define MMC_CAP_BIT_DATA_MASK (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 07/30] mci: rename MMC_CAP_MMC_x_yV_DDR to MMC_CAP_x_yV_DDR as in Linux
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (5 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 06/30] mci: add MMC_CAP_UHS constants Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 08/30] mci: compare host and card caps for supported speeds Ahmad Fatoum
` (23 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Linux names these parameters without listing MMC twice in the macro.
Follow suit in barebox to make porting a tiny bit easier.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc.c | 2 +-
drivers/mci/mci-core.c | 10 +++++-----
drivers/mci/stm32_sdmmc2.c | 4 ++--
include/mci.h | 10 +++++-----
4 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index ebc7ed539da9..923dae9cf3b0 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -324,7 +324,7 @@ static int fsl_esdhc_probe(struct device *dev)
goto err_clk_disable;
if (esdhc_is_usdhc(host) || esdhc_is_layerscape(host))
- mci->host_caps |= MMC_CAP_MMC_3_3V_DDR | MMC_CAP_MMC_1_8V_DDR;
+ mci->host_caps |= MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR;
rate = clk_get_rate(host->clk);
host->mci.f_min = rate >> 12;
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 5a3bb9d1ad13..819a059e6468 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -791,7 +791,7 @@ static int mmc_change_freq(struct mci *mci)
mci->card_caps |= MMC_CAP_MMC_HIGHSPEED_52MHZ;
if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
- mci->card_caps |= MMC_CAP_MMC_3_3V_DDR | MMC_CAP_MMC_1_8V_DDR;
+ mci->card_caps |= MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR;
}
if (IS_ENABLED(CONFIG_MCI_MMC_BOOT_PARTITIONS) &&
@@ -1563,7 +1563,7 @@ static int mci_mmc_select_hs_ddr(struct mci *mci)
* higher speed modes that require voltage switching like HS200/HS400,
* let's just check for either bit.
*/
- if (!(mci_caps(mci) & (MMC_CAP_MMC_1_8V_DDR | MMC_CAP_MMC_3_3V_DDR)))
+ if (!(mci_caps(mci) & (MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR)))
return 0;
ret = mci_mmc_try_bus_width(mci, host->ios.bus_width, MMC_TIMING_MMC_DDR52);
@@ -2340,9 +2340,9 @@ static void mci_print_caps(unsigned caps)
caps & MMC_CAP_SD_HIGHSPEED ? "sd-hs " : "",
caps & MMC_CAP_MMC_HIGHSPEED ? "mmc-hs " : "",
caps & MMC_CAP_MMC_HIGHSPEED_52MHZ ? "mmc-52MHz " : "",
- caps & MMC_CAP_MMC_3_3V_DDR ? "ddr-3.3v " : "",
- caps & MMC_CAP_MMC_1_8V_DDR ? "ddr-1.8v " : "",
- caps & MMC_CAP_MMC_1_2V_DDR ? "ddr-1.2v " : "");
+ caps & MMC_CAP_3_3V_DDR ? "ddr-3.3v " : "",
+ caps & MMC_CAP_1_8V_DDR ? "ddr-1.8v " : "",
+ caps & MMC_CAP_1_2V_DDR ? "ddr-1.2v " : "");
}
/*
diff --git a/drivers/mci/stm32_sdmmc2.c b/drivers/mci/stm32_sdmmc2.c
index b517ab7964e2..8aeda6e988b1 100644
--- a/drivers/mci/stm32_sdmmc2.c
+++ b/drivers/mci/stm32_sdmmc2.c
@@ -637,9 +637,9 @@ static int stm32_sdmmc2_probe(struct amba_device *adev,
mci->host_caps |= MMC_CAP_MMC_HIGHSPEED_52MHZ;
if (of_property_read_bool(np, "mmc-ddr-3_3v"))
- mci->host_caps |= MMC_CAP_MMC_3_3V_DDR;
+ mci->host_caps |= MMC_CAP_3_3V_DDR;
if (of_property_read_bool(np, "mmc-ddr-1_8v"))
- mci->host_caps |= MMC_CAP_MMC_1_8V_DDR;
+ mci->host_caps |= MMC_CAP_1_8V_DDR;
return mci_register(&priv->mci);
diff --git a/include/mci.h b/include/mci.h
index bb168ca2225f..126d3fe52d37 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -53,11 +53,11 @@
#define MMC_CAP_SD_HIGHSPEED (1 << 3)
#define MMC_CAP_MMC_HIGHSPEED (1 << 4)
#define MMC_CAP_MMC_HIGHSPEED_52MHZ (1 << 5)
-#define MMC_CAP_MMC_3_3V_DDR (1 << 7) /* Host supports eMMC DDR 3.3V */
-#define MMC_CAP_MMC_1_8V_DDR (1 << 8) /* Host supports eMMC DDR 1.8V */
-#define MMC_CAP_MMC_1_2V_DDR (1 << 9) /* Host supports eMMC DDR 1.2V */
-#define MMC_CAP_DDR (MMC_CAP_MMC_3_3V_DDR | MMC_CAP_MMC_1_8V_DDR | \
- MMC_CAP_MMC_1_2V_DDR)
+#define MMC_CAP_3_3V_DDR (1 << 7) /* Host supports eMMC DDR 3.3V */
+#define MMC_CAP_1_8V_DDR (1 << 8) /* Host supports eMMC DDR 1.8V */
+#define MMC_CAP_1_2V_DDR (1 << 9) /* Host supports eMMC DDR 1.2V */
+#define MMC_CAP_DDR (MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR | \
+ MMC_CAP_1_2V_DDR)
#define MMC_CAP_UHS_SDR12 (1 << 16) /* Host supports UHS SDR12 mode */
#define MMC_CAP_UHS_SDR25 (1 << 17) /* Host supports UHS SDR25 mode */
#define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 08/30] mci: compare host and card caps for supported speeds
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (6 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 07/30] mci: rename MMC_CAP_MMC_x_yV_DDR to MMC_CAP_x_yV_DDR as in Linux Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 09/30] mci: print HS200 capabilities in devinfo Ahmad Fatoum
` (22 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We currently support only a single speed mode that needs tuning, so we
took the existence of execute_tuning to mean that higher speed modes are
supported.
This breaks down once we have multiple speed modes that need tuning and
is different to what Linux does, which instead sets capabilities on the
host, which are compared with the capabilities of the card.
Do the same in barebox to get rid of this quirk.
No functional change intended.
Suggested-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/arasan-sdhci.c | 1 +
drivers/mci/mci-core.c | 22 ++++++++++------------
include/mci.h | 1 +
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index f98f7eb3d10b..879339572b11 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -771,6 +771,7 @@ static int arasan_sdhci_probe(struct device *dev)
if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
if (IS_ENABLED(CONFIG_MCI_TUNING))
mci->ops.execute_tuning = arasan_zynqmp_execute_tuning;
+ mci->caps2 |= MMC_CAP2_HS200;
arasan_sdhci->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN;
}
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 819a059e6468..ed036719beb7 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1582,14 +1582,8 @@ int mci_execute_tuning(struct mci *mci)
struct mci_host *host = mci->host;
u32 opcode;
- if (!host->ops.execute_tuning) {
- /*
- * For us, implementing ->execute_tuning is mandatory to
- * support higher speed modes
- */
- dev_warn(&mci->dev, "tuning failed: no host diver support\n");
- return -EOPNOTSUPP;
- }
+ if (!host->ops.execute_tuning)
+ return 0;
/* Tuning is only supported for MMC / HS200 */
if (mmc_card_hs200(mci))
@@ -1626,29 +1620,35 @@ static void mmc_select_max_dtr(struct mci *mci)
u32 caps = mci->card_caps;
unsigned int hs_max_dtr = 0;
unsigned int hs200_max_dtr = 0;
+ unsigned int avail_type = 0;
if ((caps & MMC_CAP_MMC_HIGHSPEED) &&
(card_type & EXT_CSD_CARD_TYPE_26)) {
hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+ avail_type |= EXT_CSD_CARD_TYPE_26;
}
if ((caps & MMC_CAP_MMC_HIGHSPEED) &&
(card_type & EXT_CSD_CARD_TYPE_52)) {
hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+ avail_type |= EXT_CSD_CARD_TYPE_52;
}
if ((caps2 & MMC_CAP2_HS200_1_8V_SDR) &&
(card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)) {
hs200_max_dtr = MMC_HS200_MAX_DTR;
+ avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
}
if ((caps2 & MMC_CAP2_HS200_1_2V_SDR) &&
(card_type & EXT_CSD_CARD_TYPE_HS200_1_2V)) {
hs200_max_dtr = MMC_HS200_MAX_DTR;
+ avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
}
mci->host->hs200_max_dtr = hs200_max_dtr;
mci->host->hs_max_dtr = hs_max_dtr;
+ mci->host->mmc_avail_type = avail_type;
}
/*
* For device supporting HS200 mode, the following sequence
@@ -1733,16 +1733,14 @@ static void mmc_set_bus_speed(struct mci *mci)
*/
int mmc_select_timing(struct mci *mci)
{
- unsigned int mmc_avail_type;
int err = 0;
mmc_select_max_dtr(mci);
- mmc_avail_type = mci->ext_csd[EXT_CSD_DEVICE_TYPE] & EXT_CSD_CARD_TYPE_MASK;
- if (mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) {
+ if (mci->host->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) {
err = mmc_select_hs200(mci);
if (err == -EBADMSG)
- mmc_avail_type &= ~EXT_CSD_CARD_TYPE_HS200;
+ mci->host->mmc_avail_type &= ~EXT_CSD_CARD_TYPE_HS200;
else
goto out;
}
diff --git a/include/mci.h b/include/mci.h
index 126d3fe52d37..56527f956802 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -616,6 +616,7 @@ struct mci_host {
unsigned f_max; /**< host interface upper limit */
unsigned actual_clock;
struct mci_ios ios; /* current io bus settings */
+ unsigned mmc_avail_type; /**< supported device type by both host and card */
unsigned hs_max_dtr;
unsigned hs200_max_dtr;
unsigned max_req_size;
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 09/30] mci: print HS200 capabilities in devinfo
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (7 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 08/30] mci: compare host and card caps for supported speeds Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 10/30] mci: respect no-1-8-v OF property Ahmad Fatoum
` (21 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
HS200 capabilities didn't fit into host_caps (named just caps in Linux)
and instead were added to caps2. We copied the same scheme in barebox,
but only evaluate host_caps. Let's do the same for caps2, so devinfo
output can show whether HS200 is supported at a glance.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-core.c | 34 +++++++++++++++++++++++++++++-----
1 file changed, 29 insertions(+), 5 deletions(-)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index ed036719beb7..9031308ec3d2 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1650,6 +1650,28 @@ static void mmc_select_max_dtr(struct mci *mci)
mci->host->hs_max_dtr = hs_max_dtr;
mci->host->mmc_avail_type = avail_type;
}
+
+static u32 mmc_card_caps2_from_ext_csd(struct mci *mci)
+{
+ u8 card_type;
+ u32 caps2;
+
+ if (!mci->ext_csd)
+ return 0;
+
+ card_type = mci->ext_csd[EXT_CSD_DEVICE_TYPE];
+ caps2 = 0;
+
+ if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
+ caps2 |= MMC_CAP2_HS200_1_8V_SDR;
+
+ if ((caps2 & MMC_CAP2_HS200_1_2V_SDR) &&
+ (card_type & EXT_CSD_CARD_TYPE_HS200_1_2V))
+ caps2 |= MMC_CAP2_HS200_1_2V_SDR;
+
+ return caps2;
+}
+
/*
* For device supporting HS200 mode, the following sequence
* should be done before executing the tuning process.
@@ -2330,9 +2352,9 @@ static int mci_sd_read(struct block_device *blk, void *buffer, sector_t block,
/* ------------------ attach to the device API --------------------------- */
-static void mci_print_caps(unsigned caps)
+static void mci_print_caps(unsigned caps, unsigned caps2)
{
- printf(" capabilities: %s%s%s%s%s%s%s%s\n",
+ printf(" capabilities: %s%s%s%s%s%s%s%s%s%s\n",
caps & MMC_CAP_4_BIT_DATA ? "4bit " : "",
caps & MMC_CAP_8_BIT_DATA ? "8bit " : "",
caps & MMC_CAP_SD_HIGHSPEED ? "sd-hs " : "",
@@ -2340,7 +2362,9 @@ static void mci_print_caps(unsigned caps)
caps & MMC_CAP_MMC_HIGHSPEED_52MHZ ? "mmc-52MHz " : "",
caps & MMC_CAP_3_3V_DDR ? "ddr-3.3v " : "",
caps & MMC_CAP_1_8V_DDR ? "ddr-1.8v " : "",
- caps & MMC_CAP_1_2V_DDR ? "ddr-1.2v " : "");
+ caps & MMC_CAP_1_2V_DDR ? "ddr-1.2v " : "",
+ caps2 & MMC_CAP2_HS200_1_8V_SDR ? "hs200-1.8v " : "",
+ caps2 & MMC_CAP2_HS200_1_2V_SDR ? "hs200-1.2v " : "");
}
/*
@@ -2458,7 +2482,7 @@ static void mci_info(struct device *dev)
printf(" current buswidth: %d\n", bw);
printf(" current timing: %s\n", mci_timing_tostr(host->ios.timing));
- mci_print_caps(host->host_caps);
+ mci_print_caps(host->host_caps, host->caps2);
printf("Card information:\n");
printf(" Card type: %s\n", mci->sdio ? "SDIO" : IS_SD(mci) ? "SD" : "MMC");
@@ -2488,7 +2512,7 @@ static void mci_info(struct device *dev)
printf(" CSD: %08X-%08X-%08X-%08X\n", mci->csd[0], mci->csd[1],
mci->csd[2], mci->csd[3]);
printf(" Max. transfer speed: %u Hz\n", mci->tran_speed);
- mci_print_caps(mci->card_caps);
+ mci_print_caps(mci->card_caps, mmc_card_caps2_from_ext_csd(mci));
printf(" Manufacturer ID: 0x%02x\n", mci->cid.manfid);
printf(" OEM/Application ID: 0x%04x\n", mci->cid.oemid);
printf(" Product name: '%s'\n", mci->cid.prod_name);
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 10/30] mci: respect no-1-8-v OF property
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (8 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 09/30] mci: print HS200 capabilities in devinfo Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 11/30] mci: sdhci: add support for struct mci_data::timeout_ns Ahmad Fatoum
` (20 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
no-1-8-v is much more relevant to SD-Cards, but on the off-chance that
is' set on an eMMC node, we should respect it and disable 1.8V speed
modes accordingly.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-core.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 9031308ec3d2..2f80763d9831 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -3097,6 +3097,17 @@ void mci_of_parse_node(struct mci_host *host,
if (of_property_read_bool(np, "no-mmc-hs400"))
host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
MMC_CAP2_HS400_ES);
+ if (of_property_read_bool(np, "no-1-8-v")) {
+ /*
+ * The SDHCI controller in a SoC might support HS200/HS400
+ * (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property),
+ * but if the board is modeled such that the IO lines are not
+ * connected to 1.8v then HS200/HS400 cannot be supported.
+ * Disable HS200/HS400 if the board does not have 1.8v connected
+ * to the IO lines. (Applicable for other modes in 1.8v)
+ */
+ host->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES);
+ }
}
}
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 11/30] mci: sdhci: add support for struct mci_data::timeout_ns
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (9 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 10/30] mci: respect no-1-8-v OF property Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 12/30] mci: imx-esdhc: use unsigned types where appropriate Ahmad Fatoum
` (19 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
With tuning sequences, we will want to associate the busy timeout with
the struct mci_data, so add a timeout_ns member to it like Linux does.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/sdhci.c | 17 +++++++----------
drivers/mci/sdhci.h | 23 ++++++++++++++++++++++-
include/mci.h | 1 +
3 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index d0caee22f2f7..84acb3d163b5 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -813,11 +813,10 @@ void sdhci_enable_clk(struct sdhci *host, u16 clk)
int sdhci_wait_idle(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *data)
{
u32 mask;
- unsigned timeout_ms;
+ ktime_t timeout_ns;
int ret;
mask = SDHCI_CMD_INHIBIT_CMD;
- timeout_ms = SDHCI_CMD_DEFAULT_BUSY_TIMEOUT_MS;
if (data || (cmd && (cmd->resp_type & MMC_RSP_BUSY)))
mask |= SDHCI_CMD_INHIBIT_DATA;
@@ -825,12 +824,10 @@ int sdhci_wait_idle(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *da
if (cmd && cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
mask &= ~SDHCI_CMD_INHIBIT_DATA;
- if (cmd && cmd->busy_timeout != 0)
- timeout_ms = cmd->busy_timeout;
+ timeout_ns = sdhci_compute_timeout(cmd, data, SDHCI_CMD_DEFAULT_BUSY_TIMEOUT_NS);
- ret = wait_on_timeout(timeout_ms * MSECOND,
+ ret = wait_on_timeout(timeout_ns,
!(sdhci_read32(host, SDHCI_PRESENT_STATE) & mask));
-
if (ret) {
dev_err(sdhci_dev(host),
"SDHCI timeout while waiting for idle\n");
@@ -843,19 +840,19 @@ int sdhci_wait_idle(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *da
int sdhci_wait_idle_data(struct sdhci *host, struct mci_cmd *cmd)
{
u32 mask;
- unsigned timeout_ms;
+ unsigned timeout_ns;
int ret;
mask = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA;
- timeout_ms = SDHCI_CMD_DEFAULT_BUSY_TIMEOUT_MS;
+ timeout_ns = SDHCI_CMD_DEFAULT_BUSY_TIMEOUT_NS;
if (cmd && cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
mask &= ~SDHCI_CMD_INHIBIT_DATA;
if (cmd && cmd->busy_timeout != 0)
- timeout_ms = cmd->busy_timeout;
+ timeout_ns = cmd->busy_timeout;
- ret = wait_on_timeout(timeout_ms * MSECOND,
+ ret = wait_on_timeout(timeout_ns,
!(sdhci_read32(host, SDHCI_PRESENT_STATE) & mask));
if (ret) {
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index d3b681153134..61058ca030a8 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -3,9 +3,11 @@
#define __MCI_SDHCI_H
#include <pbl.h>
+#include <mci.h>
#include <dma.h>
#include <linux/iopoll.h>
#include <linux/sizes.h>
+#include <linux/ktime.h>
#define SDHCI_DMA_ADDRESS 0x00
#define SDHCI_BLOCK_SIZE__BLOCK_COUNT 0x04
@@ -201,7 +203,7 @@
#define SDHCI_MAX_DIV_SPEC_200 256
#define SDHCI_MAX_DIV_SPEC_300 2046
-#define SDHCI_CMD_DEFAULT_BUSY_TIMEOUT_MS 10
+#define SDHCI_CMD_DEFAULT_BUSY_TIMEOUT_NS (10 * NSEC_PER_MSEC)
struct sdhci {
u32 (*read32)(struct sdhci *host, int reg);
@@ -352,4 +354,23 @@ void sdhci_set_bus_width(struct sdhci *host, int width);
#define sdhci_read32_poll_timeout(sdhci, reg, val, cond, timeout_us) \
read_poll_timeout(sdhci_read32, val, cond, timeout_us, sdhci, reg)
+/**
+ * sdhci_compute_timeout() - compute suitable timeout for operation
+ * @cmd: MCI command being sent, can be NULL
+ * @data: MCI data being sent, can be NULL
+ * @default_timeout: fallback value
+ *
+ * Return: the number of nanoseconds to wait.
+ */
+static inline ktime_t sdhci_compute_timeout(struct mci_cmd *cmd, struct mci_data *data,
+ ktime_t default_timeout)
+{
+ if (data && data->timeout_ns != 0)
+ return data->timeout_ns;
+ else if (cmd && cmd->busy_timeout != 0)
+ return cmd->busy_timeout * (u64)NSEC_PER_MSEC;
+ else
+ return SDHCI_CMD_DEFAULT_BUSY_TIMEOUT_NS;
+}
+
#endif /* __MCI_SDHCI_H */
diff --git a/include/mci.h b/include/mci.h
index 56527f956802..d3b855f530fc 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -513,6 +513,7 @@ struct mci_data {
unsigned flags; /**< refer MMC_DATA_* to define direction */
unsigned blocks; /**< block count to handle in this command */
unsigned blocksize; /**< block size in bytes (mostly 512) */
+ unsigned timeout_ns; /**< data timeout in ns */
};
enum mci_timing {
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 12/30] mci: imx-esdhc: use unsigned types where appropriate
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (10 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 11/30] mci: sdhci: add support for struct mci_data::timeout_ns Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 13/30] mci: imx-esdhc: implement esdhc_poll using sdhci_read32_poll_timeout Ahmad Fatoum
` (18 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
clock rate and register values are both unsigned quantities, so
use the proper types for them.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 923dae9cf3b0..2e6066b20308 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -48,7 +48,7 @@ static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr)
{
int div, pre_div, ddr_pre_div = 1;
struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
- int sdhc_clk = clk_get_rate(host->clk);
+ unsigned sdhc_clk = clk_get_rate(host->clk);
u32 clk;
unsigned long cur_clock;
@@ -199,7 +199,7 @@ static int esdhc_card_present(struct mci_host *mci)
static int esdhc_reset(struct fsl_esdhc_host *host)
{
- int val;
+ u32 val;
/* reset the controller */
sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 13/30] mci: imx-esdhc: implement esdhc_poll using sdhci_read32_poll_timeout
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (11 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 12/30] mci: imx-esdhc: use unsigned types where appropriate Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 14/30] mci: imx-esdhc: drop one extra read of SDHCI_INT_STATUS Ahmad Fatoum
` (17 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
esdhc_match32 is not flexible enough for use in the upcoming HS200
tuning code, so reimplement it in terms of sdhci_read32_poll_timeout
to allow custom conditions.
No functional change.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc-common.c | 62 +++++++---------------------------
drivers/mci/imx-esdhc.c | 15 ++++----
drivers/mci/imx-esdhc.h | 29 ++++++++++++++--
3 files changed, 45 insertions(+), 61 deletions(-)
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index 7673220fe8d4..0743e7b74d22 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -78,49 +78,11 @@ static int esdhc_setup_data(struct fsl_esdhc_host *host, struct mci_data *data,
return 0;
}
-static bool esdhc_match32(struct fsl_esdhc_host *host, unsigned int off,
- unsigned int mask, unsigned int val)
-{
- const unsigned int reg = sdhci_read32(&host->sdhci, off) & mask;
-
- return reg == val;
-}
-
-#ifdef __PBL__
-/*
- * Stubs to make timeout logic below work in PBL
- */
-
-#define get_time_ns() 0
-/*
- * Use time in us (approx) as a busy counter timeout value
- */
-#define is_timeout(s, t) ((s)++ > ((t) / 1024))
-
-static void __udelay(int us)
-{
- volatile int i;
-
- for (i = 0; i < us * 4; i++);
-}
-
-#define udelay(n) __udelay(n)
-
-#endif
-
-int esdhc_poll(struct fsl_esdhc_host *host, unsigned int off,
- unsigned int mask, unsigned int val,
- uint64_t timeout)
-{
- return wait_on_timeout(timeout,
- esdhc_match32(host, off, mask, val));
-}
-
int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
struct mci_data *data)
{
u32 xfertyp, mixctrl, command;
- u32 irqstat;
+ u32 val, irqstat;
dma_addr_t dma = SDHCI_NO_DMA;
int ret;
@@ -159,8 +121,8 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
command << 16 | xfertyp);
/* Wait for the command to complete */
- ret = esdhc_poll(host, SDHCI_INT_STATUS,
- SDHCI_INT_CMD_COMPLETE, SDHCI_INT_CMD_COMPLETE,
+ ret = esdhc_poll(host, SDHCI_INT_STATUS, val,
+ val & SDHCI_INT_CMD_COMPLETE,
100 * MSECOND);
if (ret) {
dev_dbg(host->dev, "timeout 1\n");
@@ -185,9 +147,9 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
* Poll on DATA0 line for cmd with busy signal for
* timout / 10 usec since DLA polling can be insecure.
*/
- ret = esdhc_poll(host, SDHCI_PRESENT_STATE,
- PRSSTAT_DAT0, PRSSTAT_DAT0,
- 2500 * MSECOND);
+ ret = esdhc_poll(host, SDHCI_PRESENT_STATE, val,
+ val & PRSSTAT_DAT0,
+ sdhci_compute_timeout(cmd, NULL, 2500 * MSECOND));
if (ret) {
dev_err(host->dev, "timeout PRSSTAT_DAT0\n");
goto undo_setup_data;
@@ -210,17 +172,17 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, -1);
/* Wait for the bus to be idle */
- ret = esdhc_poll(host, SDHCI_PRESENT_STATE,
- SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA, 0,
- SECOND);
+ ret = esdhc_poll(host, SDHCI_PRESENT_STATE, val,
+ (val & (SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA)) == 0,
+ sdhci_compute_timeout(cmd, data, SECOND));
if (ret) {
dev_err(host->dev, "timeout 2\n");
return -ETIMEDOUT;
}
- ret = esdhc_poll(host, SDHCI_PRESENT_STATE,
- SDHCI_DATA_LINE_ACTIVE, 0,
- 100 * MSECOND);
+ ret = esdhc_poll(host, SDHCI_PRESENT_STATE, val,
+ (val & SDHCI_DATA_LINE_ACTIVE) == 0,
+ sdhci_compute_timeout(cmd, NULL, 100 * MSECOND));
if (ret) {
dev_err(host->dev, "timeout 3\n");
return -ETIMEDOUT;
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 2e6066b20308..0582b6fb8dd6 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -49,7 +49,7 @@ static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr)
int div, pre_div, ddr_pre_div = 1;
struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
unsigned sdhc_clk = clk_get_rate(host->clk);
- u32 clk;
+ u32 val, clk;
unsigned long cur_clock;
if (esdhc_is_usdhc(host) && ddr)
@@ -92,8 +92,8 @@ static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr)
esdhc_clrsetbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
SYSCTL_CLOCK_MASK, clk);
- esdhc_poll(host, SDHCI_PRESENT_STATE,
- PRSSTAT_SDSTB, PRSSTAT_SDSTB,
+ esdhc_poll(host, SDHCI_PRESENT_STATE, val,
+ val & PRSSTAT_SDSTB,
10 * MSECOND);
clk = SYSCTL_PEREN | SYSCTL_CKEN | SYSCTL_INITA;
@@ -101,8 +101,8 @@ static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr)
esdhc_setbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
clk);
- esdhc_poll(host, SDHCI_CLOCK_CONTROL,
- SYSCTL_INITA, SYSCTL_INITA,
+ esdhc_poll(host, SDHCI_CLOCK_CONTROL, val,
+ val & SYSCTL_INITA,
10 * MSECOND);
}
@@ -217,9 +217,8 @@ static int esdhc_reset(struct fsl_esdhc_host *host)
}
/* hardware clears the bit when it is done */
- if (esdhc_poll(host,
- SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
- SYSCTL_RSTA, 0, 100 * MSECOND)) {
+ if (esdhc_poll(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
+ val, (val & SYSCTL_RSTA) == 0, 100 * MSECOND)) {
dev_err(host->dev, "Reset never completed.\n");
return -EIO;
}
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index eff556f2ff79..2930676d5328 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -10,6 +10,10 @@
#include <errno.h>
#include <asm/byteorder.h>
#include <linux/bitfield.h>
+#include <linux/math.h>
+#include <linux/ktime.h>
+
+#include "sdhci.h"
#define SYSCTL_INITA 0x08000000
#define SYSCTL_TIMEOUT_MASK 0x000f0000
@@ -163,10 +167,29 @@ esdhc_setbits32(struct fsl_esdhc_host *host, unsigned int reg,
}
void esdhc_populate_sdhci(struct fsl_esdhc_host *host);
-int esdhc_poll(struct fsl_esdhc_host *host, unsigned int off,
- unsigned int mask, unsigned int val,
- uint64_t timeout);
int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
struct mci_data *data);
+#ifdef __PBL__
+#undef read_poll_get_time_ns
+#define read_poll_get_time_ns() 0
+/* Use time in us (approx) as a busy counter timeout value */
+#undef read_poll_is_timeout
+#define read_poll_is_timeout(s, t) ((s)++ > ((t) / 1024))
+
+static inline void __udelay(int us)
+{
+ volatile int i;
+
+ for (i = 0; i < us * 4; i++);
+}
+
+#define udelay(n) __udelay(n)
+
+#endif
+
+#define esdhc_poll(host, reg, val, cond, timeout_ns) \
+ sdhci_read32_poll_timeout(&host->sdhci, reg, val, cond, \
+ ktime_to_us(timeout_ns))
+
#endif /* __FSL_ESDHC_H__ */
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 14/30] mci: imx-esdhc: drop one extra read of SDHCI_INT_STATUS
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (12 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 13/30] mci: imx-esdhc: implement esdhc_poll using sdhci_read32_poll_timeout Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 15/30] mci: sdhci: add cmd parameter to sdhci_transfer_* Ahmad Fatoum
` (16 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Our new esdhc_poll implementation stores the register value read for
later use, so make use of it instead of reading the same register again
after the break condition has been triggered.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc-common.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index 0743e7b74d22..18a9f3be7239 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -121,16 +121,14 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
command << 16 | xfertyp);
/* Wait for the command to complete */
- ret = esdhc_poll(host, SDHCI_INT_STATUS, val,
- val & SDHCI_INT_CMD_COMPLETE,
+ ret = esdhc_poll(host, SDHCI_INT_STATUS, irqstat,
+ irqstat & SDHCI_INT_CMD_COMPLETE,
100 * MSECOND);
if (ret) {
dev_dbg(host->dev, "timeout 1\n");
goto undo_setup_data;
}
- irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
-
if (irqstat & CMD_ERR) {
ret = -EIO;
goto undo_setup_data;
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 15/30] mci: sdhci: add cmd parameter to sdhci_transfer_*
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (13 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 14/30] mci: imx-esdhc: drop one extra read of SDHCI_INT_STATUS Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 16/30] mci: arasan: introduce mmc_op_tuning helper Ahmad Fatoum
` (15 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
With incoming tuning support, the SDHCI flags computed inside
sdhci_transfer_* will depend on the specific MMC command that's due to
be sent, therefore add the command as parameter to the functions.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/am654-sdhci.c | 2 +-
drivers/mci/arasan-sdhci.c | 2 +-
drivers/mci/atmel-sdhci-common.c | 2 +-
drivers/mci/dwcmshc-sdhci.c | 2 +-
drivers/mci/imx-esdhc-common.c | 4 ++--
drivers/mci/mci-bcm2835.c | 2 +-
drivers/mci/rockchip-dwcmshc-sdhci.c | 2 +-
drivers/mci/sdhci.c | 14 ++++++++------
drivers/mci/sdhci.h | 10 ++++++----
9 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/drivers/mci/am654-sdhci.c b/drivers/mci/am654-sdhci.c
index 20dd03b83a9a..13c8876573c7 100644
--- a/drivers/mci/am654-sdhci.c
+++ b/drivers/mci/am654-sdhci.c
@@ -490,7 +490,7 @@ static int am654_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_read_response(&host->sdhci, cmd);
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
- ret = sdhci_transfer_data_dma(&host->sdhci, data, dma);
+ ret = sdhci_transfer_data_dma(&host->sdhci, cmd, data, dma);
error:
if (ret) {
diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 879339572b11..5774928e5a97 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -293,7 +293,7 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
if (data)
- ret = sdhci_transfer_data_dma(&host->sdhci, data, dma);
+ ret = sdhci_transfer_data_dma(&host->sdhci, cmd, data, dma);
error:
if (ret) {
diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index 12b71bc2ded3..a3ed2730e527 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -128,7 +128,7 @@ int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *cmd,
sdhci_write32(sdhci, SDHCI_INT_STATUS, mask);
if (data)
- sdhci_transfer_data_pio(sdhci, data);
+ sdhci_transfer_data_pio(sdhci, cmd, data);
udelay(1000);
diff --git a/drivers/mci/dwcmshc-sdhci.c b/drivers/mci/dwcmshc-sdhci.c
index f6d559e393d4..174cc3f76816 100644
--- a/drivers/mci/dwcmshc-sdhci.c
+++ b/drivers/mci/dwcmshc-sdhci.c
@@ -160,7 +160,7 @@ static int do_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_read_response(&host->sdhci, cmd);
- ret = sdhci_transfer_data(&host->sdhci, data, dma);
+ ret = sdhci_transfer_data(&host->sdhci, cmd, data, dma);
error:
if (ret) {
sdhci_reset(&host->sdhci, SDHCI_RESET_CMD);
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index 18a9f3be7239..9526bcfea8c1 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -159,9 +159,9 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
/* Wait until all of the blocks are transferred */
if (data) {
if (esdhc_use_pio_mode())
- ret = sdhci_transfer_data_pio(&host->sdhci, data);
+ ret = sdhci_transfer_data_pio(&host->sdhci, cmd, data);
else
- ret = sdhci_transfer_data_dma(&host->sdhci, data, dma);
+ ret = sdhci_transfer_data_dma(&host->sdhci, cmd, data, dma);
if (ret)
return ret;
diff --git a/drivers/mci/mci-bcm2835.c b/drivers/mci/mci-bcm2835.c
index ff4c6d803c32..cd4c1b866ca1 100644
--- a/drivers/mci/mci-bcm2835.c
+++ b/drivers/mci/mci-bcm2835.c
@@ -158,7 +158,7 @@ static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd,
}
if (!ret && data)
- ret = sdhci_transfer_data_pio(&host->sdhci, data);
+ ret = sdhci_transfer_data_pio(&host->sdhci, cmd, data);
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, 0xFFFFFFFF);
if (ret) {
diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c
index a7da64f4d7db..2f8d5ec140b5 100644
--- a/drivers/mci/rockchip-dwcmshc-sdhci.c
+++ b/drivers/mci/rockchip-dwcmshc-sdhci.c
@@ -277,7 +277,7 @@ static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_read_response(&host->sdhci, cmd);
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
- ret = sdhci_transfer_data_dma(&host->sdhci, data, dma);
+ ret = sdhci_transfer_data_dma(&host->sdhci, cmd, data, dma);
error:
if (ret) {
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 84acb3d163b5..55709e831a28 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -524,8 +524,8 @@ void sdhci_teardown_data(struct sdhci *sdhci,
dma_unmap_single(dev, dma, nbytes, DMA_TO_DEVICE);
}
-int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
- dma_addr_t dma)
+int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_cmd *cmd,
+ struct mci_data *data, dma_addr_t dma)
{
struct device *dev = sdhci_dev(sdhci);
u64 start;
@@ -594,7 +594,8 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
return ret;
}
-int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data)
+int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_cmd *cmd,
+ struct mci_data *data)
{
unsigned int block = 0;
u32 stat, prs;
@@ -635,7 +636,8 @@ int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data)
return 0;
}
-int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma)
+int sdhci_transfer_data(struct sdhci *sdhci, struct mci_cmd *cmd,
+ struct mci_data *data, dma_addr_t dma)
{
struct device *dev = sdhci_dev(sdhci);
@@ -643,9 +645,9 @@ int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t d
return 0;
if (dma_mapping_error(dev, dma))
- return sdhci_transfer_data_pio(sdhci, data);
+ return sdhci_transfer_data_pio(sdhci, cmd, data);
else
- return sdhci_transfer_data_dma(sdhci, data, dma);
+ return sdhci_transfer_data_dma(sdhci, cmd, data, dma);
}
int sdhci_reset(struct sdhci *sdhci, u8 mask)
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 61058ca030a8..12ab8d148144 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -326,10 +326,12 @@ void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd,
void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data);
void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data, dma_addr_t *dma);
void sdhci_teardown_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma);
-int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma);
-int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data);
-int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
- dma_addr_t dma);
+int sdhci_transfer_data(struct sdhci *sdhci, struct mci_cmd *cmd,
+ struct mci_data *data, dma_addr_t dma);
+int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_cmd *cmd,
+ struct mci_data *data);
+int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_cmd *cmd,
+ struct mci_data *data, dma_addr_t dma);
int sdhci_reset(struct sdhci *sdhci, u8 mask);
u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock,
unsigned int *actual_clock, unsigned int input_clock);
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 16/30] mci: arasan: introduce mmc_op_tuning helper
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (14 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 15/30] mci: sdhci: add cmd parameter to sdhci_transfer_* Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 17/30] mci: imx-esdhc: flesh out register description Ahmad Fatoum
` (14 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Instead of duplicating the check most tuning related places, add a
helper like Linux does that checks if a command is sending a tuning
block.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/arasan-sdhci.c | 2 +-
include/mci.h | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 5774928e5a97..ceef0b63a8b9 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -280,7 +280,7 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
/* CMD19/21 generate _only_ Buffer Read Ready interrupt */
- if (cmd->cmdidx == MMC_SEND_TUNING_BLOCK || cmd->cmdidx == MMC_SEND_TUNING_BLOCK_HS200)
+ if (mmc_op_tuning(cmd->cmdidx))
mask = SDHCI_INT_DATA_AVAIL;
ret = sdhci_wait_for_done(&host->sdhci, mask);
diff --git a/include/mci.h b/include/mci.h
index d3b855f530fc..af56f453704e 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -504,6 +504,12 @@ static inline void mci_setup_cmd(struct mci_cmd *p, unsigned cmd,
p->resp_type = response;
}
+static inline bool mmc_op_tuning(u32 cmdidx)
+{
+ return cmdidx == MMC_SEND_TUNING_BLOCK ||
+ cmdidx == MMC_SEND_TUNING_BLOCK_HS200;
+}
+
/** data information to be used with some SD/MMC commands */
struct mci_data {
union {
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 17/30] mci: imx-esdhc: flesh out register description
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (15 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 16/30] mci: arasan: introduce mmc_op_tuning helper Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 18/30] mci: imx-esdhc: add support for delay/tuning properties in DT Ahmad Fatoum
` (13 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
In preparation for adding HS200 tuning support to the driver, import
missing register definitions from Linux.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc-common.c | 14 ++++++++++++++
drivers/mci/imx-esdhc.c | 27 +++++++++++++++++++++++++++
drivers/mci/imx-esdhc.h | 20 ++++++++++++++++++++
3 files changed, 61 insertions(+)
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index 9526bcfea8c1..5fc9b7b30c76 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -10,6 +10,20 @@
#define PRSSTAT_DAT0 0x01000000
+#define ESDHC_CTRL_D3CD 0x08
+
+#define SDHCI_CTRL_VDD_180 0x0008
+
+#define ESDHC_MIX_CTRL 0x48
+#define ESDHC_MIX_CTRL_DDREN (1 << 3)
+#define ESDHC_MIX_CTRL_AC23EN (1 << 7)
+#define ESDHC_MIX_CTRL_EXE_TUNE (1 << 22)
+#define ESDHC_MIX_CTRL_SMPCLK_SEL (1 << 23)
+#define ESDHC_MIX_CTRL_AUTO_TUNE_EN (1 << 24)
+#define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25)
+#define ESDHC_MIX_CTRL_HS400_EN (1 << 26)
+#define ESDHC_MIX_CTRL_HS400_ES_EN (1 << 27)
+
static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
{
struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 0582b6fb8dd6..86dc6daba845 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -28,6 +28,33 @@
#define PRSSTAT_SDSTB 0x00000008
+#define ESDHC_BURST_LEN_EN_INCR (1 << 27)
+
+/* Bits 3 and 6 are not SDHCI standard definitions */
+#define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7
+/* Tuning bits */
+#define ESDHC_MIX_CTRL_TUNING_MASK 0x03c00000
+
+/* dll control register */
+#define ESDHC_DLL_CTRL 0x60
+#define ESDHC_DLL_OVERRIDE_VAL_SHIFT 9
+#define ESDHC_DLL_OVERRIDE_EN_SHIFT 8
+
+/* tune control register */
+#define ESDHC_TUNE_CTRL_STATUS 0x68
+#define ESDHC_TUNE_CTRL_STEP 1
+#define ESDHC_TUNE_CTRL_MIN 0
+#define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1)
+
+#define ESDHC_TUNING_CTRL 0xcc
+#define ESDHC_STD_TUNING_EN (1 << 24)
+/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
+#define ESDHC_TUNING_START_TAP_DEFAULT 0x1
+#define ESDHC_TUNING_START_TAP_MASK 0x7f
+#define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE (1 << 7)
+#define ESDHC_TUNING_STEP_DEFAULT 0x1
+#define ESDHC_TUNING_STEP_MASK 0x00070000
+#define ESDHC_TUNING_STEP_SHIFT 16
#define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci)
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index 2930676d5328..ea57ca534f80 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -64,6 +64,26 @@
#define IMX_SDHCI_DLL_CTRL 0x60
#define IMX_SDHCI_MIX_CTRL_FBCLK_SEL BIT(25)
+/* tune control register */
+#define ESDHC_TUNE_CTRL_STATUS 0x68
+#define ESDHC_TUNE_CTRL_STEP 1
+#define ESDHC_TUNE_CTRL_MIN 0
+#define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1)
+
+/* VENDOR SPEC register */
+#define ESDHC_VENDOR_SPEC 0xc0
+#define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1)
+#define ESDHC_VENDOR_SPEC_VSELECT (1 << 1)
+#define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8)
+
+#define ESDHC_VEND_SPEC2 0xc8
+#define ESDHC_VEND_SPEC2_EN_BUSY_IRQ (1 << 8)
+#define ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN (1 << 4)
+#define ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN (0 << 4)
+#define ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN (2 << 4)
+#define ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN (1 << 6)
+#define ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK (7 << 4)
+
#define ESDHC_DMA_SYSCTL 0x40c /* Layerscape specific */
#define ESDHC_SYSCTL_DMA_SNOOP BIT(6)
#define ESDHC_SYSCTL_PERIPHERAL_CLK_SEL BIT(19)
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 18/30] mci: imx-esdhc: add support for delay/tuning properties in DT
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (16 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 17/30] mci: imx-esdhc: flesh out register description Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 19/30] mci: add mci_set_timing helper Ahmad Fatoum
` (12 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
With higher data rates, we will need to fine tune delay settings, which
can be supplied via the device tree. Add support for the binding to
barebox.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc.c | 59 ++++++++++++++++++++++++++++++++++++++++-
drivers/mci/imx-esdhc.h | 14 ++++++++++
2 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 86dc6daba845..5416d0648fa8 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -145,6 +145,15 @@ static void usdhc_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing
case MMC_TIMING_MMC_DDR52:
mixctrl |= MIX_CTRL_DDREN;
sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl);
+ if (host->boarddata.delay_line) {
+ u32 v;
+ v = host->boarddata.delay_line <<
+ IMX_SDHCI_DLL_CTRL_OVERRIDE_VAL_SHIFT |
+ (1 << IMX_SDHCI_DLL_CTRL_OVERRIDE_EN_SHIFT);
+ if (cpu_is_mx53())
+ v <<= 1;
+ sdhci_write32(&host->sdhci, IMX_SDHCI_DLL_CTRL, v);
+ }
break;
default:
sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl);
@@ -290,7 +299,36 @@ static int esdhc_init(struct mci_host *mci, struct device *dev)
esdhc_clrsetbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
SYSCTL_TIMEOUT_MASK, 14 << 16);
- return ret;
+ if (IS_ENABLED(CONFIG_MCI_TUNING) && esdhc_is_usdhc(host) &&
+ (host->socdata->flags & ESDHC_FLAG_STD_TUNING)) {
+ u32 tmp;
+
+ /* disable DLL_CTRL delay line settings */
+ sdhci_write32(&host->sdhci, ESDHC_DLL_CTRL, 0x0);
+
+ tmp = sdhci_read32(&host->sdhci, ESDHC_TUNING_CTRL);
+ tmp |= ESDHC_STD_TUNING_EN;
+
+ tmp &= ~(ESDHC_TUNING_START_TAP_MASK | ESDHC_TUNING_STEP_MASK);
+ tmp |= host->boarddata.tuning_start_tap;
+
+ tmp |= host->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
+
+ /* Disable the CMD CRC check for tuning, if not, need to
+ * add some delay after every tuning command, because
+ * hardware standard tuning logic will directly go to next
+ * step once it detect the CMD CRC error, will not wait for
+ * the card side to finally send out the tuning data, trigger
+ * the buffer read ready interrupt immediately. If usdhc send
+ * the next tuning command some eMMC card will stuck, can't
+ * response, block the tuning procedure or the first command
+ * after the whole tuning procedure always can't get any response.
+ */
+ tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE;
+ sdhci_write32(&host->sdhci, ESDHC_TUNING_CTRL, tmp);
+ }
+
+ return 0;
}
static const struct mci_ops fsl_esdhc_ops = {
@@ -300,6 +338,23 @@ static const struct mci_ops fsl_esdhc_ops = {
.card_present = esdhc_card_present,
};
+static void fsl_esdhc_probe_dt(struct device *dev, struct fsl_esdhc_host *host)
+{
+ struct device_node *np = dev->of_node;
+ struct esdhc_platform_data *boarddata = &host->boarddata;
+
+ if (!IS_ENABLED(CONFIG_MCI_TUNING))
+ return;
+
+ if (of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step))
+ boarddata->tuning_step = ESDHC_TUNING_STEP_DEFAULT;
+ if (of_property_read_u32(np, "fsl,tuning-start-tap",
+ &boarddata->tuning_start_tap))
+ boarddata->tuning_start_tap = ESDHC_TUNING_START_TAP_DEFAULT;
+ if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
+ boarddata->delay_line = 0;
+}
+
static int fsl_esdhc_probe(struct device *dev)
{
struct resource *iores;
@@ -360,6 +415,8 @@ static int fsl_esdhc_probe(struct device *dev)
mci_of_parse(&host->mci);
+ fsl_esdhc_probe_dt(dev, host);
+
ret = mci_register(&host->mci);
if (ret)
goto err_release_res;
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index ea57ca534f80..569986c1bf0e 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -62,6 +62,8 @@
/* Tuning bits */
#define MIX_CTRL_TUNING_MASK 0x03c00000
#define IMX_SDHCI_DLL_CTRL 0x60
+#define IMX_SDHCI_DLL_CTRL_OVERRIDE_VAL_SHIFT 9
+#define IMX_SDHCI_DLL_CTRL_OVERRIDE_EN_SHIFT 8
#define IMX_SDHCI_MIX_CTRL_FBCLK_SEL BIT(25)
/* tune control register */
@@ -137,11 +139,23 @@ struct esdhc_soc_data {
const char *clkidx;
};
+/*
+ * struct esdhc_platform_data - platform data for esdhc on i.MX
+ */
+
+struct esdhc_platform_data {
+ unsigned int delay_line;
+ unsigned int tuning_step; /* The delay cell steps in tuning procedure */
+ unsigned int tuning_start_tap; /* The start delay cell point in tuning procedure */
+};
+
struct fsl_esdhc_host {
struct mci_host mci;
struct clk *clk;
struct device *dev;
const struct esdhc_soc_data *socdata;
+ struct esdhc_platform_data boarddata;
+ u32 last_cmd;
struct sdhci sdhci;
};
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 19/30] mci: add mci_set_timing helper
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (17 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 18/30] mci: imx-esdhc: add support for delay/tuning properties in DT Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 20/30] mci: imx-esdhc: add support for setting drive strength Ahmad Fatoum
` (11 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
HS400 support when it goes in will add a number of extra calls to
mci_set_ios after changing just the timing. We already have two places
where we do this, so let's have a helper for it like Linux does.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-core.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 2f80763d9831..f123fce59cb1 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1093,6 +1093,19 @@ static void mci_set_bus_width(struct mci *mci, enum mci_bus_width width)
mci_set_ios(mci);
}
+/**
+ * Setup host's interface timing
+ * @param mci MCI instance
+ * @param width New timing
+ */
+static void mci_set_timing(struct mci *mci, enum mci_timing timing)
+{
+ struct mci_host *host = mci->host;
+
+ host->ios.timing = timing;
+ mci_set_ios(mci);
+}
+
/**
* Extract card's version from its CSD
* @param mci MCI instance
@@ -1709,8 +1722,7 @@ static int mmc_select_hs200(struct mci *mci)
old_timing = mci->host->ios.timing;
old_clock = mci->host->ios.clock;
- mci->host->ios.timing = MMC_TIMING_MMC_HS200;
- mci_set_ios(mci);
+ mci_set_timing(mci, MMC_TIMING_MMC_HS200);
mci_set_clock(mci, mci->host->hs_max_dtr);
err = mci_switch_status(mci, true);
@@ -1721,8 +1733,7 @@ static int mmc_select_hs200(struct mci *mci)
*/
if (err == -EBADMSG) {
mci->host->ios.clock = old_clock;
- mci->host->ios.timing = old_timing;
- mci_set_ios(mci);
+ mci_set_timing(mci, old_timing);
}
}
err:
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 20/30] mci: imx-esdhc: add support for setting drive strength
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (18 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 19/30] mci: add mci_set_timing helper Ahmad Fatoum
@ 2025-05-07 8:21 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 21/30] mci: sdhci: move SDHCI_MAKE_BLKSZ definition to header Ahmad Fatoum
` (10 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:21 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
With increasing clock rates, drive strength may need to be reduced. Add
support for that to the i.MX eSDHC driver and to the core.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc.c | 2 ++
drivers/mci/mci-core.c | 40 ++++++++++++++++++++++++++++++++++++++--
drivers/mci/sdhci.c | 29 +++++++++++++++++++++++++++++
drivers/mci/sdhci.h | 6 ++++++
include/mci.h | 10 ++++++++++
5 files changed, 85 insertions(+), 2 deletions(-)
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 5416d0648fa8..3871f85ea6d6 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -207,6 +207,8 @@ static void esdhc_set_ios(struct mci_host *mci, struct mci_ios *ios)
/* Set the clock speed */
set_sysctl(mci, ios->clock, mci_timing_is_ddr(ios->timing));
+ sdhci_set_drv_type(&host->sdhci, ios->drv_type);
+
/* Set the bus width */
esdhc_clrbits32(host, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL,
PROCTL_DTW_4 | PROCTL_DTW_8);
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index f123fce59cb1..80b3496a280a 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1626,6 +1626,28 @@ int mci_send_abort_tuning(struct mci *mci, u32 opcode)
}
EXPORT_SYMBOL_GPL(mci_send_abort_tuning);
+static void mmc_select_driver_type(struct mci *mci)
+{
+ int card_drv_type, drive_strength;
+ int fixed_drv_type = mci->host->fixed_drv_type;
+
+ card_drv_type = mci->ext_csd[EXT_CSD_DRIVER_STRENGTH] |
+ mmc_driver_type_mask(0);
+
+ if (mci->host->fixed_drv_type_valid)
+ drive_strength = card_drv_type & mmc_driver_type_mask(fixed_drv_type)
+ ? fixed_drv_type : 0;
+ else
+ drive_strength = 0;
+
+ mci->host->drive_strength = drive_strength;
+
+ /* Linux only sets the drive strength immediately if the driver
+ * implements select_drive_strength, which none of our drivers
+ * do yet
+ */
+}
+
static void mmc_select_max_dtr(struct mci *mci)
{
u8 card_type = mci->ext_csd[EXT_CSD_DEVICE_TYPE];
@@ -1698,6 +1720,8 @@ static int mmc_select_hs200(struct mci *mci)
int err = -EINVAL;
u8 val;
+ mmc_select_driver_type(mci);
+
/*
* Set the bus width(4 or 8) with host's support and
* switch to HS200 mode if bus width is set successfully.
@@ -1705,8 +1729,7 @@ static int mmc_select_hs200(struct mci *mci)
/* find out maximum bus width and then try DDR if supported */
err = mci_mmc_select_bus_width(mci);
if (err > 0) {
- /* TODO actually set drive strength instead of 0. Currently unsupported. */
- val = EXT_CSD_TIMING_HS200 | 0 << EXT_CSD_DRV_STR_SHIFT;
+ val = EXT_CSD_TIMING_HS200 | (mci->host->drive_strength << EXT_CSD_DRV_STR_SHIFT);
err = mci_switch(mci, EXT_CSD_HS_TIMING, val);
if (err == -EIO)
return -EBADMSG;
@@ -3095,6 +3118,8 @@ void mci_of_parse_node(struct mci_host *host,
if (of_property_read_bool(np, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC;
if (IS_ENABLED(CONFIG_MCI_TUNING)) {
+ u32 drv_type;
+
if (of_property_read_bool(np, "mmc-hs200-1_8v"))
host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
if (of_property_read_bool(np, "mmc-hs200-1_2v"))
@@ -3119,6 +3144,17 @@ void mci_of_parse_node(struct mci_host *host,
*/
host->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES);
}
+
+ /* Must be after "non-removable" check */
+ if (of_property_read_u32(np, "fixed-emmc-driver-type", &drv_type) == 0) {
+ if (host->non_removable) {
+ host->fixed_drv_type = drv_type;
+ host->fixed_drv_type_valid = true;
+ } else {
+ dev_err(host->hw_dev,
+ "can't use fixed driver type, media is removable\n");
+ }
+ }
}
}
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 55709e831a28..b86b3f3d8d1c 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -887,6 +887,35 @@ void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_
sdhci_enable_clk(host, clk);
}
+void sdhci_set_drv_type(struct sdhci *host, unsigned drv_type)
+{
+ u16 ctrl_2;
+
+ if (host->preset_enabled)
+ return;
+
+ /*
+ * We only need to set Driver Strength if the
+ * preset value enable is not set.
+ */
+ ctrl_2 = sdhci_read16(host, SDHCI_HOST_CONTROL2);
+ ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
+ if (drv_type == MMC_SET_DRIVER_TYPE_A)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
+ else if (drv_type == MMC_SET_DRIVER_TYPE_B)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
+ else if (drv_type == MMC_SET_DRIVER_TYPE_C)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
+ else if (drv_type == MMC_SET_DRIVER_TYPE_D)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_D;
+ else {
+ dev_warn(sdhci_dev(host), "invalid driver type, default to driver type B\n");
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
+ }
+
+ sdhci_write16(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
static void sdhci_do_enable_v4_mode(struct sdhci *host)
{
u16 ctrl2;
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 12ab8d148144..31edebab1262 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -133,6 +133,11 @@
#define SDHCI_CTRL_UHS_SDR104 0x3
#define SDHCI_CTRL_UHS_DDR50 0x4
#define SDHCI_CTRL_HS400 0x5 /* Non-standard */
+#define SDHCI_CTRL_DRV_TYPE_MASK GENMASK(5, 4)
+#define SDHCI_CTRL_DRV_TYPE_B 0x0000
+#define SDHCI_CTRL_DRV_TYPE_A 0x0010
+#define SDHCI_CTRL_DRV_TYPE_C 0x0020
+#define SDHCI_CTRL_DRV_TYPE_D 0x0030
#define SDHCI_CTRL_EXEC_TUNING BIT(6)
#define SDHCI_CTRL_TUNED_CLK BIT(7)
#define SDHCI_CTRL_64BIT_ADDR BIT(13)
@@ -337,6 +342,7 @@ u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock,
unsigned int *actual_clock, unsigned int input_clock);
void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_clock);
void sdhci_enable_clk(struct sdhci *host, u16 clk);
+void sdhci_set_drv_type(struct sdhci *host, unsigned drv_type);
void sdhci_enable_v4_mode(struct sdhci *host);
int sdhci_setup_host(struct sdhci *host);
void __sdhci_read_caps(struct sdhci *host, const u16 *ver,
diff --git a/include/mci.h b/include/mci.h
index af56f453704e..29aaecb46305 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -208,6 +208,8 @@
#define SD_ERASE_ARG 0x00000000
#define SD_DISCARD_ARG 0x00000001
+#define mmc_driver_type_mask(n) (1 << (n))
+
/*
* EXT_CSD fields
*/
@@ -560,6 +562,7 @@ struct mci_ios {
unsigned int clock; /* clock rate */
enum mci_bus_width bus_width; /* data bus width */
enum mci_timing timing; /* timing specification used */
+ unsigned char drv_type; /* driver type (A, B, C, D) */
};
struct mci;
@@ -632,6 +635,13 @@ struct mci_host {
int broken_cd; /**< card detect is broken */
bool non_removable; /**< device is non removable */
bool disable_wp; /**< ignore write-protect detection logic */
+ bool fixed_drv_type_valid;
+ unsigned char fixed_drv_type; /**< fixed driver type for non-removable media */
+ unsigned char drive_strength; /**< driver type (A, B, C, D) */
+#define MMC_SET_DRIVER_TYPE_B 0
+#define MMC_SET_DRIVER_TYPE_A 1
+#define MMC_SET_DRIVER_TYPE_C 2
+#define MMC_SET_DRIVER_TYPE_D 3
struct regulator *supply;
struct mci_ops ops;
};
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 21/30] mci: sdhci: move SDHCI_MAKE_BLKSZ definition to header
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (19 preceding siblings ...)
2025-05-07 8:21 ` [PATCH v2 20/30] mci: imx-esdhc: add support for setting drive strength Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 22/30] mci: imx-esdhc: select different pinctrl state depending on frequency Ahmad Fatoum
` (9 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
This is going to be used outside of sdhci.c, so move it into the header.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/sdhci.c | 1 -
drivers/mci/sdhci.h | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index b86b3f3d8d1c..3051354a3076 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -10,7 +10,6 @@
#include "sdhci.h"
#define MAX_TUNING_LOOP 40
-#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
enum sdhci_reset_reason {
SDHCI_RESET_FOR_INIT,
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 31edebab1262..e0436425fbda 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -25,6 +25,7 @@
#define SDHCI_DEFAULT_BOUNDARY_ARG SDHCI_DMA_BOUNDARY_512K
#define SDHCI_TRANSFER_BLOCK_SIZE(x) ((x) & 0xfff)
#define SDHCI_BLOCK_COUNT 0x06
+#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
#define SDHCI_ARGUMENT 0x08
#define SDHCI_TRANSFER_MODE__COMMAND 0x0c
#define SDHCI_TRANSFER_MODE 0x0c
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 22/30] mci: imx-esdhc: select different pinctrl state depending on frequency
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (20 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 21/30] mci: sdhci: move SDHCI_MAKE_BLKSZ definition to header Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 23/30] mci: core: retry MMC_CMD_SET_BLOCKLEN up to 4 times Ahmad Fatoum
` (8 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Like done before for the card side, we need to adjust drive strength on
the host as well with higher data rates. For i.MX, this is done via
speed-specific pincontrol groups, so implement this binding.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc.c | 48 +++++++++++++++++++++++++++++++++++++++++
drivers/mci/imx-esdhc.h | 3 +++
2 files changed, 51 insertions(+)
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 3871f85ea6d6..18a5750ed0ed 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -14,6 +14,7 @@
#include <of.h>
#include <malloc.h>
#include <mci.h>
+#include <linux/pinctrl/consumer.h>
#include <clock.h>
#include <io.h>
#include <linux/clk.h>
@@ -56,6 +57,9 @@
#define ESDHC_TUNING_STEP_MASK 0x00070000
#define ESDHC_TUNING_STEP_SHIFT 16
+/* pinctrl state */
+#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz"
+#define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz"
#define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci)
@@ -133,6 +137,37 @@ static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr)
10 * MSECOND);
}
+static int esdhc_change_pinstate(struct fsl_esdhc_host *host,
+ unsigned int uhs)
+{
+ struct pinctrl_state *pinctrl;
+
+ dev_dbg(host->dev, "change pinctrl state for uhs %d\n", uhs);
+
+ if (IS_ERR(host->pinctrl) ||
+ IS_ERR(host->pins_100mhz) ||
+ IS_ERR(host->pins_200mhz))
+ return -EINVAL;
+
+ switch (uhs) {
+ case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_DDR50:
+ pinctrl = host->pins_100mhz;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ case MMC_TIMING_MMC_HS400:
+ pinctrl = host->pins_200mhz;
+ break;
+ default:
+ /* back to default state for other legacy timing */
+ return pinctrl_select_state_default(host->dev);
+ }
+
+ return pinctrl_select_state(host->pinctrl, pinctrl);
+}
+
+
static void usdhc_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing)
{
u32 mixctrl;
@@ -159,6 +194,8 @@ static void usdhc_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing
sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl);
}
+ esdhc_change_pinstate(host, timing);
+
host->sdhci.timing = timing;
}
@@ -355,6 +392,13 @@ static void fsl_esdhc_probe_dt(struct device *dev, struct fsl_esdhc_host *host)
boarddata->tuning_start_tap = ESDHC_TUNING_START_TAP_DEFAULT;
if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
boarddata->delay_line = 0;
+
+ if (esdhc_is_usdhc(host) && !IS_ERR(host->pinctrl)) {
+ host->pins_100mhz = pinctrl_lookup_state(host->pinctrl,
+ ESDHC_PINCTRL_STATE_100MHZ);
+ host->pins_200mhz = pinctrl_lookup_state(host->pinctrl,
+ ESDHC_PINCTRL_STATE_200MHZ);
+ }
}
static int fsl_esdhc_probe(struct device *dev)
@@ -417,6 +461,10 @@ static int fsl_esdhc_probe(struct device *dev)
mci_of_parse(&host->mci);
+ host->pinctrl = pinctrl_get(dev);
+ if (IS_ERR(host->pinctrl))
+ dev_warn(host->dev, "could not get pinctrl\n");
+
fsl_esdhc_probe_dt(dev, host);
ret = mci_register(&host->mci);
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index 569986c1bf0e..e24d76d0c687 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -153,6 +153,9 @@ struct fsl_esdhc_host {
struct mci_host mci;
struct clk *clk;
struct device *dev;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_100mhz;
+ struct pinctrl_state *pins_200mhz;
const struct esdhc_soc_data *socdata;
struct esdhc_platform_data boarddata;
u32 last_cmd;
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 23/30] mci: core: retry MMC_CMD_SET_BLOCKLEN up to 4 times
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (21 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 22/30] mci: imx-esdhc: select different pinctrl state depending on frequency Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 24/30] mci: imx-esdhc: don't reconfigure clock unless required Ahmad Fatoum
` (7 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
This is what Linux is doing, so follow suit for reliability.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 80b3496a280a..5f0fdd2206a5 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -125,7 +125,7 @@ static int mci_set_blocklen(struct mci *mci, unsigned len)
return 0;
mci_setup_cmd(&cmd, MMC_CMD_SET_BLOCKLEN, len, MMC_RSP_R1);
- return mci_send_cmd(mci, &cmd, NULL);
+ return mci_send_cmd_retry(mci, &cmd, NULL, 4);
}
static void *sector_buf;
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 24/30] mci: imx-esdhc: don't reconfigure clock unless required
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (22 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 23/30] mci: core: retry MMC_CMD_SET_BLOCKLEN up to 4 times Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 25/30] mci: sdhci: fix sdhci_transfer_data MMC_SEND_TUNING compatibility Ahmad Fatoum
` (6 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The Linux SDHCI driver skips sdhci_ops::set_clock if the clock rate is
not going to change. Let's do the same in barebox with the slight
difference that we also check for whether DDR settings have changed,
because that influences the clock configuration on the eSDHC.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 18a5750ed0ed..2bdd1532fe74 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -226,6 +226,7 @@ static void layerscape_set_timing(struct fsl_esdhc_host *host, enum mci_timing t
static void esdhc_set_ios(struct mci_host *mci, struct mci_ios *ios)
{
struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
+ bool ddr_changed = false;
/*
* call esdhc_set_timing() before update the clock rate,
@@ -235,14 +236,18 @@ static void esdhc_set_ios(struct mci_host *mci, struct mci_ios *ios)
* setting clock rate.
*/
if (host->sdhci.timing != ios->timing) {
+ if (mci_timing_is_ddr(host->sdhci.timing) != mci_timing_is_ddr(ios->timing))
+ ddr_changed = true;
+
if (esdhc_is_usdhc(host))
usdhc_set_timing(host, ios->timing);
else if (esdhc_is_layerscape(host))
layerscape_set_timing(host, ios->timing);
}
- /* Set the clock speed */
- set_sysctl(mci, ios->clock, mci_timing_is_ddr(ios->timing));
+ /* Reconfigure clock if requested speed changes */
+ if (!ios->clock || mci->actual_clock != ios->clock || ddr_changed)
+ set_sysctl(mci, ios->clock, mci_timing_is_ddr(ios->timing));
sdhci_set_drv_type(&host->sdhci, ios->drv_type);
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 25/30] mci: sdhci: fix sdhci_transfer_data MMC_SEND_TUNING compatibility
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (23 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 24/30] mci: imx-esdhc: don't reconfigure clock unless required Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 26/30] mci: core: implement mmc_send_tuning Ahmad Fatoum
` (5 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Depending on whether we are executing a tuning sequence or not, we need
to poll for different status bits. Implement the logic in preparation
for adding HS200 support to the i.MX eSDHC driver.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/sdhci.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 3051354a3076..c8fd78a5e62d 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -291,8 +291,10 @@ void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd,
if (data->flags & MMC_DATA_READ)
*xfer |= SDHCI_DATA_TO_HOST;
- if (dma)
+ if (dma && !mmc_op_tuning(cmd->cmdidx))
*xfer |= SDHCI_DMA_EN;
+ } else if (mmc_op_tuning(cmd->cmdidx)) {
+ *command |= SDHCI_DATA_PRESENT;
}
}
@@ -529,7 +531,7 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_cmd *cmd,
struct device *dev = sdhci_dev(sdhci);
u64 start;
int nbytes;
- u32 irqstat;
+ u32 irqcheck, irqstat;
int ret;
if (!data)
@@ -539,6 +541,10 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_cmd *cmd,
start = get_time_ns();
+ irqcheck = SDHCI_INT_XFER_COMPLETE;
+ if (mmc_op_tuning(cmd->cmdidx))
+ irqcheck = SDHCI_INT_DATA_AVAIL;
+
do {
irqstat = sdhci_read32(sdhci, SDHCI_INT_STATUS);
@@ -575,7 +581,7 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_cmd *cmd,
sdhci_set_sdma_addr(sdhci, ALIGN(dma, SDHCI_DEFAULT_BOUNDARY_SIZE));
}
- if (irqstat & SDHCI_INT_XFER_COMPLETE)
+ if (irqstat & irqcheck)
break;
if (is_timeout(start, 10 * SECOND)) {
@@ -597,12 +603,16 @@ int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_cmd *cmd,
struct mci_data *data)
{
unsigned int block = 0;
- u32 stat, prs;
+ u32 stat, prs, irqcheck;
uint64_t start = get_time_ns();
if (!data)
return 0;
+ irqcheck = SDHCI_INT_XFER_COMPLETE;
+ if (mmc_op_tuning(cmd->cmdidx))
+ irqcheck = SDHCI_INT_DATA_AVAIL;
+
do {
stat = sdhci_read32(sdhci, SDHCI_INT_STATUS);
if (stat & SDHCI_INT_ERROR)
@@ -630,7 +640,7 @@ int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_cmd *cmd,
if (is_timeout(start, 10 * SECOND))
return -ETIMEDOUT;
- } while (!(stat & SDHCI_INT_XFER_COMPLETE));
+ } while (!(stat & irqcheck));
return 0;
}
@@ -822,7 +832,8 @@ int sdhci_wait_idle(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *da
if (data || (cmd && (cmd->resp_type & MMC_RSP_BUSY)))
mask |= SDHCI_CMD_INHIBIT_DATA;
- if (cmd && cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+ if (cmd && (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION ||
+ mmc_op_tuning(cmd->cmdidx)))
mask &= ~SDHCI_CMD_INHIBIT_DATA;
timeout_ns = sdhci_compute_timeout(cmd, data, SDHCI_CMD_DEFAULT_BUSY_TIMEOUT_NS);
@@ -847,7 +858,8 @@ int sdhci_wait_idle_data(struct sdhci *host, struct mci_cmd *cmd)
mask = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA;
timeout_ns = SDHCI_CMD_DEFAULT_BUSY_TIMEOUT_NS;
- if (cmd && cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+ if (cmd && (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION ||
+ mmc_op_tuning(cmd->cmdidx)))
mask &= ~SDHCI_CMD_INHIBIT_DATA;
if (cmd && cmd->busy_timeout != 0)
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 26/30] mci: core: implement mmc_send_tuning
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (24 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 25/30] mci: sdhci: fix sdhci_transfer_data MMC_SEND_TUNING compatibility Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 27/30] mci: imx-esdhc: set burst_length_enable Ahmad Fatoum
` (4 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
For use by drivers that support eMMC standard tuning, add a new
mmc_send_tuning helper that sends 64-128 bytes and checks the result
for bit errors.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-core.c | 78 ++++++++++++++++++++++++++++++++++++++++++
include/mci.h | 1 +
2 files changed, 79 insertions(+)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 5f0fdd2206a5..23cde58c0c5b 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1607,6 +1607,84 @@ int mci_execute_tuning(struct mci *mci)
return host->ops.execute_tuning(host, opcode);
}
+static const u8 tuning_blk_pattern_4bit[] = {
+ 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+ 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+ 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+ 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+ 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+ 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+ 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+ 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+};
+
+static const u8 tuning_blk_pattern_8bit[] = {
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+ 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+ 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+ 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+ 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+ 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+ 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+ 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+ 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+ 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+ 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+ 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+ 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+};
+
+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;
+
+ if (mci->host->ios.bus_width == MMC_BUS_WIDTH_8) {
+ tuning_block_pattern = tuning_blk_pattern_8bit;
+ size = sizeof(tuning_blk_pattern_8bit);
+ } else if (mci->host->ios.bus_width == MMC_BUS_WIDTH_4) {
+ tuning_block_pattern = tuning_blk_pattern_4bit;
+ size = sizeof(tuning_blk_pattern_4bit);
+ } else
+ return -EINVAL;
+
+ data_buf = calloc(size, 1);
+ if (!data_buf)
+ return -ENOMEM;
+
+ mci_setup_cmd(&cmd, opcode, 0, MMC_RSP_R1 | MMC_CMD_ADTC);
+
+
+ data.blocksize = size;
+ data.blocks = 1;
+ 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;
+
+ err = mci_send_cmd(mci, &cmd, &data);
+ if (err)
+ goto out;
+
+ if (memcmp(data_buf, tuning_block_pattern, size))
+ err = -EIO;
+
+out:
+ free(data_buf);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mmc_send_tuning);
+
int mci_send_abort_tuning(struct mci *mci, u32 opcode)
{
struct mci_cmd cmd = {};
diff --git a/include/mci.h b/include/mci.h
index 29aaecb46305..207fb9779a14 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -773,6 +773,7 @@ static inline int mmc_card_hs(struct mci *mci)
*/
int mmc_hs200_tuning(struct mci *mci);
int mci_execute_tuning(struct mci *mci);
+int mmc_send_tuning(struct mci *mci, u32 opcode);
int mci_send_abort_tuning(struct mci *mci, u32 opcode);
int mmc_select_timing(struct mci *mci);
int mci_set_blockcount(struct mci *mci, unsigned int cmdarg);
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 27/30] mci: imx-esdhc: set burst_length_enable
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (25 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 26/30] mci: core: implement mmc_send_tuning Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 28/30] mci: imx-esdhc: fixup quirks in standard SDHCI registers Ahmad Fatoum
` (3 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Linux writes this register unconditionally for all usdhc. As we didn't
seem to be hurt by its lack so far, we will set it only when
tuning support is enabled.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 2bdd1532fe74..00b7e0693fcc 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -347,6 +347,21 @@ static int esdhc_init(struct mci_host *mci, struct device *dev)
(host->socdata->flags & ESDHC_FLAG_STD_TUNING)) {
u32 tmp;
+ /*
+ * ROM code will change the bit burst_length_enable setting
+ * to zero if this usdhc is chosen to boot system. Change
+ * it back here, otherwise it will impact the performance a
+ * lot. This bit is used to enable/disable the burst length
+ * for the external AHB2AXI bridge. It's useful especially
+ * for INCR transfer because without burst length indicator,
+ * the AHB2AXI bridge does not know the burst length in
+ * advance. And without burst length indicator, AHB INCR
+ * transfer can only be converted to singles on the AXI side.
+ */
+ sdhci_write32(&host->sdhci, SDHCI_HOST_CONTROL,
+ sdhci_read32(&host->sdhci, SDHCI_HOST_CONTROL)
+ | ESDHC_BURST_LEN_EN_INCR);
+
/* disable DLL_CTRL delay line settings */
sdhci_write32(&host->sdhci, ESDHC_DLL_CTRL, 0x0);
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 28/30] mci: imx-esdhc: fixup quirks in standard SDHCI registers
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (26 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 27/30] mci: imx-esdhc: set burst_length_enable Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 29/30] mci: sdhci: support Linux SDHCI_QUIRK2_BROKEN_HS200 flag Ahmad Fatoum
` (2 subsequent siblings)
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The eSDHC implementation differs from the spec sufficiently to break the
generic SDHCI tuning support. Linux works around this by intercepting
some particular register reads and faking the content.
Let's begrudgingly do the same for barebox.
Mildly interesting statistic: As of Linux v6.12, the generic SDHCI driver
defines 51 quirk bits and 32 callbacks to handle differences.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc-common.c | 229 +++++++++++++++++++++++++++++++++
drivers/mci/imx-esdhc.h | 30 +++++
drivers/mci/sdhci.h | 1 +
3 files changed, 260 insertions(+)
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index 5fc9b7b30c76..caa8505ac00e 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -23,6 +23,10 @@
#define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25)
#define ESDHC_MIX_CTRL_HS400_EN (1 << 26)
#define ESDHC_MIX_CTRL_HS400_ES_EN (1 << 27)
+/* Bits 3 and 6 are not SDHCI standard definitions */
+#define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7
+/* Tuning bits */
+#define ESDHC_MIX_CTRL_TUNING_MASK 0x03c00000
static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
{
@@ -52,6 +56,224 @@ static void esdhc_op_write16_be(struct sdhci *sdhci, int reg, u16 val)
out_be16(host->sdhci.base + reg, val);
}
+static u16 esdhc_op_read16_le_tuning(struct sdhci *sdhci, int reg)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+ u16 ret = 0;
+ u32 val;
+
+ if (unlikely(reg == SDHCI_HOST_VERSION)) {
+ /*
+ * The usdhc register returns a wrong host version.
+ * Correct it here.
+ */
+ return SDHCI_SPEC_300;
+ }
+
+ if (unlikely(reg == SDHCI_HOST_CONTROL2)) {
+ val = readl(sdhci->base + ESDHC_VENDOR_SPEC);
+ if (val & ESDHC_VENDOR_SPEC_VSELECT)
+ ret |= SDHCI_CTRL_VDD_180;
+
+ if (host->socdata->flags & ESDHC_FLAG_MAN_TUNING)
+ val = readl(sdhci->base + ESDHC_MIX_CTRL);
+ else if (host->socdata->flags & ESDHC_FLAG_STD_TUNING)
+ /* the std tuning bits is in ACMD12_ERR for imx6sl */
+ val = readl(sdhci->base + SDHCI_ACMD12_ERR__HOST_CONTROL2);
+
+ if (val & ESDHC_MIX_CTRL_EXE_TUNE)
+ ret |= SDHCI_CTRL_EXEC_TUNING;
+ if (val & ESDHC_MIX_CTRL_SMPCLK_SEL)
+ ret |= SDHCI_CTRL_TUNED_CLK;
+
+ ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+
+ return ret;
+ }
+
+ if (unlikely(reg == SDHCI_TRANSFER_MODE)) {
+ u32 m = readl(sdhci->base + ESDHC_MIX_CTRL);
+ ret = m & ESDHC_MIX_CTRL_SDHCI_MASK;
+ /* Swap AC23 bit */
+ if (m & ESDHC_MIX_CTRL_AC23EN) {
+ ret &= ~ESDHC_MIX_CTRL_AC23EN;
+ ret |= SDHCI_TRNS_AUTO_CMD23;
+ }
+
+ return ret;
+ }
+
+ return readw(sdhci->base + reg);
+}
+
+static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci *sdhci)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+ u32 present_state;
+ int ret;
+
+ ret = readl_poll_timeout(sdhci->base + ESDHC_PRSSTAT, present_state,
+ (present_state & ESDHC_CLOCK_GATE_OFF), 100);
+ if (ret == -ETIMEDOUT)
+ dev_warn(host->dev, "%s: card clock still not gate off in 100us!.\n", __func__);
+}
+
+static inline void esdhc_clrset_le(struct sdhci *sdhci, u32 mask, u32 val, int reg)
+{
+ void __iomem *base = sdhci->base + (reg & ~0x3);
+ u32 shift = (reg & 0x3) * 8;
+
+ writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
+}
+
+static void esdhc_op_write16_le_tuning(struct sdhci *sdhci, int reg, u16 val)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+ u32 new_val = 0;
+
+ switch (reg) {
+ case SDHCI_CLOCK_CONTROL:
+ new_val = readl(sdhci->base + ESDHC_VENDOR_SPEC);
+ if (val & SDHCI_CLOCK_CARD_EN)
+ new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
+ else
+ new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
+ writel(new_val, sdhci->base + ESDHC_VENDOR_SPEC);
+ if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON))
+ esdhc_wait_for_card_clock_gate_off(sdhci);
+ return;
+ case SDHCI_HOST_CONTROL2:
+ new_val = readl(sdhci->base + ESDHC_VENDOR_SPEC);
+ if (val & SDHCI_CTRL_VDD_180)
+ new_val |= ESDHC_VENDOR_SPEC_VSELECT;
+ else
+ new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
+ writel(new_val, sdhci->base + ESDHC_VENDOR_SPEC);
+ if (host->socdata->flags & ESDHC_FLAG_STD_TUNING) {
+ u32 v = readl(sdhci->base + SDHCI_ACMD12_ERR__HOST_CONTROL2);
+ u32 m = readl(sdhci->base + ESDHC_MIX_CTRL);
+ if (val & SDHCI_CTRL_TUNED_CLK) {
+ v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
+ } else {
+ v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+ m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
+ }
+
+ if (val & SDHCI_CTRL_EXEC_TUNING) {
+ v |= ESDHC_MIX_CTRL_EXE_TUNE;
+ m |= ESDHC_MIX_CTRL_FBCLK_SEL;
+ } else {
+ v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
+ }
+
+ writel(v, sdhci->base + SDHCI_ACMD12_ERR__HOST_CONTROL2);
+ writel(m, sdhci->base + ESDHC_MIX_CTRL);
+ }
+ return;
+ case SDHCI_COMMAND:
+ if (host->last_cmd == MMC_CMD_STOP_TRANSMISSION)
+ val |= SDHCI_COMMAND_CMDTYP_ABORT;
+
+ writel(val << 16,
+ sdhci->base + SDHCI_TRANSFER_MODE);
+ return;
+ case SDHCI_BLOCK_SIZE:
+ val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+ break;
+ }
+ esdhc_clrset_le(sdhci, 0xffff, val, reg);
+}
+
+static u8 esdhc_readb_le(struct sdhci *sdhci, int reg)
+{
+ u8 ret;
+ u8 val;
+
+ switch (reg) {
+ case SDHCI_HOST_CONTROL:
+ val = readl(sdhci->base + reg);
+
+ ret = val & SDHCI_CTRL_LED;
+ ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK;
+ ret |= (val & ESDHC_CTRL_4BITBUS);
+ ret |= (val & ESDHC_CTRL_8BITBUS) << 3;
+ return ret;
+ }
+
+ return readb(sdhci->base + reg);
+}
+
+static void esdhc_writeb_le(struct sdhci *sdhci, int reg, u8 val)
+{
+ u32 new_val = 0;
+ u32 mask;
+
+ switch (reg) {
+ case SDHCI_POWER_CONTROL:
+ /*
+ * FSL put some DMA bits here
+ * If your board has a regulator, code should be here
+ */
+ return;
+ case SDHCI_HOST_CONTROL:
+ /* FSL messed up here, so we need to manually compose it. */
+ new_val = val & SDHCI_CTRL_LED;
+ /* ensure the endianness */
+ new_val |= ESDHC_HOST_CONTROL_LE;
+ /* DMA mode bits are shifted */
+ new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
+
+ /*
+ * Do not touch buswidth bits here. This is done in
+ * esdhc_pltfm_bus_width.
+ * Do not touch the D3CD bit either which is used for the
+ * SDIO interrupt erratum workaround.
+ */
+ mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD);
+
+ esdhc_clrset_le(sdhci, mask, new_val, reg);
+ return;
+ case SDHCI_SOFTWARE_RESET:
+ if (val & SDHCI_RESET_DATA)
+ new_val = readl(sdhci->base + SDHCI_HOST_CONTROL);
+ break;
+ }
+ esdhc_clrset_le(sdhci, 0xff, val, reg);
+
+ if (reg == SDHCI_SOFTWARE_RESET) {
+ if (val & SDHCI_RESET_ALL) {
+ /*
+ * The esdhc has a design violation to SDHC spec which
+ * tells that software reset should not affect card
+ * detection circuit. But esdhc clears its SYSCTL
+ * register bits [0..2] during the software reset. This
+ * will stop those clocks that card detection circuit
+ * relies on. To work around it, we turn the clocks on
+ * back to keep card detection circuit functional.
+ */
+ esdhc_clrset_le(sdhci, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
+ /*
+ * The reset on usdhc fails to clear MIX_CTRL register.
+ * Do it manually here.
+ */
+ /*
+ * the tuning bits should be kept during reset
+ */
+ new_val = readl(sdhci->base + ESDHC_MIX_CTRL);
+ writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK,
+ sdhci->base + ESDHC_MIX_CTRL);
+ } else if (val & SDHCI_RESET_DATA) {
+ /*
+ * The eSDHC DAT line software reset clears at least the
+ * data transfer width on i.MX25, so make sure that the
+ * Host Control register is unaffected.
+ */
+ esdhc_clrset_le(sdhci, 0xff, new_val,
+ SDHCI_HOST_CONTROL);
+ }
+ }
+}
+
void esdhc_populate_sdhci(struct fsl_esdhc_host *host)
{
if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN) {
@@ -59,6 +281,11 @@ void esdhc_populate_sdhci(struct fsl_esdhc_host *host)
host->sdhci.write16 = esdhc_op_write16_be;
host->sdhci.read32 = esdhc_op_read32_be;
host->sdhci.write32 = esdhc_op_write32_be;
+ } else if (esdhc_is_usdhc(host)){
+ host->sdhci.read8 = esdhc_readb_le;
+ host->sdhci.write8 = esdhc_writeb_le;
+ host->sdhci.read16 = esdhc_op_read16_le_tuning;
+ host->sdhci.write16 = esdhc_op_write16_le_tuning;
}
}
@@ -100,6 +327,8 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
dma_addr_t dma = SDHCI_NO_DMA;
int ret;
+ host->last_cmd = cmd ? cmd->cmdidx : 0;
+
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, -1);
/* Wait at least 8 SD clock cycles before the next command */
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index e24d76d0c687..df8aca18ad32 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -66,6 +66,36 @@
#define IMX_SDHCI_DLL_CTRL_OVERRIDE_EN_SHIFT 8
#define IMX_SDHCI_MIX_CTRL_FBCLK_SEL BIT(25)
+/* pltfm-specific */
+#define ESDHC_HOST_CONTROL_LE 0x20
+
+/*
+ * eSDHC register definition
+ */
+
+/* Present State Register */
+#define ESDHC_PRSSTAT 0x24
+#define ESDHC_CLOCK_GATE_OFF 0x00000080
+#define ESDHC_CLOCK_STABLE 0x00000008
+
+/* Protocol Control Register */
+#define ESDHC_PROCTL 0x28
+#define ESDHC_VOLT_SEL 0x00000400
+#define ESDHC_CTRL_4BITBUS (0x1 << 1)
+#define ESDHC_CTRL_8BITBUS (0x2 << 1)
+#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
+#define ESDHC_HOST_CONTROL_RES 0x01
+
+/* System Control Register */
+#define ESDHC_SYSTEM_CONTROL 0x2c
+#define ESDHC_CLOCK_MASK 0x0000fff0
+#define ESDHC_PREDIV_SHIFT 8
+#define ESDHC_DIVIDER_SHIFT 4
+#define ESDHC_CLOCK_SDCLKEN 0x00000008
+#define ESDHC_CLOCK_PEREN 0x00000004
+#define ESDHC_CLOCK_HCKEN 0x00000002
+#define ESDHC_CLOCK_IPGEN 0x00000001
+
/* tune control register */
#define ESDHC_TUNE_CTRL_STATUS 0x68
#define ESDHC_TUNE_CTRL_STEP 1
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index e0436425fbda..038b52cfe619 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -143,6 +143,7 @@
#define SDHCI_CTRL_TUNED_CLK BIT(7)
#define SDHCI_CTRL_64BIT_ADDR BIT(13)
#define SDHCI_CTRL_V4_MODE BIT(12)
+#define SDHCI_CTRL_PRESET_VAL_ENABLE BIT(15)
#define SDHCI_CAPABILITIES 0x40
#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0)
#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 29/30] mci: sdhci: support Linux SDHCI_QUIRK2_BROKEN_HS200 flag
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (27 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 28/30] mci: imx-esdhc: fixup quirks in standard SDHCI registers Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 30/30] mci: imx-esdhc: implement HS200 support Ahmad Fatoum
2025-05-08 7:30 ` [PATCH v2 00/30] mci: imx-esdhc: add " Sascha Hauer
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
In Linux HS200 is opt-out for SDHCI. Let's do the same in barebox.
We intentionally keep MMC_CAP2_HS200 for Arasan, as I have not verified
on the hardware that the SDHCI implementation there correctly reports
SDR104 as supported (which would imply HS200 when used for eMMC).
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/am654-sdhci.c | 3 +++
drivers/mci/arasan-sdhci.c | 3 +++
drivers/mci/dwcmshc-sdhci.c | 2 ++
drivers/mci/imx-esdhc.c | 3 +++
drivers/mci/rockchip-dwcmshc-sdhci.c | 3 +++
drivers/mci/sdhci.c | 32 ++++++++++++++++++++++++++++
drivers/mci/sdhci.h | 4 ++++
7 files changed, 50 insertions(+)
diff --git a/drivers/mci/am654-sdhci.c b/drivers/mci/am654-sdhci.c
index 13c8876573c7..be0a6e09f796 100644
--- a/drivers/mci/am654-sdhci.c
+++ b/drivers/mci/am654-sdhci.c
@@ -638,6 +638,9 @@ static int am654_sdhci_probe(struct device *dev)
if (ret)
return ret;
+ /* HS200 not supported by this driver at the moment */
+ plat->sdhci.quirks2 = SDHCI_QUIRK2_BROKEN_HS200;
+
plat->sdhci.mci = mci;
sdhci_setup_host(&plat->sdhci);
diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index ceef0b63a8b9..4adaaa243d2c 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -773,6 +773,9 @@ static int arasan_sdhci_probe(struct device *dev)
mci->ops.execute_tuning = arasan_zynqmp_execute_tuning;
mci->caps2 |= MMC_CAP2_HS200;
arasan_sdhci->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN;
+ } else {
+ /* HS200 only supported for ZynqMP at the moment */
+ arasan_sdhci->sdhci.quirks2 = SDHCI_QUIRK2_BROKEN_HS200;
}
/*
diff --git a/drivers/mci/dwcmshc-sdhci.c b/drivers/mci/dwcmshc-sdhci.c
index 174cc3f76816..6fdbb61565f2 100644
--- a/drivers/mci/dwcmshc-sdhci.c
+++ b/drivers/mci/dwcmshc-sdhci.c
@@ -325,6 +325,8 @@ static int dwcmshc_probe(struct device *dev)
host->sdhci.base = IOMEM(iores->start);
host->sdhci.mci = mci;
host->sdhci.max_clk = clk_get_rate(clk);
+ /* HS200 not supported by this driver at the moment */
+ host->sdhci.quirks2 = SDHCI_QUIRK2_BROKEN_HS200;
host->cb = dwcmshc_cb;
mci->hw_dev = dev;
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 00b7e0693fcc..4f2f02cfbdbe 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -466,6 +466,9 @@ static int fsl_esdhc_probe(struct device *dev)
host->mci.hw_dev = dev;
host->sdhci.mci = &host->mci;
+ if (!(host->socdata->flags & ESDHC_FLAG_HS200))
+ host->sdhci.quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
+
ret = sdhci_setup_host(&host->sdhci);
if (ret)
goto err_clk_disable;
diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c
index 2f8d5ec140b5..c4c03f703a15 100644
--- a/drivers/mci/rockchip-dwcmshc-sdhci.c
+++ b/drivers/mci/rockchip-dwcmshc-sdhci.c
@@ -341,6 +341,9 @@ static int rk_sdhci_probe(struct device *dev)
mci_of_parse(&host->mci);
+ /* HS200 not supported by this driver at the moment */
+ host->sdhci.quirks2 = SDHCI_QUIRK2_BROKEN_HS200;
+
sdhci_setup_host(&host->sdhci);
dev->priv = host;
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index c8fd78a5e62d..17847a13ed5f 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -1044,6 +1044,38 @@ int sdhci_setup_host(struct sdhci *host)
if (sdhci_can_64bit_dma(host))
host->flags |= SDHCI_USE_64_BIT_DMA;
+ if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
+ host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
+ SDHCI_SUPPORT_DDR50);
+ /*
+ * The SDHCI controller in a SoC might support HS200/HS400
+ * (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property),
+ * but if the board is modeled such that the IO lines are not
+ * connected to 1.8v then HS200/HS400 cannot be supported.
+ * Disable HS200/HS400 if the board does not have 1.8v connected
+ * to the IO lines. (Applicable for other modes in 1.8v)
+ */
+ mci->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES);
+ mci->host_caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS);
+ }
+
+ /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
+ if (host->caps1 & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
+ SDHCI_SUPPORT_DDR50))
+ mci->host_caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
+
+ /* SDR104 supports also implies SDR50 support */
+ if (host->caps1 & SDHCI_SUPPORT_SDR104) {
+ mci->host_caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
+ /* SD3.0: SDR104 is supported so (for eMMC) the caps2
+ * field can be promoted to support HS200.
+ */
+ if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200))
+ mci->caps2 |= MMC_CAP2_HS200;
+ } else if (host->caps1 & SDHCI_SUPPORT_SDR50) {
+ mci->host_caps |= MMC_CAP_UHS_SDR50;
+ }
+
if ((mci->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)))
host->flags |= SDHCI_SIGNALING_180;
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 038b52cfe619..25d257b23145 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -249,6 +249,10 @@ struct sdhci {
unsigned int quirks;
#define SDHCI_QUIRK_MISSING_CAPS BIT(27)
unsigned int quirks2;
+/* The system physically doesn't support 1.8v, even if the host does */
+#define SDHCI_QUIRK2_NO_1_8_V BIT(2)
+/* Controller does not support HS200 */
+#define SDHCI_QUIRK2_BROKEN_HS200 BIT(6)
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN BIT(15)
#define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER BIT(19)
u32 caps; /* CAPABILITY_0 */
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 30/30] mci: imx-esdhc: implement HS200 support
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (28 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 29/30] mci: sdhci: support Linux SDHCI_QUIRK2_BROKEN_HS200 flag Ahmad Fatoum
@ 2025-05-07 8:22 ` Ahmad Fatoum
2025-05-08 7:30 ` [PATCH v2 00/30] mci: imx-esdhc: add " Sascha Hauer
30 siblings, 0 replies; 32+ messages in thread
From: Ahmad Fatoum @ 2025-05-07 8:22 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Now everything is in place, so we can actually implement execute_tuning
for i.MX6SL or later. i.MX6Q would be possible as well, but that
requires a different manual tuning scheme which was not ported here.
Comparison copying 64M off a Samsung 8GTF4R eMMC on an i.MX8MP.
Before:
imx8mp-ddr52: time cp /dev/mmc2.2 .
time: 884ms
After:
imx8mp-hs200: time cp /dev/mmc2.2 .
time: 488ms
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/imx-esdhc-common.c | 8 +-
drivers/mci/imx-esdhc.c | 153 ++++++++++++++++++++++++++++++++-
2 files changed, 157 insertions(+), 4 deletions(-)
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index caa8505ac00e..228f4a9b03fe 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -323,7 +323,7 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
struct mci_data *data)
{
u32 xfertyp, mixctrl, command;
- u32 val, irqstat;
+ u32 val, irqflags, irqstat;
dma_addr_t dma = SDHCI_NO_DMA;
int ret;
@@ -363,9 +363,13 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
sdhci_write32(&host->sdhci, SDHCI_TRANSFER_MODE__COMMAND,
command << 16 | xfertyp);
+ irqflags = SDHCI_INT_CMD_COMPLETE;
+ if (mmc_op_tuning(cmd->cmdidx))
+ irqflags = SDHCI_INT_DATA_AVAIL;
+
/* Wait for the command to complete */
ret = esdhc_poll(host, SDHCI_INT_STATUS, irqstat,
- irqstat & SDHCI_INT_CMD_COMPLETE,
+ irqstat & irqflags,
100 * MSECOND);
if (ret) {
dev_dbg(host->dev, "timeout 1\n");
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 4f2f02cfbdbe..c6547d94a4f9 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -61,6 +61,14 @@
#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz"
#define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz"
+/*
+ * Our interpretation of the SDHCI_HOST_CONTROL register
+ */
+#define ESDHC_CTRL_4BITBUS (0x1 << 1)
+#define ESDHC_CTRL_8BITBUS (0x2 << 1)
+#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
+#define USDHC_GET_BUSWIDTH(c) (c & ESDHC_CTRL_BUSWIDTH_MASK)
+
#define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci)
/*
@@ -137,6 +145,104 @@ static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr)
10 * MSECOND);
}
+static inline void esdhc_clrset_le(struct fsl_esdhc_host *host,
+ u32 mask, u32 val, int reg)
+{
+ void __iomem *base = host->sdhci.base + (reg & ~0x3);
+ u32 shift = (reg & 0x3) * 8;
+
+ writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
+}
+
+/* Enable the auto tuning circuit to check the CMD line and BUS line */
+static inline void usdhc_auto_tuning_mode_sel_and_en(struct fsl_esdhc_host *host)
+{
+ u32 buswidth, auto_tune_buswidth;
+ u32 reg;
+
+ buswidth = USDHC_GET_BUSWIDTH(sdhci_read32(&host->sdhci, SDHCI_HOST_CONTROL));
+
+ switch (buswidth) {
+ case ESDHC_CTRL_8BITBUS:
+ auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN;
+ break;
+ case ESDHC_CTRL_4BITBUS:
+ auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN;
+ break;
+ default: /* 1BITBUS */
+ auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN;
+ break;
+ }
+
+ esdhc_clrset_le(host, ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK,
+ auto_tune_buswidth | ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN,
+ ESDHC_VEND_SPEC2);
+
+ reg = sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL);
+ reg |= MIX_CTRL_AUTO_TUNE_EN;
+ sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, reg);
+}
+
+static void esdhc_reset_tuning(struct fsl_esdhc_host *host)
+{
+ u32 ctrl;
+ int ret;
+
+ /* Reset the tuning circuit */
+ if (esdhc_is_usdhc(host)) {
+ ctrl = sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL);
+ ctrl &= ~MIX_CTRL_AUTO_TUNE_EN;
+ if (host->socdata->flags & ESDHC_FLAG_STD_TUNING) {
+ sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, ctrl);
+ ctrl = sdhci_read32(&host->sdhci, SDHCI_ACMD12_ERR__HOST_CONTROL2);
+ ctrl &= ~MIX_CTRL_SMPCLK_SEL;
+ ctrl &= ~MIX_CTRL_EXE_TUNE;
+ sdhci_write32(&host->sdhci, SDHCI_ACMD12_ERR__HOST_CONTROL2, ctrl);
+ /* Make sure MIX_CTRL_EXE_TUNE cleared */
+ ret = sdhci_read32_poll_timeout(&host->sdhci, SDHCI_ACMD12_ERR__HOST_CONTROL2,
+ ctrl, !(ctrl & MIX_CTRL_EXE_TUNE), 50);
+ if (ret == -ETIMEDOUT)
+ dev_warn(host->dev,
+ "Warning! clear execute tuning bit failed\n");
+ /*
+ * SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the
+ * usdhc IP internal logic flag execute_tuning_with_clr_buf, which
+ * will finally make sure the normal data transfer logic correct.
+ */
+ ctrl = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
+ ctrl |= SDHCI_INT_DATA_AVAIL;
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ctrl);
+ }
+ }
+}
+
+static int usdhc_execute_tuning(struct mci_host *mci, u32 opcode)
+{
+ struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
+ int err;
+
+ /*
+ * i.MX uSDHC internally already uses a fixed optimized timing for
+ * DDR50, normally does not require tuning for DDR50 mode.
+ */
+ if (host->sdhci.timing == MMC_TIMING_UHS_DDR50)
+ return 0;
+
+ /*
+ * Reset tuning circuit logic. If not, the previous tuning result
+ * will impact current tuning, make current tuning can't set the
+ * correct delay cell.
+ */
+ esdhc_reset_tuning(host);
+
+ err = sdhci_execute_tuning(&host->sdhci, opcode);
+ /* If tuning done, enable auto tuning */
+ if (!err)
+ usdhc_auto_tuning_mode_sel_and_en(host);
+
+ return err;
+}
+
static int esdhc_change_pinstate(struct fsl_esdhc_host *host,
unsigned int uhs)
{
@@ -190,8 +296,18 @@ static void usdhc_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing
sdhci_write32(&host->sdhci, IMX_SDHCI_DLL_CTRL, v);
}
break;
- default:
+ case MMC_TIMING_UHS_SDR12:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_MMC_HS200:
sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl);
+ break;
+ case MMC_TIMING_LEGACY:
+ default:
+ esdhc_reset_tuning(host);
+ break;
}
esdhc_change_pinstate(host, timing);
@@ -421,6 +537,39 @@ static void fsl_esdhc_probe_dt(struct device *dev, struct fsl_esdhc_host *host)
}
}
+static bool usdhc_setup_tuning(struct fsl_esdhc_host *host)
+{
+ struct mci_host *mci = &host->mci;
+
+ if (!IS_ENABLED(CONFIG_MCI_TUNING) || !esdhc_is_usdhc(host))
+ return false;
+
+ /*
+ * clear tuning bits in case ROM has set it already
+ * We use writel, because we haven't set up SDHCI yet
+ */
+ writel(0x0, host->sdhci.base + IMX_SDHCI_MIXCTRL);
+ writel(0x0, host->sdhci.base + SDHCI_ACMD12_ERR__HOST_CONTROL2);
+ writel(0x0, host->sdhci.base + ESDHC_TUNE_CTRL_STATUS);
+
+ if (!(host->socdata->flags & ESDHC_FLAG_HS200))
+ return false;
+
+ if (host->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
+ dev_dbg(host->dev, "i.MX6Q manual tuning not supported\n");
+ return false;
+ }
+
+ /*
+ * Link usdhc specific mmc_host_ops execute_tuning function,
+ * to replace the standard one in sdhci_ops.
+ */
+ mci->ops.execute_tuning = usdhc_execute_tuning;
+ mci->caps2 |= MMC_CAP2_HS200;
+
+ return true;
+}
+
static int fsl_esdhc_probe(struct device *dev)
{
struct resource *iores;
@@ -466,7 +615,7 @@ static int fsl_esdhc_probe(struct device *dev)
host->mci.hw_dev = dev;
host->sdhci.mci = &host->mci;
- if (!(host->socdata->flags & ESDHC_FLAG_HS200))
+ if (!usdhc_setup_tuning(host))
host->sdhci.quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
ret = sdhci_setup_host(&host->sdhci);
--
2.39.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 00/30] mci: imx-esdhc: add HS200 support
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
` (29 preceding siblings ...)
2025-05-07 8:22 ` [PATCH v2 30/30] mci: imx-esdhc: implement HS200 support Ahmad Fatoum
@ 2025-05-08 7:30 ` Sascha Hauer
30 siblings, 0 replies; 32+ messages in thread
From: Sascha Hauer @ 2025-05-08 7:30 UTC (permalink / raw)
To: barebox, Ahmad Fatoum
On Wed, 07 May 2025 10:21:39 +0200, Ahmad Fatoum wrote:
> On my i.MX8MP board this increases sequential read nearly from
> 72 MiB/s to 131 MiB/s.
>
> I also got HS400ES running, but it gives me occasional CRC errors, so
> this series only concerns itself with HS200 for now.
>
> v1 -> v2:
> - use correct speed comparison in commit message. v1 had KASAN
> and DMA_API_DEBUG enabled..
> - define and use new sdhci_compute_timeout helper (Sascha)
> - remove superfluous comment about clearing bits (Sascha)
> - always populate delay settings in boarddata (Sascha)
> - reduce number of Linux SDHCI quirks mentioned in commit
> message to 51 (Sascha)
>
> [...]
Applied, thanks!
[01/30] mci: sdhci: fix SDHCI_TRNS_AUTO_CMD12 definition
https://git.pengutronix.de/cgit/barebox/commit/?id=3854b61a6eb2 (link may not be stable)
[02/30] mci: move most recent I/O settings into mci_host::ios
https://git.pengutronix.de/cgit/barebox/commit/?id=365b66461683 (link may not be stable)
[03/30] mci: use struct mci_host::ios inside mci_set_ios
https://git.pengutronix.de/cgit/barebox/commit/?id=103d060182d0 (link may not be stable)
[04/30] mci: tuning: fix fallback to DDR52
https://git.pengutronix.de/cgit/barebox/commit/?id=3cf0ddbd3f19 (link may not be stable)
[05/30] mci: sdhci: unmap DMA buffers on timeout
https://git.pengutronix.de/cgit/barebox/commit/?id=ce6ff8b4be4d (link may not be stable)
[06/30] mci: add MMC_CAP_UHS constants
https://git.pengutronix.de/cgit/barebox/commit/?id=88f55d158d33 (link may not be stable)
[07/30] mci: rename MMC_CAP_MMC_x_yV_DDR to MMC_CAP_x_yV_DDR as in Linux
https://git.pengutronix.de/cgit/barebox/commit/?id=b8b702948038 (link may not be stable)
[08/30] mci: compare host and card caps for supported speeds
https://git.pengutronix.de/cgit/barebox/commit/?id=a242a89a274f (link may not be stable)
[09/30] mci: print HS200 capabilities in devinfo
https://git.pengutronix.de/cgit/barebox/commit/?id=d3882ad438fc (link may not be stable)
[10/30] mci: respect no-1-8-v OF property
https://git.pengutronix.de/cgit/barebox/commit/?id=50c62ba74801 (link may not be stable)
[11/30] mci: sdhci: add support for struct mci_data::timeout_ns
https://git.pengutronix.de/cgit/barebox/commit/?id=bbecd0b7bb7e (link may not be stable)
[12/30] mci: imx-esdhc: use unsigned types where appropriate
https://git.pengutronix.de/cgit/barebox/commit/?id=e535fc5d3e83 (link may not be stable)
[13/30] mci: imx-esdhc: implement esdhc_poll using sdhci_read32_poll_timeout
https://git.pengutronix.de/cgit/barebox/commit/?id=02986964885c (link may not be stable)
[14/30] mci: imx-esdhc: drop one extra read of SDHCI_INT_STATUS
https://git.pengutronix.de/cgit/barebox/commit/?id=a1aa6df5f81f (link may not be stable)
[15/30] mci: sdhci: add cmd parameter to sdhci_transfer_*
https://git.pengutronix.de/cgit/barebox/commit/?id=f35385a1ccaa (link may not be stable)
[16/30] mci: arasan: introduce mmc_op_tuning helper
https://git.pengutronix.de/cgit/barebox/commit/?id=60c69c089fee (link may not be stable)
[17/30] mci: imx-esdhc: flesh out register description
https://git.pengutronix.de/cgit/barebox/commit/?id=a92af4b8188b (link may not be stable)
[18/30] mci: imx-esdhc: add support for delay/tuning properties in DT
https://git.pengutronix.de/cgit/barebox/commit/?id=fadd0942f11d (link may not be stable)
[19/30] mci: add mci_set_timing helper
https://git.pengutronix.de/cgit/barebox/commit/?id=663eb4f5b8df (link may not be stable)
[20/30] mci: imx-esdhc: add support for setting drive strength
https://git.pengutronix.de/cgit/barebox/commit/?id=ab10a18526e1 (link may not be stable)
[21/30] mci: sdhci: move SDHCI_MAKE_BLKSZ definition to header
https://git.pengutronix.de/cgit/barebox/commit/?id=f37f0ab77c79 (link may not be stable)
[22/30] mci: imx-esdhc: select different pinctrl state depending on frequency
https://git.pengutronix.de/cgit/barebox/commit/?id=8395625eec32 (link may not be stable)
[23/30] mci: core: retry MMC_CMD_SET_BLOCKLEN up to 4 times
https://git.pengutronix.de/cgit/barebox/commit/?id=3f1a9f9037e4 (link may not be stable)
[24/30] mci: imx-esdhc: don't reconfigure clock unless required
https://git.pengutronix.de/cgit/barebox/commit/?id=fe803b9faaf8 (link may not be stable)
[25/30] mci: sdhci: fix sdhci_transfer_data MMC_SEND_TUNING compatibility
https://git.pengutronix.de/cgit/barebox/commit/?id=12d4384a64cc (link may not be stable)
[26/30] mci: core: implement mmc_send_tuning
https://git.pengutronix.de/cgit/barebox/commit/?id=8adfce51b38d (link may not be stable)
[27/30] mci: imx-esdhc: set burst_length_enable
https://git.pengutronix.de/cgit/barebox/commit/?id=30a7d2c657fa (link may not be stable)
[28/30] mci: imx-esdhc: fixup quirks in standard SDHCI registers
https://git.pengutronix.de/cgit/barebox/commit/?id=cb831446eb5f (link may not be stable)
[29/30] mci: sdhci: support Linux SDHCI_QUIRK2_BROKEN_HS200 flag
https://git.pengutronix.de/cgit/barebox/commit/?id=72a71ebb5f91 (link may not be stable)
[30/30] mci: imx-esdhc: implement HS200 support
https://git.pengutronix.de/cgit/barebox/commit/?id=bfcae5ddd3d3 (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2025-05-08 7:35 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-07 8:21 [PATCH v2 00/30] mci: imx-esdhc: add HS200 support Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 01/30] mci: sdhci: fix SDHCI_TRNS_AUTO_CMD12 definition Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 02/30] mci: move most recent I/O settings into mci_host::ios Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 03/30] mci: use struct mci_host::ios inside mci_set_ios Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 04/30] mci: tuning: fix fallback to DDR52 Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 05/30] mci: sdhci: unmap DMA buffers on timeout Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 06/30] mci: add MMC_CAP_UHS constants Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 07/30] mci: rename MMC_CAP_MMC_x_yV_DDR to MMC_CAP_x_yV_DDR as in Linux Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 08/30] mci: compare host and card caps for supported speeds Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 09/30] mci: print HS200 capabilities in devinfo Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 10/30] mci: respect no-1-8-v OF property Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 11/30] mci: sdhci: add support for struct mci_data::timeout_ns Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 12/30] mci: imx-esdhc: use unsigned types where appropriate Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 13/30] mci: imx-esdhc: implement esdhc_poll using sdhci_read32_poll_timeout Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 14/30] mci: imx-esdhc: drop one extra read of SDHCI_INT_STATUS Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 15/30] mci: sdhci: add cmd parameter to sdhci_transfer_* Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 16/30] mci: arasan: introduce mmc_op_tuning helper Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 17/30] mci: imx-esdhc: flesh out register description Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 18/30] mci: imx-esdhc: add support for delay/tuning properties in DT Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 19/30] mci: add mci_set_timing helper Ahmad Fatoum
2025-05-07 8:21 ` [PATCH v2 20/30] mci: imx-esdhc: add support for setting drive strength Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 21/30] mci: sdhci: move SDHCI_MAKE_BLKSZ definition to header Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 22/30] mci: imx-esdhc: select different pinctrl state depending on frequency Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 23/30] mci: core: retry MMC_CMD_SET_BLOCKLEN up to 4 times Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 24/30] mci: imx-esdhc: don't reconfigure clock unless required Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 25/30] mci: sdhci: fix sdhci_transfer_data MMC_SEND_TUNING compatibility Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 26/30] mci: core: implement mmc_send_tuning Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 27/30] mci: imx-esdhc: set burst_length_enable Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 28/30] mci: imx-esdhc: fixup quirks in standard SDHCI registers Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 29/30] mci: sdhci: support Linux SDHCI_QUIRK2_BROKEN_HS200 flag Ahmad Fatoum
2025-05-07 8:22 ` [PATCH v2 30/30] mci: imx-esdhc: implement HS200 support Ahmad Fatoum
2025-05-08 7:30 ` [PATCH v2 00/30] mci: imx-esdhc: add " Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox