From: Bernhard Beschow <[email protected]> In Linux, the ESDHC_MIX_CTRL quirk 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. Cc: [email protected] Fixes: 75e98bc4f859 ("hw/sd/sdhci: Add TYPE_FSL_ESDHC_BE") Reviewed-by: Bin Meng <[email protected]> Signed-off-by: Bernhard Beschow <[email protected]> Message-ID: <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[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 c86dfa281f4..e58a6103970 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: - /* - * 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, -- 2.53.0
