From: qianfan Zhao <qianfanguijin@163.com>
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>
---
hw/arm/allwinner-r40.c | 2 +-
hw/sd/allwinner-sdhost.c | 70 ++++++++++++++++++++++++++++++--
include/hw/sd/allwinner-sdhost.h | 9 ++++
3 files changed, 77 insertions(+), 4 deletions(-)
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
index 0e4542d35f..b148c56449 100644
--- a/hw/arm/allwinner-r40.c
+++ b/hw/arm/allwinner-r40.c
@@ -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);
diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
index 92a0f42708..f4fa2d179b 100644
--- a/hw/sd/allwinner-sdhost.c
+++ b/hw/sd/allwinner-sdhost.c
@@ -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)
@@ -888,6 +920,24 @@ static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
sc->is_sun4i = 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 = {
.name = TYPE_AW_SDHOST,
.parent = TYPE_SYS_BUS_DEVICE,
@@ -910,6 +960,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 +984,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);
}
diff --git a/include/hw/sd/allwinner-sdhost.h b/include/hw/sd/allwinner-sdhost.h
index 30c1e60404..1b951177dd 100644
--- a/include/hw/sd/allwinner-sdhost.h
+++ b/include/hw/sd/allwinner-sdhost.h
@@ -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 */
--
2.25.1
On Wed, May 10, 2023 at 12:30 PM <qianfanguijin@163.com> wrote:
> From: qianfan Zhao <qianfanguijin@163.com>
>
> 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>
> ---
> hw/arm/allwinner-r40.c | 2 +-
> hw/sd/allwinner-sdhost.c | 70 ++++++++++++++++++++++++++++++--
> include/hw/sd/allwinner-sdhost.h | 9 ++++
> 3 files changed, 77 insertions(+), 4 deletions(-)
>
> diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
> index 0e4542d35f..b148c56449 100644
> --- a/hw/arm/allwinner-r40.c
> +++ b/hw/arm/allwinner-r40.c
> @@ -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);
> diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
> index 92a0f42708..f4fa2d179b 100644
> --- a/hw/sd/allwinner-sdhost.c
> +++ b/hw/sd/allwinner-sdhost.c
> @@ -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)
> @@ -888,6 +920,24 @@ static void
> allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
> sc->is_sun4i = 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;
>
For the existing functions allwinner_sdhost_sun4i_class_init() and
allwinner_sdhost_sun5i_class_init(), could you please add
'sc->can_calibrate = false'?
That way, we make it explicit that those types do not support the sample
delay register.
With that resolved, the code looks good to me:
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
> +}
> +
> +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 = {
> .name = TYPE_AW_SDHOST,
> .parent = TYPE_SYS_BUS_DEVICE,
> @@ -910,6 +960,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 +984,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);
> }
>
> diff --git a/include/hw/sd/allwinner-sdhost.h
> b/include/hw/sd/allwinner-sdhost.h
> index 30c1e60404..1b951177dd 100644
> --- a/include/hw/sd/allwinner-sdhost.h
> +++ b/include/hw/sd/allwinner-sdhost.h
> @@ -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 */
> --
> 2.25.1
>
>
--
Niek Linnenbank
在 2023/5/16 3:54, Niek Linnenbank 写道:
>
>
> On Wed, May 10, 2023 at 12:30 PM <qianfanguijin@163.com> wrote:
>
> From: qianfan Zhao <qianfanguijin@163.com>
>
> 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>
> ---
> hw/arm/allwinner-r40.c | 2 +-
> hw/sd/allwinner-sdhost.c | 70
> ++++++++++++++++++++++++++++++--
> include/hw/sd/allwinner-sdhost.h | 9 ++++
> 3 files changed, 77 insertions(+), 4 deletions(-)
>
> diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
> index 0e4542d35f..b148c56449 100644
> --- a/hw/arm/allwinner-r40.c
> +++ b/hw/arm/allwinner-r40.c
> @@ -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);
> diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
> index 92a0f42708..f4fa2d179b 100644
> --- a/hw/sd/allwinner-sdhost.c
> +++ b/hw/sd/allwinner-sdhost.c
> @@ -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)
> @@ -888,6 +920,24 @@ static void
> allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
> sc->is_sun4i = 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;
>
>
> For the existing functions allwinner_sdhost_sun4i_class_init() and
> allwinner_sdhost_sun5i_class_init(), could you please add
> 'sc->can_calibrate = false'?
> That way, we make it explicit that those types do not support the
> sample delay register.
Sure.
>
> With that resolved, the code looks good to me:
>
> Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
>
> +}
> +
> +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 = {
> .name = TYPE_AW_SDHOST,
> .parent = TYPE_SYS_BUS_DEVICE,
> @@ -910,6 +960,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 +984,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);
> }
>
> diff --git a/include/hw/sd/allwinner-sdhost.h
> b/include/hw/sd/allwinner-sdhost.h
> index 30c1e60404..1b951177dd 100644
> --- a/include/hw/sd/allwinner-sdhost.h
> +++ b/include/hw/sd/allwinner-sdhost.h
> @@ -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 */
> --
> 2.25.1
>
>
>
> --
> Niek Linnenbank
>
© 2016 - 2026 Red Hat, Inc.