Hi, On Tue, Nov 01, 2022 at 11:29:33PM +0100, Philippe Mathieu-Daudé wrote: > Some SDHCI IP can be synthetized in various endianness: > https://github.com/u-boot/u-boot/blob/v2021.04/doc/README.fsl-esdhc > > - CONFIG_SYS_FSL_ESDHC_BE > > ESDHC IP is in big-endian mode. Accessing ESDHC registers can be > determined by ESDHC IP's endian mode or processor's endian mode. > > Our current implementation is little-endian. In order to support > big endianness: > > - Rename current MemoryRegionOps as sdhci_mmio_le_ops ('le') > - Add an 'endianness' property to SDHCIState (default little endian) > - Set the 'io_ops' field in realize() after checking the property > - Add the sdhci_mmio_be_ops (big-endian) MemoryRegionOps. > > Signed-off-by: Philippe Mathieu-Daudé <phi...@linaro.org>
With this patch in place (in qemu v8.0), I can no longer boot linux from SD card with sabrelite, mcimx6ul-evk, and mcimx7d-sabre emulations. I get the following persistent errors. [ 12.210101] sdhci-esdhc-imx 2194000.mmc: esdhc_wait_for_card_clock_gate_off: card clock still not gate off in 100us!. [ 12.213222] sdhci-esdhc-imx 2194000.mmc: esdhc_wait_for_card_clock_gate_off: card clock still not gate off in 100us!. [ 12.215072] sdhci-esdhc-imx 2194000.mmc: esdhc_wait_for_card_clock_gate_off: card clock still not gate off in 100us!. [ 12.218766] sdhci-esdhc-imx 2190000.mmc: esdhc_wait_for_card_clock_gate_off: card clock still not gate off in 100us!. [ 12.220441] sdhci-esdhc-imx 2190000.mmc: esdhc_wait_for_card_clock_gate_off: card clock still not gate off in 100us!. [ 12.221542] sdhci-esdhc-imx 2190000.mmc: esdhc_wait_for_card_clock_gate_off: card clock still not gate off in 100us!. [ 12.241544] sdhci-esdhc-imx 2190000.mmc: esdhc_wait_for_card_clock_gate_off: card clock still not gate off in 100us!. [ 12.242608] sdhci-esdhc-imx 2190000.mmc: card clock still not stable in 100us!. The emulations start to work again after reverting this patch. Guenter > --- > hw/sd/sdhci-internal.h | 1 + > hw/sd/sdhci.c | 32 +++++++++++++++++++++++++++++--- > include/hw/sd/sdhci.h | 1 + > 3 files changed, 31 insertions(+), 3 deletions(-) > > diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h > index 964570f8e8..5f3765f12d 100644 > --- a/hw/sd/sdhci-internal.h > +++ b/hw/sd/sdhci-internal.h > @@ -308,6 +308,7 @@ extern const VMStateDescription sdhci_vmstate; > #define SDHC_CAPAB_REG_DEFAULT 0x057834b4 > > #define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \ > + DEFINE_PROP_UINT8("endianness", _state, endianness, > DEVICE_LITTLE_ENDIAN), \ > DEFINE_PROP_UINT8("sd-spec-version", _state, sd_spec_version, 2), \ > DEFINE_PROP_UINT8("uhs", _state, uhs_mode, UHS_NOT_SUPPORTED), \ > DEFINE_PROP_UINT8("vendor", _state, vendor, SDHCI_VENDOR_NONE), \ > diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c > index 22c758ad91..289baa879e 100644 > --- a/hw/sd/sdhci.c > +++ b/hw/sd/sdhci.c > @@ -1329,7 +1329,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, > unsigned size) > value >> shift, value >> shift); > } > > -static const MemoryRegionOps sdhci_mmio_ops = { > +static const MemoryRegionOps sdhci_mmio_le_ops = { > .read = sdhci_read, > .write = sdhci_write, > .impl = { > @@ -1344,6 +1344,21 @@ static const MemoryRegionOps sdhci_mmio_ops = { > .endianness = DEVICE_LITTLE_ENDIAN, > }; > > +static const MemoryRegionOps sdhci_mmio_be_ops = { > + .read = sdhci_read, > + .write = sdhci_write, > + .impl = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > + .valid = { > + .min_access_size = 1, > + .max_access_size = 4, > + .unaligned = false > + }, > + .endianness = DEVICE_BIG_ENDIAN, > +}; > + > static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp) > { > ERRP_GUARD(); > @@ -1371,8 +1386,6 @@ void sdhci_initfn(SDHCIState *s) > > s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, > sdhci_raise_insertion_irq, s); > s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, > sdhci_data_transfer, s); > - > - s->io_ops = &sdhci_mmio_ops; > } > > void sdhci_uninitfn(SDHCIState *s) > @@ -1388,10 +1401,23 @@ void sdhci_common_realize(SDHCIState *s, Error **errp) > { > ERRP_GUARD(); > > + switch (s->endianness) { > + case DEVICE_LITTLE_ENDIAN: > + s->io_ops = &sdhci_mmio_le_ops; > + break; > + case DEVICE_BIG_ENDIAN: > + s->io_ops = &sdhci_mmio_be_ops; > + break; > + default: > + error_setg(errp, "Incorrect endianness"); > + return; > + } > + > sdhci_init_readonly_registers(s, errp); > if (*errp) { > return; > } > + > s->buf_maxsz = sdhci_get_fifolen(s); > s->fifo_buffer = g_malloc0(s->buf_maxsz); > > diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h > index 01a64c5442..a989fca3b2 100644 > --- a/include/hw/sd/sdhci.h > +++ b/include/hw/sd/sdhci.h > @@ -96,6 +96,7 @@ struct SDHCIState { > /* Configurable properties */ > bool pending_insert_quirk; /* Quirk for Raspberry Pi card insert int */ > uint32_t quirks; > + uint8_t endianness; > uint8_t sd_spec_version; > uint8_t uhs_mode; > uint8_t vendor; /* For vendor specific functionality */