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:
parent
4a52ef61d9
commit
2c992b88cc
@ -271,7 +271,7 @@ static void allwinner_r40_init(Object *obj)
|
||||
|
||||
for (int i = 0; i < AW_R40_NUM_MMCS; i++) {
|
||||
object_initialize_child(obj, mmc_names[i], &s->mmc[i],
|
||||
TYPE_AW_SDHOST_SUN5I);
|
||||
TYPE_AW_SDHOST_SUN50I_A64);
|
||||
}
|
||||
|
||||
object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C_SUN6I);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,12 @@
|
||||
/** Allwinner sun5i family and newer (A13, H2+, H3, etc) */
|
||||
#define TYPE_AW_SDHOST_SUN5I TYPE_AW_SDHOST "-sun5i"
|
||||
|
||||
/** Allwinner sun50i-a64 */
|
||||
#define TYPE_AW_SDHOST_SUN50I_A64 TYPE_AW_SDHOST "-sun50i-a64"
|
||||
|
||||
/** Allwinner sun50i-a64 emmc */
|
||||
#define TYPE_AW_SDHOST_SUN50I_A64_EMMC TYPE_AW_SDHOST "-sun50i-a64-emmc"
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@ -110,6 +116,7 @@ struct AwSdHostState {
|
||||
uint32_t startbit_detect; /**< eMMC DDR Start Bit Detection Control */
|
||||
uint32_t response_crc; /**< Response CRC */
|
||||
uint32_t data_crc[8]; /**< Data CRC */
|
||||
uint32_t sample_delay; /**< Sample delay control */
|
||||
uint32_t status_crc; /**< Status CRC */
|
||||
|
||||
/** @} */
|
||||
@ -132,6 +139,8 @@ struct AwSdHostClass {
|
||||
size_t max_desc_size;
|
||||
bool is_sun4i;
|
||||
|
||||
/** does the IP block support autocalibration? */
|
||||
bool can_calibrate;
|
||||
};
|
||||
|
||||
#endif /* HW_SD_ALLWINNER_SDHOST_H */
|
||||
|
Loading…
Reference in New Issue
Block a user