hw: sd: allwinner-sdhost: Add sun50i-a64 SoC support

A64's sd register was similar to H3, and it introduced a new register
named SAMP_DL_REG location at 0x144. The dma descriptor buffer size of
mmc2 is only 8K and the other mmc controllers has 64K.

Also fix allwinner-r40's mmc controller type.

Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
qianfan Zhao 2023-06-06 10:19:33 +01:00 committed by Peter Maydell
parent 4a52ef61d9
commit 2c992b88cc
3 changed files with 79 additions and 4 deletions

View file

@ -77,6 +77,7 @@ enum {
REG_SD_DATA1_CRC = 0x12C, /* CRC Data 1 from card/eMMC */
REG_SD_DATA0_CRC = 0x130, /* CRC Data 0 from card/eMMC */
REG_SD_CRC_STA = 0x134, /* CRC status from card/eMMC during write */
REG_SD_SAMP_DL = 0x144, /* Sample Delay Control (sun50i-a64) */
REG_SD_FIFO = 0x200, /* Read/Write FIFO */
};
@ -158,6 +159,7 @@ enum {
REG_SD_RES_CRC_RST = 0x0,
REG_SD_DATA_CRC_RST = 0x0,
REG_SD_CRC_STA_RST = 0x0,
REG_SD_SAMPLE_DL_RST = 0x00002000,
REG_SD_FIFO_RST = 0x0,
};
@ -459,6 +461,7 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset,
{
AwSdHostState *s = AW_SDHOST(opaque);
AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
bool out_of_bounds = false;
uint32_t res = 0;
switch (offset) {
@ -577,13 +580,24 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset,
case REG_SD_FIFO: /* Read/Write FIFO */
res = allwinner_sdhost_fifo_read(s);
break;
case REG_SD_SAMP_DL: /* Sample Delay */
if (sc->can_calibrate) {
res = s->sample_delay;
} else {
out_of_bounds = true;
}
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %"
HWADDR_PRIx"\n", __func__, offset);
out_of_bounds = true;
res = 0;
break;
}
if (out_of_bounds) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %"
HWADDR_PRIx"\n", __func__, offset);
}
trace_allwinner_sdhost_read(offset, res, size);
return res;
}
@ -602,6 +616,7 @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset,
{
AwSdHostState *s = AW_SDHOST(opaque);
AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
bool out_of_bounds = false;
trace_allwinner_sdhost_write(offset, value, size);
@ -725,10 +740,21 @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset,
case REG_SD_DATA0_CRC: /* CRC Data 0 from card/eMMC */
case REG_SD_CRC_STA: /* CRC status from card/eMMC in write operation */
break;
case REG_SD_SAMP_DL: /* Sample delay control */
if (sc->can_calibrate) {
s->sample_delay = value;
} else {
out_of_bounds = true;
}
break;
default:
out_of_bounds = true;
break;
}
if (out_of_bounds) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %"
HWADDR_PRIx"\n", __func__, offset);
break;
}
}
@ -777,6 +803,7 @@ static const VMStateDescription vmstate_allwinner_sdhost = {
VMSTATE_UINT32(response_crc, AwSdHostState),
VMSTATE_UINT32_ARRAY(data_crc, AwSdHostState, 8),
VMSTATE_UINT32(status_crc, AwSdHostState),
VMSTATE_UINT32(sample_delay, AwSdHostState),
VMSTATE_END_OF_LIST()
}
};
@ -815,6 +842,7 @@ static void allwinner_sdhost_realize(DeviceState *dev, Error **errp)
static void allwinner_sdhost_reset(DeviceState *dev)
{
AwSdHostState *s = AW_SDHOST(dev);
AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
s->global_ctl = REG_SD_GCTL_RST;
s->clock_ctl = REG_SD_CKCR_RST;
@ -855,6 +883,10 @@ static void allwinner_sdhost_reset(DeviceState *dev)
}
s->status_crc = REG_SD_CRC_STA_RST;
if (sc->can_calibrate) {
s->sample_delay = REG_SD_SAMPLE_DL_RST;
}
}
static void allwinner_sdhost_bus_class_init(ObjectClass *klass, void *data)
@ -879,6 +911,7 @@ static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data)
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 8 * KiB;
sc->is_sun4i = true;
sc->can_calibrate = false;
}
static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
@ -886,6 +919,25 @@ static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 64 * KiB;
sc->is_sun4i = false;
sc->can_calibrate = false;
}
static void allwinner_sdhost_sun50i_a64_class_init(ObjectClass *klass,
void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 64 * KiB;
sc->is_sun4i = false;
sc->can_calibrate = true;
}
static void allwinner_sdhost_sun50i_a64_emmc_class_init(ObjectClass *klass,
void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 8 * KiB;
sc->is_sun4i = false;
sc->can_calibrate = true;
}
static const TypeInfo allwinner_sdhost_info = {
@ -910,6 +962,18 @@ static const TypeInfo allwinner_sdhost_sun5i_info = {
.class_init = allwinner_sdhost_sun5i_class_init,
};
static const TypeInfo allwinner_sdhost_sun50i_a64_info = {
.name = TYPE_AW_SDHOST_SUN50I_A64,
.parent = TYPE_AW_SDHOST,
.class_init = allwinner_sdhost_sun50i_a64_class_init,
};
static const TypeInfo allwinner_sdhost_sun50i_a64_emmc_info = {
.name = TYPE_AW_SDHOST_SUN50I_A64_EMMC,
.parent = TYPE_AW_SDHOST,
.class_init = allwinner_sdhost_sun50i_a64_emmc_class_init,
};
static const TypeInfo allwinner_sdhost_bus_info = {
.name = TYPE_AW_SDHOST_BUS,
.parent = TYPE_SD_BUS,
@ -922,6 +986,8 @@ static void allwinner_sdhost_register_types(void)
type_register_static(&allwinner_sdhost_info);
type_register_static(&allwinner_sdhost_sun4i_info);
type_register_static(&allwinner_sdhost_sun5i_info);
type_register_static(&allwinner_sdhost_sun50i_a64_info);
type_register_static(&allwinner_sdhost_sun50i_a64_emmc_info);
type_register_static(&allwinner_sdhost_bus_info);
}