Re: [PATCH v4] mmc: litex_mmc: Set mandatory idle clocks before CMD0
From: Inochi Amaoto
Date: Mon May 18 2026 - 22:52:00 EST
On Mon, May 18, 2026 at 06:45:26PM -0400, Gabriel L. Somlo wrote:
> On Tue, May 19, 2026 at 06:24:19AM +0800, Inochi Amaoto wrote:
> > On Mon, May 18, 2026 at 06:20:49PM -0400, Gabriel L. Somlo wrote:
> > > with this patch on top of today's latest (4d3a2a466b8d), I get
> > > (on 64-bit rocketchip with Litex):
> > >
> > > [ 6.475114] mmc0: invalid bus width
> > > [ 6.477870] mmc0: error -22 whilst initialising SD card
> > >
> > > Thanks,
> > > --Gabriel
> > >
> >
> > Hi, Gabriel,
> >
> > Could you share the board link and build commands? I think I need to
> > take a look for why this occurs.
> >
> > Regards,
> > Inochi
>
> Hi Inochi,
>
> it's the digilent nexys-video board; the command line to build the
> bitstream is:
>
> litex-boards/litex_boards/targets/digilent_nexys_video.py --build \
> --cpu-type rocket --cpu-variant linux --cpu-num-cores 4 --cpu-mem-width 2 \
> --sys-clk-freq 50e6 --with-ethernet --with-sdcard --with-sata --sata-gen 1
>
> (for more details see https://github.com/litex-hub/linux-on-litex-rocket)
>
> I've added your patch on top of the LiteX kernel tree at
> https://github.com/litex-hub/linux/tree/litex-rebase
>
> and compiled it with:
>
> make clean
> make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- litex_rocket_defconfig
> make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu-
>
> FWIW, your previous versions of the patch did work, and did fix the
> issue you were trying to address (which I did notice being a problem
> on my configuration :)
>
> Thanks,
> --Gabriel
>
Hi Gabriel,
Although I fail to compile the rocket and can not reproduced this
error with VexiiRiscv, I have noticed some interesting things:
[ 745.321341] mmc0: card aaaa removed
[ 745.363624] litex-mmc f0004000.mmc: clock 25000000 -> 0
[ 747.357770] litex-mmc f0004000.mmc: clock 0 -> 12500000
[ 747.374898] litex-mmc f0004000.mmc: clock 12500000 -> 400000
[ 747.706917] litex-mmc f0004000.mmc: clock 400000 -> 25000000
[ 747.711954] mmc0: new SDHC card at address aaaa
[ 747.722665] mmcblk0: mmc0:aaaa SL16G 14.8 GiB
[ 747.751452] mmcblk0: p1 p2
It seems like that the controller does not switch to the required init
frequency. Instead, it jump to a working frequency. It may lead to a
false reset.
Another thing is that I noticed the bios sets the PHY to x1 when
initing, but the current set_ios() does nothing with this, only
setting x4 every time that sends the command. I have added a simple
reset that changes the PHY to x1 when setting MMC_CS_HIGH.
(And I think it could be better to add bus width length handler
instead of leaving a force x4 mode).
I have prepared a new patch for these thing. Could you have a try?
Regards,
Inochi
diff --git a/drivers/mmc/host/litex_mmc.c b/drivers/mmc/host/litex_mmc.c
index d2f19c2dc673..97e07222872e 100644
--- a/drivers/mmc/host/litex_mmc.c
+++ b/drivers/mmc/host/litex_mmc.c
@@ -28,6 +28,7 @@
#define LITEX_PHY_CLOCKERDIV 0x04
#define LITEX_PHY_INITIALIZE 0x08
#define LITEX_PHY_WRITESTATUS 0x0C
+#define LITEX_PHY_SETTINGS 0x18
#define LITEX_CORE_CMDARG 0x00
#define LITEX_CORE_CMDCMD 0x04
#define LITEX_CORE_CMDSND 0x08
@@ -68,6 +69,12 @@
#define SD_SLEEP_US 5
#define SD_TIMEOUT_US 20000
+#define SD_INIT_DELAY_US 1000
+#define SD_INIT_CLK_HZ 400000
+
+#define SD_PHY_SPEED_1X 0
+#define SD_PHY_SPEED_4X 1
+
#define SDIRQ_CARD_DETECT 1
#define SDIRQ_SD_TO_MEM_DONE 2
#define SDIRQ_MEM_TO_SD_DONE 4
@@ -220,6 +227,8 @@ static int litex_mmc_set_bus_width(struct litex_mmc_host *host)
if (ret)
return ret;
+ litex_write8(host->sdphy + LITEX_PHY_SETTINGS, SD_PHY_SPEED_4X);
+
/* Re-send 'app_cmd' if necessary */
if (app_cmd_sent) {
ret = litex_mmc_send_app_cmd(host);
@@ -449,6 +458,12 @@ static void litex_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct litex_mmc_host *host = mmc_priv(mmc);
+ if (ios->chip_select == MMC_CS_HIGH) {
+ litex_write8(host->sdphy + LITEX_PHY_SETTINGS, SD_PHY_SPEED_1X);
+ ios->clock = SD_INIT_CLK_HZ;
+ host->is_bus_width_set = false;
+ }
+
/*
* NOTE: Ignore any ios->bus_width updates; they occur right after
* the mmc core sends its own acmd6 bus-width change notification,
@@ -457,8 +472,14 @@ static void litex_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
*/
/* Update sd_clk */
- if (ios->clock != host->sd_clk)
+ if (ios->clock != host->sd_clk) {
litex_mmc_setclk(host, ios->clock);
+ }
+
+ if (ios->chip_select == MMC_CS_HIGH) {
+ litex_write8(host->sdphy + LITEX_PHY_INITIALIZE, 1);
+ fsleep(SD_INIT_DELAY_US);
+ }
}
static const struct mmc_host_ops litex_mmc_ops = {
@@ -590,7 +611,7 @@ static int litex_mmc_probe(struct platform_device *pdev)
* Set default sd_clk frequency range based on empirical observations
* of LiteSDCard gateware behavior on typical SDCard media
*/
- mmc->f_min = 12.5e6;
+ mmc->f_min = SD_INIT_CLK_HZ;
mmc->f_max = 50e6;
ret = mmc_of_parse(mmc);
---