* [PATCH 1/5] mmc: fix mmc_poll_for_busy() false timeout when card is ready
2026-07-12 13:07 [PATCH 0/5] mmc: misc fixes across MMC/SDHCI/RPMB Peng Fan (OSS)
@ 2026-07-12 13:07 ` Peng Fan (OSS)
2026-07-12 13:07 ` [PATCH 2/5] mmc: rpmb: fix tautological condition in RPMB_REQ_READ_DATA validation Peng Fan (OSS)
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Peng Fan (OSS) @ 2026-07-12 13:07 UTC (permalink / raw)
To: u-boot
Cc: Jaehoon Chung, Tom Rini, Tanmay Kathpalia, Jens Wiklander,
Bhimeswararao Matsa, Yanir Levin, Eran Moshe, Andrew Goodbody,
Kaustabh Chakraborty, Christoph Stoidner, Tanmay Kathpalia,
Jimmy Durand Wesolowski, Iulian Banaga, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
mmc_poll_for_busy() returns a false -ETIMEDOUT if the card becomes
ready on the exact iteration where timeout_ms reaches 0. The card-ready
check breaks out of the loop, but then the post-loop check
"if (timeout_ms <= 0)" fires and returns -ETIMEDOUT despite the card
being ready.
Fix by returning 0 directly when the card is ready instead of breaking
out of the loop. The only exit from the loop is now the timeout path,
so the post-loop code unconditionally returns -ETIMEDOUT.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/mmc/mmc.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 2e565560656..ef7defcde71 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -325,7 +325,7 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
if ((status & MMC_STATUS_RDY_FOR_DATA) &&
(status & MMC_STATUS_CURR_STATE) !=
MMC_STATE_PRG)
- break;
+ return 0;
if (status & MMC_STATUS_MASK) {
#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
@@ -340,14 +340,10 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
udelay(1000);
}
- if (timeout_ms <= 0) {
#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- log_err("Timeout waiting card ready\n");
+ log_err("Timeout waiting card ready\n");
#endif
- return -ETIMEDOUT;
- }
-
- return 0;
+ return -ETIMEDOUT;
}
int mmc_set_blocklen(struct mmc *mmc, int len)
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 2/5] mmc: rpmb: fix tautological condition in RPMB_REQ_READ_DATA validation
2026-07-12 13:07 [PATCH 0/5] mmc: misc fixes across MMC/SDHCI/RPMB Peng Fan (OSS)
2026-07-12 13:07 ` [PATCH 1/5] mmc: fix mmc_poll_for_busy() false timeout when card is ready Peng Fan (OSS)
@ 2026-07-12 13:07 ` Peng Fan (OSS)
2026-07-12 13:07 ` [PATCH 3/5] mmc: sdhci: fix align_buffer memory leak on re-initialization Peng Fan (OSS)
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Peng Fan (OSS) @ 2026-07-12 13:07 UTC (permalink / raw)
To: u-boot
Cc: Jaehoon Chung, Tom Rini, Tanmay Kathpalia, Jens Wiklander,
Bhimeswararao Matsa, Yanir Levin, Eran Moshe, Andrew Goodbody,
Kaustabh Chakraborty, Christoph Stoidner, Tanmay Kathpalia,
Jimmy Durand Wesolowski, Iulian Banaga, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
In rpmb_route_frames(), the RPMB_REQ_READ_DATA case checks
"req_cnt != 1 || !req_cnt" which is tautological -- !req_cnt (req_cnt
== 0) is always a subset of req_cnt != 1. The second operand is dead
code.
Based on the pattern of all other cases in the switch (RPMB_REQ_KEY,
RPMB_REQ_WRITE_DATA, RPMB_REQ_WCOUNTER) which validate rsp_cnt, this
was meant to be "req_cnt != 1 || !rsp_cnt". Without this fix, a caller
could pass rsp_cnt=0 for a read request without validation.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/mmc/rpmb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c
index 8bfdffd56f5..26d2262ef45 100644
--- a/drivers/mmc/rpmb.c
+++ b/drivers/mmc/rpmb.c
@@ -452,7 +452,7 @@ static int rpmb_route_frames(struct mmc *mmc, struct s_rpmb *req,
return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
case RPMB_REQ_READ_DATA:
- if (req_cnt != 1 || !req_cnt)
+ if (req_cnt != 1 || !rsp_cnt)
return -EINVAL;
return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 3/5] mmc: sdhci: fix align_buffer memory leak on re-initialization
2026-07-12 13:07 [PATCH 0/5] mmc: misc fixes across MMC/SDHCI/RPMB Peng Fan (OSS)
2026-07-12 13:07 ` [PATCH 1/5] mmc: fix mmc_poll_for_busy() false timeout when card is ready Peng Fan (OSS)
2026-07-12 13:07 ` [PATCH 2/5] mmc: rpmb: fix tautological condition in RPMB_REQ_READ_DATA validation Peng Fan (OSS)
@ 2026-07-12 13:07 ` Peng Fan (OSS)
2026-07-12 18:50 ` Kathpalia, Tanmay
2026-07-12 13:07 ` [PATCH 4/5] mmc: fix mmc_bwrite() ignoring host get_b_max() callback Peng Fan (OSS)
2026-07-12 13:07 ` [PATCH 5/5] mmc: fix mmc_deinit regression when card is at 1.8V signaling Peng Fan (OSS)
4 siblings, 1 reply; 10+ messages in thread
From: Peng Fan (OSS) @ 2026-07-12 13:07 UTC (permalink / raw)
To: u-boot
Cc: Jaehoon Chung, Tom Rini, Tanmay Kathpalia, Jens Wiklander,
Bhimeswararao Matsa, Yanir Levin, Eran Moshe, Andrew Goodbody,
Kaustabh Chakraborty, Christoph Stoidner, Tanmay Kathpalia,
Jimmy Durand Wesolowski, Iulian Banaga, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
sdhci_init() allocates a 512KB aligned bounce buffer for controllers
with SDHCI_QUIRK_32BIT_DMA_ADDR. In the non-DM code path, sdhci_init()
is registered as ops->init and called on every mmc_init(). Each call
allocates a new buffer without checking or freeing the previous one,
leaking 512KB per re-initialization.
Fix by guarding the allocation with !host->align_buffer so it only
allocates on the first call.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/mmc/sdhci.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 08594e10266..ef20e881542 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -733,7 +733,8 @@ static int sdhci_init(struct mmc *mmc)
*/
host->force_align_buffer = true;
#else
- if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) {
+ if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
+ !host->align_buffer) {
host->align_buffer = memalign(8, 512 * 1024);
if (!host->align_buffer) {
log_err("Aligned buffer alloc failed\n");
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH 3/5] mmc: sdhci: fix align_buffer memory leak on re-initialization
2026-07-12 13:07 ` [PATCH 3/5] mmc: sdhci: fix align_buffer memory leak on re-initialization Peng Fan (OSS)
@ 2026-07-12 18:50 ` Kathpalia, Tanmay
2026-07-13 8:42 ` Peng Fan
0 siblings, 1 reply; 10+ messages in thread
From: Kathpalia, Tanmay @ 2026-07-12 18:50 UTC (permalink / raw)
To: Peng Fan (OSS), u-boot
Cc: Jaehoon Chung, Tom Rini, Jens Wiklander, Bhimeswararao Matsa,
Yanir Levin, Eran Moshe, Andrew Goodbody, Kaustabh Chakraborty,
Christoph Stoidner, Tanmay Kathpalia, Jimmy Durand Wesolowski,
Iulian Banaga, Peng Fan
On 7/12/2026 6:37 PM, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@nxp.com>
>
> sdhci_init() allocates a 512KB aligned bounce buffer for controllers
> with SDHCI_QUIRK_32BIT_DMA_ADDR. In the non-DM code path, sdhci_init()
> is registered as ops->init and called on every mmc_init(). Each call
> allocates a new buffer without checking or freeing the previous one,
> leaking 512KB per re-initialization.
>
> Fix by guarding the allocation with !host->align_buffer so it only
> allocates on the first call.
>
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/5] mmc: sdhci: fix align_buffer memory leak on re-initialization
2026-07-12 18:50 ` Kathpalia, Tanmay
@ 2026-07-13 8:42 ` Peng Fan
2026-07-13 9:23 ` Kathpalia, Tanmay
0 siblings, 1 reply; 10+ messages in thread
From: Peng Fan @ 2026-07-13 8:42 UTC (permalink / raw)
To: Kathpalia, Tanmay
Cc: u-boot, Jaehoon Chung, Tom Rini, Jens Wiklander,
Bhimeswararao Matsa, Yanir Levin, Eran Moshe, Andrew Goodbody,
Kaustabh Chakraborty, Christoph Stoidner, Tanmay Kathpalia,
Jimmy Durand Wesolowski, Iulian Banaga, Peng Fan
Hi Tanmay,
On Mon, Jul 13, 2026 at 12:20:10AM +0530, Kathpalia, Tanmay wrote:
>
>On 7/12/2026 6:37 PM, Peng Fan (OSS) wrote:
>> From: Peng Fan <peng.fan@nxp.com>
>>
>> sdhci_init() allocates a 512KB aligned bounce buffer for controllers
>> with SDHCI_QUIRK_32BIT_DMA_ADDR. In the non-DM code path, sdhci_init()
>> is registered as ops->init and called on every mmc_init(). Each call
>> allocates a new buffer without checking or freeing the previous one,
>> leaking 512KB per re-initialization.
>>
>> Fix by guarding the allocation with !host->align_buffer so it only
>> allocates on the first call.
>>
>> Signed-off-by: Peng Fan <peng.fan@nxp.com>
>
>Signed-off-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
This should be R-b or A-b. I will use R-b if no objections.
Thanks
Peng
>
>>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/5] mmc: sdhci: fix align_buffer memory leak on re-initialization
2026-07-13 8:42 ` Peng Fan
@ 2026-07-13 9:23 ` Kathpalia, Tanmay
0 siblings, 0 replies; 10+ messages in thread
From: Kathpalia, Tanmay @ 2026-07-13 9:23 UTC (permalink / raw)
To: Peng Fan
Cc: u-boot, Jaehoon Chung, Tom Rini, Jens Wiklander,
Bhimeswararao Matsa, Yanir Levin, Eran Moshe, Andrew Goodbody,
Kaustabh Chakraborty, Christoph Stoidner, Tanmay Kathpalia,
Jimmy Durand Wesolowski, Iulian Banaga, Peng Fan
Hi Peng,
On 7/13/2026 2:12 PM, Peng Fan wrote:
> Hi Tanmay,
>
> On Mon, Jul 13, 2026 at 12:20:10AM +0530, Kathpalia, Tanmay wrote:
>> On 7/12/2026 6:37 PM, Peng Fan (OSS) wrote:
>>> From: Peng Fan <peng.fan@nxp.com>
>>>
>>> sdhci_init() allocates a 512KB aligned bounce buffer for controllers
>>> with SDHCI_QUIRK_32BIT_DMA_ADDR. In the non-DM code path, sdhci_init()
>>> is registered as ops->init and called on every mmc_init(). Each call
>>> allocates a new buffer without checking or freeing the previous one,
>>> leaking 512KB per re-initialization.
>>>
>>> Fix by guarding the allocation with !host->align_buffer so it only
>>> allocates on the first call.
>>>
>>> Signed-off-by: Peng Fan <peng.fan@nxp.com>
>> Signed-off-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
> This should be R-b or A-b. I will use R-b if no objections.
>
Yes, R-b is fine.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 4/5] mmc: fix mmc_bwrite() ignoring host get_b_max() callback
2026-07-12 13:07 [PATCH 0/5] mmc: misc fixes across MMC/SDHCI/RPMB Peng Fan (OSS)
` (2 preceding siblings ...)
2026-07-12 13:07 ` [PATCH 3/5] mmc: sdhci: fix align_buffer memory leak on re-initialization Peng Fan (OSS)
@ 2026-07-12 13:07 ` Peng Fan (OSS)
2026-07-12 13:07 ` [PATCH 5/5] mmc: fix mmc_deinit regression when card is at 1.8V signaling Peng Fan (OSS)
4 siblings, 0 replies; 10+ messages in thread
From: Peng Fan (OSS) @ 2026-07-12 13:07 UTC (permalink / raw)
To: u-boot
Cc: Jaehoon Chung, Tom Rini, Tanmay Kathpalia, Jens Wiklander,
Bhimeswararao Matsa, Yanir Levin, Eran Moshe, Andrew Goodbody,
Kaustabh Chakraborty, Christoph Stoidner, Tanmay Kathpalia,
Jimmy Durand Wesolowski, Iulian Banaga, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
mmc_bwrite() uses mmc->cfg->b_max directly to limit per-transfer block
count. The read path (mmc_bread()) correctly calls mmc_get_b_max()
which dispatches to the host driver get_b_max() callback. This callback
allows host drivers to enforce DMA boundary constraints based on the
buffer address.
Fix mmc_bwrite() to use mmc_get_b_max() to match the read path. This
requires removing the static qualifier from the non-DM mmc_get_b_max()
and adding its declaration to mmc_private.h.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/mmc/mmc.c | 2 +-
drivers/mmc/mmc_private.h | 4 ++++
drivers/mmc/mmc_write.c | 6 ++++--
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index ef7defcde71..5fd12d21f92 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -490,7 +490,7 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
}
#if !CONFIG_IS_ENABLED(DM_MMC)
-static int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt)
+int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt)
{
if (mmc->cfg->ops->get_b_max)
return mmc->cfg->ops->get_b_max(mmc, dst, blkcnt);
diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h
index fc45f017e5d..24e68ceb5e6 100644
--- a/drivers/mmc/mmc_private.h
+++ b/drivers/mmc/mmc_private.h
@@ -17,6 +17,10 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout);
int mmc_set_blocklen(struct mmc *mmc, int len);
+#if !CONFIG_IS_ENABLED(DM_MMC)
+int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt);
+#endif
+
#if CONFIG_IS_ENABLED(BLK)
ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
void *dst);
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
index 928c05872ca..9cf07b4ad1f 100644
--- a/drivers/mmc/mmc_write.c
+++ b/drivers/mmc/mmc_write.c
@@ -228,6 +228,7 @@ ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
int dev_num = block_dev->devnum;
lbaint_t cur, blocks_todo = blkcnt;
int err;
+ uint b_max;
struct mmc *mmc = find_mmc_device(dev_num);
if (!mmc)
@@ -240,9 +241,10 @@ ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
if (mmc_set_blocklen(mmc, mmc->write_bl_len))
return 0;
+ b_max = mmc_get_b_max(mmc, (void *)src, blkcnt);
+
do {
- cur = (blocks_todo > mmc->cfg->b_max) ?
- mmc->cfg->b_max : blocks_todo;
+ cur = (blocks_todo > b_max) ? b_max : blocks_todo;
if (mmc_write_blocks(mmc, start, cur, src) != cur)
return 0;
blocks_todo -= cur;
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 5/5] mmc: fix mmc_deinit regression when card is at 1.8V signaling
2026-07-12 13:07 [PATCH 0/5] mmc: misc fixes across MMC/SDHCI/RPMB Peng Fan (OSS)
` (3 preceding siblings ...)
2026-07-12 13:07 ` [PATCH 4/5] mmc: fix mmc_bwrite() ignoring host get_b_max() callback Peng Fan (OSS)
@ 2026-07-12 13:07 ` Peng Fan (OSS)
2026-07-12 18:20 ` Kathpalia, Tanmay
4 siblings, 1 reply; 10+ messages in thread
From: Peng Fan (OSS) @ 2026-07-12 13:07 UTC (permalink / raw)
To: u-boot
Cc: Jaehoon Chung, Tom Rini, Tanmay Kathpalia, Jens Wiklander,
Bhimeswararao Matsa, Yanir Levin, Eran Moshe, Andrew Goodbody,
Kaustabh Chakraborty, Christoph Stoidner, Tanmay Kathpalia,
Jimmy Durand Wesolowski, Iulian Banaga, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
Commit 906ee6785b1c ("mmc: sd: Handle UHS-I voltage signaling without
power cycle") added detection of cards already operating at 1.8V
signaling via mmc_sd_card_using_v18(). This correctly handles the
warm-reboot scenario in mmc_startup(), but causes a regression in
mmc_deinit().
The problem: mmc_deinit() strips ALL UHS capabilities from the card
caps and calls sd_select_mode_and_width() to downgrade the card before
kernel handoff. But sd_select_mode_and_width() now checks
mmc_sd_card_using_v18(), sees the card is at 1.8V, sets uhs_en=true,
and tries to use UHS modes -- which were just stripped from the caps.
The fallback modes (SD_HS, MMC_LEGACY) all fail because they require
3.3V signaling, which the card cannot revert to without a power cycle.
Per SD Physical Layer Specification: "Once the card enters 1.8V
signaling mode, the card cannot be switched to 3.3V signaling without
power cycle. If the card receives CMD0, card returns to Idle state but
still works with SDR12 timing."
Fix this by preserving UHS_SDR12 in the filtered caps when the card is
operating at 1.8V. SDR12 is the minimum valid UHS-I mode and is always
available at 1.8V signaling per the SD specification.
Fixes: 906ee6785b1c ("mmc: sd: Handle UHS-I voltage signaling without power cycle")
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/mmc/mmc.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 5fd12d21f92..809d7b6b578 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -3178,6 +3178,17 @@ int mmc_deinit(struct mmc *mmc)
MMC_CAP(UHS_SDR50) | MMC_CAP(UHS_DDR50) |
MMC_CAP(UHS_SDR104));
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ /*
+ * Per SD spec, once a card enters 1.8V signaling it
+ * cannot revert to 3.3V without a power cycle.
+ * If the card is operating at 1.8V, keep UHS_SDR12
+ * as the minimum fallback mode.
+ */
+ if (mmc_sd_card_using_v18(mmc))
+ caps_filtered |= MMC_CAP(UHS_SDR12);
+#endif
+
return sd_select_mode_and_width(mmc, caps_filtered);
} else {
caps_filtered = mmc->card_caps &
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH 5/5] mmc: fix mmc_deinit regression when card is at 1.8V signaling
2026-07-12 13:07 ` [PATCH 5/5] mmc: fix mmc_deinit regression when card is at 1.8V signaling Peng Fan (OSS)
@ 2026-07-12 18:20 ` Kathpalia, Tanmay
0 siblings, 0 replies; 10+ messages in thread
From: Kathpalia, Tanmay @ 2026-07-12 18:20 UTC (permalink / raw)
To: Peng Fan (OSS), u-boot
Cc: Jaehoon Chung, Tom Rini, Jens Wiklander, Bhimeswararao Matsa,
Yanir Levin, Eran Moshe, Andrew Goodbody, Kaustabh Chakraborty,
Christoph Stoidner, Tanmay Kathpalia, Jimmy Durand Wesolowski,
Iulian Banaga, Peng Fan
Hi Peng,
A few comments.
On 7/12/2026 6:37 PM, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@nxp.com>
>
> Commit 906ee6785b1c ("mmc: sd: Handle UHS-I voltage signaling without
> power cycle") added detection of cards already operating at 1.8V
> signaling via mmc_sd_card_using_v18(). This correctly handles the
> warm-reboot scenario in mmc_startup(), but causes a regression in
> mmc_deinit().
>
> The problem: mmc_deinit() strips ALL UHS capabilities from the card
> caps and calls sd_select_mode_and_width() to downgrade the card before
> kernel handoff. But sd_select_mode_and_width() now checks
> mmc_sd_card_using_v18(), sees the card is at 1.8V, sets uhs_en=true,
> and tries to use UHS modes -- which were just stripped from the caps.
Even before 906ee6785b1c, sd_select_mode_and_width() computed:
bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
For a card that has switched to 1.8V, OCR_S18R (S18A) is already set in
mmc->ocr, so uhs_en was already true in this path before the commit.
So sd_select_mode_and_width() did not newly set uhs_en=true because
of this commit; that was already the case. Could you reword the
attribution to reflect that?
> The fallback modes (SD_HS, MMC_LEGACY) all fail because they require
> 3.3V signaling, which the card cannot revert to without a power cycle.
I think CMD6 switches speed over whatever signaling is already active,
so this doesn't necessarily fail outright - it likely leaves the card
in an invalid/inconsistent state (a 3.3V speed mode while signaling at
1.8V). Might be worth softening "all fail" to that wording, but I'll
leave it to your judgment/testing.
>
> Per SD Physical Layer Specification: "Once the card enters 1.8V
> signaling mode, the card cannot be switched to 3.3V signaling without
> power cycle. If the card receives CMD0, card returns to Idle state but
> still works with SDR12 timing."
>
> Fix this by preserving UHS_SDR12 in the filtered caps when the card is
> operating at 1.8V. SDR12 is the minimum valid UHS-I mode and is always
> available at 1.8V signaling per the SD specification.
>
> Fixes: 906ee6785b1c ("mmc: sd: Handle UHS-I voltage signaling without power cycle")
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> ---
> drivers/mmc/mmc.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
> index 5fd12d21f92..809d7b6b578 100644
> --- a/drivers/mmc/mmc.c
> +++ b/drivers/mmc/mmc.c
> @@ -3178,6 +3178,17 @@ int mmc_deinit(struct mmc *mmc)
> MMC_CAP(UHS_SDR50) | MMC_CAP(UHS_DDR50) |
> MMC_CAP(UHS_SDR104));
>
> +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
> + /*
> + * Per SD spec, once a card enters 1.8V signaling it
> + * cannot revert to 3.3V without a power cycle.
> + * If the card is operating at 1.8V, keep UHS_SDR12
> + * as the minimum fallback mode.
> + */
> + if (mmc_sd_card_using_v18(mmc))
> + caps_filtered |= MMC_CAP(UHS_SDR12);
> +#endif
> +
> return sd_select_mode_and_width(mmc, caps_filtered);
> } else {
> caps_filtered = mmc->card_caps &
Cleaner to decide the mask up front instead of stripping then adding
back, and reuse UHS_CAPS instead of re-listing the bits:
if (IS_SD(mmc)) {
u32 uhs_mask = UHS_CAPS;
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
/*
* Per SD spec, once a card enters 1.8V signaling it cannot
* revert to 3.3V without a power cycle. If the card is operating
* at 1.8V, keep UHS_SDR12 as the minimum fallback mode so the
* card is left in a consistent (1.8V) state at a low, safe speed.
*/
if (mmc_sd_card_using_v18(mmc))
uhs_mask &= ~MMC_CAP(UHS_SDR12);
#endif
caps_filtered = mmc->card_caps & ~uhs_mask;
Regards,
Tanmay
^ permalink raw reply [flat|nested] 10+ messages in thread