hw/sd/sdhci: Support big endian SD host controller interfaces
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é <philmd@linaro.org> Tested-by: Bernhard Beschow <shentey@gmail.com> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Message-Id: <20221101222934.52444-3-philmd@linaro.org> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
This commit is contained in:
parent
2e93a90f4f
commit
c0a55a0c9d
@ -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), \
|
||||
|
@ -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,
|
||||
.valid = {
|
||||
@ -1340,6 +1340,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();
|
||||
@ -1367,8 +1382,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)
|
||||
@ -1384,10 +1397,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);
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user