Am 20. Juli 2026 14:50:24 UTC schrieb Bin Meng <[email protected]>:

Hi Bin,

Thanks for yor reviews and R-b tags!

>On Mon, Jul 20, 2026 at 5:19 AM Bernhard Beschow <[email protected]> wrote:
>>
>> In Linux, the ESDHC_MIX_CTRL qirk is guarded by esdhc_is_usdhc() while
>> the eSDHC code path uses the standard SDHC interface. Extract the quirk
>> into a new `usdhc_write()` function.
>>
>> Fixes file system corruption on emulated i.MX53 where Linux'
>> esdhc_is_usdhc() returns false. The same likely happens on e500 and
>> imx25-pdk machines.
>>
>> Fixes: 75e98bc4f859 ("hw/sd/sdhci: Add TYPE_FSL_ESDHC_BE")
>> cc: qemu-stable
>> Signed-off-by: Bernhard Beschow <[email protected]>
>> ---
>>  hw/sd/sdhci.c | 73 +++++++++++++++++++++++++++++++--------------------
>>  1 file changed, 44 insertions(+), 29 deletions(-)
>>
>> diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
>> index c86dfa281f..e58a610397 100644
>> --- a/hw/sd/sdhci.c
>> +++ b/hw/sd/sdhci.c
>> @@ -1795,34 +1795,6 @@ esdhc_write(void *opaque, hwaddr offset, uint64_t 
>> val, unsigned size)
>>          sdhci_write(opaque, offset, value, size);
>>          break;
>>
>> -    case ESDHC_MIX_CTRL:
>> -        /*
>> -         * So, when SD/MMC stack in Linux tries to write to "Transfer
>> -         * Mode Register", ESDHC i.MX quirk code will translate it
>> -         * into a write to ESDHC_MIX_CTRL, so we do the opposite in
>> -         * order to get where we started
>> -         *
>> -         * Note that Auto CMD23 Enable bit is located in a wrong place
>> -         * on i.MX, but since it is not used by QEMU we do not care.
>> -         *
>> -         * We don't want to call sdhci_write(.., SDHC_TRNMOD, ...)
>> -         * here because it will result in a call to
>> -         * sdhci_send_command(s) which we don't want.
>> -         *
>> -         */
>> -        s->trnmod = value & UINT16_MAX;
>> -        break;
>> -    case SDHC_TRNMOD:
>
>Looks like this register is not eSDHC specific?

Not quite sure what you mean exactly. The SDHC_TRNMOD isn't eSDHC specific but 
as per the comment above trnmod partial handling is deferred here, i.e. needs 
to be intercepted.

>I looked at linux
>driver source codes and suspect we may need some more turning here
>other than uSDHC only.

Yeah, there is certainly a lot of room for improvement. I have some 
clock-related and SDMA buffer boundary patches in the pipeline which are 
necessary for satisfying U-Boot. But that's a story for another day.

Best regards,
Bernhard

>
>
>> -        /*
>> -         * Similar to above, but this time a write to "Command
>> -         * Register" will be translated into a 4-byte write to
>> -         * "Transfer Mode register" where lower 16-bit of value would
>> -         * be set to zero. So what we do is fill those bits with
>> -         * cached value from s->trnmod and let the SDHCI
>> -         * infrastructure handle the rest
>> -         */
>> -        sdhci_write(opaque, offset, val | s->trnmod, size);
>> -        break;
>>      case SDHC_BLKSIZE:
>>          /*
>>           * ESDHCI does not implement "Host SDMA Buffer Boundary", and
>> @@ -1891,9 +1863,52 @@ static void fsl_esdhc_le_init(Object *obj)
>>      qdev_prop_set_uint8(dev, "sd-spec-version", 2);
>>  }
>>
>> +static void
>> +usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
>> +{
>> +    SDHCIState *s = SYSBUS_SDHCI(opaque);
>> +    uint32_t value = (uint32_t)val;
>> +
>> +    switch (offset) {
>> +    case ESDHC_MIX_CTRL:
>> +        /*
>> +         * So, when SD/MMC stack in Linux tries to write to "Transfer
>> +         * Mode Register", uSDHC i.MX quirk code will translate it
>> +         * into a write to ESDHC_MIX_CTRL, so we do the opposite in
>> +         * order to get where we started.
>> +         *
>> +         * Note that Auto CMD23 Enable bit is located in a wrong place
>> +         * on i.MX, but since it is not used by QEMU we do not care.
>> +         *
>> +         * We don't want to call sdhci_write(.., SDHC_TRNMOD, ...)
>> +         * here because it will result in a call to
>> +         * sdhci_send_command(s) which we don't want.
>> +         *
>> +         */
>> +        s->trnmod = value & UINT16_MAX;
>> +        break;
>> +
>> +    case SDHC_TRNMOD:
>> +        /*
>> +         * Similar to above, but this time a write to "Command
>> +         * Register" will be translated into a 4-byte write to
>> +         * "Transfer Mode register" where lower 16-bit of value would
>> +         * be set to zero. So what we do is fill those bits with
>> +         * cached value from s->trnmod and let the SDHCI
>> +         * infrastructure handle the rest
>> +         */
>> +        sdhci_write(opaque, offset, val | s->trnmod, size);
>> +        break;
>> +
>> +    default:
>> +        esdhc_write(opaque, offset, val, size);
>> +        break;
>> +    }
>> +}
>> +
>>  static const MemoryRegionOps usdhc_mmio_ops = {
>>      .read = esdhc_read,
>> -    .write = esdhc_write,
>> +    .write = usdhc_write,
>>      .valid = {
>>          .min_access_size = 1,
>>          .max_access_size = 4,
>> --
>
>Regards,
>Bin

Reply via email to