|
@@ -77,6 +77,7 @@ enum {
|
|
REG_SD_DATA1_CRC = 0x12C, /* CRC Data 1 from card/eMMC */
|
|
REG_SD_DATA1_CRC = 0x12C, /* CRC Data 1 from card/eMMC */
|
|
REG_SD_DATA0_CRC = 0x130, /* CRC Data 0 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_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 */
|
|
REG_SD_FIFO = 0x200, /* Read/Write FIFO */
|
|
};
|
|
};
|
|
|
|
|
|
@@ -158,6 +159,7 @@ enum {
|
|
REG_SD_RES_CRC_RST = 0x0,
|
|
REG_SD_RES_CRC_RST = 0x0,
|
|
REG_SD_DATA_CRC_RST = 0x0,
|
|
REG_SD_DATA_CRC_RST = 0x0,
|
|
REG_SD_CRC_STA_RST = 0x0,
|
|
REG_SD_CRC_STA_RST = 0x0,
|
|
|
|
+ REG_SD_SAMPLE_DL_RST = 0x00002000,
|
|
REG_SD_FIFO_RST = 0x0,
|
|
REG_SD_FIFO_RST = 0x0,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -459,6 +461,7 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset,
|
|
{
|
|
{
|
|
AwSdHostState *s = AW_SDHOST(opaque);
|
|
AwSdHostState *s = AW_SDHOST(opaque);
|
|
AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
|
|
AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
|
|
|
|
+ bool out_of_bounds = false;
|
|
uint32_t res = 0;
|
|
uint32_t res = 0;
|
|
|
|
|
|
switch (offset) {
|
|
switch (offset) {
|
|
@@ -577,13 +580,24 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset,
|
|
case REG_SD_FIFO: /* Read/Write FIFO */
|
|
case REG_SD_FIFO: /* Read/Write FIFO */
|
|
res = allwinner_sdhost_fifo_read(s);
|
|
res = allwinner_sdhost_fifo_read(s);
|
|
break;
|
|
break;
|
|
|
|
+ case REG_SD_SAMP_DL: /* Sample Delay */
|
|
|
|
+ if (sc->can_calibrate) {
|
|
|
|
+ res = s->sample_delay;
|
|
|
|
+ } else {
|
|
|
|
+ out_of_bounds = true;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
- qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %"
|
|
|
|
- HWADDR_PRIx"\n", __func__, offset);
|
|
|
|
|
|
+ out_of_bounds = true;
|
|
res = 0;
|
|
res = 0;
|
|
break;
|
|
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);
|
|
trace_allwinner_sdhost_read(offset, res, size);
|
|
return res;
|
|
return res;
|
|
}
|
|
}
|
|
@@ -602,6 +616,7 @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset,
|
|
{
|
|
{
|
|
AwSdHostState *s = AW_SDHOST(opaque);
|
|
AwSdHostState *s = AW_SDHOST(opaque);
|
|
AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
|
|
AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
|
|
|
|
+ bool out_of_bounds = false;
|
|
|
|
|
|
trace_allwinner_sdhost_write(offset, value, size);
|
|
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_DATA0_CRC: /* CRC Data 0 from card/eMMC */
|
|
case REG_SD_CRC_STA: /* CRC status from card/eMMC in write operation */
|
|
case REG_SD_CRC_STA: /* CRC status from card/eMMC in write operation */
|
|
break;
|
|
break;
|
|
|
|
+ case REG_SD_SAMP_DL: /* Sample delay control */
|
|
|
|
+ if (sc->can_calibrate) {
|
|
|
|
+ s->sample_delay = value;
|
|
|
|
+ } else {
|
|
|
|
+ out_of_bounds = true;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
|
|
+ out_of_bounds = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (out_of_bounds) {
|
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %"
|
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %"
|
|
HWADDR_PRIx"\n", __func__, offset);
|
|
HWADDR_PRIx"\n", __func__, offset);
|
|
- break;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -777,6 +803,7 @@ static const VMStateDescription vmstate_allwinner_sdhost = {
|
|
VMSTATE_UINT32(response_crc, AwSdHostState),
|
|
VMSTATE_UINT32(response_crc, AwSdHostState),
|
|
VMSTATE_UINT32_ARRAY(data_crc, AwSdHostState, 8),
|
|
VMSTATE_UINT32_ARRAY(data_crc, AwSdHostState, 8),
|
|
VMSTATE_UINT32(status_crc, AwSdHostState),
|
|
VMSTATE_UINT32(status_crc, AwSdHostState),
|
|
|
|
+ VMSTATE_UINT32(sample_delay, AwSdHostState),
|
|
VMSTATE_END_OF_LIST()
|
|
VMSTATE_END_OF_LIST()
|
|
}
|
|
}
|
|
};
|
|
};
|
|
@@ -815,6 +842,7 @@ static void allwinner_sdhost_realize(DeviceState *dev, Error **errp)
|
|
static void allwinner_sdhost_reset(DeviceState *dev)
|
|
static void allwinner_sdhost_reset(DeviceState *dev)
|
|
{
|
|
{
|
|
AwSdHostState *s = AW_SDHOST(dev);
|
|
AwSdHostState *s = AW_SDHOST(dev);
|
|
|
|
+ AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
|
|
|
|
|
|
s->global_ctl = REG_SD_GCTL_RST;
|
|
s->global_ctl = REG_SD_GCTL_RST;
|
|
s->clock_ctl = REG_SD_CKCR_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;
|
|
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)
|
|
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);
|
|
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
|
|
sc->max_desc_size = 8 * KiB;
|
|
sc->max_desc_size = 8 * KiB;
|
|
sc->is_sun4i = true;
|
|
sc->is_sun4i = true;
|
|
|
|
+ sc->can_calibrate = false;
|
|
}
|
|
}
|
|
|
|
|
|
static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
|
|
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);
|
|
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
|
|
sc->max_desc_size = 64 * KiB;
|
|
sc->max_desc_size = 64 * KiB;
|
|
sc->is_sun4i = false;
|
|
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 = {
|
|
static const TypeInfo allwinner_sdhost_info = {
|
|
@@ -910,6 +962,18 @@ static const TypeInfo allwinner_sdhost_sun5i_info = {
|
|
.class_init = allwinner_sdhost_sun5i_class_init,
|
|
.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 = {
|
|
static const TypeInfo allwinner_sdhost_bus_info = {
|
|
.name = TYPE_AW_SDHOST_BUS,
|
|
.name = TYPE_AW_SDHOST_BUS,
|
|
.parent = TYPE_SD_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_info);
|
|
type_register_static(&allwinner_sdhost_sun4i_info);
|
|
type_register_static(&allwinner_sdhost_sun4i_info);
|
|
type_register_static(&allwinner_sdhost_sun5i_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);
|
|
type_register_static(&allwinner_sdhost_bus_info);
|
|
}
|
|
}
|
|
|
|
|