* [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver
@ 2026-10-02 21:29 Dave Klotz
2026-10-02 21:29 ` [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
` (4 more replies)
0 siblings, 5 replies; 33+ messages in thread
From: Dave Klotz @ 2026-10-02 21:29 UTC (permalink / raw)
To: u-boot
Cc: Huan Zhou, Eric Chung, Peng Fan, Jaehoon Chung, Tanmay Kathpalia,
Yixun Lan, Tom Rini, u-boot-spacemit
Three fixes for the K1 SDHCI driver that went into next with
"mmc: k1: add sdhci platform driver":
1. A node without max-frequency asks the clock framework for 0 Hz and
then fails in sdhci_setup_cfg(), and any non-zero return from
clk_set_rate() is treated as an error although it returns the rate.
2. The SPL reads SD cards one block per command, about 2000 commands
for a 1 MiB u-boot.itb. Multi-block PIO reads work in the SPL.
3. A failed probe releases the clock and reset bulks, whose first
entries are the SDH AXI clock and reset shared by all three
controllers. One controller failing then hangs the next access to
another. Patch 1 removes the trigger I hit, but the error path
should not stop the other controllers either way.
Tested on an OrangePi RV2 (upstream k1-orangepi-rv2.dts plus a board
-u-boot.dtsi and defconfig I will post separately): SPL boot from
microSD with multi-block reads, both SDHCI controllers probing in
U-Boot proper, and an EFI boot of FreeBSD from there. Before patch 3,
with the RV2's eMMC node lacking max-frequency, U-Boot hung at "MMC:".
On an OrangePi R2S booting from eMMC, the io clock change in probe
only takes effect with "clk: spacemit: ccu_mix: fix inverted condition
in ccu_mix_trigger_fc()" from the K3 clock series applied.
Dave Klotz (3):
mmc: k1: handle a missing max-frequency and clk_set_rate()'s return
value
mmc: k1: let the SPL read SD cards more than one block at a time
mmc: k1: do not release the shared AXI clock and reset on probe
failure
drivers/mmc/spacemit_sdhci.c | 45 ++++++++++++++++++++++--------------
1 file changed, 28 insertions(+), 17 deletions(-)
base-commit: a000f2af240eaa996cec92f8d44bad96fdf3f898
--
2.55.0
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value
2026-10-02 21:29 [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver Dave Klotz
@ 2026-10-02 21:29 ` Dave Klotz
2026-10-04 9:14 ` Kathpalia, Tanmay
2026-10-04 9:30 ` Kathpalia, Tanmay
2026-10-02 21:29 ` [PATCH 2/3] mmc: k1: let the SPL read SD cards more than one block at a time Dave Klotz
` (3 subsequent siblings)
4 siblings, 2 replies; 33+ messages in thread
From: Dave Klotz @ 2026-10-02 21:29 UTC (permalink / raw)
To: u-boot
Cc: Huan Zhou, Eric Chung, Peng Fan, Jaehoon Chung, Tanmay Kathpalia,
Yixun Lan, Tom Rini, u-boot-spacemit
The driver sets the io clock to the max-frequency the device tree gives
and fails the probe on any non-zero return from clk_set_rate(). Two
problems follow:
- clk_set_rate() returns the new rate on success and a negative error
code on failure. The SpacemiT clock driver happens to return 0, but
any clock driver that reports the rate makes the probe fail.
- A node without max-frequency asks for 0 Hz. On the K1 clock driver
that picks no divider at all and writes whatever the calculation left
behind into the io clock's divider field; host->max_clk is then 0,
the capabilities register gives no base clock either, and the probe
fails in sdhci_setup_cfg().
Treat only a negative return as an error. Without max-frequency, leave
the io clock as an earlier stage set it and run from its current rate.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
---
drivers/mmc/spacemit_sdhci.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
index f5578f38bd..bbd49b76c6 100644
--- a/drivers/mmc/spacemit_sdhci.c
+++ b/drivers/mmc/spacemit_sdhci.c
@@ -606,10 +606,28 @@ static int spacemit_sdhci_probe(struct udevice *dev)
goto err_reset;
}
- ret = clk_set_rate(&clk, plat->cfg.f_max);
- if (ret) {
- log_err("Failed to set io clk: %d\n", ret);
- goto err_reset;
+ /*
+ * Without max-frequency there is no rate to ask for: leave the io
+ * clock as an earlier stage set it and run from its current rate. The
+ * capabilities register gives no base clock on the K1, so it cannot
+ * stand in. clk_set_rate() returns the new rate on success, so only a
+ * negative value is an error.
+ */
+ if (plat->cfg.f_max) {
+ long rate = clk_set_rate(&clk, plat->cfg.f_max);
+
+ if (rate < 0) {
+ ret = rate;
+ log_err("Failed to set io clk: %d\n", ret);
+ goto err_reset;
+ }
+ } else {
+ plat->cfg.f_max = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(plat->cfg.f_max) || !plat->cfg.f_max) {
+ ret = -EINVAL;
+ log_err("No max-frequency and no io clk rate\n");
+ goto err_reset;
+ }
}
/* Set quirks */
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-02 21:29 [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver Dave Klotz
2026-10-02 21:29 ` [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
@ 2026-10-02 21:29 ` Dave Klotz
2026-10-04 9:28 ` Kathpalia, Tanmay
2026-10-02 21:29 ` [PATCH 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure Dave Klotz
` (2 subsequent siblings)
4 siblings, 1 reply; 33+ messages in thread
From: Dave Klotz @ 2026-10-02 21:29 UTC (permalink / raw)
To: u-boot
Cc: Huan Zhou, Eric Chung, Peng Fan, Jaehoon Chung, Tanmay Kathpalia,
Yixun Lan, Tom Rini, u-boot-spacemit
spacemit_sdhci_get_b_max() limits every SD read in the SPL to a single
block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
separate commands. The controller handles multi-block PIO reads in the
SPL: the OrangePi RV2 has loaded U-Boot from microSD with them through
the v2026.07 and v2026.10 trees.
Drop the limit and use the host's b_max.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
---
drivers/mmc/spacemit_sdhci.c | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
index bbd49b76c6..fec95e3bd7 100644
--- a/drivers/mmc/spacemit_sdhci.c
+++ b/drivers/mmc/spacemit_sdhci.c
@@ -324,16 +324,6 @@ static int spacemit_sdhci_wait_dat0(struct udevice *dev, int state,
return 0;
}
-static int spacemit_sdhci_get_b_max(struct udevice *dev, void *dst,
- lbaint_t blkcnt)
-{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
-
- if (IS_ENABLED(CONFIG_SPL_BUILD) && mmc && IS_SD(mmc))
- return 1;
- return mmc->cfg->b_max;
-}
-
static void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
{
struct mmc *mmc = host->mmc;
@@ -574,7 +564,6 @@ static int spacemit_sdhci_probe(struct udevice *dev)
spacemit_mmc_ops = sdhci_ops;
spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
- spacemit_mmc_ops.get_b_max = spacemit_sdhci_get_b_max;
ret = clk_get_bulk(dev, &plat->clks);
if (ret) {
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure
2026-10-02 21:29 [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver Dave Klotz
2026-10-02 21:29 ` [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
2026-10-02 21:29 ` [PATCH 2/3] mmc: k1: let the SPL read SD cards more than one block at a time Dave Klotz
@ 2026-10-02 21:29 ` Dave Klotz
2026-10-04 9:28 ` Kathpalia, Tanmay
2026-10-02 22:06 ` [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver Dave Klotz
2026-10-05 17:50 ` [PATCH v2 " Dave Klotz
4 siblings, 1 reply; 33+ messages in thread
From: Dave Klotz @ 2026-10-02 21:29 UTC (permalink / raw)
To: u-boot
Cc: Huan Zhou, Eric Chung, Peng Fan, Jaehoon Chung, Tanmay Kathpalia,
Yixun Lan, Tom Rini, u-boot-spacemit
When the probe fails, the driver releases its clock and reset bulks.
clk_release_bulk() disables every clock and reset_release_bulk()
asserts every reset, and the first entry of each is the SDH AXI bus
clock and reset, which all three SDHCI controllers of the K1 share.
One controller failing to probe therefore stops the bus of the others,
and the next register access to any of them hangs the hart. On an
OrangePi RV2, whose device tree enables the eMMC controller without a
max-frequency, the eMMC probe failed in sdhci_setup_cfg() and U-Boot
then hung at "MMC:" probing the microSD controller.
Keep the clocks running and the resets deasserted on failure.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
---
drivers/mmc/spacemit_sdhci.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
index fec95e3bd7..c191d78067 100644
--- a/drivers/mmc/spacemit_sdhci.c
+++ b/drivers/mmc/spacemit_sdhci.c
@@ -640,10 +640,14 @@ static int spacemit_sdhci_probe(struct udevice *dev)
spacemit_sdhci_phy_init(dev, host);
return 0;
+ /*
+ * Leave the clocks and resets alone on failure. The "core" clock and
+ * the "axi" reset are the AXI clock and reset that every SDHCI
+ * controller of the K1 shares: releasing them would gate the bus of
+ * the other controllers, and the next access to one of them hangs.
+ */
err_reset:
- reset_release_bulk(&plat->resets);
err_clk:
- clk_release_bulk(&plat->clks);
return ret;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver
2026-10-02 21:29 [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver Dave Klotz
` (2 preceding siblings ...)
2026-10-02 21:29 ` [PATCH 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure Dave Klotz
@ 2026-10-02 22:06 ` Dave Klotz
2026-10-05 17:50 ` [PATCH v2 " Dave Klotz
4 siblings, 0 replies; 33+ messages in thread
From: Dave Klotz @ 2026-10-02 22:06 UTC (permalink / raw)
To: u-boot
Cc: Huan Zhou, Eric Chung, Peng Fan, Jaehoon Chung, Tanmay Kathpalia,
Yixun Lan, Tom Rini
Also tested on an OrangePi R2S (K1, 2 GiB, boots from eMMC), with the
same tree as the RV2 runs (upstream next plus these series and board
support that is not posted yet):
- the SPL starts the eMMC (SDH2, io clock moved from the BootROM's
409.6 MHz to 204.8 MHz through max-frequency) and loads U-Boot;
- U-Boot proper runs the eMMC in HS200 with tuning ("Mode: HS200
(200MHz)"), finds the EFI system partition and boots FreeBSD;
- FreeBSD then runs the eMMC at 200 MHz, 8-bit, without errors.
Patch 2 (SD only) and the failure path of patch 3 are not exercised on
this board.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value
2026-10-02 21:29 ` [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
@ 2026-10-04 9:14 ` Kathpalia, Tanmay
2026-10-04 9:30 ` Kathpalia, Tanmay
1 sibling, 0 replies; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-04 9:14 UTC (permalink / raw)
To: Dave Klotz, u-boot
Cc: Huan Zhou, Eric Chung, Peng Fan, Jaehoon Chung, Yixun Lan,
Tom Rini, u-boot-spacemit
On 03-10-2026 02:59, Dave Klotz wrote:
> The driver sets the io clock to the max-frequency the device tree gives
> and fails the probe on any non-zero return from clk_set_rate(). Two
> problems follow:
>
> - clk_set_rate() returns the new rate on success and a negative error
> code on failure. The SpacemiT clock driver happens to return 0, but
> any clock driver that reports the rate makes the probe fail.
> - A node without max-frequency asks for 0 Hz. On the K1 clock driver
> that picks no divider at all and writes whatever the calculation left
> behind into the io clock's divider field; host->max_clk is then 0,
> the capabilities register gives no base clock either, and the probe
> fails in sdhci_setup_cfg().
>
> Treat only a negative return as an error. Without max-frequency, leave
> the io clock as an earlier stage set it and run from its current rate.
>
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
> ---
> drivers/mmc/spacemit_sdhci.c | 26 ++++++++++++++++++++++----
> 1 file changed, 22 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> index f5578f38bd..bbd49b76c6 100644
> --- a/drivers/mmc/spacemit_sdhci.c
> +++ b/drivers/mmc/spacemit_sdhci.c
> @@ -606,10 +606,28 @@ static int spacemit_sdhci_probe(struct udevice *dev)
> goto err_reset;
> }
>
> - ret = clk_set_rate(&clk, plat->cfg.f_max);
> - if (ret) {
> - log_err("Failed to set io clk: %d\n", ret);
> - goto err_reset;
> + /*
> + * Without max-frequency there is no rate to ask for: leave the io
> + * clock as an earlier stage set it and run from its current rate. The
> + * capabilities register gives no base clock on the K1, so it cannot
> + * stand in. clk_set_rate() returns the new rate on success, so only a
> + * negative value is an error.
> + */
> + if (plat->cfg.f_max) {
> + long rate = clk_set_rate(&clk, plat->cfg.f_max);
The clock API returns ulong; please use ulong rate with
IS_ERR_VALUE(rate) for consistency.
> +
> + if (rate < 0) {
> + ret = rate;
> + log_err("Failed to set io clk: %d\n", ret);
> + goto err_reset;
> + }
> + } else {
> + plat->cfg.f_max = clk_get_rate(&clk);
clk_get_rate() returns ulong, but f_max is uint. On RV64, assigning a
negative error first truncates it, so IS_ERR_VALUE(f_max) no longer
detects the error. Please validate the ulong rate before assigning it:
rate = clk_get_rate(&clk);
if (IS_ERR_VALUE(rate) || !rate) {
ret = rate ? (int)rate : -EINVAL;
goto err_reset;
}
plat->cfg.f_max = rate;
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-02 21:29 ` [PATCH 2/3] mmc: k1: let the SPL read SD cards more than one block at a time Dave Klotz
@ 2026-10-04 9:28 ` Kathpalia, Tanmay
0 siblings, 0 replies; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-04 9:28 UTC (permalink / raw)
To: Dave Klotz, u-boot
Cc: Huan Zhou, Eric Chung, Peng Fan, Jaehoon Chung, Yixun Lan,
Tom Rini, u-boot-spacemit
On 03-10-2026 02:59, Dave Klotz wrote:
> spacemit_sdhci_get_b_max() limits every SD read in the SPL to a single
> block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
> separate commands. The controller handles multi-block PIO reads in the
> SPL: the OrangePi RV2 has loaded U-Boot from microSD with them through
> the v2026.07 and v2026.10 trees.
>
> Drop the limit and use the host's b_max.
>
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure
2026-10-02 21:29 ` [PATCH 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure Dave Klotz
@ 2026-10-04 9:28 ` Kathpalia, Tanmay
0 siblings, 0 replies; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-04 9:28 UTC (permalink / raw)
To: Dave Klotz, u-boot
Cc: Huan Zhou, Eric Chung, Peng Fan, Jaehoon Chung, Yixun Lan,
Tom Rini, u-boot-spacemit
On 03-10-2026 02:59, Dave Klotz wrote:
> When the probe fails, the driver releases its clock and reset bulks.
> clk_release_bulk() disables every clock and reset_release_bulk()
> asserts every reset, and the first entry of each is the SDH AXI bus
> clock and reset, which all three SDHCI controllers of the K1 share.
>
> One controller failing to probe therefore stops the bus of the others,
> and the next register access to any of them hangs the hart. On an
> OrangePi RV2, whose device tree enables the eMMC controller without a
> max-frequency, the eMMC probe failed in sdhci_setup_cfg() and U-Boot
> then hung at "MMC:" probing the microSD controller.
>
> Keep the clocks running and the resets deasserted on failure.
>
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value
2026-10-02 21:29 ` [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
2026-10-04 9:14 ` Kathpalia, Tanmay
@ 2026-10-04 9:30 ` Kathpalia, Tanmay
2026-10-05 17:46 ` Dave Klotz
1 sibling, 1 reply; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-04 9:30 UTC (permalink / raw)
To: Dave Klotz, u-boot
Cc: Huan Zhou, Eric Chung, Peng Fan, Jaehoon Chung, Yixun Lan,
Tom Rini, u-boot-spacemit
On 03-10-2026 02:59, Dave Klotz wrote:
> The driver sets the io clock to the max-frequency the device tree gives
> and fails the probe on any non-zero return from clk_set_rate(). Two
> problems follow:
>
> - clk_set_rate() returns the new rate on success and a negative error
> code on failure. The SpacemiT clock driver happens to return 0, but
> any clock driver that reports the rate makes the probe fail.
> - A node without max-frequency asks for 0 Hz. On the K1 clock driver
> that picks no divider at all and writes whatever the calculation left
> behind into the io clock's divider field; host->max_clk is then 0,
> the capabilities register gives no base clock either, and the probe
> fails in sdhci_setup_cfg().
>
> Treat only a negative return as an error. Without max-frequency, leave
> the io clock as an earlier stage set it and run from its current rate.
>
> Signed-off-by: Dave Klotz<DaveWK225@protonmail.com>
> ---
> drivers/mmc/spacemit_sdhci.c | 26 ++++++++++++++++++++++----
> 1 file changed, 22 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> index f5578f38bd..bbd49b76c6 100644
> --- a/drivers/mmc/spacemit_sdhci.c
> +++ b/drivers/mmc/spacemit_sdhci.c
> @@ -606,10 +606,28 @@ static int spacemit_sdhci_probe(struct udevice *dev)
> goto err_reset;
> }
>
> - ret = clk_set_rate(&clk, plat->cfg.f_max);
> - if (ret) {
> - log_err("Failed to set io clk: %d\n", ret);
> - goto err_reset;
> + /*
> + * Without max-frequency there is no rate to ask for: leave the io
> + * clock as an earlier stage set it and run from its current rate. The
> + * capabilities register gives no base clock on the K1, so it cannot
> + * stand in. clk_set_rate() returns the new rate on success, so only a
> + * negative value is an error.
> + */
> + if (plat->cfg.f_max) {
> + long rate = clk_set_rate(&clk, plat->cfg.f_max);
The clock API returns ulong; please use ulong rate with
IS_ERR_VALUE(rate) for consistency.
> +
> + if (rate < 0) {
> + ret = rate;
> + log_err("Failed to set io clk: %d\n", ret);
> + goto err_reset;
> + }
> + } else {
> + plat->cfg.f_max = clk_get_rate(&clk);
clk_get_rate() returns ulong, but f_max is uint. On RV64, assigning a
negative error first truncates it, so IS_ERR_VALUE(f_max) no longer
detects the error. Please validate the ulong rate before assigning it:
rate = clk_get_rate(&clk);
if (IS_ERR_VALUE(rate) || !rate) {
ret = rate ? (int)rate : -EINVAL;
goto err_reset;
}
plat->cfg.f_max = rate;
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value
2026-10-04 9:30 ` Kathpalia, Tanmay
@ 2026-10-05 17:46 ` Dave Klotz
0 siblings, 0 replies; 33+ messages in thread
From: Dave Klotz @ 2026-10-05 17:46 UTC (permalink / raw)
To: Tanmay Kathpalia
Cc: Yixun Lan, Eric Chung, Peng Fan, u-boot, Jaehoon Chung, Tom Rini
Hi Tanmay,
Thanks for the review. I've updated v2 patch 1/3 to keep the clock API
return values in ulong and test IS_ERR_VALUE(). The missing-max-frequency
path now checks clk_get_rate() before assigning it to cfg.f_max, rejects
a zero rate, and preserves the clock API's error code.
I've retained your Reviewed-by on patches 2/3 and 3/3. Patch 2/3 now
explains the intentional reversal of the driver's v9 single-block SPL
policy and the MMC core's CMD12 path; its code is unchanged from v1.
The revised three-patch stack replays cleanly on its exact base and
passes checkpatch. Both R2S and RV2 configurations build successfully.
With the separate DDR firmware overlap fix included, the combined
firmware passed DDR initialization, FIT verification and automatic
EFI/FreeBSD boot on the 2 GiB R2S and the 4 GiB RV2.
These are combined-firmware warm-boot results, not isolated tests of
this series. Cold boot of the corrected firmware, alternate cards,
missing-frequency/error paths and error recovery remain untested.
Thanks,
Dave
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver
2026-10-02 21:29 [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver Dave Klotz
` (3 preceding siblings ...)
2026-10-02 22:06 ` [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver Dave Klotz
@ 2026-10-05 17:50 ` Dave Klotz
2026-10-05 17:55 ` [PATCH v2 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
` (2 more replies)
4 siblings, 3 replies; 33+ messages in thread
From: Dave Klotz @ 2026-10-05 17:50 UTC (permalink / raw)
To: Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tanmay Kathpalia, Tom Rini
This revision addresses Tanmay Kathpalia's review of patch 1/3: use
ulong and IS_ERR_VALUE() for clock API results, and validate the current
clock rate before narrowing it to cfg.f_max. Preserve the actual error
code and reject a zero current rate.
Patches 2/3 and 3/3 retain Tanmay's Reviewed-by. Patch 2/3 also explains
the intentional reversal of the driver's v9 single-block SPL policy and
the MMC core's CMD12 path; its executable change is unchanged from v1.
Patch 3/3's executable change is unchanged from v1.
Exact-base source replay and checkpatch pass for all three revised
patches. Both R2S and RV2 configurations build successfully.
An integration containing this series, the clock-mux rename and a
separate DDR firmware overlap fix passed warm-boot tests on a 2 GiB
OrangePi R2S and a 4 GiB OrangePi RV2. Both reached DDR/SPL, FIT
verification and automatic EFI boot to their existing FreeBSD 16
installation, with the expected memory and eight CPUs. These are
combined-integration results, not isolated tests of this series.
Cold boot of the corrected firmware, alternate cards, missing-frequency/
clock error paths and error recovery remain untested.
Dave Klotz (3):
mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value
mmc: k1: let the SPL read SD cards more than one block at a time
mmc: k1: do not release the shared AXI clock and reset on probe failure
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value
2026-10-05 17:50 ` [PATCH v2 " Dave Klotz
@ 2026-10-05 17:55 ` Dave Klotz
2026-10-06 5:40 ` Kathpalia, Tanmay
2026-10-10 8:45 ` Yixun Lan
2026-10-05 18:01 ` [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time Dave Klotz
2026-10-05 18:11 ` [PATCH v2 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure Dave Klotz
2 siblings, 2 replies; 33+ messages in thread
From: Dave Klotz @ 2026-10-05 17:55 UTC (permalink / raw)
To: Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tanmay Kathpalia, Tom Rini
The driver sets the io clock to the max-frequency the device tree gives
and fails the probe on any non-zero return from clk_set_rate(). Two
problems follow:
- clk_set_rate() returns the new rate on success and a negative error
code on failure. The SpacemiT clock driver happens to return 0, but
any clock driver that reports the rate makes the probe fail.
- A node without max-frequency asks for 0 Hz. On the K1 clock driver
that picks no divider at all and writes whatever the calculation left
behind into the io clock's divider field; host->max_clk is then 0,
the capabilities register gives no base clock either, and the probe
fails in sdhci_setup_cfg().
Treat only a negative return as an error. Without max-frequency, leave
the io clock as an earlier stage set it and run from its current rate.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
Changes in v2:
- Use ulong and IS_ERR_VALUE() for the clock API return values.
- Validate clk_get_rate() before narrowing to cfg.f_max and retain the error.
---
drivers/mmc/spacemit_sdhci.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
index f5578f38bd..6488ae0fdb 100644
--- a/drivers/mmc/spacemit_sdhci.c
+++ b/drivers/mmc/spacemit_sdhci.c
@@ -606,10 +606,30 @@
goto err_reset;
}
- ret = clk_set_rate(&clk, plat->cfg.f_max);
- if (ret) {
- log_err("Failed to set io clk: %d\n", ret);
- goto err_reset;
+ /*
+ * Without max-frequency there is no rate to ask for: leave the io
+ * clock as an earlier stage set it and run from its current rate. The
+ * capabilities register gives no base clock on the K1, so it cannot
+ * stand in. clk_set_rate() returns the new rate on success, so only a
+ * negative value is an error.
+ */
+ if (plat->cfg.f_max) {
+ ulong rate = clk_set_rate(&clk, plat->cfg.f_max);
+
+ if (IS_ERR_VALUE(rate)) {
+ ret = (int)rate;
+ log_err("Failed to set io clk: %d\n", ret);
+ goto err_reset;
+ }
+ } else {
+ ulong rate = clk_get_rate(&clk);
+
+ if (IS_ERR_VALUE(rate) || !rate) {
+ ret = rate ? (int)rate : -EINVAL;
+ log_err("No max-frequency and no io clk rate\n");
+ goto err_reset;
+ }
+ plat->cfg.f_max = rate;
}
/* Set quirks */
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-05 17:50 ` [PATCH v2 " Dave Klotz
2026-10-05 17:55 ` [PATCH v2 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
@ 2026-10-05 18:01 ` Dave Klotz
2026-10-10 6:17 ` Zixian Zeng
2026-10-05 18:11 ` [PATCH v2 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure Dave Klotz
2 siblings, 1 reply; 33+ messages in thread
From: Dave Klotz @ 2026-10-05 18:01 UTC (permalink / raw)
To: Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tanmay Kathpalia, Tom Rini
spacemit_sdhci_get_b_max() limits every SD read in the SPL to a single
block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
separate commands. The controller handles multi-block PIO reads in the
SPL: the OrangePi RV2 has loaded U-Boot from microSD with them through
the v2026.07 and v2026.10 trees.
Drop the limit and use the host's b_max.
The merged v13 cover retains the v9 changelog entry choosing single-
block SD reads in SPL. This reverses that deliberate policy for the
recorded RV2 SPL boot use case; no general multi-card reliability claim
is made. K1 does not advertise MMC_CAP_CMD23, so the MMC core sends
CMD12 after a multi-block read rather than requiring CMD23. Additional
card models, cold boots and transfer-error recovery remain required.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
---
Validation: unchanged executable change from v1; exact-base source
replay and checkpatch pass. The corrected combined integration, with
separate clock/MMC and DDR relocation fixes, passed SD SPL/FIT and
automatic NVMe EFI boot on the 4 GiB RV2 in a warm-boot trial. This is
an integration result, not an isolated test of this patch.
drivers/mmc/spacemit_sdhci.c | 11 -----------
1 file changed, 0 insertions(+), 11 deletions(-)
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
index 6488ae0fdb..4284553177 100644
--- a/drivers/mmc/spacemit_sdhci.c
+++ b/drivers/mmc/spacemit_sdhci.c
@@ -324,16 +324,6 @@
return 0;
}
-static int spacemit_sdhci_get_b_max(struct udevice *dev, void *dst,
- lbaint_t blkcnt)
-{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
-
- if (IS_ENABLED(CONFIG_SPL_BUILD) && mmc && IS_SD(mmc))
- return 1;
- return mmc->cfg->b_max;
-}
-
static void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
{
struct mmc *mmc = host->mmc;
@@ -574,7 +564,6 @@
spacemit_mmc_ops = sdhci_ops;
spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
- spacemit_mmc_ops.get_b_max = spacemit_sdhci_get_b_max;
ret = clk_get_bulk(dev, &plat->clks);
if (ret) {
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure
2026-10-05 17:50 ` [PATCH v2 " Dave Klotz
2026-10-05 17:55 ` [PATCH v2 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
2026-10-05 18:01 ` [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time Dave Klotz
@ 2026-10-05 18:11 ` Dave Klotz
2026-10-10 7:14 ` Yixun Lan
2 siblings, 1 reply; 33+ messages in thread
From: Dave Klotz @ 2026-10-05 18:11 UTC (permalink / raw)
To: Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tanmay Kathpalia, Tom Rini
When the probe fails, the driver releases its clock and reset bulks.
clk_release_bulk() disables every clock and reset_release_bulk()
asserts every reset, and the first entry of each is the SDH AXI bus
clock and reset, which all three SDHCI controllers of the K1 share.
One controller failing to probe therefore stops the bus of the others,
and the next register access to any of them hangs the hart. On an
OrangePi RV2, whose device tree enables the eMMC controller without a
max-frequency, the eMMC probe failed in sdhci_setup_cfg() and U-Boot
then hung at "MMC:" probing the microSD controller.
Keep the clocks running and the resets deasserted on failure.
Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
---
Validation: executable diff unchanged from v1; exact-base replay and
checkpatch pass. Combined-firmware warm-boot results are in the cover;
probe-failure paths have not been retested on hardware.
drivers/mmc/spacemit_sdhci.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
index 4284553177..88e06a681c 100644
--- a/drivers/mmc/spacemit_sdhci.c
+++ b/drivers/mmc/spacemit_sdhci.c
@@ -642,10 +642,14 @@
spacemit_sdhci_phy_init(dev, host);
return 0;
+ /*
+ * Leave the clocks and resets alone on failure. The "core" clock and
+ * the "axi" reset are the AXI clock and reset that every SDHCI
+ * controller of the K1 shares: releasing them would gate the bus of
+ * the other controllers, and the next access to one of them hangs.
+ */
err_reset:
- reset_release_bulk(&plat->resets);
err_clk:
- clk_release_bulk(&plat->clks);
return ret;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value
2026-10-05 17:55 ` [PATCH v2 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
@ 2026-10-06 5:40 ` Kathpalia, Tanmay
2026-10-10 8:45 ` Yixun Lan
1 sibling, 0 replies; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-06 5:40 UTC (permalink / raw)
To: Dave Klotz, Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tom Rini
On 05-10-2026 23:25, Dave Klotz wrote:
> The driver sets the io clock to the max-frequency the device tree gives
> and fails the probe on any non-zero return from clk_set_rate(). Two
> problems follow:
>
> - clk_set_rate() returns the new rate on success and a negative error
> code on failure. The SpacemiT clock driver happens to return 0, but
> any clock driver that reports the rate makes the probe fail.
> - A node without max-frequency asks for 0 Hz. On the K1 clock driver
> that picks no divider at all and writes whatever the calculation left
> behind into the io clock's divider field; host->max_clk is then 0,
> the capabilities register gives no base clock either, and the probe
> fails in sdhci_setup_cfg().
>
> Treat only a negative return as an error. Without max-frequency, leave
> the io clock as an earlier stage set it and run from its current rate.
>
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
>
Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-05 18:01 ` [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time Dave Klotz
@ 2026-10-10 6:17 ` Zixian Zeng
2026-10-10 19:02 ` Kathpalia, Tanmay
0 siblings, 1 reply; 33+ messages in thread
From: Zixian Zeng @ 2026-10-10 6:17 UTC (permalink / raw)
To: Dave Klotz, Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tanmay Kathpalia, Tom Rini,
u-boot-spacemit
Hi, Dave:
On 2026/10/6 02:01, Dave Klotz wrote:
> spacemit_sdhci_get_b_max() limits every SD read in the SPL to a single
> block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
> separate commands. The controller handles multi-block PIO reads in the
> SPL: the OrangePi RV2 has loaded U-Boot from microSD with them through
> the v2026.07 and v2026.10 trees.
>
> Drop the limit and use the host's b_max.
>
> The merged v13 cover retains the v9 changelog entry choosing single-
> block SD reads in SPL. This reverses that deliberate policy for the
> recorded RV2 SPL boot use case; no general multi-card reliability claim
> is made. K1 does not advertise MMC_CAP_CMD23, so the MMC core sends
> CMD12 after a multi-block read rather than requiring CMD23. Additional
> card models, cold boots and transfer-error recovery remain required.
>
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
> Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
> ---
> Validation: unchanged executable change from v1; exact-base source
> replay and checkpatch pass. The corrected combined integration, with
> separate clock/MMC and DDR relocation fixes, passed SD SPL/FIT and
> automatic NVMe EFI boot on the 4 GiB RV2 in a warm-boot trial. This is
> an integration result, not an isolated test of this patch.
>
> drivers/mmc/spacemit_sdhci.c | 11 -----------
> 1 file changed, 0 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> index 6488ae0fdb..4284553177 100644
> --- a/drivers/mmc/spacemit_sdhci.c
> +++ b/drivers/mmc/spacemit_sdhci.c
> @@ -324,16 +324,6 @@
> return 0;
> }
>
> -static int spacemit_sdhci_get_b_max(struct udevice *dev, void *dst,
> - lbaint_t blkcnt)
> -{
> - struct mmc *mmc = mmc_get_mmc_dev(dev);
> -
> - if (IS_ENABLED(CONFIG_SPL_BUILD) && mmc && IS_SD(mmc))
> - return 1;
> - return mmc->cfg->b_max;
> -}
> -
> static void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
> {
> struct mmc *mmc = host->mmc;
> @@ -574,7 +564,6 @@
>
> spacemit_mmc_ops = sdhci_ops;
> spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
> - spacemit_mmc_ops.get_b_max = spacemit_sdhci_get_b_max;
>
> ret = clk_get_bulk(dev, &plat->clks);
> if (ret) {
Using the current version of the next branch u-boot (ed869863c7),
with your MMC patch series applied.
Since the SPI controller is not enabled by default on the BananaPi-F3,
I also applied another patch series:
Link:
https://lore.kernel.org/u-boot/cover.1790976767.git.DaveWK225@protonmail.com/
I tested u-boot SPL with three SD cards on a BananaPi-F3 and found
a reproducible issue, the specific error I encountered is spl: partition
error (Error: -38)
At the meantime, when i was revert the commit:
mmc: k1: let the SPL read SD cards more than one block at a time
the error has gone. Same SD card, same operation steps.
Maybe BananaPi-F3 do not support read SD cards more than one block at a
time?
The issue logs are as follows:
⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ↑ git log --oneline
origin/next..HEAD
6b4af8b1dd8 (HEAD -> k1-dave-mmc) mmc: k1: do not release the shared AXI
clock and reset on probe failure
4114764d716 mmc: k1: let the SPL read SD cards more than one block at a
time
6676ce89521 mmc: k1: handle a missing max-frequency and clk_set_rate()'s
return value
6427189ef33 spacemit: k1: fall back to the other boot devices in SPL
b58a31797d7 spacemit: k1: do not require a PMIC or an SPI controller in SPL
⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ↑ export
CROSS_COMPILE=riscv64-linux-gnu- ARCH=riscv
export
DDR=/home/hack/k1/spacemit-firmware/k1/v0.2/ddr_fw.bin
export
SBI=/home/hack/k1/opensbi/build/platform/generic/firmware/fw_dynamic.bin
⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ↑ make O=build-fix
spacemit_k1_defconfig
make O=build-fix
DDR_FW_FILE=$DDR OPENSBI=$SBI DEVICE_TREE=spacemit/k1-bananapi-f3
-j"$(nproc)"
GEN Makefile
#
# configuration written to .config
#
GEN Makefile
scripts/kconfig/conf --syncconfig Kconfig
CFG u-boot.cfg
GEN include/autoconf.mk.dep
CFG spl/u-boot.cfg
GEN include/autoconf.mk
GEN spl/include/autoconf.mk
GEN Makefile
UPD include/generated/timestamp_autogenerated.h
ENVC include/generated/env.txt
Using .. as source for U-Boot
ENVP include/generated/env.in
ENVT include/generated/environment.h
PYMOD rebuild
LDS u-boot.lds
CC common/version.o
AR common/built-in.a
CC env/common.o
AR env/built-in.a
LD u-boot
OBJCOPY u-boot.srec
OBJCOPY u-boot-nodtb.bin
SYM u-boot.sym
MKIMAGE fit-dtb.blob
MKIMAGE u-boot.img
CC spl/common/spl/spl.o
MKIMAGE u-boot-dtb.img
CAT u-boot-fit-dtb.bin
COPY u-boot.bin
AR spl/common/spl/built-in.a
LD spl/u-boot-spl
OBJCOPY spl/u-boot-spl-nodtb.bin
SYM spl/u-boot-spl.sym
CAT spl/u-boot-spl-dtb.bin
COPY spl/u-boot-spl.bin
BINMAN .binman_stamp
OFCHK .config
⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ↑ cd ~/k1/uboot-2022.10/
⋊> hack@morise ⋊> ~/k/uboot-2022.10 on k1-bl-v2.2.y ◦ cat mainline-fsbl.sh
SPL=$1
FSBL=$2
cd /home/hack/k1/uboot-2022.10
cp "$SPL" board/spacemit/k1-x/
python3 tools/build_binary_file.py \
-c board/spacemit/k1-x/configs/fsbl_ddr.json \
-o "$FSBL"
rm -f board/spacemit/k1-x/u-boot-spl-ddr.bin
echo "Mainline SPL is included in $FSBL"
⋊> hack@morise ⋊> ~/k/uboot-2022.10 on k1-bl-v2.2.y ◦ bash
mainline-fsbl.sh /home/hack/k1/u-boot/build-fix/u-boot-spl-ddr.bin
/home/hack/k1/uboot-2022.10/mainline-spl/FSBL-dave.bin
(2026-10-09 21:37:10,279) arch : RISCV64
(2026-10-09 21:37:10,279) description : spacemit k1x fsbl image
writing RSA key
writing RSA key
Mainline SPL is included in
/home/hack/k1/uboot-2022.10/mainline-spl/FSBL-dave.bin
⋊> hack@morise ⋊> ~/k/uboot-2022.10 on k1-bl-v2.2.y ◦ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 29.7G 0 disk
├─mmcblk0p1 179:1 0 256K 0 part
├─mmcblk0p2 179:2 0 64K 0 part
├─mmcblk0p3 179:3 0 1M 0 part
├─mmcblk0p4 179:4 0 2M 0 part
├─mmcblk0p5 179:5 0 256M 0 part
└─mmcblk0p6 179:6 0 29.5G 0 part
⋊> hack@morise ⋊> ~/k/uboot-2022.10 on k1-bl-v2.2.y ◦ sudo dd
if=/home/hack/k1/flash-dir/factory/bootinfo_sd.bin of=/dev/mmcblk0
bs=512 seek=0 count=1 conv=notrunc status=progress
0+1 records in
0+1 records out
80 bytes copied, 0.685238 s, 0.1 kB/s
⋊> hack@morise ⋊> ~/k/uboot-2022.10 on k1-bl-v2.2.y ◦ sudo dd
if=/home/hack/k1/uboot-2022.10/mainline-spl/FSBL-dave.bin
of=/dev/mmcblk0 bs=512 seek=256 conv=notrunc status=progress
304+1 records in
304+1 records out
156128 bytes (156 kB, 152 KiB) copied, 0.72263 s, 216 kB/s
⋊> hack@morise ⋊> ~/k/uboot-2022.10 on k1-bl-v2.2.y ◦ sudo dd
if=/home/hack/k1/u-boot/build-fix/u-boot.itb of=/dev/mmcblk0 bs=512
seek=4096 conv=notrunc status=progress
1953+1 records in
1953+1 records out
1000145 bytes (1.0 MB, 977 KiB) copied, 0.818001 s, 1.2 MB/s
⋊> hack@morise ⋊> ~/k/uboot-2022.10 on k1-bl-v2.2.y ◦ sync
⋊> hack@morise ⋊> ~/k/uboot-2022.10 on k1-bl-v2.2.y ◦ picocom -b 115200
/dev/ttyUSB1
picocom v3.1
port is : /dev/ttyUSB1
flowcontrol : none
baudrate is : 115200
parity is : none
databits are : 8
stopbits are : 1
escape is : C-a
local echo is : no
noinit is : no
noreset is : no
hangup is : no
nolock is : no
send_cmd is : sz -vv
receive_cmd is : rz -vv -E
imap is :
omap is :
emap is : crcrlf,delbs,
logfile is : none
initstring : none
exit_after is : not set
exit is : no
Type [C-a] [C-h] to see available commands
Terminal ready
sys: 0x0
try sd...
bm:3
j...
<debug_uart>
U-Boot SPL 2026.10-rc5-00639-g6b4af8b1dd89 (Oct 09 2026 - 21:36:48 +0800)
Fail to detect board:-2
vdd_core, value:900000
vdd_1v8, value:1800000
vdd_1v8_mmc, value:1800000
DDR firmware: [0xc081d340]:0xf0227179, size:0x8d98
DDR is ready
No SPI controller (-19)
Trying to boot from MMC2
spl: partition error
Error: -38
SPL: Unsupported Boot Device!
Trying to boot from MMC1
alloc space exhausted ptr 104380 limit 100000
Aligned buffer alloc failed
spl: could not find mmc device 0. error: -19
Error: -19
SPL: Unsupported Boot Device!
Trying to boot from SPI
Invalid bus 0 (err=-19)
SPI probe failed.
Error: -19
SPL: Unsupported Boot Device!
SPL: Unsupported Boot Device!
SPL: failed to boot from all boot devices
### ERROR ### Please RESET the board ###
Reported-by: Zixian Zeng <sycamoremoon376@gmail.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure
2026-10-05 18:11 ` [PATCH v2 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure Dave Klotz
@ 2026-10-10 7:14 ` Yixun Lan
2026-10-10 19:27 ` Kathpalia, Tanmay
0 siblings, 1 reply; 33+ messages in thread
From: Yixun Lan @ 2026-10-10 7:14 UTC (permalink / raw)
To: Dave Klotz
Cc: Eric Chung, Peng Fan, u-boot, Jaehoon Chung, Tanmay Kathpalia,
Tom Rini
Hi Dave,
On 18:11 Mon 05 Oct , Dave Klotz wrote:
> When the probe fails, the driver releases its clock and reset bulks.
> clk_release_bulk() disables every clock and reset_release_bulk()
> asserts every reset, and the first entry of each is the SDH AXI bus
> clock and reset, which all three SDHCI controllers of the K1 share.
>
> One controller failing to probe therefore stops the bus of the others,
> and the next register access to any of them hangs the hart. On an
> OrangePi RV2, whose device tree enables the eMMC controller without a
> max-frequency, the eMMC probe failed in sdhci_setup_cfg() and U-Boot
> then hung at "MMC:" probing the microSD controller.
>
> Keep the clocks running and the resets deasserted on failure.
>
For the clock part:
This doesn't make sense to me, but I've not put my hands on board to
test and actually replicate the case myself..
It occur to me the clk driver should take care of the consumers and
only disable the clock once 'enable_count' drop to zero, see
https://git.u-boot-project.org/u-boot/custodians/u-boot-spacemit/-/blob/main/drivers/clk/clk-uclass.c?ref_type=heads#L744
For the reset part:
As I checked the code, it seems exactly match what you described here,
where there is no enable count tracking mechanism, so release() will
trigger an assert() operation in hardware layer
so, would this issue only relate to reset?
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
> Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
> ---
> Validation: executable diff unchanged from v1; exact-base replay and
> checkpatch pass. Combined-firmware warm-boot results are in the cover;
> probe-failure paths have not been retested on hardware.
>
> drivers/mmc/spacemit_sdhci.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> index 4284553177..88e06a681c 100644
> --- a/drivers/mmc/spacemit_sdhci.c
> +++ b/drivers/mmc/spacemit_sdhci.c
> @@ -642,10 +642,14 @@
> spacemit_sdhci_phy_init(dev, host);
> return 0;
>
> + /*
> + * Leave the clocks and resets alone on failure. The "core" clock and
> + * the "axi" reset are the AXI clock and reset that every SDHCI
> + * controller of the K1 shares: releasing them would gate the bus of
> + * the other controllers, and the next access to one of them hangs.
> + */
> err_reset:
> - reset_release_bulk(&plat->resets);
> err_clk:
> - clk_release_bulk(&plat->clks);
> return ret;
> }
>
> --
> 2.55.0
>
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value
2026-10-05 17:55 ` [PATCH v2 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
2026-10-06 5:40 ` Kathpalia, Tanmay
@ 2026-10-10 8:45 ` Yixun Lan
1 sibling, 0 replies; 33+ messages in thread
From: Yixun Lan @ 2026-10-10 8:45 UTC (permalink / raw)
To: Dave Klotz
Cc: Eric Chung, Peng Fan, u-boot, Jaehoon Chung, Tanmay Kathpalia,
Tom Rini
Hi Dave,
On 17:55 Mon 05 Oct , Dave Klotz wrote:
> The driver sets the io clock to the max-frequency the device tree gives
> and fails the probe on any non-zero return from clk_set_rate(). Two
> problems follow:
>
I can understand your problem and what to solve.. but wouldn't it be
a more simpler way to just setting max-frequency?
currently, only two boards are supported in mainline uboot:
k1-bananapi-f3 k1-musepi-pro
so, you likely also need to add a customized u-boot dtsi file for
supporting OrangePi R2S, something as file below, where setting the
max-frequency property
arch/riscv/dts/k1-bananapi-f3-u-boot.dtsi
> - clk_set_rate() returns the new rate on success and a negative error
> code on failure. The SpacemiT clock driver happens to return 0, but
> any clock driver that reports the rate makes the probe fail.
Could you elaborate a bit "happens to return 0, ..probe fail" ?
> - A node without max-frequency asks for 0 Hz. On the K1 clock driver
A node with DT property get 0 Hz - that's expected behavior
> that picks no divider at all and writes whatever the calculation left
> behind into the io clock's divider field; host->max_clk is then 0,
> the capabilities register gives no base clock either, and the probe
> fails in sdhci_setup_cfg().
I occur to me, we should further check these logic, like a rate = 0 input
for clk subsystem - clk_set_rate(, 0) is actually a valid case? also if
need to set host->max_clk ..
>
> Treat only a negative return as an error. Without max-frequency, leave
> the io clock as an earlier stage set it and run from its current rate.
>
> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
>
> Changes in v2:
> - Use ulong and IS_ERR_VALUE() for the clock API return values.
> - Validate clk_get_rate() before narrowing to cfg.f_max and retain the error.
>
> ---
> drivers/mmc/spacemit_sdhci.c | 28 ++++++++++++++++++++++++----
> 1 file changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> index f5578f38bd..6488ae0fdb 100644
> --- a/drivers/mmc/spacemit_sdhci.c
> +++ b/drivers/mmc/spacemit_sdhci.c
> @@ -606,10 +606,30 @@
> goto err_reset;
> }
>
> - ret = clk_set_rate(&clk, plat->cfg.f_max);
> - if (ret) {
> - log_err("Failed to set io clk: %d\n", ret);
> - goto err_reset;
> + /*
> + * Without max-frequency there is no rate to ask for: leave the io
> + * clock as an earlier stage set it and run from its current rate. The
I'm wondering if we could set a sane default max-frequency if no DT property
provided? as we can't always trust previous earlier stage which may in
an undetermined state, it will be fragile and easy to fail..
> + * capabilities register gives no base clock on the K1, so it cannot
> + * stand in. clk_set_rate() returns the new rate on success, so only a
> + * negative value is an error.
> + */
> + if (plat->cfg.f_max) {
> + ulong rate = clk_set_rate(&clk, plat->cfg.f_max);
> +
> + if (IS_ERR_VALUE(rate)) {
> + ret = (int)rate;
> + log_err("Failed to set io clk: %d\n", ret);
> + goto err_reset;
> + }
> + } else {
> + ulong rate = clk_get_rate(&clk);
> +
> + if (IS_ERR_VALUE(rate) || !rate) {
> + ret = rate ? (int)rate : -EINVAL;
> + log_err("No max-frequency and no io clk rate\n");
> + goto err_reset;
> + }
> + plat->cfg.f_max = rate;
> }
>
> /* Set quirks */
> --
> 2.55.0
>
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-10 6:17 ` Zixian Zeng
@ 2026-10-10 19:02 ` Kathpalia, Tanmay
2026-10-10 19:16 ` Kathpalia, Tanmay
0 siblings, 1 reply; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-10 19:02 UTC (permalink / raw)
To: Zixian Zeng, Dave Klotz, Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tom Rini, u-boot-spacemit
On 10-10-2026 11:47, Zixian Zeng wrote:
> Hi, Dave:
>
> On 2026/10/6 02:01, Dave Klotz wrote:
>> spacemit_sdhci_get_b_max() limits every SD read in the SPL to a single
>> block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
>> separate commands. The controller handles multi-block PIO reads in the
>> SPL: the OrangePi RV2 has loaded U-Boot from microSD with them through
>> the v2026.07 and v2026.10 trees.
>>
>> Drop the limit and use the host's b_max.
>>
>> The merged v13 cover retains the v9 changelog entry choosing single-
>> block SD reads in SPL. This reverses that deliberate policy for the
>> recorded RV2 SPL boot use case; no general multi-card reliability claim
>> is made. K1 does not advertise MMC_CAP_CMD23, so the MMC core sends
>> CMD12 after a multi-block read rather than requiring CMD23. Additional
>> card models, cold boots and transfer-error recovery remain required.
>>
>> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
>> Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
>> ---
>> Validation: unchanged executable change from v1; exact-base source
>> replay and checkpatch pass. The corrected combined integration, with
>> separate clock/MMC and DDR relocation fixes, passed SD SPL/FIT and
>> automatic NVMe EFI boot on the 4 GiB RV2 in a warm-boot trial. This is
>> an integration result, not an isolated test of this patch.
>>
>> drivers/mmc/spacemit_sdhci.c | 11 -----------
>> 1 file changed, 0 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
>> index 6488ae0fdb..4284553177 100644
>> --- a/drivers/mmc/spacemit_sdhci.c
>> +++ b/drivers/mmc/spacemit_sdhci.c
>> @@ -324,16 +324,6 @@
>> return 0;
>> }
>> -static int spacemit_sdhci_get_b_max(struct udevice *dev, void *dst,
>> - lbaint_t blkcnt)
>> -{
>> - struct mmc *mmc = mmc_get_mmc_dev(dev);
>> -
>> - if (IS_ENABLED(CONFIG_SPL_BUILD) && mmc && IS_SD(mmc))
>> - return 1;
>> - return mmc->cfg->b_max;
>> -}
>> -
>> static void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
>> {
>> struct mmc *mmc = host->mmc;
>> @@ -574,7 +564,6 @@
>> spacemit_mmc_ops = sdhci_ops;
>> spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
>> - spacemit_mmc_ops.get_b_max = spacemit_sdhci_get_b_max;
>> ret = clk_get_bulk(dev, &plat->clks);
>> if (ret) {
> Using the current version of the next branch u-boot (ed869863c7),
> with your MMC patch series applied.
> Since the SPI controller is not enabled by default on the BananaPi-F3,
> I also applied another patch series:
> Link:
> https://lore.kernel.org/u-boot/cover.1790976767.git.DaveWK225@protonmail.com/
>
>
> I tested u-boot SPL with three SD cards on a BananaPi-F3 and found
> a reproducible issue, the specific error I encountered is spl:
> partition error (Error: -38)
> At the meantime, when i was revert the commit:
> mmc: k1: let the SPL read SD cards more than one block at a time
> the error has gone. Same SD card, same operation steps.
> Maybe BananaPi-F3 do not support read SD cards more than one block at
> a time?
>
>
Hi Zixian,
Thanks for testing this on the BananaPi-F3 and reporting this. The
same cards and steps failing only with this patch shows that
multi-block SD reads in the SPL are not reliable yet.
I would request to try one more experiment before dropping it.
Please add MMC_CAP_CMD23 to host->host_caps and boot the same cards
again. CMD23 (SET_BLOCK_COUNT) tells the card how many blocks to
transfer. mmc_read_blocks() then uses CMD23 plus CMD18, and it does
not send CMD12 afterwards. The current driver does not set
MMC_CAP_CMD23, so a multi-block read is CMD18 followed by CMD12.
After the SCR is read, the MMC core clears MMC_CAP_CMD23 when the card
does not advertise SD_SCR_CMD23_SUPPORT. Those cards stay on CMD18
plus CMD12.
This also matches Eric's earlier note that on K1 ADMA depends on CMD23:
https://patchwork.ozlabs.org/project/uboot/patch/20260707-m4-v4-3-dbd01185f911@riscstar.com/
If the CMD23 test also fails, I agree that this patch should be
dropped.
Regards,
Tanmay
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-10 19:02 ` Kathpalia, Tanmay
@ 2026-10-10 19:16 ` Kathpalia, Tanmay
2026-10-11 3:38 ` Zixian Zeng
0 siblings, 1 reply; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-10 19:16 UTC (permalink / raw)
To: Zixian Zeng, Dave Klotz, Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tom Rini, u-boot-spacemit
On 11-10-2026 00:32, Kathpalia, Tanmay wrote:
>
> On 10-10-2026 11:47, Zixian Zeng wrote:
>> Hi, Dave:
>>
>> On 2026/10/6 02:01, Dave Klotz wrote:
>>> spacemit_sdhci_get_b_max() limits every SD read in the SPL to a single
>>> block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
>>> separate commands. The controller handles multi-block PIO reads in the
>>> SPL: the OrangePi RV2 has loaded U-Boot from microSD with them through
>>> the v2026.07 and v2026.10 trees.
>>>
>>> Drop the limit and use the host's b_max.
>>>
>>> The merged v13 cover retains the v9 changelog entry choosing single-
>>> block SD reads in SPL. This reverses that deliberate policy for the
>>> recorded RV2 SPL boot use case; no general multi-card reliability claim
>>> is made. K1 does not advertise MMC_CAP_CMD23, so the MMC core sends
>>> CMD12 after a multi-block read rather than requiring CMD23. Additional
>>> card models, cold boots and transfer-error recovery remain required.
>>>
>>> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
>>> Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
>>> ---
>>> Validation: unchanged executable change from v1; exact-base source
>>> replay and checkpatch pass. The corrected combined integration, with
>>> separate clock/MMC and DDR relocation fixes, passed SD SPL/FIT and
>>> automatic NVMe EFI boot on the 4 GiB RV2 in a warm-boot trial. This is
>>> an integration result, not an isolated test of this patch.
>>>
>>> drivers/mmc/spacemit_sdhci.c | 11 -----------
>>> 1 file changed, 0 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/drivers/mmc/spacemit_sdhci.c
>>> b/drivers/mmc/spacemit_sdhci.c
>>> index 6488ae0fdb..4284553177 100644
>>> --- a/drivers/mmc/spacemit_sdhci.c
>>> +++ b/drivers/mmc/spacemit_sdhci.c
>>> @@ -324,16 +324,6 @@
>>> return 0;
>>> }
>>> -static int spacemit_sdhci_get_b_max(struct udevice *dev, void *dst,
>>> - lbaint_t blkcnt)
>>> -{
>>> - struct mmc *mmc = mmc_get_mmc_dev(dev);
>>> -
>>> - if (IS_ENABLED(CONFIG_SPL_BUILD) && mmc && IS_SD(mmc))
>>> - return 1;
>>> - return mmc->cfg->b_max;
>>> -}
>>> -
>>> static void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
>>> {
>>> struct mmc *mmc = host->mmc;
>>> @@ -574,7 +564,6 @@
>>> spacemit_mmc_ops = sdhci_ops;
>>> spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
>>> - spacemit_mmc_ops.get_b_max = spacemit_sdhci_get_b_max;
>>> ret = clk_get_bulk(dev, &plat->clks);
>>> if (ret) {
>> Using the current version of the next branch u-boot (ed869863c7),
>> with your MMC patch series applied.
>> Since the SPI controller is not enabled by default on the BananaPi-F3,
>> I also applied another patch series:
>> Link:
>> https://lore.kernel.org/u-boot/cover.1790976767.git.DaveWK225@protonmail.com/
>>
>>
>> I tested u-boot SPL with three SD cards on a BananaPi-F3 and found
>> a reproducible issue, the specific error I encountered is spl:
>> partition error (Error: -38)
>> At the meantime, when i was revert the commit:
>> mmc: k1: let the SPL read SD cards more than one block at a time
>> the error has gone. Same SD card, same operation steps.
>> Maybe BananaPi-F3 do not support read SD cards more than one block at
>> a time?
>>
>>
>
> Hi Zixian,
>
> Thanks for testing this on the BananaPi-F3 and reporting this. The
> same cards and steps failing only with this patch shows that
> multi-block SD reads in the SPL are not reliable yet.
>
> I would request to try one more experiment before dropping it.
> Please add MMC_CAP_CMD23 to host->host_caps and boot the same cards
> again. CMD23 (SET_BLOCK_COUNT) tells the card how many blocks to
> transfer. mmc_read_blocks() then uses CMD23 plus CMD18, and it does
> not send CMD12 afterwards. The current driver does not set
> MMC_CAP_CMD23, so a multi-block read is CMD18 followed by CMD12.
>
> After the SCR is read, the MMC core clears MMC_CAP_CMD23 when the card
> does not advertise SD_SCR_CMD23_SUPPORT. Those cards stay on CMD18
> plus CMD12.
>
> This also matches Eric's earlier note that on K1 ADMA depends on CMD23:
> https://patchwork.ozlabs.org/project/uboot/patch/20260707-m4-v4-3-dbd01185f911@riscstar.com/
>
>
> If the CMD23 test also fails, I agree that this patch should be
> dropped.
>
Hi Zixian,
A few follow-up questions about the SPL-only failure:
The callback limits reads only when CONFIG_SPL_BUILD is enabled. U-Boot
proper already uses mmc->cfg->b_max, even without this patch.
Therefore, multi-block SD reads should already be used in U-Boot proper.
Could you please boot U-Boot proper from another device and test a
multi-block read from the same SD cards?
Could you also compare the following between SPL and U-Boot proper?
- selected SD timing mode
- card clock frequency
- bus width
- PIO, SDMA, or ADMA transfer path
- whether the card advertises CMD23 support
Although both stages use the same driver source, they may use different
configuration options, transfer paths, clocks, and timing modes. This
could explain why CMD18 works in U-Boot proper but fails in SPL.
Regards,
Tanmay
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure
2026-10-10 7:14 ` Yixun Lan
@ 2026-10-10 19:27 ` Kathpalia, Tanmay
0 siblings, 0 replies; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-10 19:27 UTC (permalink / raw)
To: Yixun Lan, Dave Klotz
Cc: Eric Chung, Peng Fan, u-boot, Jaehoon Chung, Tom Rini
On 10-10-2026 12:44, Yixun Lan wrote:
> Hi Dave,
>
> On 18:11 Mon 05 Oct , Dave Klotz wrote:
>> When the probe fails, the driver releases its clock and reset bulks.
>> clk_release_bulk() disables every clock and reset_release_bulk()
>> asserts every reset, and the first entry of each is the SDH AXI bus
>> clock and reset, which all three SDHCI controllers of the K1 share.
>>
>> One controller failing to probe therefore stops the bus of the others,
>> and the next register access to any of them hangs the hart. On an
>> OrangePi RV2, whose device tree enables the eMMC controller without a
>> max-frequency, the eMMC probe failed in sdhci_setup_cfg() and U-Boot
>> then hung at "MMC:" probing the microSD controller.
>>
>> Keep the clocks running and the resets deasserted on failure.
>>
> For the clock part:
>
> This doesn't make sense to me, but I've not put my hands on board to
> test and actually replicate the case myself..
>
> It occur to me the clk driver should take care of the consumers and
> only disable the clock once 'enable_count' drop to zero, see
>
> https://git.u-boot-project.org/u-boot/custodians/u-boot-spacemit/-/blob/main/drivers/clk/clk-uclass.c?ref_type=heads#L744
>
>
> For the reset part:
> As I checked the code, it seems exactly match what you described here,
> where there is no enable count tracking mechanism, so release() will
> trigger an assert() operation in hardware layer
>
> so, would this issue only relate to reset?
>
Given Dlan’s finding, I would withdraw the Reviewed-by pending that
test or a narrower reset-only revision.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-10 19:16 ` Kathpalia, Tanmay
@ 2026-10-11 3:38 ` Zixian Zeng
2026-10-11 14:31 ` Kathpalia, Tanmay
0 siblings, 1 reply; 33+ messages in thread
From: Zixian Zeng @ 2026-10-11 3:38 UTC (permalink / raw)
To: Kathpalia, Tanmay, Dave Klotz, Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tom Rini, u-boot-spacemit
On 2026/10/11 03:16, Kathpalia, Tanmay wrote:
>
> On 11-10-2026 00:32, Kathpalia, Tanmay wrote:
>>
>> On 10-10-2026 11:47, Zixian Zeng wrote:
>>> Hi, Dave:
>>>
>>> On 2026/10/6 02:01, Dave Klotz wrote:
>>>> spacemit_sdhci_get_b_max() limits every SD read in the SPL to a single
>>>> block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
>>>> separate commands. The controller handles multi-block PIO reads in the
>>>> SPL: the OrangePi RV2 has loaded U-Boot from microSD with them through
>>>> the v2026.07 and v2026.10 trees.
>>>>
>>>> Drop the limit and use the host's b_max.
>>>>
>>>> The merged v13 cover retains the v9 changelog entry choosing single-
>>>> block SD reads in SPL. This reverses that deliberate policy for the
>>>> recorded RV2 SPL boot use case; no general multi-card reliability claim
>>>> is made. K1 does not advertise MMC_CAP_CMD23, so the MMC core sends
>>>> CMD12 after a multi-block read rather than requiring CMD23. Additional
>>>> card models, cold boots and transfer-error recovery remain required.
>>>>
>>>> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
>>>> Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
>>>> ---
>>>> Validation: unchanged executable change from v1; exact-base source
>>>> replay and checkpatch pass. The corrected combined integration, with
>>>> separate clock/MMC and DDR relocation fixes, passed SD SPL/FIT and
>>>> automatic NVMe EFI boot on the 4 GiB RV2 in a warm-boot trial. This is
>>>> an integration result, not an isolated test of this patch.
>>>>
>>>> drivers/mmc/spacemit_sdhci.c | 11 -----------
>>>> 1 file changed, 0 insertions(+), 11 deletions(-)
>>>>
>>>> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/
>>>> spacemit_sdhci.c
>>>> index 6488ae0fdb..4284553177 100644
>>>> --- a/drivers/mmc/spacemit_sdhci.c
>>>> +++ b/drivers/mmc/spacemit_sdhci.c
>>>> @@ -324,16 +324,6 @@
>>>> return 0;
>>>> }
>>>> -static int spacemit_sdhci_get_b_max(struct udevice *dev, void *dst,
>>>> - lbaint_t blkcnt)
>>>> -{
>>>> - struct mmc *mmc = mmc_get_mmc_dev(dev);
>>>> -
>>>> - if (IS_ENABLED(CONFIG_SPL_BUILD) && mmc && IS_SD(mmc))
>>>> - return 1;
>>>> - return mmc->cfg->b_max;
>>>> -}
>>>> -
>>>> static void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
>>>> {
>>>> struct mmc *mmc = host->mmc;
>>>> @@ -574,7 +564,6 @@
>>>> spacemit_mmc_ops = sdhci_ops;
>>>> spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
>>>> - spacemit_mmc_ops.get_b_max = spacemit_sdhci_get_b_max;
>>>> ret = clk_get_bulk(dev, &plat->clks);
>>>> if (ret) {
>>> Using the current version of the next branch u-boot (ed869863c7),
>>> with your MMC patch series applied.
>>> Since the SPI controller is not enabled by default on the BananaPi-F3,
>>> I also applied another patch series:
>>> Link: https://lore.kernel.org/u-boot/
>>> cover.1790976767.git.DaveWK225@protonmail.com/
>>>
>>> I tested u-boot SPL with three SD cards on a BananaPi-F3 and found
>>> a reproducible issue, the specific error I encountered is spl:
>>> partition error (Error: -38)
>>> At the meantime, when i was revert the commit:
>>> mmc: k1: let the SPL read SD cards more than one block at a time
>>> the error has gone. Same SD card, same operation steps.
>>> Maybe BananaPi-F3 do not support read SD cards more than one block at
>>> a time?
>>>
>>>
>>
>> Hi Zixian,
>>
>> Thanks for testing this on the BananaPi-F3 and reporting this. The
>> same cards and steps failing only with this patch shows that
>> multi-block SD reads in the SPL are not reliable yet.
>>
>> I would request to try one more experiment before dropping it.
>> Please add MMC_CAP_CMD23 to host->host_caps and boot the same cards
>> again. CMD23 (SET_BLOCK_COUNT) tells the card how many blocks to
>> transfer. mmc_read_blocks() then uses CMD23 plus CMD18, and it does
>> not send CMD12 afterwards. The current driver does not set
>> MMC_CAP_CMD23, so a multi-block read is CMD18 followed by CMD12.
>>
>> After the SCR is read, the MMC core clears MMC_CAP_CMD23 when the card
>> does not advertise SD_SCR_CMD23_SUPPORT. Those cards stay on CMD18
>> plus CMD12.
>>
>> This also matches Eric's earlier note that on K1 ADMA depends on CMD23:
>> https://patchwork.ozlabs.org/project/uboot/patch/20260707-m4-v4-3-
>> dbd01185f911@riscstar.com/
>>
>> If the CMD23 test also fails, I agree that this patch should be
>> dropped.
>>
>
> Hi Zixian,
>
> A few follow-up questions about the SPL-only failure:
>
> The callback limits reads only when CONFIG_SPL_BUILD is enabled. U-Boot
> proper already uses mmc->cfg->b_max, even without this patch.
> Therefore, multi-block SD reads should already be used in U-Boot proper.
>
> Could you please boot U-Boot proper from another device and test a
> multi-block read from the same SD cards?
> Could you also compare the following between SPL and U-Boot proper?
>
> - selected SD timing mode
> - card clock frequency
> - bus width
> - PIO, SDMA, or ADMA transfer path
> - whether the card advertises CMD23 support
>
> Although both stages use the same driver source, they may use different
> configuration options, transfer paths, clocks, and timing modes. This
> could explain why CMD18 works in U-Boot proper but fails in SPL.
>
> Regards,
> Tanmay
Hi, Tanmay,
Sure, I've added some print logs, which you can see below:
commit 53c0ff5f65b0c7c4ae9f4563265741cd0ca23a0c
Author: Zixian Zeng <sycamoremoon376@gmail.com>
Date: Sun Oct 11 09:34:03 2026 +0800
Add mmc debug log
Signed-off-by: Zixian Zeng <sycamoremoon376@gmail.com>
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index a619440fc4c..6e18d13884a 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -458,6 +458,13 @@ static int mmc_read_blocks(struct mmc *mmc, void
*dst, lbaint_t start,
struct mmc_cmd cmd;
struct mmc_data data;
+ if (blkcnt > 1)
+ printf("mmc: multi-blk blkcnt=%lu clk=%u mode=%u
width=%u caps=%x cmd23_host=%u scr0=%x cmd23_card=%u\n",
+ (ulong)blkcnt, mmc->clock,
+ (unsigned)mmc->selected_mode, mmc->bus_width,
+ mmc->host_caps, !!(mmc->host_caps & MMC_CAP_CMD23),
+ mmc->scr[0], !!(mmc->scr[0] & SD_SCR_CMD23_SUPPORT));
+
if (blkcnt > 1 && (mmc->host_caps & MMC_CAP_CMD23)) {
cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
cmd.cmdarg = blkcnt & 0x0000ffff;
@@ -483,8 +490,12 @@ static int mmc_read_blocks(struct mmc *mmc, void
*dst, lbaint_t start,
data.blocksize = mmc->read_bl_len;
data.flags = MMC_DATA_READ;
- if (mmc_send_cmd(mmc, &cmd, &data))
+ if (mmc_send_cmd(mmc, &cmd, &data)) {
+ log_err("mmc: cmd%u read failed: blks=%lu blksz=%lu
arg=%lx\n",
+ cmd.cmdidx, (ulong)blkcnt, (ulong)mmc->read_bl_len,
+ (ulong)cmd.cmdarg);
return 0;
+ }
if (blkcnt > 1 && !(mmc->host_caps & MMC_CAP_CMD23)) {
if (mmc_send_stop_transmission(mmc, false)) {
@@ -547,6 +558,8 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t
start, lbaint_t blkcnt,
}
if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
+ log_err("mmc: CMD16 blocklen=%lu failed, read of %lu
blocks aborted\n",
+ (ulong)mmc->read_bl_len, (ulong)blkcnt);
pr_debug("%s: Failed to set blocklen\n", __func__);
return 0;
}
@@ -556,6 +569,8 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t
start, lbaint_t blkcnt,
do {
cur = (blocks_todo > b_max) ? b_max : blocks_todo;
if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
+ log_err("mmc: read of %lu blocks at lba %lx
failed (b_max=%u)\n",
+ (ulong)cur, (ulong)start, b_max);
pr_debug("%s: Failed to read blocks\n", __func__);
return 0;
}
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 962a99cd05a..339b222bb68 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -131,6 +131,7 @@ static int sdhci_transfer_data(struct sdhci_host
*host, struct mmc_data *data)
dma_addr_t start_addr = host->start_addr;
unsigned int stat, rdy, mask, timeout, block = 0;
bool transfer_done = false;
+ ulong t0 = get_timer(0);
timeout = 1000000;
rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
@@ -138,6 +139,13 @@ static int sdhci_transfer_data(struct sdhci_host
*host, struct mmc_data *data)
do {
stat = sdhci_readl(host, SDHCI_INT_STATUS);
if (stat & SDHCI_INT_ERROR) {
+ log_err("sdhci: data err irq=%x present=%x
mode=%x blksz=%x blkcnt=%x blocks=%u/%u t=%lums\n",
+ stat,
+ sdhci_readl(host, SDHCI_PRESENT_STATE),
+ sdhci_readw(host, SDHCI_TRANSFER_MODE),
+ sdhci_readw(host, SDHCI_BLOCK_SIZE),
+ sdhci_readw(host, SDHCI_BLOCK_COUNT),
+ block, data->blocks, get_timer(t0));
log_debug("Error detected in status(%#x)!\n",
stat);
return -EIO;
}
@@ -294,6 +302,11 @@ static int sdhci_send_command(struct mmc *mmc,
struct mmc_cmd *cmd,
SDHCI_BLOCK_SIZE);
sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
+ if (data->blocks > 1)
+ printf("sdhci: multi cmd%u arg=%lx blks=%u
blksz=%u mode=%x dma=%u\n",
+ cmd->cmdidx, (ulong)cmd->cmdarg,
data->blocks,
+ data->blocksize, mode,
+ !!(host->flags & USE_DMA));
} else if (cmd->resp_type & MMC_RSP_BUSY) {
sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
}
@@ -325,8 +338,12 @@ static int sdhci_send_command(struct mmc *mmc,
struct mmc_cmd *cmd,
if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
sdhci_cmd_done(host, cmd);
sdhci_writel(host, mask, SDHCI_INT_STATUS);
- } else
+ } else {
+ log_err("sdhci: cmd%u status mismatch irq=%x mask=%x
present=%x\n",
+ cmd->cmdidx, stat, mask,
+ sdhci_readl(host, SDHCI_PRESENT_STATE));
ret = -1;
+ }
if (!ret && data)
ret = sdhci_transfer_data(host, data);
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
index 13bf6bf6000..23c655c6def 100644
--- a/drivers/mmc/spacemit_sdhci.c
+++ b/drivers/mmc/spacemit_sdhci.c
@@ -640,6 +640,19 @@ static int spacemit_sdhci_probe(struct udevice *dev)
goto err_reset;
spacemit_sdhci_phy_init(dev, host);
+
+ {
+ u32 caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+ const char *path = (host->flags & USE_ADMA64) ? "ADMA64" :
+ (host->flags & USE_ADMA) ? "ADMA" :
+ (host->flags & USE_SDMA) ? "SDMA" :
"PIO";
+
+ printf("sdhci: %s path=%s flags=%x caps_sdma=%u
caps_adma2=%u max_clk=%u\n",
+ dev->name, path, host->flags,
+ !!(caps & SDHCI_CAN_DO_SDMA),
+ !!(caps & SDHCI_CAN_DO_ADMA2),
+ host->max_clk);
+ }
return 0;
/*
commit 75d6b28ba7b020d3100586f586ee6d1a4488ac84
Author: Zixian Zeng <sycamoremoon376@gmail.com>
Date: Sun Oct 11 09:33:20 2026 +0800
debug: Add MMC_CAPS_CMD23
Signed-off-by: Zixian Zeng <sycamoremoon376@gmail.com>
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
index 88e06a681ca..13bf6bf6000 100644
--- a/drivers/mmc/spacemit_sdhci.c
+++ b/drivers/mmc/spacemit_sdhci.c
@@ -624,7 +624,7 @@ static int spacemit_sdhci_probe(struct udevice *dev)
/* Set quirks */
host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
SDHCI_QUIRK_32BIT_DMA_ADDR;
- host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+ host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_CAP_CMD23;
host->max_clk = plat->cfg.f_max;
plat->cfg.f_min = SDHC_MIN_CLOCK;
With appling these two commits, Debug logs as follows:
⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ⥄ git log --oneline
origin/next..HEAD
53c0ff5f65b (HEAD -> k1-dave-mmc) Add mmc debug log
75d6b28ba7b debug: Add MMC_CAPS_CMD23
6b4af8b1dd8 mmc: k1: do not release the shared AXI clock and reset on
probe failure
4114764d716 mmc: k1: let the SPL read SD cards more than one block at a time
6676ce89521 mmc: k1: handle a missing max-frequency and clk_set_rate()'s
return value
6427189ef33 spacemit: k1: fall back to the other boot devices in SPL
b58a31797d7 spacemit: k1: do not require a PMIC or an SPI controller in SPL
U-Boot SPL 2026.10-rc5-00641-g53c0ff5f65b0 (Oct 11 2026 - 10:31:28 +0800)
Fail to detect board:-2
vdd_core, value:900000
vdd_1v8, value:1800000
vdd_1v8_mmc, value:1800000
DDR firmware: [0xc081d700]:0xf0227179, size:0x8d98
DDR is ready
No SPI controller (-19)
Trying to boot from MMC2
sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
max_clk=204800000
mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
cmd23_host=1 scr0=2358043 cmd23_card=1
sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
sdhci: data err irq=408020 present=1070800 mode=32 blksz=7200 blkcnt=12
blocks=12/32 t=2ms
mmc: cmd18 read failed: blks=32 blksz=512 arg=2
mmc: read of 32 blocks at lba 2 failed (b_max=65535)
sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
mmc: CMD16 blocklen=512 failed, read of 1 blocks aborted
spl: partition error
Error: -38
SPL: Unsupported Boot Device!
Trying to boot from MMC1
alloc space exhausted ptr 104380 limit 100000
Aligned buffer alloc failed
spl: could not find mmc device 0. error: -19
Error: -19
SPL: Unsupported Boot Device!
Trying to boot from SPI
Invalid bus 0 (err=-19)
SPI probe failed.
Error: -19
SPL: Unsupported Boot Device!
SPL: Unsupported Boot Device!
SPL: failed to boot from all boot devices
### ERROR ### Please RESET the board ###
After I revert the multi-block SD read commit,
I booted into u-boot proper. Debug logs as follows:
⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ⥄ git log --oneline
origin/next..HEAD
55e8da25a70 (HEAD -> k1-dave-mmc) Revert "mmc: k1: let the SPL read SD
cards more than one block at a time"
53c0ff5f65b Add mmc debug log
75d6b28ba7b debug: Add MMC_CAPS_CMD23
6b4af8b1dd8 mmc: k1: do not release the shared AXI clock and reset on
probe failure
4114764d716 mmc: k1: let the SPL read SD cards more than one block at a time
6676ce89521 mmc: k1: handle a missing max-frequency and clk_set_rate()'s
return value
6427189ef33 spacemit: k1: fall back to the other boot devices in SPL
b58a31797d7 spacemit: k1: do not require a PMIC or an SPI controller in SPL
U-Boot SPL 2026.10-rc5-00642-g55e8da25a70c (Oct 11 2026 - 10:38:42 +0800)
Fail to detect board:-2
vdd_core, value:900000
vdd_1v8, value:1800000
vdd_1v8_mmc, value:1800000
DDR firmware: [0xc081d740]:0xf0227179, size:0x8d98
DDR is ready
No SPI controller (-19)
Trying to boot from MMC2
sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
max_clk=204800000
<debug_uart>
U-Boot 2026.10-rc5-00642-g55e8da25a70c (Oct 11 2026 - 10:38:42 +0800)
DRAM: 4 GiB
Core: 339 devices, 23 uclasses, devicetree: separate
MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
max_clk=204800000
sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
max_clk=204800000
mmc@d4280000: 1, mmc@d4281000: 0
Loading Environment from nowhere... OK
In: serial@d4017000
Out: serial@d4017000
Err: serial@d4017000
Net: No ethernet found.
=> mmc dev 1
mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
cmd23_host=1 scr0=2358043 cmd23_card=1
sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
cmd23_host=1 scr0=2358043 cmd23_card=1
sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
... omit duplicate logs
mmc: multi-blk blkcnt=2 clk=50000000 mode=2 width=4 caps=300207ef
cmd23_host=1 scr0=2358043 cmd23_card=1
sdhci: multi cmd18 arg=82002 blks=2 blksz=512 mode=32 dma=0
switch to partitions #0, OK
mmc1 is current device
=>
=> mmc list
mmc@d4280000: 1 (SD)
mmc@d4281000: 0
=>
=> mmc info
Device: mmc@d4280000
Manufacturer ID: 3
OEM: 5344
Name: SD32G
Bus Speed: 50000000
Mode: SD High Speed (50MHz)
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 29.7 GiB
Bus Width: 4-bit
Erase Group Size: 512 Bytes
I enabled MMC_CAP_CMD23 and the card does support it (SCR bit 1,
cmd23_host=1 and cmd23_card=1 in the log above), so the SPL really
used SET_BLOCK_COUNT + CMD18 without CMD12 - and it still aborts the
data phase with SDHCI_INT_DATA_END_BIT after ~20 of 32 blocks.
Booting U-Boot proper and issuing the same 32 block CMD18 from the same
card succeeds, with the same PIO path (flags=0, dma=0), the same SD_HS
mode, the same 4-bit bus and the same CMD23 usage.
So I think CMD23 is not the trigger, the SPL fails with the FIFO
permanently backed up (it drains slower than card delivers, so the
controller has to stop the SD clock inside a block).
Now answering your questions:
mode : mode=2 = SD_HS, in both stages
clock : requested 50 MHz (SD_HS) in both stages
bus : 4-bit bus, in both stages
path : PIO in both stages
CMD23 : the card supports it and both stages use CMD23 + CMD18
Best regards,
Zixian
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-11 3:38 ` Zixian Zeng
@ 2026-10-11 14:31 ` Kathpalia, Tanmay
2026-10-11 15:33 ` Anand Moon
2026-10-12 13:15 ` Zixian Zeng
0 siblings, 2 replies; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-11 14:31 UTC (permalink / raw)
To: Zixian Zeng, Dave Klotz, Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tom Rini, u-boot-spacemit
On 11-10-2026 09:08, Zixian Zeng wrote:
> On 2026/10/11 03:16, Kathpalia, Tanmay wrote:
>>
>> On 11-10-2026 00:32, Kathpalia, Tanmay wrote:
>>>
>>> On 10-10-2026 11:47, Zixian Zeng wrote:
>>>> Hi, Dave:
>>>>
>>>> On 2026/10/6 02:01, Dave Klotz wrote:
>>>>> spacemit_sdhci_get_b_max() limits every SD read in the SPL to a
>>>>> single
>>>>> block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
>>>>> separate commands. The controller handles multi-block PIO reads in
>>>>> the
>>>>> SPL: the OrangePi RV2 has loaded U-Boot from microSD with them
>>>>> through
>>>>> the v2026.07 and v2026.10 trees.
>>>>>
>>>>> Drop the limit and use the host's b_max.
>>>>>
>>>>> The merged v13 cover retains the v9 changelog entry choosing single-
>>>>> block SD reads in SPL. This reverses that deliberate policy for the
>>>>> recorded RV2 SPL boot use case; no general multi-card reliability
>>>>> claim
>>>>> is made. K1 does not advertise MMC_CAP_CMD23, so the MMC core sends
>>>>> CMD12 after a multi-block read rather than requiring CMD23.
>>>>> Additional
>>>>> card models, cold boots and transfer-error recovery remain required.
>>>>>
>>>>> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
>>>>> Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
>>>>> ---
>>>>> Validation: unchanged executable change from v1; exact-base source
>>>>> replay and checkpatch pass. The corrected combined integration, with
>>>>> separate clock/MMC and DDR relocation fixes, passed SD SPL/FIT and
>>>>> automatic NVMe EFI boot on the 4 GiB RV2 in a warm-boot trial.
>>>>> This is
>>>>> an integration result, not an isolated test of this patch.
>>>>>
>>>>> drivers/mmc/spacemit_sdhci.c | 11 -----------
>>>>> 1 file changed, 0 insertions(+), 11 deletions(-)
>>>>>
>>>>> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/
>>>>> spacemit_sdhci.c
>>>>> index 6488ae0fdb..4284553177 100644
>>>>> --- a/drivers/mmc/spacemit_sdhci.c
>>>>> +++ b/drivers/mmc/spacemit_sdhci.c
>>>>> @@ -324,16 +324,6 @@
>>>>> return 0;
>>>>> }
>>>>> -static int spacemit_sdhci_get_b_max(struct udevice *dev, void
>>>>> *dst,
>>>>> - lbaint_t blkcnt)
>>>>> -{
>>>>> - struct mmc *mmc = mmc_get_mmc_dev(dev);
>>>>> -
>>>>> - if (IS_ENABLED(CONFIG_SPL_BUILD) && mmc && IS_SD(mmc))
>>>>> - return 1;
>>>>> - return mmc->cfg->b_max;
>>>>> -}
>>>>> -
>>>>> static void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
>>>>> {
>>>>> struct mmc *mmc = host->mmc;
>>>>> @@ -574,7 +564,6 @@
>>>>> spacemit_mmc_ops = sdhci_ops;
>>>>> spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
>>>>> - spacemit_mmc_ops.get_b_max = spacemit_sdhci_get_b_max;
>>>>> ret = clk_get_bulk(dev, &plat->clks);
>>>>> if (ret) {
>>>> Using the current version of the next branch u-boot (ed869863c7),
>>>> with your MMC patch series applied.
>>>> Since the SPI controller is not enabled by default on the BananaPi-F3,
>>>> I also applied another patch series:
>>>> Link: https://lore.kernel.org/u-boot/
>>>> cover.1790976767.git.DaveWK225@protonmail.com/
>>>>
>>>> I tested u-boot SPL with three SD cards on a BananaPi-F3 and found
>>>> a reproducible issue, the specific error I encountered is spl:
>>>> partition error (Error: -38)
>>>> At the meantime, when i was revert the commit:
>>>> mmc: k1: let the SPL read SD cards more than one block at a time
>>>> the error has gone. Same SD card, same operation steps.
>>>> Maybe BananaPi-F3 do not support read SD cards more than one block
>>>> at a time?
>>>>
>>>>
>>>
>>> Hi Zixian,
>>>
>>> Thanks for testing this on the BananaPi-F3 and reporting this. The
>>> same cards and steps failing only with this patch shows that
>>> multi-block SD reads in the SPL are not reliable yet.
>>>
>>> I would request to try one more experiment before dropping it.
>>> Please add MMC_CAP_CMD23 to host->host_caps and boot the same cards
>>> again. CMD23 (SET_BLOCK_COUNT) tells the card how many blocks to
>>> transfer. mmc_read_blocks() then uses CMD23 plus CMD18, and it does
>>> not send CMD12 afterwards. The current driver does not set
>>> MMC_CAP_CMD23, so a multi-block read is CMD18 followed by CMD12.
>>>
>>> After the SCR is read, the MMC core clears MMC_CAP_CMD23 when the card
>>> does not advertise SD_SCR_CMD23_SUPPORT. Those cards stay on CMD18
>>> plus CMD12.
>>>
>>> This also matches Eric's earlier note that on K1 ADMA depends on CMD23:
>>> https://patchwork.ozlabs.org/project/uboot/patch/20260707-m4-v4-3-
>>> dbd01185f911@riscstar.com/
>>>
>>> If the CMD23 test also fails, I agree that this patch should be
>>> dropped.
>>>
>>
>> Hi Zixian,
>>
>> A few follow-up questions about the SPL-only failure:
>>
>> The callback limits reads only when CONFIG_SPL_BUILD is enabled. U-Boot
>> proper already uses mmc->cfg->b_max, even without this patch.
>> Therefore, multi-block SD reads should already be used in U-Boot proper.
>>
>> Could you please boot U-Boot proper from another device and test a
>> multi-block read from the same SD cards?
>> Could you also compare the following between SPL and U-Boot proper?
>>
>> - selected SD timing mode
>> - card clock frequency
>> - bus width
>> - PIO, SDMA, or ADMA transfer path
>> - whether the card advertises CMD23 support
>>
>> Although both stages use the same driver source, they may use different
>> configuration options, transfer paths, clocks, and timing modes. This
>> could explain why CMD18 works in U-Boot proper but fails in SPL.
>>
>> Regards,
>> Tanmay
>
> Hi, Tanmay,
>
> Sure, I've added some print logs, which you can see below:
>
> commit 53c0ff5f65b0c7c4ae9f4563265741cd0ca23a0c
> Author: Zixian Zeng <sycamoremoon376@gmail.com>
> Date: Sun Oct 11 09:34:03 2026 +0800
>
> Add mmc debug log
>
> Signed-off-by: Zixian Zeng <sycamoremoon376@gmail.com>
>
> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
> index a619440fc4c..6e18d13884a 100644
> --- a/drivers/mmc/mmc.c
> +++ b/drivers/mmc/mmc.c
> @@ -458,6 +458,13 @@ static int mmc_read_blocks(struct mmc *mmc, void
> *dst, lbaint_t start,
> struct mmc_cmd cmd;
> struct mmc_data data;
>
> + if (blkcnt > 1)
> + printf("mmc: multi-blk blkcnt=%lu clk=%u mode=%u
> width=%u caps=%x cmd23_host=%u scr0=%x cmd23_card=%u\n",
> + (ulong)blkcnt, mmc->clock,
> + (unsigned)mmc->selected_mode, mmc->bus_width,
> + mmc->host_caps, !!(mmc->host_caps &
> MMC_CAP_CMD23),
> + mmc->scr[0], !!(mmc->scr[0] &
> SD_SCR_CMD23_SUPPORT));
> +
> if (blkcnt > 1 && (mmc->host_caps & MMC_CAP_CMD23)) {
> cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
> cmd.cmdarg = blkcnt & 0x0000ffff;
> @@ -483,8 +490,12 @@ static int mmc_read_blocks(struct mmc *mmc, void
> *dst, lbaint_t start,
> data.blocksize = mmc->read_bl_len;
> data.flags = MMC_DATA_READ;
>
> - if (mmc_send_cmd(mmc, &cmd, &data))
> + if (mmc_send_cmd(mmc, &cmd, &data)) {
> + log_err("mmc: cmd%u read failed: blks=%lu blksz=%lu
> arg=%lx\n",
> + cmd.cmdidx, (ulong)blkcnt,
> (ulong)mmc->read_bl_len,
> + (ulong)cmd.cmdarg);
> return 0;
> + }
>
> if (blkcnt > 1 && !(mmc->host_caps & MMC_CAP_CMD23)) {
> if (mmc_send_stop_transmission(mmc, false)) {
> @@ -547,6 +558,8 @@ ulong mmc_bread(struct blk_desc *block_dev,
> lbaint_t start, lbaint_t blkcnt,
> }
>
> if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
> + log_err("mmc: CMD16 blocklen=%lu failed, read of %lu
> blocks aborted\n",
> + (ulong)mmc->read_bl_len, (ulong)blkcnt);
> pr_debug("%s: Failed to set blocklen\n", __func__);
> return 0;
> }
> @@ -556,6 +569,8 @@ ulong mmc_bread(struct blk_desc *block_dev,
> lbaint_t start, lbaint_t blkcnt,
> do {
> cur = (blocks_todo > b_max) ? b_max : blocks_todo;
> if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
> + log_err("mmc: read of %lu blocks at lba %lx
> failed (b_max=%u)\n",
> + (ulong)cur, (ulong)start, b_max);
> pr_debug("%s: Failed to read blocks\n",
> __func__);
> return 0;
> }
> diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
> index 962a99cd05a..339b222bb68 100644
> --- a/drivers/mmc/sdhci.c
> +++ b/drivers/mmc/sdhci.c
> @@ -131,6 +131,7 @@ static int sdhci_transfer_data(struct sdhci_host
> *host, struct mmc_data *data)
> dma_addr_t start_addr = host->start_addr;
> unsigned int stat, rdy, mask, timeout, block = 0;
> bool transfer_done = false;
> + ulong t0 = get_timer(0);
>
> timeout = 1000000;
> rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
> @@ -138,6 +139,13 @@ static int sdhci_transfer_data(struct sdhci_host
> *host, struct mmc_data *data)
> do {
> stat = sdhci_readl(host, SDHCI_INT_STATUS);
> if (stat & SDHCI_INT_ERROR) {
> + log_err("sdhci: data err irq=%x present=%x
> mode=%x blksz=%x blkcnt=%x blocks=%u/%u t=%lums\n",
> + stat,
> + sdhci_readl(host, SDHCI_PRESENT_STATE),
> + sdhci_readw(host, SDHCI_TRANSFER_MODE),
> + sdhci_readw(host, SDHCI_BLOCK_SIZE),
> + sdhci_readw(host, SDHCI_BLOCK_COUNT),
> + block, data->blocks, get_timer(t0));
> log_debug("Error detected in status(%#x)!\n",
> stat);
> return -EIO;
> }
> @@ -294,6 +302,11 @@ static int sdhci_send_command(struct mmc *mmc,
> struct mmc_cmd *cmd,
> SDHCI_BLOCK_SIZE);
> sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
> sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
> + if (data->blocks > 1)
> + printf("sdhci: multi cmd%u arg=%lx blks=%u
> blksz=%u mode=%x dma=%u\n",
> + cmd->cmdidx, (ulong)cmd->cmdarg,
> data->blocks,
> + data->blocksize, mode,
> + !!(host->flags & USE_DMA));
> } else if (cmd->resp_type & MMC_RSP_BUSY) {
> sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
> }
> @@ -325,8 +338,12 @@ static int sdhci_send_command(struct mmc *mmc,
> struct mmc_cmd *cmd,
> if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
> sdhci_cmd_done(host, cmd);
> sdhci_writel(host, mask, SDHCI_INT_STATUS);
> - } else
> + } else {
> + log_err("sdhci: cmd%u status mismatch irq=%x mask=%x
> present=%x\n",
> + cmd->cmdidx, stat, mask,
> + sdhci_readl(host, SDHCI_PRESENT_STATE));
> ret = -1;
> + }
>
> if (!ret && data)
> ret = sdhci_transfer_data(host, data);
> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> index 13bf6bf6000..23c655c6def 100644
> --- a/drivers/mmc/spacemit_sdhci.c
> +++ b/drivers/mmc/spacemit_sdhci.c
> @@ -640,6 +640,19 @@ static int spacemit_sdhci_probe(struct udevice *dev)
> goto err_reset;
>
> spacemit_sdhci_phy_init(dev, host);
> +
> + {
> + u32 caps = sdhci_readl(host, SDHCI_CAPABILITIES);
> + const char *path = (host->flags & USE_ADMA64) ?
> "ADMA64" :
> + (host->flags & USE_ADMA) ? "ADMA" :
> + (host->flags & USE_SDMA) ? "SDMA" :
> "PIO";
> +
> + printf("sdhci: %s path=%s flags=%x caps_sdma=%u
> caps_adma2=%u max_clk=%u\n",
> + dev->name, path, host->flags,
> + !!(caps & SDHCI_CAN_DO_SDMA),
> + !!(caps & SDHCI_CAN_DO_ADMA2),
> + host->max_clk);
> + }
> return 0;
>
> /*
>
>
> commit 75d6b28ba7b020d3100586f586ee6d1a4488ac84
> Author: Zixian Zeng <sycamoremoon376@gmail.com>
> Date: Sun Oct 11 09:33:20 2026 +0800
>
> debug: Add MMC_CAPS_CMD23
>
> Signed-off-by: Zixian Zeng <sycamoremoon376@gmail.com>
>
> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> index 88e06a681ca..13bf6bf6000 100644
> --- a/drivers/mmc/spacemit_sdhci.c
> +++ b/drivers/mmc/spacemit_sdhci.c
> @@ -624,7 +624,7 @@ static int spacemit_sdhci_probe(struct udevice *dev)
> /* Set quirks */
> host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
> SDHCI_QUIRK_32BIT_DMA_ADDR;
> - host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
> + host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz |
> MMC_CAP_CMD23;
> host->max_clk = plat->cfg.f_max;
>
> plat->cfg.f_min = SDHC_MIN_CLOCK;
>
>
> With appling these two commits, Debug logs as follows:
>
> ⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ⥄ git log --oneline
> origin/next..HEAD
> 53c0ff5f65b (HEAD -> k1-dave-mmc) Add mmc debug log
> 75d6b28ba7b debug: Add MMC_CAPS_CMD23
> 6b4af8b1dd8 mmc: k1: do not release the shared AXI clock and reset on
> probe failure
> 4114764d716 mmc: k1: let the SPL read SD cards more than one block at
> a time
> 6676ce89521 mmc: k1: handle a missing max-frequency and
> clk_set_rate()'s return value
> 6427189ef33 spacemit: k1: fall back to the other boot devices in SPL
> b58a31797d7 spacemit: k1: do not require a PMIC or an SPI controller
> in SPL
>
> U-Boot SPL 2026.10-rc5-00641-g53c0ff5f65b0 (Oct 11 2026 - 10:31:28 +0800)
> Fail to detect board:-2
> vdd_core, value:900000
> vdd_1v8, value:1800000
> vdd_1v8_mmc, value:1800000
> DDR firmware: [0xc081d700]:0xf0227179, size:0x8d98
> DDR is ready
> No SPI controller (-19)
> Trying to boot from MMC2
> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> cmd23_host=1 scr0=2358043 cmd23_card=1
> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> sdhci: data err irq=408020 present=1070800 mode=32 blksz=7200
> blkcnt=12 blocks=12/32 t=2ms
> mmc: cmd18 read failed: blks=32 blksz=512 arg=2
> mmc: read of 32 blocks at lba 2 failed (b_max=65535)
> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> mmc: CMD16 blocklen=512 failed, read of 1 blocks aborted
> spl: partition error
> Error: -38
> SPL: Unsupported Boot Device!
> Trying to boot from MMC1
> alloc space exhausted ptr 104380 limit 100000
> Aligned buffer alloc failed
> spl: could not find mmc device 0. error: -19
> Error: -19
> SPL: Unsupported Boot Device!
> Trying to boot from SPI
> Invalid bus 0 (err=-19)
> SPI probe failed.
> Error: -19
> SPL: Unsupported Boot Device!
> SPL: Unsupported Boot Device!
> SPL: failed to boot from all boot devices
> ### ERROR ### Please RESET the board ###
>
>
> After I revert the multi-block SD read commit,
> I booted into u-boot proper. Debug logs as follows:
>
> ⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ⥄ git log --oneline
> origin/next..HEAD
> 55e8da25a70 (HEAD -> k1-dave-mmc) Revert "mmc: k1: let the SPL read SD
> cards more than one block at a time"
> 53c0ff5f65b Add mmc debug log
> 75d6b28ba7b debug: Add MMC_CAPS_CMD23
> 6b4af8b1dd8 mmc: k1: do not release the shared AXI clock and reset on
> probe failure
> 4114764d716 mmc: k1: let the SPL read SD cards more than one block at
> a time
> 6676ce89521 mmc: k1: handle a missing max-frequency and
> clk_set_rate()'s return value
> 6427189ef33 spacemit: k1: fall back to the other boot devices in SPL
> b58a31797d7 spacemit: k1: do not require a PMIC or an SPI controller
> in SPL
>
>
> U-Boot SPL 2026.10-rc5-00642-g55e8da25a70c (Oct 11 2026 - 10:38:42 +0800)
> Fail to detect board:-2
> vdd_core, value:900000
> vdd_1v8, value:1800000
> vdd_1v8_mmc, value:1800000
> DDR firmware: [0xc081d740]:0xf0227179, size:0x8d98
> DDR is ready
> No SPI controller (-19)
> Trying to boot from MMC2
> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
>
> <debug_uart>
>
>
> U-Boot 2026.10-rc5-00642-g55e8da25a70c (Oct 11 2026 - 10:38:42 +0800)
>
> DRAM: 4 GiB
> Core: 339 devices, 23 uclasses, devicetree: separate
> MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
> mmc@d4280000: 1, mmc@d4281000: 0
> Loading Environment from nowhere... OK
> In: serial@d4017000
> Out: serial@d4017000
> Err: serial@d4017000
> Net: No ethernet found.
> => mmc dev 1
> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> cmd23_host=1 scr0=2358043 cmd23_card=1
> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> cmd23_host=1 scr0=2358043 cmd23_card=1
> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> ... omit duplicate logs
> mmc: multi-blk blkcnt=2 clk=50000000 mode=2 width=4 caps=300207ef
> cmd23_host=1 scr0=2358043 cmd23_card=1
> sdhci: multi cmd18 arg=82002 blks=2 blksz=512 mode=32 dma=0
> switch to partitions #0, OK
> mmc1 is current device
> =>
> => mmc list
> mmc@d4280000: 1 (SD)
> mmc@d4281000: 0
> =>
> => mmc info
> Device: mmc@d4280000
> Manufacturer ID: 3
> OEM: 5344
> Name: SD32G
> Bus Speed: 50000000
> Mode: SD High Speed (50MHz)
> Rd Block Len: 512
> SD version 3.0
> High Capacity: Yes
> Capacity: 29.7 GiB
> Bus Width: 4-bit
> Erase Group Size: 512 Bytes
>
> I enabled MMC_CAP_CMD23 and the card does support it (SCR bit 1,
> cmd23_host=1 and cmd23_card=1 in the log above), so the SPL really
> used SET_BLOCK_COUNT + CMD18 without CMD12 - and it still aborts the
> data phase with SDHCI_INT_DATA_END_BIT after ~20 of 32 blocks.
> Booting U-Boot proper and issuing the same 32 block CMD18 from the same
> card succeeds, with the same PIO path (flags=0, dma=0), the same SD_HS
> mode, the same 4-bit bus and the same CMD23 usage.
> So I think CMD23 is not the trigger, the SPL fails with the FIFO
> permanently backed up (it drains slower than card delivers, so the
> controller has to stop the SD clock inside a block).
>
> Now answering your questions:
> mode : mode=2 = SD_HS, in both stages
> clock : requested 50 MHz (SD_HS) in both stages
> bus : 4-bit bus, in both stages
> path : PIO in both stages
> CMD23 : the card supports it and both stages use CMD23 + CMD18
>
>
Hi Zixian,
Thanks for the logs.
I hit the same pattern while testing the Cadence SD6HC driver.
Multi-block reads failed and single-block reads worked. On that board
the host and the card were in 1.8 V mode, but the I/O supply had been
left at 3.3 V. A short transfer got through; a longer one failed on the
data lines.
Both stages on K1 use the same PIO loop, so a FIFO that drains slower
than the card delivers would show up in U-Boot proper as well. Your
SPL/proper split fits an electrical setup difference.
The SPL failure is irq=408020. Bit 22 is the Data End Bit Error (EDEB,
SD mode only): the controller detected 0 at the end-bit position of
read data on DAT, or of the write CRC status. That is a bad edge on
the data line during the transfer.
On the Banana Pi F3, aldo1 is vqmmc-supply of &sdhci0. The U-Boot
dtsi names it vdd_1v8_mmc, and the SPL prints "vdd_1v8_mmc,
value:1800000" before MMC2. set_vdd_mmc() in board/spacemit/k1/spl.c,
called from board_init_f(), writes 1800000. The dts leaves aldo1 at
0.5 V to 3.4 V. SD High Speed (mode=2) uses 3.3 V signaling; 1.8 V is
only after a UHS switch. mmc1_cfg is power-source 3300, and
mmc1_uhs_cfg is the 1.8 V state. For this mode the rail should be 3.3 V.
CONFIG_SPL_MMC_IO_VOLTAGE is not set, so mmc_set_signal_voltage() is a
stub and signal_voltage stays MMC_SIGNAL_VOLTAGE_000. aldo1 stays at
1.8 V. U-Boot proper has CONFIG_MMC_IO_VOLTAGE. mmc_set_initial_state()
requests MMC_SIGNAL_VOLTAGE_330, so the driver writes 3300000 to the
same vqmmc-supply and clears SDHCI_CTRL_VDD_180 before the transfer
that succeeds.
CONFIG_SPL_PINCTRL is not set either. The driver calls
pinctrl_select_state() under IS_ENABLED(CONFIG_PINCTRL), but that
function is a stub unless CONFIG_IS_ENABLED(PINCTRL), and the return
is ignored. SPL never applies mmc1_cfg. Proper selects "default" for
SD_HS, which is that state.
Keeping the multi-block path, set_vdd_mmc() to 3300000, or enable
CONFIG_SPL_MMC_IO_VOLTAGE. If the 32-block CMD18 still fails, enable
CONFIG_SPL_PINCTRL so mmc1_cfg is applied. If either makes the read
succeed, this is the F3 failure.
Regards,
Tanmay
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-11 14:31 ` Kathpalia, Tanmay
@ 2026-10-11 15:33 ` Anand Moon
2026-10-11 19:41 ` Kathpalia, Tanmay
2026-10-12 13:15 ` Zixian Zeng
1 sibling, 1 reply; 33+ messages in thread
From: Anand Moon @ 2026-10-11 15:33 UTC (permalink / raw)
To: Kathpalia, Tanmay
Cc: Zixian Zeng, Dave Klotz, Yixun Lan, Eric Chung, Peng Fan, u-boot,
Jaehoon Chung, Tom Rini, u-boot-spacemit
Hi Al,L
On Sun, 11 Oct 2026 at 20:07, Kathpalia, Tanmay
<tanmay.kathpalia@altera.com> wrote:
>
>
> On 11-10-2026 09:08, Zixian Zeng wrote:
> > On 2026/10/11 03:16, Kathpalia, Tanmay wrote:
> >>
> >> On 11-10-2026 00:32, Kathpalia, Tanmay wrote:
> >>>
> >>> On 10-10-2026 11:47, Zixian Zeng wrote:
> >>>> Hi, Dave:
> >>>>
> >>>> On 2026/10/6 02:01, Dave Klotz wrote:
> >>>>> spacemit_sdhci_get_b_max() limits every SD read in the SPL to a
> >>>>> single
> >>>>> block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
> >>>>> separate commands. The controller handles multi-block PIO reads in
> >>>>> the
> >>>>> SPL: the OrangePi RV2 has loaded U-Boot from microSD with them
> >>>>> through
> >>>>> the v2026.07 and v2026.10 trees.
> >>>>>
> >>>>> Drop the limit and use the host's b_max.
> >>>>>
> >>>>> The merged v13 cover retains the v9 changelog entry choosing single-
> >>>>> block SD reads in SPL. This reverses that deliberate policy for the
> >>>>> recorded RV2 SPL boot use case; no general multi-card reliability
> >>>>> claim
> >>>>> is made. K1 does not advertise MMC_CAP_CMD23, so the MMC core sends
> >>>>> CMD12 after a multi-block read rather than requiring CMD23.
> >>>>> Additional
> >>>>> card models, cold boots and transfer-error recovery remain required.
> >>>>>
> >>>>> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
> >>>>> Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
> >>>>> ---
> >>>>> Validation: unchanged executable change from v1; exact-base source
> >>>>> replay and checkpatch pass. The corrected combined integration, with
> >>>>> separate clock/MMC and DDR relocation fixes, passed SD SPL/FIT and
> >>>>> automatic NVMe EFI boot on the 4 GiB RV2 in a warm-boot trial.
> >>>>> This is
> >>>>> an integration result, not an isolated test of this patch.
> >>>>>
> >>>>> drivers/mmc/spacemit_sdhci.c | 11 -----------
> >>>>> 1 file changed, 0 insertions(+), 11 deletions(-)
> >>>>>
> >>>>> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/
> >>>>> spacemit_sdhci.c
> >>>>> index 6488ae0fdb..4284553177 100644
> >>>>> --- a/drivers/mmc/spacemit_sdhci.c
> >>>>> +++ b/drivers/mmc/spacemit_sdhci.c
> >>>>> @@ -324,16 +324,6 @@
> >>>>> return 0;
> >>>>> }
> >>>>> -static int spacemit_sdhci_get_b_max(struct udevice *dev, void
> >>>>> *dst,
> >>>>> - lbaint_t blkcnt)
> >>>>> -{
> >>>>> - struct mmc *mmc = mmc_get_mmc_dev(dev);
> >>>>> -
> >>>>> - if (IS_ENABLED(CONFIG_SPL_BUILD) && mmc && IS_SD(mmc))
> >>>>> - return 1;
> >>>>> - return mmc->cfg->b_max;
> >>>>> -}
> >>>>> -
> >>>>> static void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
> >>>>> {
> >>>>> struct mmc *mmc = host->mmc;
> >>>>> @@ -574,7 +564,6 @@
> >>>>> spacemit_mmc_ops = sdhci_ops;
> >>>>> spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
> >>>>> - spacemit_mmc_ops.get_b_max = spacemit_sdhci_get_b_max;
> >>>>> ret = clk_get_bulk(dev, &plat->clks);
> >>>>> if (ret) {
> >>>> Using the current version of the next branch u-boot (ed869863c7),
> >>>> with your MMC patch series applied.
> >>>> Since the SPI controller is not enabled by default on the BananaPi-F3,
> >>>> I also applied another patch series:
> >>>> Link: https://lore.kernel.org/u-boot/
> >>>> cover.1790976767.git.DaveWK225@protonmail.com/
> >>>>
> >>>> I tested u-boot SPL with three SD cards on a BananaPi-F3 and found
> >>>> a reproducible issue, the specific error I encountered is spl:
> >>>> partition error (Error: -38)
> >>>> At the meantime, when i was revert the commit:
> >>>> mmc: k1: let the SPL read SD cards more than one block at a time
> >>>> the error has gone. Same SD card, same operation steps.
> >>>> Maybe BananaPi-F3 do not support read SD cards more than one block
> >>>> at a time?
> >>>>
> >>>>
> >>>
> >>> Hi Zixian,
> >>>
> >>> Thanks for testing this on the BananaPi-F3 and reporting this. The
> >>> same cards and steps failing only with this patch shows that
> >>> multi-block SD reads in the SPL are not reliable yet.
> >>>
> >>> I would request to try one more experiment before dropping it.
> >>> Please add MMC_CAP_CMD23 to host->host_caps and boot the same cards
> >>> again. CMD23 (SET_BLOCK_COUNT) tells the card how many blocks to
> >>> transfer. mmc_read_blocks() then uses CMD23 plus CMD18, and it does
> >>> not send CMD12 afterwards. The current driver does not set
> >>> MMC_CAP_CMD23, so a multi-block read is CMD18 followed by CMD12.
> >>>
> >>> After the SCR is read, the MMC core clears MMC_CAP_CMD23 when the card
> >>> does not advertise SD_SCR_CMD23_SUPPORT. Those cards stay on CMD18
> >>> plus CMD12.
> >>>
> >>> This also matches Eric's earlier note that on K1 ADMA depends on CMD23:
> >>> https://patchwork.ozlabs.org/project/uboot/patch/20260707-m4-v4-3-
> >>> dbd01185f911@riscstar.com/
> >>>
> >>> If the CMD23 test also fails, I agree that this patch should be
> >>> dropped.
> >>>
> >>
> >> Hi Zixian,
> >>
> >> A few follow-up questions about the SPL-only failure:
> >>
> >> The callback limits reads only when CONFIG_SPL_BUILD is enabled. U-Boot
> >> proper already uses mmc->cfg->b_max, even without this patch.
> >> Therefore, multi-block SD reads should already be used in U-Boot proper.
> >>
> >> Could you please boot U-Boot proper from another device and test a
> >> multi-block read from the same SD cards?
> >> Could you also compare the following between SPL and U-Boot proper?
> >>
> >> - selected SD timing mode
> >> - card clock frequency
> >> - bus width
> >> - PIO, SDMA, or ADMA transfer path
> >> - whether the card advertises CMD23 support
> >>
> >> Although both stages use the same driver source, they may use different
> >> configuration options, transfer paths, clocks, and timing modes. This
> >> could explain why CMD18 works in U-Boot proper but fails in SPL.
> >>
> >> Regards,
> >> Tanmay
> >
> > Hi, Tanmay,
> >
> > Sure, I've added some print logs, which you can see below:
> >
> > commit 53c0ff5f65b0c7c4ae9f4563265741cd0ca23a0c
> > Author: Zixian Zeng <sycamoremoon376@gmail.com>
> > Date: Sun Oct 11 09:34:03 2026 +0800
> >
> > Add mmc debug log
> >
> > Signed-off-by: Zixian Zeng <sycamoremoon376@gmail.com>
> >
> > diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
> > index a619440fc4c..6e18d13884a 100644
> > --- a/drivers/mmc/mmc.c
> > +++ b/drivers/mmc/mmc.c
> > @@ -458,6 +458,13 @@ static int mmc_read_blocks(struct mmc *mmc, void
> > *dst, lbaint_t start,
> > struct mmc_cmd cmd;
> > struct mmc_data data;
> >
> > + if (blkcnt > 1)
> > + printf("mmc: multi-blk blkcnt=%lu clk=%u mode=%u
> > width=%u caps=%x cmd23_host=%u scr0=%x cmd23_card=%u\n",
> > + (ulong)blkcnt, mmc->clock,
> > + (unsigned)mmc->selected_mode, mmc->bus_width,
> > + mmc->host_caps, !!(mmc->host_caps &
> > MMC_CAP_CMD23),
> > + mmc->scr[0], !!(mmc->scr[0] &
> > SD_SCR_CMD23_SUPPORT));
> > +
> > if (blkcnt > 1 && (mmc->host_caps & MMC_CAP_CMD23)) {
> > cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
> > cmd.cmdarg = blkcnt & 0x0000ffff;
> > @@ -483,8 +490,12 @@ static int mmc_read_blocks(struct mmc *mmc, void
> > *dst, lbaint_t start,
> > data.blocksize = mmc->read_bl_len;
> > data.flags = MMC_DATA_READ;
> >
> > - if (mmc_send_cmd(mmc, &cmd, &data))
> > + if (mmc_send_cmd(mmc, &cmd, &data)) {
> > + log_err("mmc: cmd%u read failed: blks=%lu blksz=%lu
> > arg=%lx\n",
> > + cmd.cmdidx, (ulong)blkcnt,
> > (ulong)mmc->read_bl_len,
> > + (ulong)cmd.cmdarg);
> > return 0;
> > + }
> >
> > if (blkcnt > 1 && !(mmc->host_caps & MMC_CAP_CMD23)) {
> > if (mmc_send_stop_transmission(mmc, false)) {
> > @@ -547,6 +558,8 @@ ulong mmc_bread(struct blk_desc *block_dev,
> > lbaint_t start, lbaint_t blkcnt,
> > }
> >
> > if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
> > + log_err("mmc: CMD16 blocklen=%lu failed, read of %lu
> > blocks aborted\n",
> > + (ulong)mmc->read_bl_len, (ulong)blkcnt);
> > pr_debug("%s: Failed to set blocklen\n", __func__);
> > return 0;
> > }
> > @@ -556,6 +569,8 @@ ulong mmc_bread(struct blk_desc *block_dev,
> > lbaint_t start, lbaint_t blkcnt,
> > do {
> > cur = (blocks_todo > b_max) ? b_max : blocks_todo;
> > if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
> > + log_err("mmc: read of %lu blocks at lba %lx
> > failed (b_max=%u)\n",
> > + (ulong)cur, (ulong)start, b_max);
> > pr_debug("%s: Failed to read blocks\n",
> > __func__);
> > return 0;
> > }
> > diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
> > index 962a99cd05a..339b222bb68 100644
> > --- a/drivers/mmc/sdhci.c
> > +++ b/drivers/mmc/sdhci.c
> > @@ -131,6 +131,7 @@ static int sdhci_transfer_data(struct sdhci_host
> > *host, struct mmc_data *data)
> > dma_addr_t start_addr = host->start_addr;
> > unsigned int stat, rdy, mask, timeout, block = 0;
> > bool transfer_done = false;
> > + ulong t0 = get_timer(0);
> >
> > timeout = 1000000;
> > rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
> > @@ -138,6 +139,13 @@ static int sdhci_transfer_data(struct sdhci_host
> > *host, struct mmc_data *data)
> > do {
> > stat = sdhci_readl(host, SDHCI_INT_STATUS);
> > if (stat & SDHCI_INT_ERROR) {
> > + log_err("sdhci: data err irq=%x present=%x
> > mode=%x blksz=%x blkcnt=%x blocks=%u/%u t=%lums\n",
> > + stat,
> > + sdhci_readl(host, SDHCI_PRESENT_STATE),
> > + sdhci_readw(host, SDHCI_TRANSFER_MODE),
> > + sdhci_readw(host, SDHCI_BLOCK_SIZE),
> > + sdhci_readw(host, SDHCI_BLOCK_COUNT),
> > + block, data->blocks, get_timer(t0));
> > log_debug("Error detected in status(%#x)!\n",
> > stat);
> > return -EIO;
> > }
> > @@ -294,6 +302,11 @@ static int sdhci_send_command(struct mmc *mmc,
> > struct mmc_cmd *cmd,
> > SDHCI_BLOCK_SIZE);
> > sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
> > sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
> > + if (data->blocks > 1)
> > + printf("sdhci: multi cmd%u arg=%lx blks=%u
> > blksz=%u mode=%x dma=%u\n",
> > + cmd->cmdidx, (ulong)cmd->cmdarg,
> > data->blocks,
> > + data->blocksize, mode,
> > + !!(host->flags & USE_DMA));
> > } else if (cmd->resp_type & MMC_RSP_BUSY) {
> > sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
> > }
> > @@ -325,8 +338,12 @@ static int sdhci_send_command(struct mmc *mmc,
> > struct mmc_cmd *cmd,
> > if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
> > sdhci_cmd_done(host, cmd);
> > sdhci_writel(host, mask, SDHCI_INT_STATUS);
> > - } else
> > + } else {
> > + log_err("sdhci: cmd%u status mismatch irq=%x mask=%x
> > present=%x\n",
> > + cmd->cmdidx, stat, mask,
> > + sdhci_readl(host, SDHCI_PRESENT_STATE));
> > ret = -1;
> > + }
> >
> > if (!ret && data)
> > ret = sdhci_transfer_data(host, data);
> > diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> > index 13bf6bf6000..23c655c6def 100644
> > --- a/drivers/mmc/spacemit_sdhci.c
> > +++ b/drivers/mmc/spacemit_sdhci.c
> > @@ -640,6 +640,19 @@ static int spacemit_sdhci_probe(struct udevice *dev)
> > goto err_reset;
> >
> > spacemit_sdhci_phy_init(dev, host);
> > +
> > + {
> > + u32 caps = sdhci_readl(host, SDHCI_CAPABILITIES);
> > + const char *path = (host->flags & USE_ADMA64) ?
> > "ADMA64" :
> > + (host->flags & USE_ADMA) ? "ADMA" :
> > + (host->flags & USE_SDMA) ? "SDMA" :
> > "PIO";
> > +
> > + printf("sdhci: %s path=%s flags=%x caps_sdma=%u
> > caps_adma2=%u max_clk=%u\n",
> > + dev->name, path, host->flags,
> > + !!(caps & SDHCI_CAN_DO_SDMA),
> > + !!(caps & SDHCI_CAN_DO_ADMA2),
> > + host->max_clk);
> > + }
> > return 0;
> >
> > /*
> >
> >
> > commit 75d6b28ba7b020d3100586f586ee6d1a4488ac84
> > Author: Zixian Zeng <sycamoremoon376@gmail.com>
> > Date: Sun Oct 11 09:33:20 2026 +0800
> >
> > debug: Add MMC_CAPS_CMD23
> >
> > Signed-off-by: Zixian Zeng <sycamoremoon376@gmail.com>
> >
> > diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> > index 88e06a681ca..13bf6bf6000 100644
> > --- a/drivers/mmc/spacemit_sdhci.c
> > +++ b/drivers/mmc/spacemit_sdhci.c
> > @@ -624,7 +624,7 @@ static int spacemit_sdhci_probe(struct udevice *dev)
> > /* Set quirks */
> > host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
> > SDHCI_QUIRK_32BIT_DMA_ADDR;
> > - host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
> > + host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz |
> > MMC_CAP_CMD23;
> > host->max_clk = plat->cfg.f_max;
> >
> > plat->cfg.f_min = SDHC_MIN_CLOCK;
> >
> >
> > With appling these two commits, Debug logs as follows:
> >
> > ⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ⥄ git log --oneline
> > origin/next..HEAD
> > 53c0ff5f65b (HEAD -> k1-dave-mmc) Add mmc debug log
> > 75d6b28ba7b debug: Add MMC_CAPS_CMD23
> > 6b4af8b1dd8 mmc: k1: do not release the shared AXI clock and reset on
> > probe failure
> > 4114764d716 mmc: k1: let the SPL read SD cards more than one block at
> > a time
> > 6676ce89521 mmc: k1: handle a missing max-frequency and
> > clk_set_rate()'s return value
> > 6427189ef33 spacemit: k1: fall back to the other boot devices in SPL
> > b58a31797d7 spacemit: k1: do not require a PMIC or an SPI controller
> > in SPL
> >
> > U-Boot SPL 2026.10-rc5-00641-g53c0ff5f65b0 (Oct 11 2026 - 10:31:28 +0800)
> > Fail to detect board:-2
> > vdd_core, value:900000
> > vdd_1v8, value:1800000
> > vdd_1v8_mmc, value:1800000
> > DDR firmware: [0xc081d700]:0xf0227179, size:0x8d98
> > DDR is ready
> > No SPI controller (-19)
> > Trying to boot from MMC2
> > sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> > max_clk=204800000
> > mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> > cmd23_host=1 scr0=2358043 cmd23_card=1
> > sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> > sdhci: data err irq=408020 present=1070800 mode=32 blksz=7200
> > blkcnt=12 blocks=12/32 t=2ms
> > mmc: cmd18 read failed: blks=32 blksz=512 arg=2
> > mmc: read of 32 blocks at lba 2 failed (b_max=65535)
> > sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> > sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> > sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> > sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> > sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
> > mmc: CMD16 blocklen=512 failed, read of 1 blocks aborted
> > spl: partition error
> > Error: -38
> > SPL: Unsupported Boot Device!
> > Trying to boot from MMC1
> > alloc space exhausted ptr 104380 limit 100000
> > Aligned buffer alloc failed
> > spl: could not find mmc device 0. error: -19
> > Error: -19
> > SPL: Unsupported Boot Device!
> > Trying to boot from SPI
> > Invalid bus 0 (err=-19)
> > SPI probe failed.
> > Error: -19
> > SPL: Unsupported Boot Device!
> > SPL: Unsupported Boot Device!
> > SPL: failed to boot from all boot devices
> > ### ERROR ### Please RESET the board ###
> >
> >
> > After I revert the multi-block SD read commit,
> > I booted into u-boot proper. Debug logs as follows:
> >
> > ⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ⥄ git log --oneline
> > origin/next..HEAD
> > 55e8da25a70 (HEAD -> k1-dave-mmc) Revert "mmc: k1: let the SPL read SD
> > cards more than one block at a time"
> > 53c0ff5f65b Add mmc debug log
> > 75d6b28ba7b debug: Add MMC_CAPS_CMD23
> > 6b4af8b1dd8 mmc: k1: do not release the shared AXI clock and reset on
> > probe failure
> > 4114764d716 mmc: k1: let the SPL read SD cards more than one block at
> > a time
> > 6676ce89521 mmc: k1: handle a missing max-frequency and
> > clk_set_rate()'s return value
> > 6427189ef33 spacemit: k1: fall back to the other boot devices in SPL
> > b58a31797d7 spacemit: k1: do not require a PMIC or an SPI controller
> > in SPL
> >
> >
> > U-Boot SPL 2026.10-rc5-00642-g55e8da25a70c (Oct 11 2026 - 10:38:42 +0800)
> > Fail to detect board:-2
> > vdd_core, value:900000
> > vdd_1v8, value:1800000
> > vdd_1v8_mmc, value:1800000
> > DDR firmware: [0xc081d740]:0xf0227179, size:0x8d98
> > DDR is ready
> > No SPI controller (-19)
> > Trying to boot from MMC2
> > sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> > max_clk=204800000
> >
> > <debug_uart>
> >
> >
> > U-Boot 2026.10-rc5-00642-g55e8da25a70c (Oct 11 2026 - 10:38:42 +0800)
> >
> > DRAM: 4 GiB
> > Core: 339 devices, 23 uclasses, devicetree: separate
> > MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> > max_clk=204800000
> > sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> > max_clk=204800000
> > mmc@d4280000: 1, mmc@d4281000: 0
> > Loading Environment from nowhere... OK
> > In: serial@d4017000
> > Out: serial@d4017000
> > Err: serial@d4017000
> > Net: No ethernet found.
> > => mmc dev 1
> > mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> > cmd23_host=1 scr0=2358043 cmd23_card=1
> > sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> > mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> > cmd23_host=1 scr0=2358043 cmd23_card=1
> > sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> > ... omit duplicate logs
> > mmc: multi-blk blkcnt=2 clk=50000000 mode=2 width=4 caps=300207ef
> > cmd23_host=1 scr0=2358043 cmd23_card=1
> > sdhci: multi cmd18 arg=82002 blks=2 blksz=512 mode=32 dma=0
> > switch to partitions #0, OK
> > mmc1 is current device
> > =>
> > => mmc list
> > mmc@d4280000: 1 (SD)
> > mmc@d4281000: 0
> > =>
> > => mmc info
> > Device: mmc@d4280000
> > Manufacturer ID: 3
> > OEM: 5344
> > Name: SD32G
> > Bus Speed: 50000000
> > Mode: SD High Speed (50MHz)
> > Rd Block Len: 512
> > SD version 3.0
> > High Capacity: Yes
> > Capacity: 29.7 GiB
> > Bus Width: 4-bit
> > Erase Group Size: 512 Bytes
> >
> > I enabled MMC_CAP_CMD23 and the card does support it (SCR bit 1,
> > cmd23_host=1 and cmd23_card=1 in the log above), so the SPL really
> > used SET_BLOCK_COUNT + CMD18 without CMD12 - and it still aborts the
> > data phase with SDHCI_INT_DATA_END_BIT after ~20 of 32 blocks.
> > Booting U-Boot proper and issuing the same 32 block CMD18 from the same
> > card succeeds, with the same PIO path (flags=0, dma=0), the same SD_HS
> > mode, the same 4-bit bus and the same CMD23 usage.
> > So I think CMD23 is not the trigger, the SPL fails with the FIFO
> > permanently backed up (it drains slower than card delivers, so the
> > controller has to stop the SD clock inside a block).
> >
> > Now answering your questions:
> > mode : mode=2 = SD_HS, in both stages
> > clock : requested 50 MHz (SD_HS) in both stages
> > bus : 4-bit bus, in both stages
> > path : PIO in both stages
> > CMD23 : the card supports it and both stages use CMD23 + CMD18
> >
> >
>
> Hi Zixian,
>
> Thanks for the logs.
>
> I hit the same pattern while testing the Cadence SD6HC driver.
> Multi-block reads failed and single-block reads worked. On that board
> the host and the card were in 1.8 V mode, but the I/O supply had been
> left at 3.3 V. A short transfer got through; a longer one failed on the
> data lines.
> Both stages on K1 use the same PIO loop, so a FIFO that drains slower
> than the card delivers would show up in U-Boot proper as well. Your
> SPL/proper split fits an electrical setup difference.
>
> The SPL failure is irq=408020. Bit 22 is the Data End Bit Error (EDEB,
> SD mode only): the controller detected 0 at the end-bit position of
> read data on DAT, or of the write CRC status. That is a bad edge on
> the data line during the transfer.
>
> On the Banana Pi F3, aldo1 is vqmmc-supply of &sdhci0. The U-Boot
> dtsi names it vdd_1v8_mmc, and the SPL prints "vdd_1v8_mmc,
> value:1800000" before MMC2. set_vdd_mmc() in board/spacemit/k1/spl.c,
> called from board_init_f(), writes 1800000. The dts leaves aldo1 at
> 0.5 V to 3.4 V. SD High Speed (mode=2) uses 3.3 V signaling; 1.8 V is
> only after a UHS switch. mmc1_cfg is power-source 3300, and
> mmc1_uhs_cfg is the 1.8 V state. For this mode the rail should be 3.3 V.
>
> CONFIG_SPL_MMC_IO_VOLTAGE is not set, so mmc_set_signal_voltage() is a
> stub and signal_voltage stays MMC_SIGNAL_VOLTAGE_000. aldo1 stays at
> 1.8 V. U-Boot proper has CONFIG_MMC_IO_VOLTAGE. mmc_set_initial_state()
> requests MMC_SIGNAL_VOLTAGE_330, so the driver writes 3300000 to the
> same vqmmc-supply and clears SDHCI_CTRL_VDD_180 before the transfer
> that succeeds.
>
> CONFIG_SPL_PINCTRL is not set either. The driver calls
> pinctrl_select_state() under IS_ENABLED(CONFIG_PINCTRL), but that
> function is a stub unless CONFIG_IS_ENABLED(PINCTRL), and the return
> is ignored. SPL never applies mmc1_cfg. Proper selects "default" for
> SD_HS, which is that state.
>
> Keeping the multi-block path, set_vdd_mmc() to 3300000, or enable
> CONFIG_SPL_MMC_IO_VOLTAGE. If the 32-block CMD18 still fails, enable
> CONFIG_SPL_PINCTRL so mmc1_cfg is applied. If either makes the read
> succeed, this is the F3 failure.
>
We need to enable CONFIG_SPL_SPACEMIT_GPIO?
Thanks. I am seeing the same issue on the F3 board.
Since spacemit/k1-musepi-pro is configured as the default device tree,
do we also need to make similar changes to k1-bananapi-f3-u-boot.dtsi?
$ grep spacemit configs/spacemit_k1_defconfig
CONFIG_DEFAULT_DEVICE_TREE="spacemit/k1-musepi-pro"
CONFIG_OF_LIST="spacemit/k1-bananapi-f3 spacemit/k1-musepi-pro"
On my board, the system fails with the following error: Unhandled
exception: Illegal instruction
Could this be caused by k1-bananapi-f3-u-boot.dtsi not being updated
in the same way as
spacemit/k1-musepi-pro?
sys: 0x2
try sd...
bm:3
j...
<debug_uart>
U-Boot SPL 2026.10-00722-g6eaefa1cf807-dirty (Oct 11 2026 - 18:36:52 +0530)
Fail to detect board:-2
vdd_core, value:900000
vdd_1v8, value:1800000
vdd_1v8_mmc, value:1800000
DDR firmware: [0xc081dc80]:0xf0227179, size:0x8d98
DDR is ready
jedec_spi_nor flash@0: unrecognized JEDEC id bytes: 00, 00, 00
Fail to detect spi nor flash.
Trying to boot from MMC2
sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1 max_clk=204800000
Unhandled exception: Illegal instruction
EPC: 0000000000200000 RA: 00000000c08017fa TVAL: 000000006d9058eb
Code: 0001 0006 0000 0000 0000 0000 0000 0000 (58eb 6d90)
resetting ...
reset not supported yet
### ERROR ### Please RESET the board ###
> Regards,
> Tanmay
>
Thanks
-Anand
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-11 15:33 ` Anand Moon
@ 2026-10-11 19:41 ` Kathpalia, Tanmay
0 siblings, 0 replies; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-11 19:41 UTC (permalink / raw)
To: Anand Moon
Cc: Zixian Zeng, Dave Klotz, Yixun Lan, Eric Chung, Peng Fan, u-boot,
Jaehoon Chung, Tom Rini, u-boot-spacemit
On 11-10-2026 21:03, Anand Moon wrote:
> Hi Al,L
>
> On Sun, 11 Oct 2026 at 20:07, Kathpalia, Tanmay
> <tanmay.kathpalia@altera.com> wrote:
>>
>> On 11-10-2026 09:08, Zixian Zeng wrote:
>>> On 2026/10/11 03:16, Kathpalia, Tanmay wrote:
>>>> On 11-10-2026 00:32, Kathpalia, Tanmay wrote:
>>>>> On 10-10-2026 11:47, Zixian Zeng wrote:
>>>>>> Hi, Dave:
>>>>>>
>>>>>> On 2026/10/6 02:01, Dave Klotz wrote:
>>>>>>> spacemit_sdhci_get_b_max() limits every SD read in the SPL to a
>>>>>>> single
>>>>>>> block, so loading a ~1 MiB u-boot.itb from a card takes about 2000
>>>>>>> separate commands. The controller handles multi-block PIO reads in
>>>>>>> the
>>>>>>> SPL: the OrangePi RV2 has loaded U-Boot from microSD with them
>>>>>>> through
>>>>>>> the v2026.07 and v2026.10 trees.
>>>>>>>
>>>>>>> Drop the limit and use the host's b_max.
>>>>>>>
>>>>>>> The merged v13 cover retains the v9 changelog entry choosing single-
>>>>>>> block SD reads in SPL. This reverses that deliberate policy for the
>>>>>>> recorded RV2 SPL boot use case; no general multi-card reliability
>>>>>>> claim
>>>>>>> is made. K1 does not advertise MMC_CAP_CMD23, so the MMC core sends
>>>>>>> CMD12 after a multi-block read rather than requiring CMD23.
>>>>>>> Additional
>>>>>>> card models, cold boots and transfer-error recovery remain required.
>>>>>>>
>>>>>>> Signed-off-by: Dave Klotz <DaveWK225@protonmail.com>
>>>>>>> Reviewed-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
>>>>>>> ---
>>>>>>> Validation: unchanged executable change from v1; exact-base source
>>>>>>> replay and checkpatch pass. The corrected combined integration, with
>>>>>>> separate clock/MMC and DDR relocation fixes, passed SD SPL/FIT and
>>>>>>> automatic NVMe EFI boot on the 4 GiB RV2 in a warm-boot trial.
>>>>>>> This is
>>>>>>> an integration result, not an isolated test of this patch.
>>>>>>>
>>>>>>> drivers/mmc/spacemit_sdhci.c | 11 -----------
>>>>>>> 1 file changed, 0 insertions(+), 11 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/
>>>>>>> spacemit_sdhci.c
>>>>>>> index 6488ae0fdb..4284553177 100644
>>>>>>> --- a/drivers/mmc/spacemit_sdhci.c
>>>>>>> +++ b/drivers/mmc/spacemit_sdhci.c
>>>>>>> @@ -324,16 +324,6 @@
>>>>>>> return 0;
>>>>>>> }
>>>>>>> -static int spacemit_sdhci_get_b_max(struct udevice *dev, void
>>>>>>> *dst,
>>>>>>> - lbaint_t blkcnt)
>>>>>>> -{
>>>>>>> - struct mmc *mmc = mmc_get_mmc_dev(dev);
>>>>>>> -
>>>>>>> - if (IS_ENABLED(CONFIG_SPL_BUILD) && mmc && IS_SD(mmc))
>>>>>>> - return 1;
>>>>>>> - return mmc->cfg->b_max;
>>>>>>> -}
>>>>>>> -
>>>>>>> static void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
>>>>>>> {
>>>>>>> struct mmc *mmc = host->mmc;
>>>>>>> @@ -574,7 +564,6 @@
>>>>>>> spacemit_mmc_ops = sdhci_ops;
>>>>>>> spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
>>>>>>> - spacemit_mmc_ops.get_b_max = spacemit_sdhci_get_b_max;
>>>>>>> ret = clk_get_bulk(dev, &plat->clks);
>>>>>>> if (ret) {
>>>>>> Using the current version of the next branch u-boot (ed869863c7),
>>>>>> with your MMC patch series applied.
>>>>>> Since the SPI controller is not enabled by default on the BananaPi-F3,
>>>>>> I also applied another patch series:
>>>>>> Link: https://lore.kernel.org/u-boot/
>>>>>> cover.1790976767.git.DaveWK225@protonmail.com/
>>>>>>
>>>>>> I tested u-boot SPL with three SD cards on a BananaPi-F3 and found
>>>>>> a reproducible issue, the specific error I encountered is spl:
>>>>>> partition error (Error: -38)
>>>>>> At the meantime, when i was revert the commit:
>>>>>> mmc: k1: let the SPL read SD cards more than one block at a time
>>>>>> the error has gone. Same SD card, same operation steps.
>>>>>> Maybe BananaPi-F3 do not support read SD cards more than one block
>>>>>> at a time?
>>>>>>
>>>>>>
>>>>> Hi Zixian,
>>>>>
>>>>> Thanks for testing this on the BananaPi-F3 and reporting this. The
>>>>> same cards and steps failing only with this patch shows that
>>>>> multi-block SD reads in the SPL are not reliable yet.
>>>>>
>>>>> I would request to try one more experiment before dropping it.
>>>>> Please add MMC_CAP_CMD23 to host->host_caps and boot the same cards
>>>>> again. CMD23 (SET_BLOCK_COUNT) tells the card how many blocks to
>>>>> transfer. mmc_read_blocks() then uses CMD23 plus CMD18, and it does
>>>>> not send CMD12 afterwards. The current driver does not set
>>>>> MMC_CAP_CMD23, so a multi-block read is CMD18 followed by CMD12.
>>>>>
>>>>> After the SCR is read, the MMC core clears MMC_CAP_CMD23 when the card
>>>>> does not advertise SD_SCR_CMD23_SUPPORT. Those cards stay on CMD18
>>>>> plus CMD12.
>>>>>
>>>>> This also matches Eric's earlier note that on K1 ADMA depends on CMD23:
>>>>> https://patchwork.ozlabs.org/project/uboot/patch/20260707-m4-v4-3-
>>>>> dbd01185f911@riscstar.com/
>>>>>
>>>>> If the CMD23 test also fails, I agree that this patch should be
>>>>> dropped.
>>>>>
>>>> Hi Zixian,
>>>>
>>>> A few follow-up questions about the SPL-only failure:
>>>>
>>>> The callback limits reads only when CONFIG_SPL_BUILD is enabled. U-Boot
>>>> proper already uses mmc->cfg->b_max, even without this patch.
>>>> Therefore, multi-block SD reads should already be used in U-Boot proper.
>>>>
>>>> Could you please boot U-Boot proper from another device and test a
>>>> multi-block read from the same SD cards?
>>>> Could you also compare the following between SPL and U-Boot proper?
>>>>
>>>> - selected SD timing mode
>>>> - card clock frequency
>>>> - bus width
>>>> - PIO, SDMA, or ADMA transfer path
>>>> - whether the card advertises CMD23 support
>>>>
>>>> Although both stages use the same driver source, they may use different
>>>> configuration options, transfer paths, clocks, and timing modes. This
>>>> could explain why CMD18 works in U-Boot proper but fails in SPL.
>>>>
>>>> Regards,
>>>> Tanmay
>>> Hi, Tanmay,
>>>
>>> Sure, I've added some print logs, which you can see below:
>>>
>>> commit 53c0ff5f65b0c7c4ae9f4563265741cd0ca23a0c
>>> Author: Zixian Zeng <sycamoremoon376@gmail.com>
>>> Date: Sun Oct 11 09:34:03 2026 +0800
>>>
>>> Add mmc debug log
>>>
>>> Signed-off-by: Zixian Zeng <sycamoremoon376@gmail.com>
>>>
>>> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
>>> index a619440fc4c..6e18d13884a 100644
>>> --- a/drivers/mmc/mmc.c
>>> +++ b/drivers/mmc/mmc.c
>>> @@ -458,6 +458,13 @@ static int mmc_read_blocks(struct mmc *mmc, void
>>> *dst, lbaint_t start,
>>> struct mmc_cmd cmd;
>>> struct mmc_data data;
>>>
>>> + if (blkcnt > 1)
>>> + printf("mmc: multi-blk blkcnt=%lu clk=%u mode=%u
>>> width=%u caps=%x cmd23_host=%u scr0=%x cmd23_card=%u\n",
>>> + (ulong)blkcnt, mmc->clock,
>>> + (unsigned)mmc->selected_mode, mmc->bus_width,
>>> + mmc->host_caps, !!(mmc->host_caps &
>>> MMC_CAP_CMD23),
>>> + mmc->scr[0], !!(mmc->scr[0] &
>>> SD_SCR_CMD23_SUPPORT));
>>> +
>>> if (blkcnt > 1 && (mmc->host_caps & MMC_CAP_CMD23)) {
>>> cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
>>> cmd.cmdarg = blkcnt & 0x0000ffff;
>>> @@ -483,8 +490,12 @@ static int mmc_read_blocks(struct mmc *mmc, void
>>> *dst, lbaint_t start,
>>> data.blocksize = mmc->read_bl_len;
>>> data.flags = MMC_DATA_READ;
>>>
>>> - if (mmc_send_cmd(mmc, &cmd, &data))
>>> + if (mmc_send_cmd(mmc, &cmd, &data)) {
>>> + log_err("mmc: cmd%u read failed: blks=%lu blksz=%lu
>>> arg=%lx\n",
>>> + cmd.cmdidx, (ulong)blkcnt,
>>> (ulong)mmc->read_bl_len,
>>> + (ulong)cmd.cmdarg);
>>> return 0;
>>> + }
>>>
>>> if (blkcnt > 1 && !(mmc->host_caps & MMC_CAP_CMD23)) {
>>> if (mmc_send_stop_transmission(mmc, false)) {
>>> @@ -547,6 +558,8 @@ ulong mmc_bread(struct blk_desc *block_dev,
>>> lbaint_t start, lbaint_t blkcnt,
>>> }
>>>
>>> if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
>>> + log_err("mmc: CMD16 blocklen=%lu failed, read of %lu
>>> blocks aborted\n",
>>> + (ulong)mmc->read_bl_len, (ulong)blkcnt);
>>> pr_debug("%s: Failed to set blocklen\n", __func__);
>>> return 0;
>>> }
>>> @@ -556,6 +569,8 @@ ulong mmc_bread(struct blk_desc *block_dev,
>>> lbaint_t start, lbaint_t blkcnt,
>>> do {
>>> cur = (blocks_todo > b_max) ? b_max : blocks_todo;
>>> if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
>>> + log_err("mmc: read of %lu blocks at lba %lx
>>> failed (b_max=%u)\n",
>>> + (ulong)cur, (ulong)start, b_max);
>>> pr_debug("%s: Failed to read blocks\n",
>>> __func__);
>>> return 0;
>>> }
>>> diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
>>> index 962a99cd05a..339b222bb68 100644
>>> --- a/drivers/mmc/sdhci.c
>>> +++ b/drivers/mmc/sdhci.c
>>> @@ -131,6 +131,7 @@ static int sdhci_transfer_data(struct sdhci_host
>>> *host, struct mmc_data *data)
>>> dma_addr_t start_addr = host->start_addr;
>>> unsigned int stat, rdy, mask, timeout, block = 0;
>>> bool transfer_done = false;
>>> + ulong t0 = get_timer(0);
>>>
>>> timeout = 1000000;
>>> rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
>>> @@ -138,6 +139,13 @@ static int sdhci_transfer_data(struct sdhci_host
>>> *host, struct mmc_data *data)
>>> do {
>>> stat = sdhci_readl(host, SDHCI_INT_STATUS);
>>> if (stat & SDHCI_INT_ERROR) {
>>> + log_err("sdhci: data err irq=%x present=%x
>>> mode=%x blksz=%x blkcnt=%x blocks=%u/%u t=%lums\n",
>>> + stat,
>>> + sdhci_readl(host, SDHCI_PRESENT_STATE),
>>> + sdhci_readw(host, SDHCI_TRANSFER_MODE),
>>> + sdhci_readw(host, SDHCI_BLOCK_SIZE),
>>> + sdhci_readw(host, SDHCI_BLOCK_COUNT),
>>> + block, data->blocks, get_timer(t0));
>>> log_debug("Error detected in status(%#x)!\n",
>>> stat);
>>> return -EIO;
>>> }
>>> @@ -294,6 +302,11 @@ static int sdhci_send_command(struct mmc *mmc,
>>> struct mmc_cmd *cmd,
>>> SDHCI_BLOCK_SIZE);
>>> sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
>>> sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
>>> + if (data->blocks > 1)
>>> + printf("sdhci: multi cmd%u arg=%lx blks=%u
>>> blksz=%u mode=%x dma=%u\n",
>>> + cmd->cmdidx, (ulong)cmd->cmdarg,
>>> data->blocks,
>>> + data->blocksize, mode,
>>> + !!(host->flags & USE_DMA));
>>> } else if (cmd->resp_type & MMC_RSP_BUSY) {
>>> sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
>>> }
>>> @@ -325,8 +338,12 @@ static int sdhci_send_command(struct mmc *mmc,
>>> struct mmc_cmd *cmd,
>>> if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
>>> sdhci_cmd_done(host, cmd);
>>> sdhci_writel(host, mask, SDHCI_INT_STATUS);
>>> - } else
>>> + } else {
>>> + log_err("sdhci: cmd%u status mismatch irq=%x mask=%x
>>> present=%x\n",
>>> + cmd->cmdidx, stat, mask,
>>> + sdhci_readl(host, SDHCI_PRESENT_STATE));
>>> ret = -1;
>>> + }
>>>
>>> if (!ret && data)
>>> ret = sdhci_transfer_data(host, data);
>>> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
>>> index 13bf6bf6000..23c655c6def 100644
>>> --- a/drivers/mmc/spacemit_sdhci.c
>>> +++ b/drivers/mmc/spacemit_sdhci.c
>>> @@ -640,6 +640,19 @@ static int spacemit_sdhci_probe(struct udevice *dev)
>>> goto err_reset;
>>>
>>> spacemit_sdhci_phy_init(dev, host);
>>> +
>>> + {
>>> + u32 caps = sdhci_readl(host, SDHCI_CAPABILITIES);
>>> + const char *path = (host->flags & USE_ADMA64) ?
>>> "ADMA64" :
>>> + (host->flags & USE_ADMA) ? "ADMA" :
>>> + (host->flags & USE_SDMA) ? "SDMA" :
>>> "PIO";
>>> +
>>> + printf("sdhci: %s path=%s flags=%x caps_sdma=%u
>>> caps_adma2=%u max_clk=%u\n",
>>> + dev->name, path, host->flags,
>>> + !!(caps & SDHCI_CAN_DO_SDMA),
>>> + !!(caps & SDHCI_CAN_DO_ADMA2),
>>> + host->max_clk);
>>> + }
>>> return 0;
>>>
>>> /*
>>>
>>>
>>> commit 75d6b28ba7b020d3100586f586ee6d1a4488ac84
>>> Author: Zixian Zeng <sycamoremoon376@gmail.com>
>>> Date: Sun Oct 11 09:33:20 2026 +0800
>>>
>>> debug: Add MMC_CAPS_CMD23
>>>
>>> Signed-off-by: Zixian Zeng <sycamoremoon376@gmail.com>
>>>
>>> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
>>> index 88e06a681ca..13bf6bf6000 100644
>>> --- a/drivers/mmc/spacemit_sdhci.c
>>> +++ b/drivers/mmc/spacemit_sdhci.c
>>> @@ -624,7 +624,7 @@ static int spacemit_sdhci_probe(struct udevice *dev)
>>> /* Set quirks */
>>> host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
>>> SDHCI_QUIRK_32BIT_DMA_ADDR;
>>> - host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
>>> + host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz |
>>> MMC_CAP_CMD23;
>>> host->max_clk = plat->cfg.f_max;
>>>
>>> plat->cfg.f_min = SDHC_MIN_CLOCK;
>>>
>>>
>>> With appling these two commits, Debug logs as follows:
>>>
>>> ⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ⥄ git log --oneline
>>> origin/next..HEAD
>>> 53c0ff5f65b (HEAD -> k1-dave-mmc) Add mmc debug log
>>> 75d6b28ba7b debug: Add MMC_CAPS_CMD23
>>> 6b4af8b1dd8 mmc: k1: do not release the shared AXI clock and reset on
>>> probe failure
>>> 4114764d716 mmc: k1: let the SPL read SD cards more than one block at
>>> a time
>>> 6676ce89521 mmc: k1: handle a missing max-frequency and
>>> clk_set_rate()'s return value
>>> 6427189ef33 spacemit: k1: fall back to the other boot devices in SPL
>>> b58a31797d7 spacemit: k1: do not require a PMIC or an SPI controller
>>> in SPL
>>>
>>> U-Boot SPL 2026.10-rc5-00641-g53c0ff5f65b0 (Oct 11 2026 - 10:31:28 +0800)
>>> Fail to detect board:-2
>>> vdd_core, value:900000
>>> vdd_1v8, value:1800000
>>> vdd_1v8_mmc, value:1800000
>>> DDR firmware: [0xc081d700]:0xf0227179, size:0x8d98
>>> DDR is ready
>>> No SPI controller (-19)
>>> Trying to boot from MMC2
>>> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
>>> max_clk=204800000
>>> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
>>> cmd23_host=1 scr0=2358043 cmd23_card=1
>>> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
>>> sdhci: data err irq=408020 present=1070800 mode=32 blksz=7200
>>> blkcnt=12 blocks=12/32 t=2ms
>>> mmc: cmd18 read failed: blks=32 blksz=512 arg=2
>>> mmc: read of 32 blocks at lba 2 failed (b_max=65535)
>>> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
>>> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
>>> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
>>> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
>>> sdhci: cmd16 status mismatch irq=18000 mask=1 present=1070000
>>> mmc: CMD16 blocklen=512 failed, read of 1 blocks aborted
>>> spl: partition error
>>> Error: -38
>>> SPL: Unsupported Boot Device!
>>> Trying to boot from MMC1
>>> alloc space exhausted ptr 104380 limit 100000
>>> Aligned buffer alloc failed
>>> spl: could not find mmc device 0. error: -19
>>> Error: -19
>>> SPL: Unsupported Boot Device!
>>> Trying to boot from SPI
>>> Invalid bus 0 (err=-19)
>>> SPI probe failed.
>>> Error: -19
>>> SPL: Unsupported Boot Device!
>>> SPL: Unsupported Boot Device!
>>> SPL: failed to boot from all boot devices
>>> ### ERROR ### Please RESET the board ###
>>>
>>>
>>> After I revert the multi-block SD read commit,
>>> I booted into u-boot proper. Debug logs as follows:
>>>
>>> ⋊> hack@morise ⋊> ~/k/u-boot on k1-dave-mmc ⥄ git log --oneline
>>> origin/next..HEAD
>>> 55e8da25a70 (HEAD -> k1-dave-mmc) Revert "mmc: k1: let the SPL read SD
>>> cards more than one block at a time"
>>> 53c0ff5f65b Add mmc debug log
>>> 75d6b28ba7b debug: Add MMC_CAPS_CMD23
>>> 6b4af8b1dd8 mmc: k1: do not release the shared AXI clock and reset on
>>> probe failure
>>> 4114764d716 mmc: k1: let the SPL read SD cards more than one block at
>>> a time
>>> 6676ce89521 mmc: k1: handle a missing max-frequency and
>>> clk_set_rate()'s return value
>>> 6427189ef33 spacemit: k1: fall back to the other boot devices in SPL
>>> b58a31797d7 spacemit: k1: do not require a PMIC or an SPI controller
>>> in SPL
>>>
>>>
>>> U-Boot SPL 2026.10-rc5-00642-g55e8da25a70c (Oct 11 2026 - 10:38:42 +0800)
>>> Fail to detect board:-2
>>> vdd_core, value:900000
>>> vdd_1v8, value:1800000
>>> vdd_1v8_mmc, value:1800000
>>> DDR firmware: [0xc081d740]:0xf0227179, size:0x8d98
>>> DDR is ready
>>> No SPI controller (-19)
>>> Trying to boot from MMC2
>>> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
>>> max_clk=204800000
>>>
>>> <debug_uart>
>>>
>>>
>>> U-Boot 2026.10-rc5-00642-g55e8da25a70c (Oct 11 2026 - 10:38:42 +0800)
>>>
>>> DRAM: 4 GiB
>>> Core: 339 devices, 23 uclasses, devicetree: separate
>>> MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
>>> max_clk=204800000
>>> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
>>> max_clk=204800000
>>> mmc@d4280000: 1, mmc@d4281000: 0
>>> Loading Environment from nowhere... OK
>>> In: serial@d4017000
>>> Out: serial@d4017000
>>> Err: serial@d4017000
>>> Net: No ethernet found.
>>> => mmc dev 1
>>> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
>>> cmd23_host=1 scr0=2358043 cmd23_card=1
>>> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
>>> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
>>> cmd23_host=1 scr0=2358043 cmd23_card=1
>>> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
>>> ... omit duplicate logs
>>> mmc: multi-blk blkcnt=2 clk=50000000 mode=2 width=4 caps=300207ef
>>> cmd23_host=1 scr0=2358043 cmd23_card=1
>>> sdhci: multi cmd18 arg=82002 blks=2 blksz=512 mode=32 dma=0
>>> switch to partitions #0, OK
>>> mmc1 is current device
>>> =>
>>> => mmc list
>>> mmc@d4280000: 1 (SD)
>>> mmc@d4281000: 0
>>> =>
>>> => mmc info
>>> Device: mmc@d4280000
>>> Manufacturer ID: 3
>>> OEM: 5344
>>> Name: SD32G
>>> Bus Speed: 50000000
>>> Mode: SD High Speed (50MHz)
>>> Rd Block Len: 512
>>> SD version 3.0
>>> High Capacity: Yes
>>> Capacity: 29.7 GiB
>>> Bus Width: 4-bit
>>> Erase Group Size: 512 Bytes
>>>
>>> I enabled MMC_CAP_CMD23 and the card does support it (SCR bit 1,
>>> cmd23_host=1 and cmd23_card=1 in the log above), so the SPL really
>>> used SET_BLOCK_COUNT + CMD18 without CMD12 - and it still aborts the
>>> data phase with SDHCI_INT_DATA_END_BIT after ~20 of 32 blocks.
>>> Booting U-Boot proper and issuing the same 32 block CMD18 from the same
>>> card succeeds, with the same PIO path (flags=0, dma=0), the same SD_HS
>>> mode, the same 4-bit bus and the same CMD23 usage.
>>> So I think CMD23 is not the trigger, the SPL fails with the FIFO
>>> permanently backed up (it drains slower than card delivers, so the
>>> controller has to stop the SD clock inside a block).
>>>
>>> Now answering your questions:
>>> mode : mode=2 = SD_HS, in both stages
>>> clock : requested 50 MHz (SD_HS) in both stages
>>> bus : 4-bit bus, in both stages
>>> path : PIO in both stages
>>> CMD23 : the card supports it and both stages use CMD23 + CMD18
>>>
>>>
>> Hi Zixian,
>>
>> Thanks for the logs.
>>
>> I hit the same pattern while testing the Cadence SD6HC driver.
>> Multi-block reads failed and single-block reads worked. On that board
>> the host and the card were in 1.8 V mode, but the I/O supply had been
>> left at 3.3 V. A short transfer got through; a longer one failed on the
>> data lines.
>> Both stages on K1 use the same PIO loop, so a FIFO that drains slower
>> than the card delivers would show up in U-Boot proper as well. Your
>> SPL/proper split fits an electrical setup difference.
>>
>> The SPL failure is irq=408020. Bit 22 is the Data End Bit Error (EDEB,
>> SD mode only): the controller detected 0 at the end-bit position of
>> read data on DAT, or of the write CRC status. That is a bad edge on
>> the data line during the transfer.
>>
>> On the Banana Pi F3, aldo1 is vqmmc-supply of &sdhci0. The U-Boot
>> dtsi names it vdd_1v8_mmc, and the SPL prints "vdd_1v8_mmc,
>> value:1800000" before MMC2. set_vdd_mmc() in board/spacemit/k1/spl.c,
>> called from board_init_f(), writes 1800000. The dts leaves aldo1 at
>> 0.5 V to 3.4 V. SD High Speed (mode=2) uses 3.3 V signaling; 1.8 V is
>> only after a UHS switch. mmc1_cfg is power-source 3300, and
>> mmc1_uhs_cfg is the 1.8 V state. For this mode the rail should be 3.3 V.
>>
>> CONFIG_SPL_MMC_IO_VOLTAGE is not set, so mmc_set_signal_voltage() is a
>> stub and signal_voltage stays MMC_SIGNAL_VOLTAGE_000. aldo1 stays at
>> 1.8 V. U-Boot proper has CONFIG_MMC_IO_VOLTAGE. mmc_set_initial_state()
>> requests MMC_SIGNAL_VOLTAGE_330, so the driver writes 3300000 to the
>> same vqmmc-supply and clears SDHCI_CTRL_VDD_180 before the transfer
>> that succeeds.
>>
>> CONFIG_SPL_PINCTRL is not set either. The driver calls
>> pinctrl_select_state() under IS_ENABLED(CONFIG_PINCTRL), but that
>> function is a stub unless CONFIG_IS_ENABLED(PINCTRL), and the return
>> is ignored. SPL never applies mmc1_cfg. Proper selects "default" for
>> SD_HS, which is that state.
>>
>> Keeping the multi-block path, set_vdd_mmc() to 3300000, or enable
>> CONFIG_SPL_MMC_IO_VOLTAGE. If the 32-block CMD18 still fails, enable
>> CONFIG_SPL_PINCTRL so mmc1_cfg is applied. If either makes the read
>> succeed, this is the F3 failure.
>>
> We need to enable CONFIG_SPL_SPACEMIT_GPIO?
>
> Thanks. I am seeing the same issue on the F3 board.
> Since spacemit/k1-musepi-pro is configured as the default device tree,
> do we also need to make similar changes to k1-bananapi-f3-u-boot.dtsi?
>
> $ grep spacemit configs/spacemit_k1_defconfig
> CONFIG_DEFAULT_DEVICE_TREE="spacemit/k1-musepi-pro"
> CONFIG_OF_LIST="spacemit/k1-bananapi-f3 spacemit/k1-musepi-pro"
>
> On my board, the system fails with the following error: Unhandled
> exception: Illegal instruction
> Could this be caused by k1-bananapi-f3-u-boot.dtsi not being updated
> in the same way as
> spacemit/k1-musepi-pro?
>
> sys: 0x2
> try sd...
> bm:3
> j...
>
> <debug_uart>
>
> U-Boot SPL 2026.10-00722-g6eaefa1cf807-dirty (Oct 11 2026 - 18:36:52 +0530)
> Fail to detect board:-2
> vdd_core, value:900000
> vdd_1v8, value:1800000
> vdd_1v8_mmc, value:1800000
> DDR firmware: [0xc081dc80]:0xf0227179, size:0x8d98
> DDR is ready
> jedec_spi_nor flash@0: unrecognized JEDEC id bytes: 00, 00, 00
> Fail to detect spi nor flash.
> Trying to boot from MMC2
> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1 max_clk=204800000
> Unhandled exception: Illegal instruction
> EPC: 0000000000200000 RA: 00000000c08017fa TVAL: 000000006d9058eb
>
> Code: 0001 0006 0000 0000 0000 0000 0000 0000 (58eb 6d90)
>
>
> resetting ...
> reset not supported yet
> ### ERROR ### Please RESET the board ###
Hi Anand,
The illegal instruction at EPC 0x200000 could mean that SPL loaded a
corrupted U-Boot image and then jumped to its load address. Therefore,
it may be related to the multi-block failure, but the current log
does not confirm that.
Could you first try the options suggested above: set the SPL SD I/O
supply to 3.3 V, or enable CONFIG_SPL_MMC_IO_VOLTAGE, followed by
CONFIG_SPL_PINCTRL if needed?
CONFIG_SPL_SPACEMIT_GPIO is related to the card-detect GPIO and is
separate from the voltage and pinctrl setup.
If the illegal instruction remains after the SD transfer issue is
resolved, let us start a separate thread for it.
Regards,
Tanmay
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-11 14:31 ` Kathpalia, Tanmay
2026-10-11 15:33 ` Anand Moon
@ 2026-10-12 13:15 ` Zixian Zeng
2026-10-12 14:00 ` Kathpalia, Tanmay
2026-10-12 16:07 ` Anand Moon
1 sibling, 2 replies; 33+ messages in thread
From: Zixian Zeng @ 2026-10-12 13:15 UTC (permalink / raw)
To: Kathpalia, Tanmay, Dave Klotz, Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tom Rini, u-boot-spacemit
On 2026/10/11 22:31, Kathpalia, Tanmay wrote:
> Hi Zixian,
>
> Thanks for the logs.
>
> I hit the same pattern while testing the Cadence SD6HC driver.
> Multi-block reads failed and single-block reads worked. On that board
> the host and the card were in 1.8 V mode, but the I/O supply had been
> left at 3.3 V. A short transfer got through; a longer one failed on the
> data lines.
> Both stages on K1 use the same PIO loop, so a FIFO that drains slower
> than the card delivers would show up in U-Boot proper as well. Your
> SPL/proper split fits an electrical setup difference.
>
> The SPL failure is irq=408020. Bit 22 is the Data End Bit Error (EDEB,
> SD mode only): the controller detected 0 at the end-bit position of
> read data on DAT, or of the write CRC status. That is a bad edge on
> the data line during the transfer.
>
> On the Banana Pi F3, aldo1 is vqmmc-supply of &sdhci0. The U-Boot
> dtsi names it vdd_1v8_mmc, and the SPL prints "vdd_1v8_mmc,
> value:1800000" before MMC2. set_vdd_mmc() in board/spacemit/k1/spl.c,
> called from board_init_f(), writes 1800000. The dts leaves aldo1 at
> 0.5 V to 3.4 V. SD High Speed (mode=2) uses 3.3 V signaling; 1.8 V is
> only after a UHS switch. mmc1_cfg is power-source 3300, and
> mmc1_uhs_cfg is the 1.8 V state. For this mode the rail should be 3.3 V.
>
> CONFIG_SPL_MMC_IO_VOLTAGE is not set, so mmc_set_signal_voltage() is a
> stub and signal_voltage stays MMC_SIGNAL_VOLTAGE_000. aldo1 stays at
> 1.8 V. U-Boot proper has CONFIG_MMC_IO_VOLTAGE. mmc_set_initial_state()
> requests MMC_SIGNAL_VOLTAGE_330, so the driver writes 3300000 to the
> same vqmmc-supply and clears SDHCI_CTRL_VDD_180 before the transfer
> that succeeds.
>
> CONFIG_SPL_PINCTRL is not set either. The driver calls
> pinctrl_select_state() under IS_ENABLED(CONFIG_PINCTRL), but that
> function is a stub unless CONFIG_IS_ENABLED(PINCTRL), and the return
> is ignored. SPL never applies mmc1_cfg. Proper selects "default" for
> SD_HS, which is that state.
>
> Keeping the multi-block path, set_vdd_mmc() to 3300000, or enable
> CONFIG_SPL_MMC_IO_VOLTAGE. If the 32-block CMD18 still fails, enable
> CONFIG_SPL_PINCTRL so mmc1_cfg is applied. If either makes the read
> succeed, this is the F3 failure.
>
> Regards,
> Tanmay
Hi Tanmay,
Your diagnosis was right - it is the I/O voltage.
Enabling CONFIG_SPL_MMC_IO_VOLTAGE makes
the multi-block read work on the Banana Pi-F3:
Based on previous commit, I patched the following changes:
diff --git a/configs/spacemit_k1_defconfig b/configs/spacemit_k1_defconfig
index 9c15d96eae2..f5c717e5965 100644
--- a/configs/spacemit_k1_defconfig
+++ b/configs/spacemit_k1_defconfig
@@ -95,6 +95,7 @@ CONFIG_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_SPACEMIT=y
CONFIG_MMC_IO_VOLTAGE=y
+CONFIG_SPL_MMC_IO_VOLTAGE=y
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_MMC_HS400_ES_SUPPORT=y
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
index 23c655c6def..58374c482b3 100644
--- a/drivers/mmc/spacemit_sdhci.c
+++ b/drivers/mmc/spacemit_sdhci.c
@@ -251,6 +251,10 @@ static void spacemit_sdhci_set_voltage(struct
sdhci_host *host)
bool ok;
int voltage_mv = to_180 ? 1800000 : 3300000;
+ printf("sdhci: voltage signal_voltage=%u
vqmmc=%s -> %dmV\n",
+ mmc->signal_voltage,
+ mmc->vqmmc_supply ?
mmc->vqmmc_supply->name : "none",
+ voltage_mv);
if (spacemit_sdhci_set_vqmmc_voltage(mmc,
voltage_mv))
return;
if (!IS_SD(mmc))
@@ -274,7 +278,8 @@ static void spacemit_sdhci_set_voltage(struct
sdhci_host *host)
break;
}
default:
- /* No signal voltage switch required */
+ printf("sdhci: voltage signal_voltage=%u -> no
switch\n",
+ mmc->signal_voltage);
return;
}
}
Booting logs as follows:
U-Boot SPL 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
Fail to detect board:-2
vdd_core, value:900000
vdd_1v8, value:1800000
vdd_1v8_mmc, value:1800000
DDR firmware: [0xc081d880]:0xf0227179, size:0x8d98
DDR is ready
No SPI controller (-19)
Trying to boot from MMC2
sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
max_clk=204800000
sdhci: voltage signal_voltage=0 -> no switch
sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
cmd23_host=1 scr0=2358043 cmd23_card=1
sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
mmc: multi-blk blkcnt=1956 clk=50000000 mode=2 width=4 caps=300207ef
cmd23_host=1 scr0=2358043 cmd23_card=1
sdhci: multi cmd18 arg=1000 blks=1956 blksz=512 mode=32 dma=0
<debug_uart>
U-Boot 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
DRAM: 4 GiB
Core: 338 devices, 22 uclasses, devicetree: separate
MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
max_clk=204800000
sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
max_clk=204800000
mmc@d4280000: 1, mmc@d4281000: 0
Loading Environment from nowhere... OK
In: serial@d4017000
Out: serial@d4017000
Err: serial@d4017000
Net: No ethernet found.
=>
With the voltage corrected, a single 1956 block PIO CMD18 loads
the whole FIT,so the controller is fine with the FIFO back pressure,
the slow SPL drain was a symptom, not the cause :-).
Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
"sdhci: voltage signal_voltage=0 -> no switch".
Since mmc_set_signWith the voltage corrected, a single 1956 block PIO
CMD18 loads
the whole FIT,so the controller is fine with the FIFO back pressure,
the slow SPL drain was a symptom, not the cause :-).
Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
"sdhci: voltage signal_voltage=0 -> no switch".
Since mmc_set_signal_voltage() is a stub in SPL, so mmc->signal_voltage
stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
"no switch required" path, and aldo1 stayed at the initial 1800000 that
set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
what hid it.
On the pinctrl side I had already run the SPL with standalone
CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
mmc1_uhs_cfg plus their pin groups. I confirmed that
pinctrl_select_state() return successfully. The multi-block read still
failed the same way with the rail at 1.8V.
Therefore, I suspect that configuring the MMC signal voltage to 1.8V
in pmic_init() may need to be modified.
Thanks for your suggestions and guidance.
Best regards,
Zixianal_voltage() is a stub in SPL, so mmc->signal_voltage
stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
"no switch required" path, and aldo1 stayed at the initial 1800000 that
set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
what hid it.
On the pinctrl side I had already run the SPL with standalone
CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
mmc1_uhs_cfg plus their pin groups. I confirmed that
pinctrl_select_state() return successfully. The multi-block read still
failed the same way with the rail at 1.8V.
Therefore, I suspect that configuring the MMC signal voltage to 1.8V
in pmic_init() may need to be modified.
Thanks for your suggestions and guidance.
Best regards,
Zixian
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-12 13:15 ` Zixian Zeng
@ 2026-10-12 14:00 ` Kathpalia, Tanmay
2026-10-12 14:30 ` Yixun Lan
2026-10-12 16:07 ` Anand Moon
1 sibling, 1 reply; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-12 14:00 UTC (permalink / raw)
To: Zixian Zeng, Dave Klotz, Yixun Lan, Eric Chung, Peng Fan
Cc: u-boot, Jaehoon Chung, Tom Rini, u-boot-spacemit
On 12-10-2026 18:45, Zixian Zeng wrote:
> On 2026/10/11 22:31, Kathpalia, Tanmay wrote:
>> Hi Zixian,
>>
>> Thanks for the logs.
>>
>> I hit the same pattern while testing the Cadence SD6HC driver.
>> Multi-block reads failed and single-block reads worked. On that board
>> the host and the card were in 1.8 V mode, but the I/O supply had been
>> left at 3.3 V. A short transfer got through; a longer one failed on the
>> data lines.
>> Both stages on K1 use the same PIO loop, so a FIFO that drains slower
>> than the card delivers would show up in U-Boot proper as well. Your
>> SPL/proper split fits an electrical setup difference.
>>
>> The SPL failure is irq=408020. Bit 22 is the Data End Bit Error (EDEB,
>> SD mode only): the controller detected 0 at the end-bit position of
>> read data on DAT, or of the write CRC status. That is a bad edge on
>> the data line during the transfer.
>>
>> On the Banana Pi F3, aldo1 is vqmmc-supply of &sdhci0. The U-Boot
>> dtsi names it vdd_1v8_mmc, and the SPL prints "vdd_1v8_mmc,
>> value:1800000" before MMC2. set_vdd_mmc() in board/spacemit/k1/spl.c,
>> called from board_init_f(), writes 1800000. The dts leaves aldo1 at
>> 0.5 V to 3.4 V. SD High Speed (mode=2) uses 3.3 V signaling; 1.8 V is
>> only after a UHS switch. mmc1_cfg is power-source 3300, and
>> mmc1_uhs_cfg is the 1.8 V state. For this mode the rail should be 3.3 V.
>>
>> CONFIG_SPL_MMC_IO_VOLTAGE is not set, so mmc_set_signal_voltage() is a
>> stub and signal_voltage stays MMC_SIGNAL_VOLTAGE_000. aldo1 stays at
>> 1.8 V. U-Boot proper has CONFIG_MMC_IO_VOLTAGE. mmc_set_initial_state()
>> requests MMC_SIGNAL_VOLTAGE_330, so the driver writes 3300000 to the
>> same vqmmc-supply and clears SDHCI_CTRL_VDD_180 before the transfer
>> that succeeds.
>>
>> CONFIG_SPL_PINCTRL is not set either. The driver calls
>> pinctrl_select_state() under IS_ENABLED(CONFIG_PINCTRL), but that
>> function is a stub unless CONFIG_IS_ENABLED(PINCTRL), and the return
>> is ignored. SPL never applies mmc1_cfg. Proper selects "default" for
>> SD_HS, which is that state.
>>
>> Keeping the multi-block path, set_vdd_mmc() to 3300000, or enable
>> CONFIG_SPL_MMC_IO_VOLTAGE. If the 32-block CMD18 still fails, enable
>> CONFIG_SPL_PINCTRL so mmc1_cfg is applied. If either makes the read
>> succeed, this is the F3 failure.
>>
>> Regards,
>> Tanmay
>
> Hi Tanmay,
>
> Your diagnosis was right - it is the I/O voltage.
> Enabling CONFIG_SPL_MMC_IO_VOLTAGE makes
> the multi-block read work on the Banana Pi-F3:
>
> Based on previous commit, I patched the following changes:
>
> diff --git a/configs/spacemit_k1_defconfig
> b/configs/spacemit_k1_defconfig
> index 9c15d96eae2..f5c717e5965 100644
> --- a/configs/spacemit_k1_defconfig
> +++ b/configs/spacemit_k1_defconfig
> @@ -95,6 +95,7 @@ CONFIG_MMC=y
> CONFIG_MMC_SDHCI=y
> CONFIG_MMC_SDHCI_SPACEMIT=y
> CONFIG_MMC_IO_VOLTAGE=y
> +CONFIG_SPL_MMC_IO_VOLTAGE=y
> CONFIG_MMC_HS200_SUPPORT=y
> CONFIG_MMC_HS400_SUPPORT=y
> CONFIG_MMC_HS400_ES_SUPPORT=y
> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> index 23c655c6def..58374c482b3 100644
> --- a/drivers/mmc/spacemit_sdhci.c
> +++ b/drivers/mmc/spacemit_sdhci.c
> @@ -251,6 +251,10 @@ static void spacemit_sdhci_set_voltage(struct
> sdhci_host *host)
> bool ok;
> int voltage_mv = to_180 ? 1800000 : 3300000;
>
> + printf("sdhci: voltage signal_voltage=%u
> vqmmc=%s -> %dmV\n",
> + mmc->signal_voltage,
> + mmc->vqmmc_supply ?
> mmc->vqmmc_supply->name : "none",
> + voltage_mv);
> if (spacemit_sdhci_set_vqmmc_voltage(mmc,
> voltage_mv))
> return;
> if (!IS_SD(mmc))
> @@ -274,7 +278,8 @@ static void spacemit_sdhci_set_voltage(struct
> sdhci_host *host)
> break;
> }
> default:
> - /* No signal voltage switch required */
> + printf("sdhci: voltage signal_voltage=%u -> no
> switch\n",
> + mmc->signal_voltage);
> return;
> }
> }
>
> Booting logs as follows:
>
> U-Boot SPL 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
> Fail to detect board:-2
> vdd_core, value:900000
> vdd_1v8, value:1800000
> vdd_1v8_mmc, value:1800000
> DDR firmware: [0xc081d880]:0xf0227179, size:0x8d98
> DDR is ready
> No SPI controller (-19)
> Trying to boot from MMC2
> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
> sdhci: voltage signal_voltage=0 -> no switch
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> cmd23_host=1 scr0=2358043 cmd23_card=1
> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> mmc: multi-blk blkcnt=1956 clk=50000000 mode=2 width=4 caps=300207ef
> cmd23_host=1 scr0=2358043 cmd23_card=1
> sdhci: multi cmd18 arg=1000 blks=1956 blksz=512 mode=32 dma=0
>
> <debug_uart>
>
>
> U-Boot 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
>
> DRAM: 4 GiB
> Core: 338 devices, 22 uclasses, devicetree: separate
> MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
> mmc@d4280000: 1, mmc@d4281000: 0
> Loading Environment from nowhere... OK
> In: serial@d4017000
> Out: serial@d4017000
> Err: serial@d4017000
> Net: No ethernet found.
> =>
>
> With the voltage corrected, a single 1956 block PIO CMD18 loads
> the whole FIT,so the controller is fine with the FIFO back pressure,
> the slow SPL drain was a symptom, not the cause :-).
>
> Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
> "sdhci: voltage signal_voltage=0 -> no switch".
> Since mmc_set_signWith the voltage corrected, a single 1956 block PIO
> CMD18 loads
> the whole FIT,so the controller is fine with the FIFO back pressure,
> the slow SPL drain was a symptom, not the cause :-).
>
> Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
> "sdhci: voltage signal_voltage=0 -> no switch".
> Since mmc_set_signal_voltage() is a stub in SPL, so mmc->signal_voltage
> stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
> "no switch required" path, and aldo1 stayed at the initial 1800000 that
> set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
> after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
> what hid it.
>
> On the pinctrl side I had already run the SPL with standalone
> CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> mmc1_uhs_cfg plus their pin groups. I confirmed that
> pinctrl_select_state() return successfully. The multi-block read still
> failed the same way with the rail at 1.8V.
>
> Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> in pmic_init() may need to be modified.
>
> Thanks for your suggestions and guidance.
>
> Best regards,
> Zixianal_voltage() is a stub in SPL, so mmc->signal_voltage
> stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
> "no switch required" path, and aldo1 stayed at the initial 1800000 that
> set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
> after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
> what hid it.
>
> On the pinctrl side I had already run the SPL with standalone
> CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> mmc1_uhs_cfg plus their pin groups. I confirmed that
> pinctrl_select_state() return successfully. The multi-block read still
> failed the same way with the rail at 1.8V.
>
> Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> in pmic_init() may need to be modified.
>
> Thanks for your suggestions and guidance.
>
>
Hi Zixian,
Thank you for the quick testing and for posting detailed results. Your
patience with the suggested tests helped us reach the root cause
within two days.
With CONFIG_SPL_MMC_IO_VOLTAGE enabled, aldo1 is changed from its
initial 1.8 V to 3.3 V and both the 32-block and 1956-block reads
succeed.
I am still unsure why set_vdd_mmc() initializes this rail to 1.8 V.
Since we do not know the original hardware requirement, any change to
that default should be reviewed by the code owner.
I suggest enabling both CONFIG_SPL_MMC_IO_VOLTAGE and
CONFIG_SPL_PINCTRL. The former fixes the voltage issue, while the
latter ensures SPL applies the defined MMC pad configuration instead
of relying on the Boot ROM state.
Dave, I hope you are aligned with the changes discussed and tested.
Could you please post a new version incorporating them?
Signed-off-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
Regards,
Tanmay
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-12 14:00 ` Kathpalia, Tanmay
@ 2026-10-12 14:30 ` Yixun Lan
2026-10-12 14:50 ` Kathpalia, Tanmay
0 siblings, 1 reply; 33+ messages in thread
From: Yixun Lan @ 2026-10-12 14:30 UTC (permalink / raw)
To: Kathpalia, Tanmay
Cc: Zixian Zeng, Dave Klotz, Eric Chung, Peng Fan, u-boot,
Jaehoon Chung, Tom Rini, u-boot-spacemit
Hi Kathpalia, Zexian,
On 19:30 Mon 12 Oct , Kathpalia, Tanmay wrote:
>
> On 12-10-2026 18:45, Zixian Zeng wrote:
> > On 2026/10/11 22:31, Kathpalia, Tanmay wrote:
> >> Hi Zixian,
> >>
> >> Thanks for the logs.
> >>
> >> I hit the same pattern while testing the Cadence SD6HC driver.
> >> Multi-block reads failed and single-block reads worked. On that board
> >> the host and the card were in 1.8 V mode, but the I/O supply had been
> >> left at 3.3 V. A short transfer got through; a longer one failed on the
> >> data lines.
> >> Both stages on K1 use the same PIO loop, so a FIFO that drains slower
> >> than the card delivers would show up in U-Boot proper as well. Your
> >> SPL/proper split fits an electrical setup difference.
> >>
> >> The SPL failure is irq=408020. Bit 22 is the Data End Bit Error (EDEB,
> >> SD mode only): the controller detected 0 at the end-bit position of
> >> read data on DAT, or of the write CRC status. That is a bad edge on
> >> the data line during the transfer.
> >>
> >> On the Banana Pi F3, aldo1 is vqmmc-supply of &sdhci0. The U-Boot
> >> dtsi names it vdd_1v8_mmc, and the SPL prints "vdd_1v8_mmc,
> >> value:1800000" before MMC2. set_vdd_mmc() in board/spacemit/k1/spl.c,
> >> called from board_init_f(), writes 1800000. The dts leaves aldo1 at
> >> 0.5 V to 3.4 V. SD High Speed (mode=2) uses 3.3 V signaling; 1.8 V is
> >> only after a UHS switch. mmc1_cfg is power-source 3300, and
> >> mmc1_uhs_cfg is the 1.8 V state. For this mode the rail should be 3.3 V.
> >>
> >> CONFIG_SPL_MMC_IO_VOLTAGE is not set, so mmc_set_signal_voltage() is a
> >> stub and signal_voltage stays MMC_SIGNAL_VOLTAGE_000. aldo1 stays at
> >> 1.8 V. U-Boot proper has CONFIG_MMC_IO_VOLTAGE. mmc_set_initial_state()
> >> requests MMC_SIGNAL_VOLTAGE_330, so the driver writes 3300000 to the
> >> same vqmmc-supply and clears SDHCI_CTRL_VDD_180 before the transfer
> >> that succeeds.
> >>
> >> CONFIG_SPL_PINCTRL is not set either. The driver calls
> >> pinctrl_select_state() under IS_ENABLED(CONFIG_PINCTRL), but that
> >> function is a stub unless CONFIG_IS_ENABLED(PINCTRL), and the return
> >> is ignored. SPL never applies mmc1_cfg. Proper selects "default" for
> >> SD_HS, which is that state.
> >>
> >> Keeping the multi-block path, set_vdd_mmc() to 3300000, or enable
> >> CONFIG_SPL_MMC_IO_VOLTAGE. If the 32-block CMD18 still fails, enable
> >> CONFIG_SPL_PINCTRL so mmc1_cfg is applied. If either makes the read
> >> succeed, this is the F3 failure.
> >>
> >> Regards,
> >> Tanmay
> >
> > Hi Tanmay,
> >
> > Your diagnosis was right - it is the I/O voltage.
> > Enabling CONFIG_SPL_MMC_IO_VOLTAGE makes
> > the multi-block read work on the Banana Pi-F3:
> >
> > Based on previous commit, I patched the following changes:
> >
> > diff --git a/configs/spacemit_k1_defconfig
> > b/configs/spacemit_k1_defconfig
> > index 9c15d96eae2..f5c717e5965 100644
> > --- a/configs/spacemit_k1_defconfig
> > +++ b/configs/spacemit_k1_defconfig
> > @@ -95,6 +95,7 @@ CONFIG_MMC=y
> > CONFIG_MMC_SDHCI=y
> > CONFIG_MMC_SDHCI_SPACEMIT=y
> > CONFIG_MMC_IO_VOLTAGE=y
> > +CONFIG_SPL_MMC_IO_VOLTAGE=y
> > CONFIG_MMC_HS200_SUPPORT=y
> > CONFIG_MMC_HS400_SUPPORT=y
> > CONFIG_MMC_HS400_ES_SUPPORT=y
> > diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> > index 23c655c6def..58374c482b3 100644
> > --- a/drivers/mmc/spacemit_sdhci.c
> > +++ b/drivers/mmc/spacemit_sdhci.c
> > @@ -251,6 +251,10 @@ static void spacemit_sdhci_set_voltage(struct
> > sdhci_host *host)
> > bool ok;
> > int voltage_mv = to_180 ? 1800000 : 3300000;
> >
> > + printf("sdhci: voltage signal_voltage=%u
> > vqmmc=%s -> %dmV\n",
> > + mmc->signal_voltage,
> > + mmc->vqmmc_supply ?
> > mmc->vqmmc_supply->name : "none",
> > + voltage_mv);
> > if (spacemit_sdhci_set_vqmmc_voltage(mmc,
> > voltage_mv))
> > return;
> > if (!IS_SD(mmc))
> > @@ -274,7 +278,8 @@ static void spacemit_sdhci_set_voltage(struct
> > sdhci_host *host)
> > break;
> > }
> > default:
> > - /* No signal voltage switch required */
> > + printf("sdhci: voltage signal_voltage=%u -> no
> > switch\n",
> > + mmc->signal_voltage);
> > return;
> > }
> > }
> >
> > Booting logs as follows:
> >
> > U-Boot SPL 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
> > Fail to detect board:-2
> > vdd_core, value:900000
> > vdd_1v8, value:1800000
> > vdd_1v8_mmc, value:1800000
> > DDR firmware: [0xc081d880]:0xf0227179, size:0x8d98
> > DDR is ready
> > No SPI controller (-19)
> > Trying to boot from MMC2
> > sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> > max_clk=204800000
> > sdhci: voltage signal_voltage=0 -> no switch
> > sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> > sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> > sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> > sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> > sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> > mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> > cmd23_host=1 scr0=2358043 cmd23_card=1
> > sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> > mmc: multi-blk blkcnt=1956 clk=50000000 mode=2 width=4 caps=300207ef
> > cmd23_host=1 scr0=2358043 cmd23_card=1
> > sdhci: multi cmd18 arg=1000 blks=1956 blksz=512 mode=32 dma=0
> >
> > <debug_uart>
> >
> >
> > U-Boot 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
> >
> > DRAM: 4 GiB
> > Core: 338 devices, 22 uclasses, devicetree: separate
> > MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> > max_clk=204800000
> > sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> > max_clk=204800000
> > mmc@d4280000: 1, mmc@d4281000: 0
> > Loading Environment from nowhere... OK
> > In: serial@d4017000
> > Out: serial@d4017000
> > Err: serial@d4017000
> > Net: No ethernet found.
> > =>
> >
> > With the voltage corrected, a single 1956 block PIO CMD18 loads
> > the whole FIT,so the controller is fine with the FIFO back pressure,
> > the slow SPL drain was a symptom, not the cause :-).
> >
> > Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
> > "sdhci: voltage signal_voltage=0 -> no switch".
> > Since mmc_set_signWith the voltage corrected, a single 1956 block PIO
> > CMD18 loads
> > the whole FIT,so the controller is fine with the FIFO back pressure,
> > the slow SPL drain was a symptom, not the cause :-).
> >
> > Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
> > "sdhci: voltage signal_voltage=0 -> no switch".
> > Since mmc_set_signal_voltage() is a stub in SPL, so mmc->signal_voltage
> > stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
> > "no switch required" path, and aldo1 stayed at the initial 1800000 that
> > set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
> > after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
> > what hid it.
> >
> > On the pinctrl side I had already run the SPL with standalone
> > CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> > mmc1_uhs_cfg plus their pin groups. I confirmed that
> > pinctrl_select_state() return successfully. The multi-block read still
> > failed the same way with the rail at 1.8V.
> >
> > Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> > in pmic_init() may need to be modified.
> >
> > Thanks for your suggestions and guidance.
> >
> > Best regards,
> > Zixianal_voltage() is a stub in SPL, so mmc->signal_voltage
> > stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
> > "no switch required" path, and aldo1 stayed at the initial 1800000 that
> > set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
> > after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
> > what hid it.
> >
> > On the pinctrl side I had already run the SPL with standalone
> > CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> > mmc1_uhs_cfg plus their pin groups. I confirmed that
> > pinctrl_select_state() return successfully. The multi-block read still
> > failed the same way with the rail at 1.8V.
> >
> > Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> > in pmic_init() may need to be modified.
> >
> > Thanks for your suggestions and guidance.
> >
> >
>
> Hi Zixian,
>
> Thank you for the quick testing and for posting detailed results. Your
> patience with the suggested tests helped us reach the root cause
> within two days.
>
> With CONFIG_SPL_MMC_IO_VOLTAGE enabled, aldo1 is changed from its
> initial 1.8 V to 3.3 V and both the 32-block and 1956-block reads
> succeed.
>
> I am still unsure why set_vdd_mmc() initializes this rail to 1.8 V.
I'm also looking into this..
It's definitely wrong here, and should be fixed in my opinion, refer
to SD spec, the initial IO should be 3.3v, and later may change to 1.8v
according to OCR report, the BROM code will set IO to 3.3v by default
since cold boot, and I've done a test on this, drop set_vdd_mmc() & without
CONFIG_SPL_MMC_IO_VOLTAGE enabled, the multi block read still works fine
on SPL stage
Also with Zexian's above test, it also prove that, enabling CONFIG_SPL_MMC_IO_VOLTAGE
will lead the mmc core calling set_voltage() which will set IO to 3.3v, which also
fix the problem
> Since we do not know the original hardware requirement, any change to
> that default should be reviewed by the code owner.
>
> I suggest enabling both CONFIG_SPL_MMC_IO_VOLTAGE and
> CONFIG_SPL_PINCTRL. The former fixes the voltage issue, while the
> latter ensures SPL applies the defined MMC pad configuration instead
> of relying on the Boot ROM state.
>
I agree, it's safe to do this
> Dave, I hope you are aligned with the changes discussed and tested.
> Could you please post a new version incorporating them?
>
> Signed-off-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
>
> Regards,
> Tanmay
>
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-12 14:30 ` Yixun Lan
@ 2026-10-12 14:50 ` Kathpalia, Tanmay
2026-10-12 15:22 ` Yixun Lan
0 siblings, 1 reply; 33+ messages in thread
From: Kathpalia, Tanmay @ 2026-10-12 14:50 UTC (permalink / raw)
To: Yixun Lan
Cc: Zixian Zeng, Dave Klotz, Eric Chung, Peng Fan, u-boot,
Jaehoon Chung, Tom Rini, u-boot-spacemit
Hi Yixun,
On 12-10-2026 20:00, Yixun Lan wrote:
> Hi Kathpalia, Zexian,
>
> On 19:30 Mon 12 Oct , Kathpalia, Tanmay wrote:
>> On 12-10-2026 18:45, Zixian Zeng wrote:
>>> On 2026/10/11 22:31, Kathpalia, Tanmay wrote:
>>>> Hi Zixian,
>>>>
>>>> Thanks for the logs.
>>>>
>>>> I hit the same pattern while testing the Cadence SD6HC driver.
>>>> Multi-block reads failed and single-block reads worked. On that board
>>>> the host and the card were in 1.8 V mode, but the I/O supply had been
>>>> left at 3.3 V. A short transfer got through; a longer one failed on the
>>>> data lines.
>>>> Both stages on K1 use the same PIO loop, so a FIFO that drains slower
>>>> than the card delivers would show up in U-Boot proper as well. Your
>>>> SPL/proper split fits an electrical setup difference.
>>>>
>>>> The SPL failure is irq=408020. Bit 22 is the Data End Bit Error (EDEB,
>>>> SD mode only): the controller detected 0 at the end-bit position of
>>>> read data on DAT, or of the write CRC status. That is a bad edge on
>>>> the data line during the transfer.
>>>>
>>>> On the Banana Pi F3, aldo1 is vqmmc-supply of &sdhci0. The U-Boot
>>>> dtsi names it vdd_1v8_mmc, and the SPL prints "vdd_1v8_mmc,
>>>> value:1800000" before MMC2. set_vdd_mmc() in board/spacemit/k1/spl.c,
>>>> called from board_init_f(), writes 1800000. The dts leaves aldo1 at
>>>> 0.5 V to 3.4 V. SD High Speed (mode=2) uses 3.3 V signaling; 1.8 V is
>>>> only after a UHS switch. mmc1_cfg is power-source 3300, and
>>>> mmc1_uhs_cfg is the 1.8 V state. For this mode the rail should be 3.3 V.
>>>>
>>>> CONFIG_SPL_MMC_IO_VOLTAGE is not set, so mmc_set_signal_voltage() is a
>>>> stub and signal_voltage stays MMC_SIGNAL_VOLTAGE_000. aldo1 stays at
>>>> 1.8 V. U-Boot proper has CONFIG_MMC_IO_VOLTAGE. mmc_set_initial_state()
>>>> requests MMC_SIGNAL_VOLTAGE_330, so the driver writes 3300000 to the
>>>> same vqmmc-supply and clears SDHCI_CTRL_VDD_180 before the transfer
>>>> that succeeds.
>>>>
>>>> CONFIG_SPL_PINCTRL is not set either. The driver calls
>>>> pinctrl_select_state() under IS_ENABLED(CONFIG_PINCTRL), but that
>>>> function is a stub unless CONFIG_IS_ENABLED(PINCTRL), and the return
>>>> is ignored. SPL never applies mmc1_cfg. Proper selects "default" for
>>>> SD_HS, which is that state.
>>>>
>>>> Keeping the multi-block path, set_vdd_mmc() to 3300000, or enable
>>>> CONFIG_SPL_MMC_IO_VOLTAGE. If the 32-block CMD18 still fails, enable
>>>> CONFIG_SPL_PINCTRL so mmc1_cfg is applied. If either makes the read
>>>> succeed, this is the F3 failure.
>>>>
>>>> Regards,
>>>> Tanmay
>>> Hi Tanmay,
>>>
>>> Your diagnosis was right - it is the I/O voltage.
>>> Enabling CONFIG_SPL_MMC_IO_VOLTAGE makes
>>> the multi-block read work on the Banana Pi-F3:
>>>
>>> Based on previous commit, I patched the following changes:
>>>
>>> diff --git a/configs/spacemit_k1_defconfig
>>> b/configs/spacemit_k1_defconfig
>>> index 9c15d96eae2..f5c717e5965 100644
>>> --- a/configs/spacemit_k1_defconfig
>>> +++ b/configs/spacemit_k1_defconfig
>>> @@ -95,6 +95,7 @@ CONFIG_MMC=y
>>> CONFIG_MMC_SDHCI=y
>>> CONFIG_MMC_SDHCI_SPACEMIT=y
>>> CONFIG_MMC_IO_VOLTAGE=y
>>> +CONFIG_SPL_MMC_IO_VOLTAGE=y
>>> CONFIG_MMC_HS200_SUPPORT=y
>>> CONFIG_MMC_HS400_SUPPORT=y
>>> CONFIG_MMC_HS400_ES_SUPPORT=y
>>> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
>>> index 23c655c6def..58374c482b3 100644
>>> --- a/drivers/mmc/spacemit_sdhci.c
>>> +++ b/drivers/mmc/spacemit_sdhci.c
>>> @@ -251,6 +251,10 @@ static void spacemit_sdhci_set_voltage(struct
>>> sdhci_host *host)
>>> bool ok;
>>> int voltage_mv = to_180 ? 1800000 : 3300000;
>>>
>>> + printf("sdhci: voltage signal_voltage=%u
>>> vqmmc=%s -> %dmV\n",
>>> + mmc->signal_voltage,
>>> + mmc->vqmmc_supply ?
>>> mmc->vqmmc_supply->name : "none",
>>> + voltage_mv);
>>> if (spacemit_sdhci_set_vqmmc_voltage(mmc,
>>> voltage_mv))
>>> return;
>>> if (!IS_SD(mmc))
>>> @@ -274,7 +278,8 @@ static void spacemit_sdhci_set_voltage(struct
>>> sdhci_host *host)
>>> break;
>>> }
>>> default:
>>> - /* No signal voltage switch required */
>>> + printf("sdhci: voltage signal_voltage=%u -> no
>>> switch\n",
>>> + mmc->signal_voltage);
>>> return;
>>> }
>>> }
>>>
>>> Booting logs as follows:
>>>
>>> U-Boot SPL 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
>>> Fail to detect board:-2
>>> vdd_core, value:900000
>>> vdd_1v8, value:1800000
>>> vdd_1v8_mmc, value:1800000
>>> DDR firmware: [0xc081d880]:0xf0227179, size:0x8d98
>>> DDR is ready
>>> No SPI controller (-19)
>>> Trying to boot from MMC2
>>> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
>>> max_clk=204800000
>>> sdhci: voltage signal_voltage=0 -> no switch
>>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
>>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
>>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
>>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
>>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
>>> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
>>> cmd23_host=1 scr0=2358043 cmd23_card=1
>>> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
>>> mmc: multi-blk blkcnt=1956 clk=50000000 mode=2 width=4 caps=300207ef
>>> cmd23_host=1 scr0=2358043 cmd23_card=1
>>> sdhci: multi cmd18 arg=1000 blks=1956 blksz=512 mode=32 dma=0
>>>
>>> <debug_uart>
>>>
>>>
>>> U-Boot 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
>>>
>>> DRAM: 4 GiB
>>> Core: 338 devices, 22 uclasses, devicetree: separate
>>> MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
>>> max_clk=204800000
>>> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
>>> max_clk=204800000
>>> mmc@d4280000: 1, mmc@d4281000: 0
>>> Loading Environment from nowhere... OK
>>> In: serial@d4017000
>>> Out: serial@d4017000
>>> Err: serial@d4017000
>>> Net: No ethernet found.
>>> =>
>>>
>>> With the voltage corrected, a single 1956 block PIO CMD18 loads
>>> the whole FIT,so the controller is fine with the FIFO back pressure,
>>> the slow SPL drain was a symptom, not the cause :-).
>>>
>>> Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
>>> "sdhci: voltage signal_voltage=0 -> no switch".
>>> Since mmc_set_signWith the voltage corrected, a single 1956 block PIO
>>> CMD18 loads
>>> the whole FIT,so the controller is fine with the FIFO back pressure,
>>> the slow SPL drain was a symptom, not the cause :-).
>>>
>>> Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
>>> "sdhci: voltage signal_voltage=0 -> no switch".
>>> Since mmc_set_signal_voltage() is a stub in SPL, so mmc->signal_voltage
>>> stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
>>> "no switch required" path, and aldo1 stayed at the initial 1800000 that
>>> set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
>>> after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
>>> what hid it.
>>>
>>> On the pinctrl side I had already run the SPL with standalone
>>> CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
>>> mmc1_uhs_cfg plus their pin groups. I confirmed that
>>> pinctrl_select_state() return successfully. The multi-block read still
>>> failed the same way with the rail at 1.8V.
>>>
>>> Therefore, I suspect that configuring the MMC signal voltage to 1.8V
>>> in pmic_init() may need to be modified.
>>>
>>> Thanks for your suggestions and guidance.
>>>
>>> Best regards,
>>> Zixianal_voltage() is a stub in SPL, so mmc->signal_voltage
>>> stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
>>> "no switch required" path, and aldo1 stayed at the initial 1800000 that
>>> set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
>>> after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
>>> what hid it.
>>>
>>> On the pinctrl side I had already run the SPL with standalone
>>> CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
>>> mmc1_uhs_cfg plus their pin groups. I confirmed that
>>> pinctrl_select_state() return successfully. The multi-block read still
>>> failed the same way with the rail at 1.8V.
>>>
>>> Therefore, I suspect that configuring the MMC signal voltage to 1.8V
>>> in pmic_init() may need to be modified.
>>>
>>> Thanks for your suggestions and guidance.
>>>
>>>
>> Hi Zixian,
>>
>> Thank you for the quick testing and for posting detailed results. Your
>> patience with the suggested tests helped us reach the root cause
>> within two days.
>>
>> With CONFIG_SPL_MMC_IO_VOLTAGE enabled, aldo1 is changed from its
>> initial 1.8 V to 3.3 V and both the 32-block and 1956-block reads
>> succeed.
>>
>> I am still unsure why set_vdd_mmc() initializes this rail to 1.8 V.
> I'm also looking into this..
>
> It's definitely wrong here, and should be fixed in my opinion, refer
> to SD spec, the initial IO should be 3.3v, and later may change to 1.8v
> according to OCR report, the BROM code will set IO to 3.3v by default
Agreed. The host and I/O signaling rail should initially be at 3.3 V,
and the card powers up using 3.3 V signaling. It may switch to 1.8 V
later only when entering a supported UHS timing mode.
> since cold boot, and I've done a test on this, drop set_vdd_mmc() & without
> CONFIG_SPL_MMC_IO_VOLTAGE enabled, the multi block read still works fine
> on SPL stage
Thanks for testing the multi-block operation after dropping
set_vdd_mmc() and without CONFIG_SPL_MMC_IO_VOLTAGE. Since the BootROM
leaves the I/O rail at 3.3 V after a cold boot, the successful result is
expected and confirms that set_vdd_mmc() incorrectly changes it to
1.8 V.
>
> Also with Zexian's above test, it also prove that, enabling CONFIG_SPL_MMC_IO_VOLTAGE
> will lead the mmc core calling set_voltage() which will set IO to 3.3v, which also
> fix the problem
I think both changes should be made:
1. Initialize the MMC I/O rail to 3.3 V instead of 1.8 V.
2. Enable CONFIG_SPL_MMC_IO_VOLTAGE so the MMC core can manage any
subsequent signal-voltage transitions correctly.
>> Since we do not know the original hardware requirement, any change to
>> that default should be reviewed by the code owner.
>>
>> I suggest enabling both CONFIG_SPL_MMC_IO_VOLTAGE and
>> CONFIG_SPL_PINCTRL. The former fixes the voltage issue, while the
>> latter ensures SPL applies the defined MMC pad configuration instead
>> of relying on the Boot ROM state.
>>
> I agree, it's safe to do this
>
>> Dave, I hope you are aligned with the changes discussed and tested.
>> Could you please post a new version incorporating them?
>>
>> Signed-off-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
>>
>> Regards,
>> Tanmay
>>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-12 14:50 ` Kathpalia, Tanmay
@ 2026-10-12 15:22 ` Yixun Lan
0 siblings, 0 replies; 33+ messages in thread
From: Yixun Lan @ 2026-10-12 15:22 UTC (permalink / raw)
To: Kathpalia, Tanmay
Cc: Zixian Zeng, Dave Klotz, Eric Chung, Peng Fan, u-boot,
Jaehoon Chung, Tom Rini, u-boot-spacemit
Hi Kathpalia,
On 20:20 Mon 12 Oct , Kathpalia, Tanmay wrote:
> Hi Yixun,
>
> On 12-10-2026 20:00, Yixun Lan wrote:
> > Hi Kathpalia, Zexian,
> >
> > On 19:30 Mon 12 Oct , Kathpalia, Tanmay wrote:
> >> On 12-10-2026 18:45, Zixian Zeng wrote:
> >>> On 2026/10/11 22:31, Kathpalia, Tanmay wrote:
> >>>> Hi Zixian,
> >>>>
> >>>> Thanks for the logs.
> >>>>
> >>>> I hit the same pattern while testing the Cadence SD6HC driver.
> >>>> Multi-block reads failed and single-block reads worked. On that board
> >>>> the host and the card were in 1.8 V mode, but the I/O supply had been
> >>>> left at 3.3 V. A short transfer got through; a longer one failed on the
> >>>> data lines.
> >>>> Both stages on K1 use the same PIO loop, so a FIFO that drains slower
> >>>> than the card delivers would show up in U-Boot proper as well. Your
> >>>> SPL/proper split fits an electrical setup difference.
> >>>>
> >>>> The SPL failure is irq=408020. Bit 22 is the Data End Bit Error (EDEB,
> >>>> SD mode only): the controller detected 0 at the end-bit position of
> >>>> read data on DAT, or of the write CRC status. That is a bad edge on
> >>>> the data line during the transfer.
> >>>>
> >>>> On the Banana Pi F3, aldo1 is vqmmc-supply of &sdhci0. The U-Boot
> >>>> dtsi names it vdd_1v8_mmc, and the SPL prints "vdd_1v8_mmc,
> >>>> value:1800000" before MMC2. set_vdd_mmc() in board/spacemit/k1/spl.c,
> >>>> called from board_init_f(), writes 1800000. The dts leaves aldo1 at
> >>>> 0.5 V to 3.4 V. SD High Speed (mode=2) uses 3.3 V signaling; 1.8 V is
> >>>> only after a UHS switch. mmc1_cfg is power-source 3300, and
> >>>> mmc1_uhs_cfg is the 1.8 V state. For this mode the rail should be 3.3 V.
> >>>>
> >>>> CONFIG_SPL_MMC_IO_VOLTAGE is not set, so mmc_set_signal_voltage() is a
> >>>> stub and signal_voltage stays MMC_SIGNAL_VOLTAGE_000. aldo1 stays at
> >>>> 1.8 V. U-Boot proper has CONFIG_MMC_IO_VOLTAGE. mmc_set_initial_state()
> >>>> requests MMC_SIGNAL_VOLTAGE_330, so the driver writes 3300000 to the
> >>>> same vqmmc-supply and clears SDHCI_CTRL_VDD_180 before the transfer
> >>>> that succeeds.
> >>>>
> >>>> CONFIG_SPL_PINCTRL is not set either. The driver calls
> >>>> pinctrl_select_state() under IS_ENABLED(CONFIG_PINCTRL), but that
> >>>> function is a stub unless CONFIG_IS_ENABLED(PINCTRL), and the return
> >>>> is ignored. SPL never applies mmc1_cfg. Proper selects "default" for
> >>>> SD_HS, which is that state.
> >>>>
> >>>> Keeping the multi-block path, set_vdd_mmc() to 3300000, or enable
> >>>> CONFIG_SPL_MMC_IO_VOLTAGE. If the 32-block CMD18 still fails, enable
> >>>> CONFIG_SPL_PINCTRL so mmc1_cfg is applied. If either makes the read
> >>>> succeed, this is the F3 failure.
> >>>>
> >>>> Regards,
> >>>> Tanmay
> >>> Hi Tanmay,
> >>>
> >>> Your diagnosis was right - it is the I/O voltage.
> >>> Enabling CONFIG_SPL_MMC_IO_VOLTAGE makes
> >>> the multi-block read work on the Banana Pi-F3:
> >>>
> >>> Based on previous commit, I patched the following changes:
> >>>
> >>> diff --git a/configs/spacemit_k1_defconfig
> >>> b/configs/spacemit_k1_defconfig
> >>> index 9c15d96eae2..f5c717e5965 100644
> >>> --- a/configs/spacemit_k1_defconfig
> >>> +++ b/configs/spacemit_k1_defconfig
> >>> @@ -95,6 +95,7 @@ CONFIG_MMC=y
> >>> CONFIG_MMC_SDHCI=y
> >>> CONFIG_MMC_SDHCI_SPACEMIT=y
> >>> CONFIG_MMC_IO_VOLTAGE=y
> >>> +CONFIG_SPL_MMC_IO_VOLTAGE=y
> >>> CONFIG_MMC_HS200_SUPPORT=y
> >>> CONFIG_MMC_HS400_SUPPORT=y
> >>> CONFIG_MMC_HS400_ES_SUPPORT=y
> >>> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> >>> index 23c655c6def..58374c482b3 100644
> >>> --- a/drivers/mmc/spacemit_sdhci.c
> >>> +++ b/drivers/mmc/spacemit_sdhci.c
> >>> @@ -251,6 +251,10 @@ static void spacemit_sdhci_set_voltage(struct
> >>> sdhci_host *host)
> >>> bool ok;
> >>> int voltage_mv = to_180 ? 1800000 : 3300000;
> >>>
> >>> + printf("sdhci: voltage signal_voltage=%u
> >>> vqmmc=%s -> %dmV\n",
> >>> + mmc->signal_voltage,
> >>> + mmc->vqmmc_supply ?
> >>> mmc->vqmmc_supply->name : "none",
> >>> + voltage_mv);
> >>> if (spacemit_sdhci_set_vqmmc_voltage(mmc,
> >>> voltage_mv))
> >>> return;
> >>> if (!IS_SD(mmc))
> >>> @@ -274,7 +278,8 @@ static void spacemit_sdhci_set_voltage(struct
> >>> sdhci_host *host)
> >>> break;
> >>> }
> >>> default:
> >>> - /* No signal voltage switch required */
> >>> + printf("sdhci: voltage signal_voltage=%u -> no
> >>> switch\n",
> >>> + mmc->signal_voltage);
> >>> return;
> >>> }
> >>> }
> >>>
> >>> Booting logs as follows:
> >>>
> >>> U-Boot SPL 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
> >>> Fail to detect board:-2
> >>> vdd_core, value:900000
> >>> vdd_1v8, value:1800000
> >>> vdd_1v8_mmc, value:1800000
> >>> DDR firmware: [0xc081d880]:0xf0227179, size:0x8d98
> >>> DDR is ready
> >>> No SPI controller (-19)
> >>> Trying to boot from MMC2
> >>> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> >>> max_clk=204800000
> >>> sdhci: voltage signal_voltage=0 -> no switch
> >>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> >>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> >>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> >>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> >>> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> >>> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> >>> cmd23_host=1 scr0=2358043 cmd23_card=1
> >>> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> >>> mmc: multi-blk blkcnt=1956 clk=50000000 mode=2 width=4 caps=300207ef
> >>> cmd23_host=1 scr0=2358043 cmd23_card=1
> >>> sdhci: multi cmd18 arg=1000 blks=1956 blksz=512 mode=32 dma=0
> >>>
> >>> <debug_uart>
> >>>
> >>>
> >>> U-Boot 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
> >>>
> >>> DRAM: 4 GiB
> >>> Core: 338 devices, 22 uclasses, devicetree: separate
> >>> MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> >>> max_clk=204800000
> >>> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> >>> max_clk=204800000
> >>> mmc@d4280000: 1, mmc@d4281000: 0
> >>> Loading Environment from nowhere... OK
> >>> In: serial@d4017000
> >>> Out: serial@d4017000
> >>> Err: serial@d4017000
> >>> Net: No ethernet found.
> >>> =>
> >>>
> >>> With the voltage corrected, a single 1956 block PIO CMD18 loads
> >>> the whole FIT,so the controller is fine with the FIFO back pressure,
> >>> the slow SPL drain was a symptom, not the cause :-).
> >>>
> >>> Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
> >>> "sdhci: voltage signal_voltage=0 -> no switch".
> >>> Since mmc_set_signWith the voltage corrected, a single 1956 block PIO
> >>> CMD18 loads
> >>> the whole FIT,so the controller is fine with the FIFO back pressure,
> >>> the slow SPL drain was a symptom, not the cause :-).
> >>>
> >>> Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
> >>> "sdhci: voltage signal_voltage=0 -> no switch".
> >>> Since mmc_set_signal_voltage() is a stub in SPL, so mmc->signal_voltage
> >>> stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
> >>> "no switch required" path, and aldo1 stayed at the initial 1800000 that
> >>> set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
> >>> after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
> >>> what hid it.
> >>>
> >>> On the pinctrl side I had already run the SPL with standalone
> >>> CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> >>> mmc1_uhs_cfg plus their pin groups. I confirmed that
> >>> pinctrl_select_state() return successfully. The multi-block read still
> >>> failed the same way with the rail at 1.8V.
> >>>
> >>> Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> >>> in pmic_init() may need to be modified.
> >>>
> >>> Thanks for your suggestions and guidance.
> >>>
> >>> Best regards,
> >>> Zixianal_voltage() is a stub in SPL, so mmc->signal_voltage
> >>> stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
> >>> "no switch required" path, and aldo1 stayed at the initial 1800000 that
> >>> set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
> >>> after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
> >>> what hid it.
> >>>
> >>> On the pinctrl side I had already run the SPL with standalone
> >>> CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> >>> mmc1_uhs_cfg plus their pin groups. I confirmed that
> >>> pinctrl_select_state() return successfully. The multi-block read still
> >>> failed the same way with the rail at 1.8V.
> >>>
> >>> Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> >>> in pmic_init() may need to be modified.
> >>>
> >>> Thanks for your suggestions and guidance.
> >>>
> >>>
> >> Hi Zixian,
> >>
> >> Thank you for the quick testing and for posting detailed results. Your
> >> patience with the suggested tests helped us reach the root cause
> >> within two days.
> >>
> >> With CONFIG_SPL_MMC_IO_VOLTAGE enabled, aldo1 is changed from its
> >> initial 1.8 V to 3.3 V and both the 32-block and 1956-block reads
> >> succeed.
> >>
> >> I am still unsure why set_vdd_mmc() initializes this rail to 1.8 V.
> > I'm also looking into this..
> >
> > It's definitely wrong here, and should be fixed in my opinion, refer
> > to SD spec, the initial IO should be 3.3v, and later may change to 1.8v
> > according to OCR report, the BROM code will set IO to 3.3v by default
>
> Agreed. The host and I/O signaling rail should initially be at 3.3 V,
> and the card powers up using 3.3 V signaling. It may switch to 1.8 V
> later only when entering a supported UHS timing mode.
>
Currently, the spacemit_k1_defconfig does not enable UHS config, so no
1.8v switching will happen, but I think that's another problem which
should investigate later..
> > since cold boot, and I've done a test on this, drop set_vdd_mmc() & without
> > CONFIG_SPL_MMC_IO_VOLTAGE enabled, the multi block read still works fine
> > on SPL stage
>
> Thanks for testing the multi-block operation after dropping
> set_vdd_mmc() and without CONFIG_SPL_MMC_IO_VOLTAGE. Since the BootROM
> leaves the I/O rail at 3.3 V after a cold boot, the successful result is
> expected and confirms that set_vdd_mmc() incorrectly changes it to
> 1.8 V.
>
> >
> > Also with Zexian's above test, it also prove that, enabling CONFIG_SPL_MMC_IO_VOLTAGE
> > will lead the mmc core calling set_voltage() which will set IO to 3.3v, which also
> > fix the problem
>
> I think both changes should be made:
>
> 1. Initialize the MMC I/O rail to 3.3 V instead of 1.8 V.
For how to achieve on this, I'd suggest drop set_vdd_mmc() from spl.c
and the leave spacemit_sdhci.c to config the I/O rail accordingly
> 2. Enable CONFIG_SPL_MMC_IO_VOLTAGE so the MMC core can manage any
> subsequent signal-voltage transitions correctly.
>
I agree on this
> >> Since we do not know the original hardware requirement, any change to
> >> that default should be reviewed by the code owner.
> >>
> >> I suggest enabling both CONFIG_SPL_MMC_IO_VOLTAGE and
> >> CONFIG_SPL_PINCTRL. The former fixes the voltage issue, while the
> >> latter ensures SPL applies the defined MMC pad configuration instead
> >> of relying on the Boot ROM state.
> >>
> > I agree, it's safe to do this
> >
> >> Dave, I hope you are aligned with the changes discussed and tested.
> >> Could you please post a new version incorporating them?
> >>
> >> Signed-off-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
> >>
> >> Regards,
> >> Tanmay
> >>
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-12 13:15 ` Zixian Zeng
2026-10-12 14:00 ` Kathpalia, Tanmay
@ 2026-10-12 16:07 ` Anand Moon
2026-10-13 0:15 ` Yixun Lan
1 sibling, 1 reply; 33+ messages in thread
From: Anand Moon @ 2026-10-12 16:07 UTC (permalink / raw)
To: Zixian Zeng
Cc: Kathpalia, Tanmay, Dave Klotz, Yixun Lan, Eric Chung, Peng Fan,
u-boot, Jaehoon Chung, Tom Rini, u-boot-spacemit
Hi Zixian, Tanmay,
On Mon, 12 Oct 2026 at 18:49, Zixian Zeng <sycamoremoon376@gmail.com> wrote:
>
> On 2026/10/11 22:31, Kathpalia, Tanmay wrote:
> > Hi Zixian,
> >
> > Thanks for the logs.
> >
> > I hit the same pattern while testing the Cadence SD6HC driver.
> > Multi-block reads failed and single-block reads worked. On that board
> > the host and the card were in 1.8 V mode, but the I/O supply had been
> > left at 3.3 V. A short transfer got through; a longer one failed on the
> > data lines.
> > Both stages on K1 use the same PIO loop, so a FIFO that drains slower
> > than the card delivers would show up in U-Boot proper as well. Your
> > SPL/proper split fits an electrical setup difference.
> >
> > The SPL failure is irq=408020. Bit 22 is the Data End Bit Error (EDEB,
> > SD mode only): the controller detected 0 at the end-bit position of
> > read data on DAT, or of the write CRC status. That is a bad edge on
> > the data line during the transfer.
> >
> > On the Banana Pi F3, aldo1 is vqmmc-supply of &sdhci0. The U-Boot
> > dtsi names it vdd_1v8_mmc, and the SPL prints "vdd_1v8_mmc,
> > value:1800000" before MMC2. set_vdd_mmc() in board/spacemit/k1/spl.c,
> > called from board_init_f(), writes 1800000. The dts leaves aldo1 at
> > 0.5 V to 3.4 V. SD High Speed (mode=2) uses 3.3 V signaling; 1.8 V is
> > only after a UHS switch. mmc1_cfg is power-source 3300, and
> > mmc1_uhs_cfg is the 1.8 V state. For this mode the rail should be 3.3 V.
> >
> > CONFIG_SPL_MMC_IO_VOLTAGE is not set, so mmc_set_signal_voltage() is a
> > stub and signal_voltage stays MMC_SIGNAL_VOLTAGE_000. aldo1 stays at
> > 1.8 V. U-Boot proper has CONFIG_MMC_IO_VOLTAGE. mmc_set_initial_state()
> > requests MMC_SIGNAL_VOLTAGE_330, so the driver writes 3300000 to the
> > same vqmmc-supply and clears SDHCI_CTRL_VDD_180 before the transfer
> > that succeeds.
> >
> > CONFIG_SPL_PINCTRL is not set either. The driver calls
> > pinctrl_select_state() under IS_ENABLED(CONFIG_PINCTRL), but that
> > function is a stub unless CONFIG_IS_ENABLED(PINCTRL), and the return
> > is ignored. SPL never applies mmc1_cfg. Proper selects "default" for
> > SD_HS, which is that state.
> >
> > Keeping the multi-block path, set_vdd_mmc() to 3300000, or enable
> > CONFIG_SPL_MMC_IO_VOLTAGE. If the 32-block CMD18 still fails, enable
> > CONFIG_SPL_PINCTRL so mmc1_cfg is applied. If either makes the read
> > succeed, this is the F3 failure.
> >
> > Regards,
> > Tanmay
>
> Hi Tanmay,
>
> Your diagnosis was right - it is the I/O voltage.
> Enabling CONFIG_SPL_MMC_IO_VOLTAGE makes
> the multi-block read work on the Banana Pi-F3:
>
> Based on previous commit, I patched the following changes:
>
> diff --git a/configs/spacemit_k1_defconfig b/configs/spacemit_k1_defconfig
> index 9c15d96eae2..f5c717e5965 100644
> --- a/configs/spacemit_k1_defconfig
> +++ b/configs/spacemit_k1_defconfig
> @@ -95,6 +95,7 @@ CONFIG_MMC=y
> CONFIG_MMC_SDHCI=y
> CONFIG_MMC_SDHCI_SPACEMIT=y
> CONFIG_MMC_IO_VOLTAGE=y
> +CONFIG_SPL_MMC_IO_VOLTAGE=y
> CONFIG_MMC_HS200_SUPPORT=y
> CONFIG_MMC_HS400_SUPPORT=y
> CONFIG_MMC_HS400_ES_SUPPORT=y
> diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
> index 23c655c6def..58374c482b3 100644
> --- a/drivers/mmc/spacemit_sdhci.c
> +++ b/drivers/mmc/spacemit_sdhci.c
> @@ -251,6 +251,10 @@ static void spacemit_sdhci_set_voltage(struct
> sdhci_host *host)
> bool ok;
> int voltage_mv = to_180 ? 1800000 : 3300000;
>
> + printf("sdhci: voltage signal_voltage=%u
> vqmmc=%s -> %dmV\n",
> + mmc->signal_voltage,
> + mmc->vqmmc_supply ?
> mmc->vqmmc_supply->name : "none",
> + voltage_mv);
> if (spacemit_sdhci_set_vqmmc_voltage(mmc,
> voltage_mv))
> return;
> if (!IS_SD(mmc))
> @@ -274,7 +278,8 @@ static void spacemit_sdhci_set_voltage(struct
> sdhci_host *host)
> break;
> }
> default:
> - /* No signal voltage switch required */
> + printf("sdhci: voltage signal_voltage=%u -> no
> switch\n",
> + mmc->signal_voltage);
> return;
> }
> }
>
> Booting logs as follows:
>
> U-Boot SPL 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
> Fail to detect board:-2
> vdd_core, value:900000
> vdd_1v8, value:1800000
> vdd_1v8_mmc, value:1800000
> DDR firmware: [0xc081d880]:0xf0227179, size:0x8d98
> DDR is ready
> No SPI controller (-19)
> Trying to boot from MMC2
> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
> sdhci: voltage signal_voltage=0 -> no switch
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> sdhci: voltage signal_voltage=4 vqmmc=aldo1 -> 3300000mV
> mmc: multi-blk blkcnt=32 clk=50000000 mode=2 width=4 caps=300207ef
> cmd23_host=1 scr0=2358043 cmd23_card=1
> sdhci: multi cmd18 arg=2 blks=32 blksz=512 mode=32 dma=0
> mmc: multi-blk blkcnt=1956 clk=50000000 mode=2 width=4 caps=300207ef
> cmd23_host=1 scr0=2358043 cmd23_card=1
> sdhci: multi cmd18 arg=1000 blks=1956 blksz=512 mode=32 dma=0
>
> <debug_uart>
>
>
> U-Boot 2026.10-rc5-00643-g6a99fe92389a (Oct 12 2026 - 21:13:00 +0800)
>
> DRAM: 4 GiB
> Core: 338 devices, 22 uclasses, devicetree: separate
> MMC: sdhci: mmc@d4281000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
> sdhci: mmc@d4280000 path=PIO flags=0 caps_sdma=1 caps_adma2=1
> max_clk=204800000
> mmc@d4280000: 1, mmc@d4281000: 0
> Loading Environment from nowhere... OK
> In: serial@d4017000
> Out: serial@d4017000
> Err: serial@d4017000
> Net: No ethernet found.
> =>
>
> With the voltage corrected, a single 1956 block PIO CMD18 loads
> the whole FIT,so the controller is fine with the FIFO back pressure,
> the slow SPL drain was a symptom, not the cause :-).
>
> Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
> "sdhci: voltage signal_voltage=0 -> no switch".
> Since mmc_set_signWith the voltage corrected, a single 1956 block PIO
> CMD18 loads
> the whole FIT,so the controller is fine with the FIFO back pressure,
> the slow SPL drain was a symptom, not the cause :-).
>
> Without the CONFIG_SPL_MMC_IO_VOLTAGE=y change the same driver printed
> "sdhci: voltage signal_voltage=0 -> no switch".
> Since mmc_set_signal_voltage() is a stub in SPL, so mmc->signal_voltage
> stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
> "no switch required" path, and aldo1 stayed at the initial 1800000 that
> set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
> after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
> what hid it.
>
> On the pinctrl side I had already run the SPL with standalone
> CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> mmc1_uhs_cfg plus their pin groups. I confirmed that
> pinctrl_select_state() return successfully. The multi-block read still
> failed the same way with the rail at 1.8V.
>
> Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> in pmic_init() may need to be modified.
>
> Thanks for your suggestions and guidance.
>
> Best regards,
> Zixianal_voltage() is a stub in SPL, so mmc->signal_voltage
> stayed MMC_SIGNAL_VOLTAGE_000, spacemit_sdhci_set_voltage() took the
> "no switch required" path, and aldo1 stayed at the initial 1800000 that
> set_vdd_mmc() writes in pmic_init(). The 32 block CMD18 then failed
> after ~20 of 32 blocks. Single block reads passed at 1.8 V, which is
> what hid it.
>
> On the pinctrl side I had already run the SPL with standalone
> CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> mmc1_uhs_cfg plus their pin groups. I confirmed that
> pinctrl_select_state() return successfully. The multi-block read still
> failed the same way with the rail at 1.8V.
>
> Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> in pmic_init() may need to be modified.
>
> Thanks for your suggestions and guidance.
>
I have also made some changes related to SPL GPIO and pinctrl support.
On the Banana Pi BPI-F3, the MMC controller uses the following
regulator references,
which are not currently configured in `k1-musepi-pro-u-boot.dtsi`:
vmmc-supply = <&buck4>;
vqmmc-supply = <&aldo1>;
To address this, I updated `k1-bananapi-f3-u-boot.dtsi` to include the
required regulator
configuration and make it available during SPL initialization.
Could you review these changes and assess whether they can be integrated
into the mainline U-Boot code? I would also appreciate feedback on any
changes needed
to make the implementation suitable for upstream submission.
> Best regards,
> Zixian
>
[1] https://gist.github.com/moonlinux/2ae03be59f263b0797acb138bed226b5
Thanks
-Anand
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-12 16:07 ` Anand Moon
@ 2026-10-13 0:15 ` Yixun Lan
2026-10-13 3:44 ` Anand Moon
0 siblings, 1 reply; 33+ messages in thread
From: Yixun Lan @ 2026-10-13 0:15 UTC (permalink / raw)
To: Anand Moon
Cc: Zixian Zeng, Kathpalia, Tanmay, Dave Klotz, Eric Chung, Peng Fan,
u-boot, Jaehoon Chung, Tom Rini, u-boot-spacemit
Hi Anand Moon,
On 21:37 Mon 12 Oct , Anand Moon wrote:
> Hi Zixian, Tanmay,
>
> On Mon, 12 Oct 2026 at 18:49, Zixian Zeng <sycamoremoon376@gmail.com> wrote:
> >
...
> > On the pinctrl side I had already run the SPL with standalone
> > CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> > mmc1_uhs_cfg plus their pin groups. I confirmed that
> > pinctrl_select_state() return successfully. The multi-block read still
> > failed the same way with the rail at 1.8V.
> >
> > Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> > in pmic_init() may need to be modified.
> >
> > Thanks for your suggestions and guidance.
> >
> I have also made some changes related to SPL GPIO and pinctrl support.
> On the Banana Pi BPI-F3, the MMC controller uses the following
> regulator references,
> which are not currently configured in `k1-musepi-pro-u-boot.dtsi`:
> vmmc-supply = <&buck4>;
> vqmmc-supply = <&aldo1>;
>
> To address this, I updated `k1-bananapi-f3-u-boot.dtsi` to include the
> required regulator
> configuration and make it available during SPL initialization.
>
> Could you review these changes and assess whether they can be integrated
> into the mainline U-Boot code? I would also appreciate feedback on any
> changes needed
> to make the implementation suitable for upstream submission.
Hey, I'm confused, are you trying to prepare a patch here? I thought
it's Dave Klotz who would do this, let's not hijack this thread but
coordinate together, and please be patient, give Dave some time to
respond.. I think what Zexian done here is trying to investigate and
test the patches..
> [1] https://gist.github.com/moonlinux/2ae03be59f263b0797acb138bed226b5
>
No, It's not a proper way for people to review and comment..
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time
2026-10-13 0:15 ` Yixun Lan
@ 2026-10-13 3:44 ` Anand Moon
0 siblings, 0 replies; 33+ messages in thread
From: Anand Moon @ 2026-10-13 3:44 UTC (permalink / raw)
To: Yixun Lan
Cc: Zixian Zeng, Kathpalia, Tanmay, Dave Klotz, Eric Chung, Peng Fan,
u-boot, Jaehoon Chung, Tom Rini, u-boot-spacemit
Hi Yixun,
On Tue, 13 Oct 2026 at 05:45, Yixun Lan <dlan@kernel.org> wrote:
>
> Hi Anand Moon,
>
> On 21:37 Mon 12 Oct , Anand Moon wrote:
> > Hi Zixian, Tanmay,
> >
> > On Mon, 12 Oct 2026 at 18:49, Zixian Zeng <sycamoremoon376@gmail.com> wrote:
> > >
> ...
> > > On the pinctrl side I had already run the SPL with standalone
> > > CONFIG_SPL_PINCTRL=y, with bootph-pre-ram on &pinctrl, mmc1_cfg and
> > > mmc1_uhs_cfg plus their pin groups. I confirmed that
> > > pinctrl_select_state() return successfully. The multi-block read still
> > > failed the same way with the rail at 1.8V.
> > >
> > > Therefore, I suspect that configuring the MMC signal voltage to 1.8V
> > > in pmic_init() may need to be modified.
> > >
> > > Thanks for your suggestions and guidance.
> > >
> > I have also made some changes related to SPL GPIO and pinctrl support.
> > On the Banana Pi BPI-F3, the MMC controller uses the following
> > regulator references,
> > which are not currently configured in `k1-musepi-pro-u-boot.dtsi`:
> > vmmc-supply = <&buck4>;
> > vqmmc-supply = <&aldo1>;
> >
> > To address this, I updated `k1-bananapi-f3-u-boot.dtsi` to include the
> > required regulator
> > configuration and make it available during SPL initialization.
> >
> > Could you review these changes and assess whether they can be integrated
> > into the mainline U-Boot code? I would also appreciate feedback on any
> > changes needed
> > to make the implementation suitable for upstream submission.
> Hey, I'm confused, are you trying to prepare a patch here? I thought
> it's Dave Klotz who would do this, let's not hijack this thread but
> coordinate together, and please be patient, give Dave some time to
> respond.. I think what Zexian done here is trying to investigate and
> test the patches..
>
> > [1] https://gist.github.com/moonlinux/2ae03be59f263b0797acb138bed226b5
> >
> No, It's not a proper way for people to review and comment..
>
Please accept my apology for this.
> --
> Yixun Lan (dlan)
Thanks
-Anand
^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2026-10-13 3:45 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-02 21:29 [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver Dave Klotz
2026-10-02 21:29 ` [PATCH 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
2026-10-04 9:14 ` Kathpalia, Tanmay
2026-10-04 9:30 ` Kathpalia, Tanmay
2026-10-05 17:46 ` Dave Klotz
2026-10-02 21:29 ` [PATCH 2/3] mmc: k1: let the SPL read SD cards more than one block at a time Dave Klotz
2026-10-04 9:28 ` Kathpalia, Tanmay
2026-10-02 21:29 ` [PATCH 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure Dave Klotz
2026-10-04 9:28 ` Kathpalia, Tanmay
2026-10-02 22:06 ` [PATCH 0/3] mmc: k1: fixes for the SpacemiT K1 SDHCI driver Dave Klotz
2026-10-05 17:50 ` [PATCH v2 " Dave Klotz
2026-10-05 17:55 ` [PATCH v2 1/3] mmc: k1: handle a missing max-frequency and clk_set_rate()'s return value Dave Klotz
2026-10-06 5:40 ` Kathpalia, Tanmay
2026-10-10 8:45 ` Yixun Lan
2026-10-05 18:01 ` [PATCH v2 2/3] mmc: k1: let the SPL read SD cards more than one block at a time Dave Klotz
2026-10-10 6:17 ` Zixian Zeng
2026-10-10 19:02 ` Kathpalia, Tanmay
2026-10-10 19:16 ` Kathpalia, Tanmay
2026-10-11 3:38 ` Zixian Zeng
2026-10-11 14:31 ` Kathpalia, Tanmay
2026-10-11 15:33 ` Anand Moon
2026-10-11 19:41 ` Kathpalia, Tanmay
2026-10-12 13:15 ` Zixian Zeng
2026-10-12 14:00 ` Kathpalia, Tanmay
2026-10-12 14:30 ` Yixun Lan
2026-10-12 14:50 ` Kathpalia, Tanmay
2026-10-12 15:22 ` Yixun Lan
2026-10-12 16:07 ` Anand Moon
2026-10-13 0:15 ` Yixun Lan
2026-10-13 3:44 ` Anand Moon
2026-10-05 18:11 ` [PATCH v2 3/3] mmc: k1: do not release the shared AXI clock and reset on probe failure Dave Klotz
2026-10-10 7:14 ` Yixun Lan
2026-10-10 19:27 ` Kathpalia, Tanmay
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.