[PATCH v4 3/3] docs/system/arm: Add a doc for zynq board
Added the supported device list and an example command. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Reviewed-by: Francisco Iglesias --- MAINTAINERS | 1 + docs/system/arm/xlnx-zynq.rst | 47 +++ docs/system/target-arm.rst| 1 + 3 files changed, 49 insertions(+) create mode 100644 docs/system/arm/xlnx-zynq.rst diff --git a/MAINTAINERS b/MAINTAINERS index 951556224a1..2f06febc676 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1033,6 +1033,7 @@ F: hw/adc/zynq-xadc.c F: include/hw/misc/zynq_slcr.h F: include/hw/adc/zynq-xadc.h X: hw/ssi/xilinx_* +F: docs/system/arm/xlnx-zynq.rst Xilinx ZynqMP and Versal M: Alistair Francis diff --git a/docs/system/arm/xlnx-zynq.rst b/docs/system/arm/xlnx-zynq.rst new file mode 100644 index 000..ade18a3fe13 --- /dev/null +++ b/docs/system/arm/xlnx-zynq.rst @@ -0,0 +1,47 @@ +Xilinx Zynq board (``xilinx-zynq-a9``) +== +The Zynq 7000 family is based on the AMD SoC architecture. These products +integrate a feature-rich dual or single-core Arm Cortex-A9 MPCore based +processing system (PS) and AMD programmable logic (PL) in a single device. + +More details here: +https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM/Zynq-7000-SoC-Technical-Reference-Manual + +QEMU xilinx-zynq-a9 board supports following devices: +- A9 MPCORE +- cortex-a9 +- GIC v1 +- Generic timer +- wdt +- OCM 256KB +- SMC SRAM@0xe200 64MB +- Zynq SLCR +- SPI x2 +- QSPI +- UART +- TTC x2 +- Gigabit Ethernet Controller x2 +- SD Controller x2 +- XADC +- Arm PrimeCell DMA Controller +- DDR Memory +- USB 2.0 x2 + +Running +""""""" +Direct Linux boot of a generic ARM upstream Linux kernel: + +.. code-block:: bash + + $ qemu-system-aarch64 -M xilinx-zynq-a9 \ +-dtb zynq-zc702.dtb -serial null -serial mon:stdio \ +-display none -m 1024 \ +-initrd rootfs.cpio.gz -kernel zImage + +For configuring the boot-mode provide the following on the command line: + +.. code-block:: bash + + -machine boot-mode=qspi + +Supported values are jtag, sd, qspi, nor. diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 870d30e3502..7b992722846 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -109,6 +109,7 @@ undocumented; you can get a complete list by running arm/virt arm/xenpvh arm/xlnx-versal-virt + arm/xlnx-zynq Emulated CPU architecture support = -- 2.34.1
[PATCH v4 1/3] hw/misc/zynq_slcr: Add boot-mode property
boot-mode property sets user values into BOOT_MODE register, on hardware these are derived from board switches. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Reviewed-by: Francisco Iglesias --- hw/misc/zynq_slcr.c | 22 +- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index 3412ff099ea..ad814c3a79b 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -24,6 +24,8 @@ #include "hw/registerfields.h" #include "hw/qdev-clock.h" #include "qom/object.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" #ifndef ZYNQ_SLCR_ERR_DEBUG #define ZYNQ_SLCR_ERR_DEBUG 0 @@ -121,6 +123,7 @@ REG32(RST_REASON, 0x250) REG32(REBOOT_STATUS, 0x258) REG32(BOOT_MODE, 0x25c) +FIELD(BOOT_MODE, BOOT_MODE, 0, 4) REG32(APU_CTRL, 0x300) REG32(WDT_CLK_SEL, 0x304) @@ -195,6 +198,7 @@ struct ZynqSLCRState { Clock *ps_clk; Clock *uart0_ref_clk; Clock *uart1_ref_clk; +uint8_t boot_mode; }; /* @@ -371,7 +375,7 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type) s->regs[R_FPGA_RST_CTRL] = 0x01F33F0F; s->regs[R_RST_REASON] = 0x0040; -s->regs[R_BOOT_MODE] = 0x0001; +s->regs[R_BOOT_MODE] = s->boot_mode & R_BOOT_MODE_BOOT_MODE_MASK; /* 0x700 - 0x7D4 */ for (i = 0; i < 54; i++) { @@ -588,6 +592,15 @@ static const ClockPortInitArray zynq_slcr_clocks = { QDEV_CLOCK_END }; +static void zynq_slcr_realize(DeviceState *dev, Error **errp) +{ +ZynqSLCRState *s = ZYNQ_SLCR(dev); + +if (s->boot_mode > 0xF) { +error_setg(errp, "Invalid boot mode %d specified", s->boot_mode); +} +} + static void zynq_slcr_init(Object *obj) { ZynqSLCRState *s = ZYNQ_SLCR(obj); @@ -610,15 +623,22 @@ static const VMStateDescription vmstate_zynq_slcr = { } }; +static Property zynq_slcr_props[] = { +DEFINE_PROP_UINT8("boot-mode", ZynqSLCRState, boot_mode, 1), +DEFINE_PROP_END_OF_LIST(), +}; + static void zynq_slcr_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); dc->vmsd = _zynq_slcr; +dc->realize = zynq_slcr_realize; rc->phases.enter = zynq_slcr_reset_init; rc->phases.hold = zynq_slcr_reset_hold; rc->phases.exit = zynq_slcr_reset_exit; +device_class_set_props(dc, zynq_slcr_props); } static const TypeInfo zynq_slcr_info = { -- 2.34.1
[PATCH v4 2/3] hw/arm/xilinx_zynq: Add boot-mode property
Read boot-mode value as machine property and propagate that to SLCR.BOOT_MODE register. Signed-off-by: Sai Pavan Boddu Acked-by: Edgar E. Iglesias Reviewed-by: Francisco Iglesias --- hw/arm/xilinx_zynq.c | 31 +++ 1 file changed, 31 insertions(+) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 7f7a3d23fbe..97b6fd8e35d 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -38,6 +38,7 @@ #include "qom/object.h" #include "exec/tswap.h" #include "target/arm/cpu-qom.h" +#include "qapi/visitor.h" #define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9") OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE) @@ -90,6 +91,7 @@ struct ZynqMachineState { MachineState parent; Clock *ps_clk; ARMCPU *cpu[ZYNQ_MAX_CPUS]; +uint8_t boot_mode; }; static void zynq_write_board_setup(ARMCPU *cpu, @@ -176,6 +178,27 @@ static inline int zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, return unit; } +static void zynq_set_boot_mode(Object *obj, const char *str, + Error **errp) +{ +ZynqMachineState *m = ZYNQ_MACHINE(obj); +uint8_t mode = 0; + +if (!strncasecmp(str, "qspi", 4)) { +mode = 1; +} else if (!strncasecmp(str, "sd", 2)) { +mode = 5; +} else if (!strncasecmp(str, "nor", 3)) { +mode = 2; +} else if (!strncasecmp(str, "jtag", 4)) { +mode = 0; +} else { +error_setg(errp, "%s boot mode not supported", str); +return; +} +m->boot_mode = mode; +} + static void zynq_init(MachineState *machine) { ZynqMachineState *zynq_machine = ZYNQ_MACHINE(machine); @@ -241,6 +264,7 @@ static void zynq_init(MachineState *machine) /* Create slcr, keep a pointer to connect clocks */ slcr = qdev_new("xilinx-zynq_slcr"); qdev_connect_clock_in(slcr, "ps_clk", zynq_machine->ps_clk); +qdev_prop_set_uint8(slcr, "boot-mode", zynq_machine->boot_mode); sysbus_realize_and_unref(SYS_BUS_DEVICE(slcr), _fatal); sysbus_mmio_map(SYS_BUS_DEVICE(slcr), 0, 0xF800); @@ -372,6 +396,7 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data) NULL }; MachineClass *mc = MACHINE_CLASS(oc); +ObjectProperty *prop; mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; mc->init = zynq_init; mc->max_cpus = ZYNQ_MAX_CPUS; @@ -379,6 +404,12 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data) mc->ignore_memory_transaction_failures = true; mc->valid_cpu_types = valid_cpu_types; mc->default_ram_id = "zynq.ext_ram"; +prop = object_class_property_add_str(oc, "boot-mode", NULL, + zynq_set_boot_mode); +object_class_property_set_description(oc, "boot-mode", + "Supported boot modes:" + " jtag qspi sd nor"); +object_property_set_default_str(prop, "qspi"); } static const TypeInfo zynq_machine_type = { -- 2.34.1
[PATCH v4 0/3] Add boot-mode property for zynq
Add a way to update the boot-mode via machine properties. Changes for V2: Make boot-mode property work with string, Fixed few code style issues, Added zynq board doc. Changes for V3: Mentioned about zynq doc in MAINTAINERS file, Stick to small case for mentioning boot modes in doc, fixed commit message to mention right property name. Changes for V4: Use strncasecmp, Fix boot mode names to use small case in few other places, Fix code indentation. Sai Pavan Boddu (3): hw/misc/zynq_slcr: Add boot-mode property hw/arm/xilinx_zynq: Add boot-mode property docs/system/arm: Add a doc for zynq board MAINTAINERS | 1 + docs/system/arm/xlnx-zynq.rst | 47 +++ docs/system/target-arm.rst| 1 + hw/arm/xilinx_zynq.c | 31 +++ hw/misc/zynq_slcr.c | 22 +++- 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 docs/system/arm/xlnx-zynq.rst -- 2.34.1
[PATCH v3 1/3] hw/misc/zynq_slcr: Add boot-mode property
boot-mode property sets user values into BOOT_MODE register, on hardware these are derived from board switches. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias --- hw/misc/zynq_slcr.c | 22 +- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index 3412ff099ea..ad814c3a79b 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -24,6 +24,8 @@ #include "hw/registerfields.h" #include "hw/qdev-clock.h" #include "qom/object.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" #ifndef ZYNQ_SLCR_ERR_DEBUG #define ZYNQ_SLCR_ERR_DEBUG 0 @@ -121,6 +123,7 @@ REG32(RST_REASON, 0x250) REG32(REBOOT_STATUS, 0x258) REG32(BOOT_MODE, 0x25c) +FIELD(BOOT_MODE, BOOT_MODE, 0, 4) REG32(APU_CTRL, 0x300) REG32(WDT_CLK_SEL, 0x304) @@ -195,6 +198,7 @@ struct ZynqSLCRState { Clock *ps_clk; Clock *uart0_ref_clk; Clock *uart1_ref_clk; +uint8_t boot_mode; }; /* @@ -371,7 +375,7 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type) s->regs[R_FPGA_RST_CTRL] = 0x01F33F0F; s->regs[R_RST_REASON] = 0x0040; -s->regs[R_BOOT_MODE] = 0x0001; +s->regs[R_BOOT_MODE] = s->boot_mode & R_BOOT_MODE_BOOT_MODE_MASK; /* 0x700 - 0x7D4 */ for (i = 0; i < 54; i++) { @@ -588,6 +592,15 @@ static const ClockPortInitArray zynq_slcr_clocks = { QDEV_CLOCK_END }; +static void zynq_slcr_realize(DeviceState *dev, Error **errp) +{ +ZynqSLCRState *s = ZYNQ_SLCR(dev); + +if (s->boot_mode > 0xF) { +error_setg(errp, "Invalid boot mode %d specified", s->boot_mode); +} +} + static void zynq_slcr_init(Object *obj) { ZynqSLCRState *s = ZYNQ_SLCR(obj); @@ -610,15 +623,22 @@ static const VMStateDescription vmstate_zynq_slcr = { } }; +static Property zynq_slcr_props[] = { +DEFINE_PROP_UINT8("boot-mode", ZynqSLCRState, boot_mode, 1), +DEFINE_PROP_END_OF_LIST(), +}; + static void zynq_slcr_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); dc->vmsd = _zynq_slcr; +dc->realize = zynq_slcr_realize; rc->phases.enter = zynq_slcr_reset_init; rc->phases.hold = zynq_slcr_reset_hold; rc->phases.exit = zynq_slcr_reset_exit; +device_class_set_props(dc, zynq_slcr_props); } static const TypeInfo zynq_slcr_info = { -- 2.34.1
[PATCH v3 3/3] docs/system/arm: Add a doc for zynq board
Added the supported device list and an example command. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias --- MAINTAINERS | 1 + docs/system/arm/xlnx-zynq.rst | 47 +++ docs/system/target-arm.rst| 1 + 3 files changed, 49 insertions(+) create mode 100644 docs/system/arm/xlnx-zynq.rst diff --git a/MAINTAINERS b/MAINTAINERS index 951556224a1..2f06febc676 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1033,6 +1033,7 @@ F: hw/adc/zynq-xadc.c F: include/hw/misc/zynq_slcr.h F: include/hw/adc/zynq-xadc.h X: hw/ssi/xilinx_* +F: docs/system/arm/xlnx-zynq.rst Xilinx ZynqMP and Versal M: Alistair Francis diff --git a/docs/system/arm/xlnx-zynq.rst b/docs/system/arm/xlnx-zynq.rst new file mode 100644 index 000..ade18a3fe13 --- /dev/null +++ b/docs/system/arm/xlnx-zynq.rst @@ -0,0 +1,47 @@ +Xilinx Zynq board (``xilinx-zynq-a9``) +== +The Zynq 7000 family is based on the AMD SoC architecture. These products +integrate a feature-rich dual or single-core Arm Cortex-A9 MPCore based +processing system (PS) and AMD programmable logic (PL) in a single device. + +More details here: +https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM/Zynq-7000-SoC-Technical-Reference-Manual + +QEMU xilinx-zynq-a9 board supports following devices: +- A9 MPCORE +- cortex-a9 +- GIC v1 +- Generic timer +- wdt +- OCM 256KB +- SMC SRAM@0xe200 64MB +- Zynq SLCR +- SPI x2 +- QSPI +- UART +- TTC x2 +- Gigabit Ethernet Controller x2 +- SD Controller x2 +- XADC +- Arm PrimeCell DMA Controller +- DDR Memory +- USB 2.0 x2 + +Running +""""""" +Direct Linux boot of a generic ARM upstream Linux kernel: + +.. code-block:: bash + + $ qemu-system-aarch64 -M xilinx-zynq-a9 \ +-dtb zynq-zc702.dtb -serial null -serial mon:stdio \ +-display none -m 1024 \ +-initrd rootfs.cpio.gz -kernel zImage + +For configuring the boot-mode provide the following on the command line: + +.. code-block:: bash + + -machine boot-mode=qspi + +Supported values are jtag, sd, qspi, nor. diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 870d30e3502..7b992722846 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -109,6 +109,7 @@ undocumented; you can get a complete list by running arm/virt arm/xenpvh arm/xlnx-versal-virt + arm/xlnx-zynq Emulated CPU architecture support = -- 2.34.1
[PATCH v3 2/3] hw/arm/xilinx_zynq: Add boot-mode property
Read boot-mode value as machine property and propagate that to SLCR.BOOT_MODE register. Signed-off-by: Sai Pavan Boddu Acked-by: Edgar E. Iglesias --- hw/arm/xilinx_zynq.c | 31 +++ 1 file changed, 31 insertions(+) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 7f7a3d23fbe..39f07e6dfd8 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -38,6 +38,7 @@ #include "qom/object.h" #include "exec/tswap.h" #include "target/arm/cpu-qom.h" +#include "qapi/visitor.h" #define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9") OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE) @@ -90,6 +91,7 @@ struct ZynqMachineState { MachineState parent; Clock *ps_clk; ARMCPU *cpu[ZYNQ_MAX_CPUS]; +uint8_t boot_mode; }; static void zynq_write_board_setup(ARMCPU *cpu, @@ -176,6 +178,27 @@ static inline int zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, return unit; } +static void zynq_set_boot_mode(Object *obj, const char *str, + Error **errp) +{ +ZynqMachineState *m = ZYNQ_MACHINE(obj); +uint8_t mode = 0; + +if (!strcasecmp(str, "QSPI")) { +mode = 1; +} else if (!strcasecmp(str, "SD")) { +mode = 5; +} else if (!strcasecmp(str, "NOR")) { +mode = 2; +} else if (!strcasecmp(str, "JTAG")) { +mode = 0; +} else { +error_setg(errp, "bootmode %s not supported", str); +return; +} +m->boot_mode = mode; +} + static void zynq_init(MachineState *machine) { ZynqMachineState *zynq_machine = ZYNQ_MACHINE(machine); @@ -241,6 +264,7 @@ static void zynq_init(MachineState *machine) /* Create slcr, keep a pointer to connect clocks */ slcr = qdev_new("xilinx-zynq_slcr"); qdev_connect_clock_in(slcr, "ps_clk", zynq_machine->ps_clk); +qdev_prop_set_uint8(slcr, "boot-mode", zynq_machine->boot_mode); sysbus_realize_and_unref(SYS_BUS_DEVICE(slcr), _fatal); sysbus_mmio_map(SYS_BUS_DEVICE(slcr), 0, 0xF800); @@ -372,6 +396,7 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data) NULL }; MachineClass *mc = MACHINE_CLASS(oc); +ObjectProperty *prop; mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; mc->init = zynq_init; mc->max_cpus = ZYNQ_MAX_CPUS; @@ -379,6 +404,12 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data) mc->ignore_memory_transaction_failures = true; mc->valid_cpu_types = valid_cpu_types; mc->default_ram_id = "zynq.ext_ram"; +prop = object_class_property_add_str(oc, "boot-mode", NULL, + zynq_set_boot_mode); +object_class_property_set_description(oc, "boot-mode", + "Supported boot modes:" + " JTAG QSPI SD NOR"); +object_property_set_default_str(prop, "QSPI"); } static const TypeInfo zynq_machine_type = { -- 2.34.1
[PATCH v3 0/3] Add boot-mode property for zynq
Add a way to update the boot-mode via machine properties. Changes for V2: Make boot-mode property work with string Fixed few code style issues Added zynq board doc. Changes for V3: Mentioned about zynq doc in MAINTAINERS file Stick to small case for mentioning boot modes in doc fixed commit message to mention right property name. Sai Pavan Boddu (3): hw/misc/zynq_slcr: Add boot-mode property hw/arm/xilinx_zynq: Add boot-mode property docs/system/arm: Add a doc for zynq board MAINTAINERS | 1 + docs/system/arm/xlnx-zynq.rst | 47 +++ docs/system/target-arm.rst| 1 + hw/arm/xilinx_zynq.c | 31 +++ hw/misc/zynq_slcr.c | 22 +++- 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 docs/system/arm/xlnx-zynq.rst -- 2.34.1
[PATCH v2 0/3] Add boot-mode property for zynq
Add a way to update the boot-mode via machine properties. Changes for V2: Make boot-mode property work with string Fixed few code style issues Added zynq board doc. Sai Pavan Boddu (3): hw/misc/zynq_slcr: Add BootMode property hw/arm/xilinx_zynq: Add boot-mode property docs/system/arm: Add a doc for zynq board docs/system/arm/xlnx-zynq.rst | 47 +++ docs/system/target-arm.rst| 1 + hw/arm/xilinx_zynq.c | 31 +++ hw/misc/zynq_slcr.c | 22 +++- 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 docs/system/arm/xlnx-zynq.rst -- 2.34.1
[PATCH v2 2/3] hw/arm/xilinx_zynq: Add boot-mode property
Read boot-mode value as machine property and propagate that to SLCR.BOOT_MODE register. Signed-off-by: Sai Pavan Boddu --- hw/arm/xilinx_zynq.c | 31 +++ 1 file changed, 31 insertions(+) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 7f7a3d23fbe..39f07e6dfd8 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -38,6 +38,7 @@ #include "qom/object.h" #include "exec/tswap.h" #include "target/arm/cpu-qom.h" +#include "qapi/visitor.h" #define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9") OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE) @@ -90,6 +91,7 @@ struct ZynqMachineState { MachineState parent; Clock *ps_clk; ARMCPU *cpu[ZYNQ_MAX_CPUS]; +uint8_t boot_mode; }; static void zynq_write_board_setup(ARMCPU *cpu, @@ -176,6 +178,27 @@ static inline int zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, return unit; } +static void zynq_set_boot_mode(Object *obj, const char *str, + Error **errp) +{ +ZynqMachineState *m = ZYNQ_MACHINE(obj); +uint8_t mode = 0; + +if (!strcasecmp(str, "QSPI")) { +mode = 1; +} else if (!strcasecmp(str, "SD")) { +mode = 5; +} else if (!strcasecmp(str, "NOR")) { +mode = 2; +} else if (!strcasecmp(str, "JTAG")) { +mode = 0; +} else { +error_setg(errp, "%s bootmode is not supported", str); +return; +} +m->boot_mode = mode; +} + static void zynq_init(MachineState *machine) { ZynqMachineState *zynq_machine = ZYNQ_MACHINE(machine); @@ -241,6 +264,7 @@ static void zynq_init(MachineState *machine) /* Create slcr, keep a pointer to connect clocks */ slcr = qdev_new("xilinx-zynq_slcr"); qdev_connect_clock_in(slcr, "ps_clk", zynq_machine->ps_clk); +qdev_prop_set_uint8(slcr, "boot-mode", zynq_machine->boot_mode); sysbus_realize_and_unref(SYS_BUS_DEVICE(slcr), _fatal); sysbus_mmio_map(SYS_BUS_DEVICE(slcr), 0, 0xF800); @@ -372,6 +396,7 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data) NULL }; MachineClass *mc = MACHINE_CLASS(oc); +ObjectProperty *prop; mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; mc->init = zynq_init; mc->max_cpus = ZYNQ_MAX_CPUS; @@ -379,6 +404,12 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data) mc->ignore_memory_transaction_failures = true; mc->valid_cpu_types = valid_cpu_types; mc->default_ram_id = "zynq.ext_ram"; +prop = object_class_property_add_str(oc, "boot-mode", NULL, + zynq_set_boot_mode); +object_class_property_set_description(oc, "boot-mode", + "Supported boot modes:" + " JTAG QSPI SD NOR"); +object_property_set_default_str(prop, "QSPI"); } static const TypeInfo zynq_machine_type = { -- 2.34.1
[PATCH v2 3/3] docs/system/arm: Add a doc for zynq board
Added the supported device list and an example command. Signed-off-by: Sai Pavan Boddu --- docs/system/arm/xlnx-zynq.rst | 47 +++ docs/system/target-arm.rst| 1 + 2 files changed, 48 insertions(+) create mode 100644 docs/system/arm/xlnx-zynq.rst diff --git a/docs/system/arm/xlnx-zynq.rst b/docs/system/arm/xlnx-zynq.rst new file mode 100644 index 000..419cc1aec8b --- /dev/null +++ b/docs/system/arm/xlnx-zynq.rst @@ -0,0 +1,47 @@ +Xilinx Zynq board (``xilinx-zynq-a9``) +== +The Zynq 7000 family is based on the AMD SoC architecture. These products +integrate a feature-rich dual or single-core Arm Cortex-A9 MPCore based +processing system (PS) and AMD programmable logic (PL) in a single device. + +More details here: +https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM/Zynq-7000-SoC-Technical-Reference-Manual + +QEMU xilinx-zynq-a9 board supports following devices: +- A9 MPCORE +- cortex-a9 +- GIC v1 +- Generic timer +- wdt +- OCM 256KB +- SMC SRAM@0xe200 64MB +- Zynq SLCR +- SPI x2 +- QSPI +- UART +- TTC x2 +- Gigabit Ethernet Controller x2 +- SD Controller x2 +- XADC +- Arm PrimeCell DMA Controller +- DDR Memory +- USB 2.0 x2 + +Running +""""""" +Direct Linux boot of a generic ARM upstream Linux kernel: + +.. code-block:: bash + + $ qemu-system-aarch64 -M xilinx-zynq-a9 \ +-dtb zynq-zc702.dtb -serial null -serial mon:stdio \ +-display none -m 1024 \ +-initrd rootfs.cpio.gz -kernel zImage + +For configuring the boot-mode provide the following on the command line: + +.. code-block:: bash + + -machine boot-mode=qspi + +Supported values are JTAG, SD, QSPI, NOR. diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 870d30e3502..7b992722846 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -109,6 +109,7 @@ undocumented; you can get a complete list by running arm/virt arm/xenpvh arm/xlnx-versal-virt + arm/xlnx-zynq Emulated CPU architecture support = -- 2.34.1
[PATCH v2 1/3] hw/misc/zynq_slcr: Add BootMode property
BootMode property sets user values into BOOT_MODE register, on hardware these are derived from board switches. Signed-off-by: Sai Pavan Boddu --- hw/misc/zynq_slcr.c | 22 +- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index 3412ff099ea..ad814c3a79b 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -24,6 +24,8 @@ #include "hw/registerfields.h" #include "hw/qdev-clock.h" #include "qom/object.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" #ifndef ZYNQ_SLCR_ERR_DEBUG #define ZYNQ_SLCR_ERR_DEBUG 0 @@ -121,6 +123,7 @@ REG32(RST_REASON, 0x250) REG32(REBOOT_STATUS, 0x258) REG32(BOOT_MODE, 0x25c) +FIELD(BOOT_MODE, BOOT_MODE, 0, 4) REG32(APU_CTRL, 0x300) REG32(WDT_CLK_SEL, 0x304) @@ -195,6 +198,7 @@ struct ZynqSLCRState { Clock *ps_clk; Clock *uart0_ref_clk; Clock *uart1_ref_clk; +uint8_t boot_mode; }; /* @@ -371,7 +375,7 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type) s->regs[R_FPGA_RST_CTRL] = 0x01F33F0F; s->regs[R_RST_REASON] = 0x0040; -s->regs[R_BOOT_MODE] = 0x0001; +s->regs[R_BOOT_MODE] = s->boot_mode & R_BOOT_MODE_BOOT_MODE_MASK; /* 0x700 - 0x7D4 */ for (i = 0; i < 54; i++) { @@ -588,6 +592,15 @@ static const ClockPortInitArray zynq_slcr_clocks = { QDEV_CLOCK_END }; +static void zynq_slcr_realize(DeviceState *dev, Error **errp) +{ +ZynqSLCRState *s = ZYNQ_SLCR(dev); + +if (s->boot_mode > 0xF) { +error_setg(errp, "Invalid boot mode %d specified", s->boot_mode); +} +} + static void zynq_slcr_init(Object *obj) { ZynqSLCRState *s = ZYNQ_SLCR(obj); @@ -610,15 +623,22 @@ static const VMStateDescription vmstate_zynq_slcr = { } }; +static Property zynq_slcr_props[] = { +DEFINE_PROP_UINT8("boot-mode", ZynqSLCRState, boot_mode, 1), +DEFINE_PROP_END_OF_LIST(), +}; + static void zynq_slcr_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); dc->vmsd = _zynq_slcr; +dc->realize = zynq_slcr_realize; rc->phases.enter = zynq_slcr_reset_init; rc->phases.hold = zynq_slcr_reset_hold; rc->phases.exit = zynq_slcr_reset_exit; +device_class_set_props(dc, zynq_slcr_props); } static const TypeInfo zynq_slcr_info = { -- 2.34.1
[PATCH RFC 1/3] target/arm: Add dcc uart support
DCC is a debug port to transfer some data between debugger and processor, we are using this feature to connect a chardev device. Chardev frontends should be named as "dcc" inorder to connect to this interface. Signed-off-by: Sai Pavan Boddu --- target/arm/cpu.h | 11 + target/arm/internals.h | 4 ++ target/arm/debug-dcc.c | 99 ++ target/arm/helper.c| 3 ++ target/arm/meson.build | 1 + 5 files changed, 118 insertions(+) create mode 100644 target/arm/debug-dcc.c diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 3841359d0f..6b3cb8e70e 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -30,6 +30,8 @@ #include "qapi/qapi-types-common.h" #include "target/arm/multiprocessing.h" #include "target/arm/gtimer.h" +#include "chardev/char.h" +#include "chardev/char-fe.h" #ifdef TARGET_AARCH64 #define KVM_HAVE_MCE_INJECTION 1 @@ -523,6 +525,11 @@ typedef struct CPUArchState { /* NV2 register */ uint64_t vncr_el2; +/* + * Debug Trace regsiters + */ +uint32_t dbgdtr_tx; +uint32_t dbgdtr_rx; } cp15; struct { @@ -1097,6 +1104,9 @@ struct ArchCPU { /* Generic timer counter frequency, in Hz */ uint64_t gt_cntfrq_hz; + +/* dcc chardev */ +CharBackend dcc; }; typedef struct ARMCPUInfo { @@ -2388,6 +2398,7 @@ enum arm_features { * CPU types added in future. */ ARM_FEATURE_BACKCOMPAT_CNTFRQ, /* 62.5MHz timer default */ +ARM_FEATURE_DCC, }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target/arm/internals.h b/target/arm/internals.h index 11b5da2562..2fa797c5df 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1778,4 +1778,8 @@ uint64_t gt_get_countervalue(CPUARMState *env); * and CNTVCT_EL0 (this will be either 0 or the value of CNTVOFF_EL2). */ uint64_t gt_virt_cnt_offset(CPUARMState *env); +/* + * Initialise Coresight Debug interface + */ +void arm_dcc_init(ARMCPU *cpu); #endif diff --git a/target/arm/debug-dcc.c b/target/arm/debug-dcc.c new file mode 100644 index 00..9144b54994 --- /dev/null +++ b/target/arm/debug-dcc.c @@ -0,0 +1,99 @@ +#include "qemu/osdep.h" +#include "cpu.h" +#include "internals.h" +#include "cpregs.h" +#include "chardev/char-fe.h" + +#define MDCCSR_EL0_RXFULL_MASK (1 << 30) +#define MDCCSR_EL0_TXFULL_MASK (1 << 29) + +static void debug_dcc_write(CPUARMState *env, const ARMCPRegInfo *ri, +uint64_t value) +{ +ARMCPU *cpu = ri->opaque; +env->cp15.dbgdtr_tx = value; + +if (qemu_chr_fe_get_driver(>dcc)) { +/* + * Usually dcc is used for putc/getc calls which expect only + * 1 byte from external debugger. + * TODO: This needs to be generalized for other use-cases. + */ +qemu_chr_fe_write_all(>dcc, (uint8_t *)>cp15.dbgdtr_tx, 1); +} +} + +static uint64_t debug_dcc_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ +uint32_t ret = 0; +ARMCPU *cpu = ri->opaque; + +if (env->cp15.mdscr_el1 & MDCCSR_EL0_RXFULL_MASK) { +ret = env->cp15.dbgdtr_rx; +env->cp15.dbgdtr_rx = 0; +env->cp15.mdscr_el1 &= ~MDCCSR_EL0_RXFULL_MASK; +qemu_chr_fe_accept_input(>dcc); +} +return ret; +} + +static const ARMCPRegInfo dcc_cp_reginfo[] = { +/* DBGDTRTX_EL0/DBGDTRRX_EL0 depend on direction */ +{ .name = "DBGDTR_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 5, .opc2 = 0, + .access = PL0_RW, .writefn = debug_dcc_write, + .readfn = debug_dcc_read, + .type = ARM_CP_OVERRIDE, .resetvalue = 0 }, +/* DBGDTRTXint/DBGDTRRXint depend on direction */ +{ .name = "DBGDTRint", .state = ARM_CP_STATE_AA32, .cp = 14, + .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0, + .access = PL0_RW, .writefn = debug_dcc_write, + .readfn = debug_dcc_read, + .type = ARM_CP_OVERRIDE, .resetvalue = 0 }, +}; + + +static int dcc_chr_can_read(void *opaque) +{ +ARMCPU *cpu = opaque; +CPUARMState *env = >env; + +if (!(env->cp15.mdscr_el1 & MDCCSR_EL0_RXFULL_MASK)) { +/* + * Usually dcc is used for putc/getc calls which expect only + * 1 byte from external debugger. + * TODO: This needs to be generalized for other use-cases. + */ +return 1; +} + +return 0; +} + +static void dcc_chr_read(void *opaque, const uint8_t *buf, int size) +{ +ARMCPU *cpu = opaque; +CPUARMState *env = >env; + +env->cp15.dbgdtr_rx = *buf; +env->cp15.mdscr_el1 |= MDCCSR_EL0_RXFULL_MASK; +} + +void arm_dcc_init(ARMCPU *cpu) +{ +Chardev *chr; +char *dcc_name; +CPUState *p = CPU(cpu); + +dcc_name = g_strdup_printf("dcc%d",
[PATCH RFC 2/3] target/arm: Enable dcc console for a53 and R5
This enabled DCC support. Signed-off-by: Sai Pavan Boddu --- target/arm/cpu64.c | 1 + target/arm/tcg/cpu32.c | 1 + 2 files changed, 2 insertions(+) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 262a1d6c0b..e39740303b 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -667,6 +667,7 @@ static void aarch64_a53_initfn(Object *obj) set_feature(>env, ARM_FEATURE_EL2); set_feature(>env, ARM_FEATURE_EL3); set_feature(>env, ARM_FEATURE_PMU); +set_feature(>env, ARM_FEATURE_DCC); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53; cpu->midr = 0x410fd034; cpu->revidr = 0x0100; diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c index bdd82d912a..b0ef51a9bf 100644 --- a/target/arm/tcg/cpu32.c +++ b/target/arm/tcg/cpu32.c @@ -562,6 +562,7 @@ static void cortex_r5_initfn(Object *obj) set_feature(>env, ARM_FEATURE_V7MP); set_feature(>env, ARM_FEATURE_PMSA); set_feature(>env, ARM_FEATURE_PMU); +set_feature(>env, ARM_FEATURE_DCC); cpu->midr = 0x411fc153; /* r1p3 */ cpu->isar.id_pfr0 = 0x0131; cpu->isar.id_pfr1 = 0x001; -- 2.34.1
[PATCH RFC 3/3] target/arm/debug_helper: Add fieldoffset for MDCCSR_EL0 reg
MDCCSR_EL0 is aarch64 varient of DBGDSCRint, so utilize the same cpreg offset. Signed-off-by: Sai Pavan Boddu --- target/arm/debug_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index 7d856acddf..5deafa4d1f 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -970,7 +970,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0, .access = PL0_R, .accessfn = access_tdcc, - .type = ARM_CP_CONST, .resetvalue = 0 }, + .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1)}, /* Xilinx */ /* * These registers belong to the Debug Communications Channel, * which is not implemented. However we implement RAZ/WI behaviour -- 2.34.1
[PATCH RFC 0/3] Add DCC uart console support
This patch series attaches a chardev to arm Debug Communication channel registers, As each cpu has it own DBGDTRTX/RX register just tried to hook each cpu with chardev iff we find a chardev with id "dcc". ex: Below chardev switch would be connected to A53-0. ./qemu-system-aarch64 -M xlnx-zcu102 -kernel u-boot-dtb.bin -dtb zynqmp-zcu102-rev1.1.d -display none -m 2G -chardev stdio,id=dcc0 Sai Pavan Boddu (3): target/arm: Add dcc uart support target/arm: Enable dcc console for a53 and R5 target/arm/debug_helper: Add fieldoffset for MDCCSR_EL0 reg target/arm/cpu.h | 11 + target/arm/internals.h| 4 ++ target/arm/cpu64.c| 1 + target/arm/debug-dcc.c| 99 +++ target/arm/debug_helper.c | 2 +- target/arm/helper.c | 3 ++ target/arm/tcg/cpu32.c| 1 + target/arm/meson.build| 1 + 8 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 target/arm/debug-dcc.c -- 2.34.1
[PATCH 2/2] hw/arm/xilinx_zynq: Add boot-mode property
Read boot-mode value as machine property and propagate that to SLCR.BOOT_MODE register. Signed-off-by: Sai Pavan Boddu --- hw/arm/xilinx_zynq.c | 22 ++ 1 file changed, 22 insertions(+) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 7f7a3d23fb..4dfa9184ac 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -38,6 +38,7 @@ #include "qom/object.h" #include "exec/tswap.h" #include "target/arm/cpu-qom.h" +#include "qapi/visitor.h" #define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9") OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE) @@ -90,6 +91,7 @@ struct ZynqMachineState { MachineState parent; Clock *ps_clk; ARMCPU *cpu[ZYNQ_MAX_CPUS]; +uint8_t BootMode; }; static void zynq_write_board_setup(ARMCPU *cpu, @@ -176,6 +178,19 @@ static inline int zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, return unit; } +static void zynq_set_boot_mode(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ +ZynqMachineState *m = ZYNQ_MACHINE(obj); +uint8_t val; + +if (!visit_type_uint8(v, name, , errp)) { +return; +} +m->BootMode = val; +} + static void zynq_init(MachineState *machine) { ZynqMachineState *zynq_machine = ZYNQ_MACHINE(machine); @@ -241,6 +256,7 @@ static void zynq_init(MachineState *machine) /* Create slcr, keep a pointer to connect clocks */ slcr = qdev_new("xilinx-zynq_slcr"); qdev_connect_clock_in(slcr, "ps_clk", zynq_machine->ps_clk); +qdev_prop_set_uint8(slcr, "boot-mode", zynq_machine->BootMode); sysbus_realize_and_unref(SYS_BUS_DEVICE(slcr), _fatal); sysbus_mmio_map(SYS_BUS_DEVICE(slcr), 0, 0xF800); @@ -372,6 +388,7 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data) NULL }; MachineClass *mc = MACHINE_CLASS(oc); +ObjectProperty *prop; mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; mc->init = zynq_init; mc->max_cpus = ZYNQ_MAX_CPUS; @@ -379,6 +396,11 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data) mc->ignore_memory_transaction_failures = true; mc->valid_cpu_types = valid_cpu_types; mc->default_ram_id = "zynq.ext_ram"; +prop = object_class_property_add(oc, "boot-mode", "uint8_t", NULL, + zynq_set_boot_mode, NULL, NULL); +object_class_property_set_description(oc, "boot-mode", + "Update SLCR.BOOT_MODE register"); +object_property_set_default_uint(prop, 1); } static const TypeInfo zynq_machine_type = { -- 2.34.1
[PATCH 0/2] Add boot-mode property for zynq
Add a way to update the boot-mode via machine properties. Sai Pavan Boddu (2): hw/misc/zynq_slcr: Add BootMode property hw/arm/xilinx_zynq: Add boot-mode property hw/arm/xilinx_zynq.c | 22 ++ hw/misc/zynq_slcr.c | 11 ++- 2 files changed, 32 insertions(+), 1 deletion(-) -- 2.34.1
[PATCH 1/2] hw/misc/zynq_slcr: Add BootMode property
BootMode property sets user values into BOOT_MODE register, on hardware these are derived from board switches. Signed-off-by: Sai Pavan Boddu --- hw/misc/zynq_slcr.c | 11 ++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index 3412ff099e..72703e92a5 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -24,6 +24,7 @@ #include "hw/registerfields.h" #include "hw/qdev-clock.h" #include "qom/object.h" +#include "hw/qdev-properties.h" #ifndef ZYNQ_SLCR_ERR_DEBUG #define ZYNQ_SLCR_ERR_DEBUG 0 @@ -121,6 +122,7 @@ REG32(RST_REASON, 0x250) REG32(REBOOT_STATUS, 0x258) REG32(BOOT_MODE, 0x25c) +FIELD(BOOT_MODE, BOOT_MODE, 0, 4) REG32(APU_CTRL, 0x300) REG32(WDT_CLK_SEL, 0x304) @@ -195,6 +197,7 @@ struct ZynqSLCRState { Clock *ps_clk; Clock *uart0_ref_clk; Clock *uart1_ref_clk; +uint8_t BootMode; }; /* @@ -371,7 +374,7 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type) s->regs[R_FPGA_RST_CTRL] = 0x01F33F0F; s->regs[R_RST_REASON] = 0x0040; -s->regs[R_BOOT_MODE] = 0x0001; +s->regs[R_BOOT_MODE] = s->BootMode & R_BOOT_MODE_BOOT_MODE_MASK; /* 0x700 - 0x7D4 */ for (i = 0; i < 54; i++) { @@ -610,6 +613,11 @@ static const VMStateDescription vmstate_zynq_slcr = { } }; +static Property zynq_slcr_props[] = { +DEFINE_PROP_UINT8("boot-mode", ZynqSLCRState, BootMode, 1), +DEFINE_PROP_END_OF_LIST(), +}; + static void zynq_slcr_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -619,6 +627,7 @@ static void zynq_slcr_class_init(ObjectClass *klass, void *data) rc->phases.enter = zynq_slcr_reset_init; rc->phases.hold = zynq_slcr_reset_hold; rc->phases.exit = zynq_slcr_reset_exit; +device_class_set_props(dc, zynq_slcr_props); } static const TypeInfo zynq_slcr_info = { -- 2.34.1
[PATCH v2 0/2] OSPI updates
Add a new 2Gib octal flash mt35xu02gbba. Add an interface for versal virt board to swap the default flash. Changes for V2: Added type checks for provided flash part name. Sai Pavan Boddu (2): block: m25p80: Add support of mt35xu02gbba arm: xlnx-versal-virt: Add machine property ospi-flash hw/block/m25p80_sfdp.h| 1 + hw/arm/xlnx-versal-virt.c | 44 ++- hw/block/m25p80.c | 3 +++ hw/block/m25p80_sfdp.c| 36 4 files changed, 83 insertions(+), 1 deletion(-) -- 2.25.1
[PATCH v2 2/2] arm: xlnx-versal-virt: Add machine property ospi-flash
This property allows users to change flash model on command line as below. ex: "-M xlnx-versal-virt,ospi-flash=mt35xu02gbba" Signed-off-by: Sai Pavan Boddu --- hw/arm/xlnx-versal-virt.c | 44 ++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 94942c55df..bfaed1aebf 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -49,6 +49,7 @@ struct VersalVirt { struct { bool secure; } cfg; +char *ospi_model; }; static void fdt_create(VersalVirt *s) @@ -638,6 +639,22 @@ static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) _fatal); } +static char *versal_get_ospi_model(Object *obj, Error **errp) +{ +VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj); + +return g_strdup(s->ospi_model); +} + +static void versal_set_ospi_model(Object *obj, const char *value, Error **errp) +{ +VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj); + +g_free(s->ospi_model); +s->ospi_model = g_strdup(value); +} + + static void versal_virt_init(MachineState *machine) { VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine); @@ -732,12 +749,25 @@ static void versal_virt_init(MachineState *machine) for (i = 0; i < XLNX_VERSAL_NUM_OSPI_FLASH; i++) { BusState *spi_bus; DeviceState *flash_dev; +ObjectClass *flash_klass; qemu_irq cs_line; DriveInfo *dinfo = drive_get(IF_MTD, 0, i); spi_bus = qdev_get_child_bus(DEVICE(>soc.pmc.iou.ospi), "spi0"); -flash_dev = qdev_new("mt35xu01g"); +if (s->ospi_model) { +flash_klass = object_class_by_name(s->ospi_model); +if (!flash_klass || +object_class_is_abstract(flash_klass) || +!object_class_dynamic_cast(flash_klass, "m25p80-generic")) { +error_setg(_fatal, "'%s' is either abstract or" + " not a subtype of m25p80", s->ospi_model); +return; +} +} + +flash_dev = qdev_new(s->ospi_model ? s->ospi_model : "mt35xu01g"); + if (dinfo) { qdev_prop_set_drive_err(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), _fatal); @@ -770,6 +800,13 @@ static void versal_virt_machine_instance_init(Object *obj) 0); } +static void versal_virt_machine_finalize(Object *obj) +{ +VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj); + +g_free(s->ospi_model); +} + static void versal_virt_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -781,6 +818,10 @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data) mc->default_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS; mc->no_cdrom = true; mc->default_ram_id = "ddr"; +object_class_property_add_str(oc, "ospi-flash", versal_get_ospi_model, + versal_set_ospi_model); +object_class_property_set_description(oc, "ospi-flash", + "Change the OSPI Flash model"); } static const TypeInfo versal_virt_machine_init_typeinfo = { @@ -789,6 +830,7 @@ static const TypeInfo versal_virt_machine_init_typeinfo = { .class_init = versal_virt_machine_class_init, .instance_init = versal_virt_machine_instance_init, .instance_size = sizeof(VersalVirt), +.instance_finalize = versal_virt_machine_finalize, }; static void versal_virt_machine_init_register_types(void) -- 2.25.1
[PATCH v2 1/2] block: m25p80: Add support of mt35xu02gbba
Add Micro 2Gb OSPI flash part with sfdp data. Signed-off-by: Sai Pavan Boddu Reviewed-by: Francisco Iglesias --- hw/block/m25p80_sfdp.h | 1 + hw/block/m25p80.c | 3 +++ hw/block/m25p80_sfdp.c | 36 3 files changed, 40 insertions(+) diff --git a/hw/block/m25p80_sfdp.h b/hw/block/m25p80_sfdp.h index 011a880f66..1733b56950 100644 --- a/hw/block/m25p80_sfdp.h +++ b/hw/block/m25p80_sfdp.h @@ -16,6 +16,7 @@ #define M25P80_SFDP_MAX_SIZE (1 << 24) uint8_t m25p80_sfdp_n25q256a(uint32_t addr); +uint8_t m25p80_sfdp_mt35xu02g(uint32_t addr); uint8_t m25p80_sfdp_mx25l25635e(uint32_t addr); uint8_t m25p80_sfdp_mx25l25635f(uint32_t addr); diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 0a12030a3a..08a00a6d9b 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -267,6 +267,9 @@ static const FlashPartInfo known_devices[] = { { INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) }, { INFO_STACKED("mt35xu01g", 0x2c5b1b, 0x104100, 128 << 10, 1024, ER_4K | ER_32K, 2) }, +{ INFO_STACKED("mt35xu02gbba", 0x2c5b1c, 0x104100, 128 << 10, 2048, + ER_4K | ER_32K, 4), + .sfdp_read = m25p80_sfdp_mt35xu02g }, { INFO_STACKED("n25q00",0x20ba21, 0x1000, 64 << 10, 2048, ER_4K, 4) }, { INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) }, { INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) }, diff --git a/hw/block/m25p80_sfdp.c b/hw/block/m25p80_sfdp.c index b33811a4f5..6ee2cfaf11 100644 --- a/hw/block/m25p80_sfdp.c +++ b/hw/block/m25p80_sfdp.c @@ -57,6 +57,42 @@ static const uint8_t sfdp_n25q256a[] = { }; define_sfdp_read(n25q256a); +static const uint8_t sfdp_mt35xu02g[] = { +0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff, +0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff, +0x84, 0x00, 0x01, 0x02, 0x80, 0x00, 0x00, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xe5, 0x20, 0x8a, 0xff, 0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, +0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x11, 0xd8, +0x0f, 0x52, 0x00, 0x00, 0x24, 0x5a, 0x99, 0x00, +0x8b, 0x8e, 0x03, 0xe1, 0xac, 0x01, 0x27, 0x38, +0x7a, 0x75, 0x7a, 0x75, 0xfb, 0xbd, 0xd5, 0x5c, +0x00, 0x00, 0x70, 0xff, 0x81, 0xb0, 0x38, 0x36, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0x43, 0x0e, 0xff, 0xff, 0x21, 0xdc, 0x5c, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +define_sfdp_read(mt35xu02g); /* * Matronix -- 2.25.1
[PATCH v2] xlnx-versal-ospi: disable reentrancy detection for iomem_dac
The OSPI DMA reads flash data through the OSPI linear address space (the iomem_dac region), because of this the reentrancy guard introduced in commit a2e1753b ("memory: prevent dma-reentracy issues") is disabled for the memory region. Signed-off-by: Sai Pavan Boddu --- Changes for V2: Added code comments. hw/ssi/xlnx-versal-ospi.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/ssi/xlnx-versal-ospi.c b/hw/ssi/xlnx-versal-ospi.c index c7b95b1f37..c479138ec1 100644 --- a/hw/ssi/xlnx-versal-ospi.c +++ b/hw/ssi/xlnx-versal-ospi.c @@ -1772,6 +1772,12 @@ static void xlnx_versal_ospi_init(Object *obj) memory_region_init_io(>iomem_dac, obj, _dac_ops, s, TYPE_XILINX_VERSAL_OSPI "-dac", 0x2000); sysbus_init_mmio(sbd, >iomem_dac); +/* + * The OSPI DMA reads flash data through the OSPI linear address space (the + * iomem_dac region), because of this the reentrancy guard needs to be + * disabled. + */ +s->iomem_dac.disable_reentrancy_guard = true; sysbus_init_irq(sbd, >irq); -- 2.25.1
[PATCH 1/1] xlnx-versal-ospi: disable reentrancy detection for iomem_dac
The OSPI DMA reads flash data through the OSPI linear address space (the iomem_dac region), because of this the reentrancy guard introduced in commit a2e1753b ("memory: prevent dma-reentracy issues") is disabled for the memory region. Signed-off-by: Sai Pavan Boddu --- hw/ssi/xlnx-versal-ospi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ssi/xlnx-versal-ospi.c b/hw/ssi/xlnx-versal-ospi.c index 1a61679c2f..5123e7dde7 100644 --- a/hw/ssi/xlnx-versal-ospi.c +++ b/hw/ssi/xlnx-versal-ospi.c @@ -1772,6 +1772,7 @@ static void xlnx_versal_ospi_init(Object *obj) memory_region_init_io(>iomem_dac, obj, _dac_ops, s, TYPE_XILINX_VERSAL_OSPI "-dac", 0x2000); sysbus_init_mmio(sbd, >iomem_dac); +s->iomem_dac.disable_reentrancy_guard = true; sysbus_init_irq(sbd, >irq); -- 2.25.1
[PATCH 0/1] versal-ospi fix
Disable reentrancy on iomem_dac memory-region. Sai Pavan Boddu (1): xlnx-versal-ospi: disable reentrancy detection for iomem_dac hw/ssi/xlnx-versal-ospi.c | 1 + 1 file changed, 1 insertion(+) -- 2.25.1
[PATCH 0/1] versal-ospi fix
Disable reentrancy on iomem_dac memory-region. Sai Pavan Boddu (1): xlnx-versal-ospi: disable reentrancy detection for iomem_dac hw/ssi/xlnx-versal-ospi.c | 1 + 1 file changed, 1 insertion(+) -- 2.25.1
[PATCH 1/2] block: m25p80: Add support of mt35xu02gbba
Add Micro 2Gb OSPI flash part with sfdp data. Signed-off-by: Sai Pavan Boddu --- hw/block/m25p80_sfdp.h | 1 + hw/block/m25p80.c | 3 +++ hw/block/m25p80_sfdp.c | 36 3 files changed, 40 insertions(+) diff --git a/hw/block/m25p80_sfdp.h b/hw/block/m25p80_sfdp.h index 011a880f66..1733b56950 100644 --- a/hw/block/m25p80_sfdp.h +++ b/hw/block/m25p80_sfdp.h @@ -16,6 +16,7 @@ #define M25P80_SFDP_MAX_SIZE (1 << 24) uint8_t m25p80_sfdp_n25q256a(uint32_t addr); +uint8_t m25p80_sfdp_mt35xu02g(uint32_t addr); uint8_t m25p80_sfdp_mx25l25635e(uint32_t addr); uint8_t m25p80_sfdp_mx25l25635f(uint32_t addr); diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index afc3fdf4d6..c8c7f6c1c3 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -267,6 +267,9 @@ static const FlashPartInfo known_devices[] = { { INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) }, { INFO_STACKED("mt35xu01g", 0x2c5b1b, 0x104100, 128 << 10, 1024, ER_4K | ER_32K, 2) }, +{ INFO_STACKED("mt35xu02gbba", 0x2c5b1c, 0x104100, 128 << 10, 2048, + ER_4K | ER_32K, 4), + .sfdp_read = m25p80_sfdp_mt35xu02g }, { INFO_STACKED("n25q00",0x20ba21, 0x1000, 64 << 10, 2048, ER_4K, 4) }, { INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) }, { INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) }, diff --git a/hw/block/m25p80_sfdp.c b/hw/block/m25p80_sfdp.c index b33811a4f5..6ee2cfaf11 100644 --- a/hw/block/m25p80_sfdp.c +++ b/hw/block/m25p80_sfdp.c @@ -57,6 +57,42 @@ static const uint8_t sfdp_n25q256a[] = { }; define_sfdp_read(n25q256a); +static const uint8_t sfdp_mt35xu02g[] = { +0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff, +0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff, +0x84, 0x00, 0x01, 0x02, 0x80, 0x00, 0x00, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xe5, 0x20, 0x8a, 0xff, 0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, +0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x11, 0xd8, +0x0f, 0x52, 0x00, 0x00, 0x24, 0x5a, 0x99, 0x00, +0x8b, 0x8e, 0x03, 0xe1, 0xac, 0x01, 0x27, 0x38, +0x7a, 0x75, 0x7a, 0x75, 0xfb, 0xbd, 0xd5, 0x5c, +0x00, 0x00, 0x70, 0xff, 0x81, 0xb0, 0x38, 0x36, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0x43, 0x0e, 0xff, 0xff, 0x21, 0xdc, 0x5c, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +define_sfdp_read(mt35xu02g); /* * Matronix -- 2.25.1
[PATCH 2/2] arm: xlnx-versal-virt: Add machine property ospi-flash
This property allows users to change flash model on command line as below. ex: "-M xlnx-versal-virt,ospi-flash=mt35xu02gbba" Signed-off-by: Sai Pavan Boddu --- hw/arm/xlnx-versal-virt.c | 31 ++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 537118224f..c57cff74d8 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -49,6 +49,7 @@ struct VersalVirt { struct { bool secure; } cfg; +char *ospi_model; }; static void fdt_create(VersalVirt *s) @@ -637,6 +638,22 @@ static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) _fatal); } +static char *versal_get_ospi_model(Object *obj, Error **errp) +{ +VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj); + +return g_strdup(s->ospi_model); +} + +static void versal_set_ospi_model(Object *obj, const char *value, Error **errp) +{ +VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj); + +g_free(s->ospi_model); +s->ospi_model = g_strdup(value); +} + + static void versal_virt_init(MachineState *machine) { VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine); @@ -736,7 +753,7 @@ static void versal_virt_init(MachineState *machine) spi_bus = qdev_get_child_bus(DEVICE(>soc.pmc.iou.ospi), "spi0"); -flash_dev = qdev_new("mt35xu01g"); +flash_dev = qdev_new(s->ospi_model ? s->ospi_model : "mt35xu01g"); if (dinfo) { qdev_prop_set_drive_err(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), _fatal); @@ -769,6 +786,13 @@ static void versal_virt_machine_instance_init(Object *obj) 0); } +static void versal_virt_machine_finalize(Object *obj) +{ +VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj); + +g_free(s->ospi_model); +} + static void versal_virt_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -780,6 +804,10 @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data) mc->default_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS; mc->no_cdrom = true; mc->default_ram_id = "ddr"; +object_class_property_add_str(oc, "ospi-flash", versal_get_ospi_model, + versal_set_ospi_model); +object_class_property_set_description(oc, "ospi-flash", + "Change the OSPI Flash model"); } static const TypeInfo versal_virt_machine_init_typeinfo = { @@ -788,6 +816,7 @@ static const TypeInfo versal_virt_machine_init_typeinfo = { .class_init = versal_virt_machine_class_init, .instance_init = versal_virt_machine_instance_init, .instance_size = sizeof(VersalVirt), +.instance_finalize = versal_virt_machine_finalize, }; static void versal_virt_machine_init_register_types(void) -- 2.25.1
[PATCH 0/2] OSPI updates
Add a new 2Gib octal flash mt35xu02gbba. Add an interface for versal virt board to swap the default flash. Sai Pavan Boddu (2): block: m25p80: Add support of mt35xu02gbba arm: xlnx-versal-virt: Add machine property ospi-flash hw/block/m25p80_sfdp.h| 1 + hw/arm/xlnx-versal-virt.c | 31 ++- hw/block/m25p80.c | 3 +++ hw/block/m25p80_sfdp.c| 36 4 files changed, 70 insertions(+), 1 deletion(-) -- 2.25.1
[PATCH 1/1] xlnx-versal-ospi: disable reentrancy detection for iomem_dac
The OSPI DMA reads flash data through the OSPI linear address space (the iomem_dac region), because of this the reentrancy guard introduced in commit a2e1753b ("memory: prevent dma-reentracy issues") is disabled for the memory region. Signed-off-by: Sai Pavan Boddu --- hw/ssi/xlnx-versal-ospi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ssi/xlnx-versal-ospi.c b/hw/ssi/xlnx-versal-ospi.c index 1a61679c2f..5123e7dde7 100644 --- a/hw/ssi/xlnx-versal-ospi.c +++ b/hw/ssi/xlnx-versal-ospi.c @@ -1772,6 +1772,7 @@ static void xlnx_versal_ospi_init(Object *obj) memory_region_init_io(>iomem_dac, obj, _dac_ops, s, TYPE_XILINX_VERSAL_OSPI "-dac", 0x2000); sysbus_init_mmio(sbd, >iomem_dac); +s->iomem_dac.disable_reentrancy_guard = true; sysbus_init_irq(sbd, >irq); -- 2.25.1
RE: [PATCH v3 02/21] sd: emmc: Add support for eMMC cards
Hi Cedric, > -Original Message- > From: Cédric Le Goater > Sent: Monday, March 1, 2021 4:32 PM > To: Sai Pavan Boddu ; Markus Armbruster > ; Kevin Wolf ; Max Reitz > ; Vladimir Sementsov-Ogievskiy > ; Eric Blake ; Joel Stanley > ; Vincent Palatin ; Dr. David Alan > Gilbert ; Thomas Huth ; Stefan > Hajnoczi ; Peter Maydell ; > Alistair Francis ; Edgar Iglesias > ; > Luc Michel ; Paolo Bonzini > > Cc: qemu-bl...@nongnu.org; qemu-devel@nongnu.org; Sai Pavan Boddu > > Subject: Re: [PATCH v3 02/21] sd: emmc: Add support for eMMC cards > > On 2/28/21 8:33 PM, Sai Pavan Boddu wrote: > > Add eMMC device built on top of SD card. > > > > Signed-off-by: Sai Pavan Boddu > > --- > > include/hw/sd/sd.h | 2 ++ > > hw/sd/sd.c | 20 > > 2 files changed, 22 insertions(+) > > > > diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index > > 05ef9b7..b402dad 100644 > > --- a/include/hw/sd/sd.h > > +++ b/include/hw/sd/sd.h > > @@ -90,6 +90,8 @@ typedef struct { > > } SDRequest; > > > > > > +#define TYPE_EMMC "emmc" > > +OBJECT_DECLARE_SIMPLE_TYPE(EMMCState, EMMC) > > #define TYPE_SD_CARD "sd-card" > > OBJECT_DECLARE_TYPE(SDState, SDCardClass, SD_CARD) > > > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > > index 74b9162..a23af6d 100644 > > --- a/hw/sd/sd.c > > +++ b/hw/sd/sd.c > > @@ -108,6 +108,7 @@ struct SDState { > > uint8_t spec_version; > > BlockBackend *blk; > > bool spi; > > +bool emmc; > > > > /* Runtime changeables */ > > > > @@ -143,6 +144,10 @@ struct SDState { > > bool cmd_line; > > }; > > > > +struct EMMCState { > > +SDState parent; > > +}; > > + > > static void sd_realize(DeviceState *dev, Error **errp); > > > > static const char *sd_state_name(enum SDCardStates state) @@ -2105,6 > > +2110,13 @@ static void sd_instance_init(Object *obj) > > sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, > > sd_ocr_powerup, sd); } > > > > +static void emmc_instance_init(Object *obj) { > > +SDState *sd = SD_CARD(obj); > > + > > +sd->emmc = true; > > +} > I think field 'emmc' would fit better in SDCardClass since it is a device > constant. > You should not need 'struct EMMCState'. So something like below. > Then you can add handlers for specific emmc commands. > > Thanks, > > C. > > > diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index > 47360ba4ee98..80e7cd526a57 100644 > --- a/include/hw/sd/sd.h > +++ b/include/hw/sd/sd.h > @@ -93,6 +93,8 @@ typedef struct { > #define TYPE_SD_CARD "sd-card" > OBJECT_DECLARE_TYPE(SDState, SDCardClass, SD_CARD) > > +#define TYPE_EMMC "emmc" > + > struct SDCardClass { > /*< private >*/ > DeviceClass parent_class; > @@ -124,6 +126,8 @@ struct SDCardClass { > void (*enable)(SDState *sd, bool enable); > bool (*get_inserted)(SDState *sd); > bool (*get_readonly)(SDState *sd); > + > +bool emmc; > }; > > #define TYPE_SD_BUS "sd-bus" > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index 660026f2a667..95608f11b36e 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -2447,9 +2447,24 @@ static const TypeInfo sd_info = { > .instance_finalize = sd_instance_finalize, }; > > +static void emmc_class_init(ObjectClass *klass, void *data) { > +SDCardClass *sc = SD_CARD_CLASS(klass); > + > +sc->emmc = true; > +} > + > +static const TypeInfo emmc_info = { > +.name = TYPE_EMMC, > +.parent = TYPE_SD_CARD, > +.instance_size = sizeof(SDState), > +.class_init = emmc_class_init, > +}; > + [Sai Pavan Boddu] Yes, I see your point. Let me try, I was preferring a simpler approach just to not disturb the code much but lets see how this workout. Thanks, Sai Pavan > static void sd_register_types(void) > { > type_register_static(_info); > +type_register_static(_info); > } > > type_init(sd_register_types)
RE: [PATCH v3 12/21] sd: emmc: add CMD21 tuning sequence
Hi David, > -Original Message- > From: Dr. David Alan Gilbert > Sent: Monday, March 1, 2021 4:12 PM > To: Sai Pavan Boddu > Cc: Markus Armbruster ; Kevin Wolf > ; Max Reitz ; Vladimir Sementsov- > Ogievskiy ; Eric Blake ; > Joel Stanley ; Cédric Le Goater ; Vincent > Palatin ; Thomas Huth ; Stefan > Hajnoczi ; Peter Maydell ; > Alistair Francis ; Edgar Iglesias > ; > Luc Michel ; Paolo Bonzini > ; qemu-bl...@nongnu.org; qemu-devel@nongnu.org; > Sai Pavan Boddu > Subject: Re: [PATCH v3 12/21] sd: emmc: add CMD21 tuning sequence > > * Sai Pavan Boddu (sai.pavan.bo...@xilinx.com) wrote: > > eMMC cards support tuning sequence for entering HS200 mode. > > > > Signed-off-by: Sai Pavan Boddu > > Signed-off-by: Edgar E. Iglesias > > --- > > hw/sd/sd.c | 47 +++ > > 1 file changed, 47 insertions(+) > > > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > > index bf963ec..174c28e 100644 > > --- a/hw/sd/sd.c > > +++ b/hw/sd/sd.c > > @@ -1386,6 +1386,14 @@ static sd_rsp_type_t > sd_normal_command(SDState *sd, SDRequest req) > > } > > break; > > > > +case 21:/* CMD21: mmc SEND TUNING_BLOCK */ > > +if (sd->emmc && (sd->state == sd_transfer_state)) { > > +sd->state = sd_sendingdata_state; > > +sd->data_offset = 0; > > +return sd_r1; > > +} > > +break; > > + > > case 23:/* CMD23: SET_BLOCK_COUNT */ > > if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { > > break; > > @@ -2120,6 +2128,30 @@ static const uint8_t > sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = { > > 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, > > }; > > > > +#define EXCSD_BUS_WIDTH_OFFSET 183 > > +#define BUS_WIDTH_8_MASK0x4 > > +#define BUS_WIDTH_4_MASK0x2 > > +#define MMC_TUNING_BLOCK_SIZE 128 > > + > > +static const uint8_t mmc_tunning_block_pattern[128] = { > > + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, > > + 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, > > + 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, > > + 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, > > + 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, > > + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, > > + 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, > > + 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, > > + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, > > + 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, > > + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, > > + 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, > > + 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, > > + 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, > > + 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, > > + 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > > Where does this magic pattern come from? Is it part of some spec? [Sai Pavan Boddu] Yes its part of JEDEC eMMC spec. It's the tuning sequence for HS200 mode. Regards, Sai Pavan > > Dave > > > +}; > > + > > uint8_t sd_read_byte(SDState *sd) > > { > > /* TODO: Append CRCs */ > > @@ -2213,6 +2245,21 @@ uint8_t sd_read_byte(SDState *sd) > > ret = sd_tuning_block_pattern[sd->data_offset++]; > > break; > > > > +case 21:/* CMD21: SEND_TUNNING_BLOCK (MMC) */ > > +if (sd->data_offset >= MMC_TUNING_BLOCK_SIZE - 1) { > > +sd->state = sd_transfer_state; > > +} > > +if (sd->ext_csd[EXCSD_BUS_WIDTH_OFFSET] & BUS_WIDTH_8_MASK) { > > +ret = mmc_tunning_block_pattern[sd->data_offset++]; > > +} else { > > +/* Return LSB Nibbles of two byte from the 8bit tuning block > > + * for 4bit mode > > + */ > > +ret = mmc_tunning_block_pattern[sd->data_offset++] & 0x0F; > > +ret |= (mmc_tunning_block_pattern[sd->data_offset++] & 0x0F) > > << 4; > > +} > > +break; > > + > > case 22:/* ACMD22: SEND_NUM_WR_BLOCKS */ > > ret = sd->data[sd->data_offset ++]; > > > > -- > > 2.7.4 > > > -- > Dr. David Alan Gilbert / dgilb...@redhat.com / Manchester, UK
[PATCH v3 18/21] sd: sdhci: Support eMMC devices
Embedded device slots should be allowed as support of eMMC is available. Signed-off-by: Sai Pavan Boddu --- hw/sd/sdhci.c | 4 1 file changed, 4 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 8ffa539..771212a 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -99,10 +99,6 @@ static void sdhci_check_capareg(SDHCIState *s, Error **errp) msk = FIELD_DP64(msk, SDHC_CAPAB, ASYNC_INT, 0); val = FIELD_EX64(s->capareg, SDHC_CAPAB, SLOT_TYPE); -if (val) { -error_setg(errp, "slot-type not supported"); -return; -} trace_sdhci_capareg("slot type", val); msk = FIELD_DP64(msk, SDHC_CAPAB, SLOT_TYPE, 0); -- 2.7.4
[PATCH v3 16/21] sd: emmc: Support boot area in emmc image
From: Joel Stanley This assumes a specially constructued image: dd if=/dev/zero of=mmc-bootarea.img count=2 bs=1M dd if=u-boot-spl.bin of=mmc-bootarea.img conv=notrunc dd if=u-boot.bin of=mmc-bootarea.img conv=notrunc count=64 bs=1K cat mmc-bootarea.img obmc-phosphor-image.wic > mmc.img truncate --size 16GB mmc.img truncate --size 128MB mmc-bootarea.img Signed-off-by: Joel Stanley [clg: - changes on the definition names ] Signed-off-by: Cédric Le Goater [spb: use data_start property to access right emmc partition, Clean up PARTITION_ENABLE support as incomplete, Fix commit message to be generic.] Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 40 1 file changed, 40 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 08b77ad..d311477 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1044,6 +1044,34 @@ static void sd_lock_command(SDState *sd) sd->card_status &= ~CARD_IS_LOCKED; } +/* + * This requires a disk image that has two boot partitions inserted at the + * beginning of it. The size of the boot partitions are configured in the + * ext_csd structure, which is hardcoded in qemu. They are currently set to + * 1MB each. + */ +static uint32_t sd_bootpart_offset(SDState *sd) +{ +unsigned int access = sd->ext_csd[EXT_CSD_PART_CONFIG] & +EXT_CSD_PART_CONFIG_ACC_MASK; +unsigned int boot_capacity = sd->ext_csd[EXT_CSD_BOOT_MULT] << 17; + +if (!sd->emmc) { +return 0; +} + +switch (access) { +case EXT_CSD_PART_CONFIG_ACC_DEFAULT: +return boot_capacity * 2; +case EXT_CSD_PART_CONFIG_ACC_BOOT0: +return 0; +case EXT_CSD_PART_CONFIG_ACC_BOOT0 + 1: +return boot_capacity * 1; +default: + g_assert_not_reached(); +} +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint32_t rca = 0x; @@ -1359,6 +1387,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_sendingdata_state; sd->data_start = addr; sd->data_offset = 0; @@ -1378,6 +1409,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_sendingdata_state; sd->data_start = addr; sd->data_offset = 0; @@ -1434,6 +1468,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_receivingdata_state; sd->data_start = addr; sd->data_offset = 0; @@ -1464,6 +1501,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_receivingdata_state; sd->data_start = addr; sd->data_offset = 0; -- 2.7.4
[PATCH v3 14/21] sd: emmc: Add support for emmc erase
Add CMD35 and CMD36 which sets the erase start and end. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 09c1222..bba0446 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1552,6 +1552,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Erase commands (Class 5) */ case 32:/* CMD32: ERASE_WR_BLK_START */ +case 35:/* CMD35: ERASE_GROUP_START */ switch (sd->state) { case sd_transfer_state: sd->erase_start = req.arg; @@ -1563,6 +1564,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 33:/* CMD33: ERASE_WR_BLK_END */ +case 36:/* CMD36: ERASE_GROUP_END */ switch (sd->state) { case sd_transfer_state: sd->erase_end = req.arg; -- 2.7.4
[PATCH v3 05/21] sd: emmc: Add support for EXT_CSD & CSD for eMMC
From: Vincent Palatin eMMC CSD is similar to SD with an option to refer EXT_CSD for larger devices. Signed-off-by: Vincent Palatin [clg: Add user friendly macros for EXT_CSD register] Signed-off-by: Cédric Le Goater [spb: updated commit message] Signed-off-by: Sai Pavan Boddu --- hw/sd/sdmmc-internal.h | 97 ++ hw/sd/sd.c | 61 +-- 2 files changed, 156 insertions(+), 2 deletions(-) diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h index d8bf17d..7ab7b4d 100644 --- a/hw/sd/sdmmc-internal.h +++ b/hw/sd/sdmmc-internal.h @@ -37,4 +37,101 @@ const char *sd_cmd_name(uint8_t cmd); */ const char *sd_acmd_name(uint8_t cmd); +/* + * EXT_CSD fields + */ + +#define EXT_CSD_CMDQ_MODE_EN15 /* R/W */ +#define EXT_CSD_FLUSH_CACHE 32 /* W */ +#define EXT_CSD_CACHE_CTRL33 /* R/W */ +#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ +#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */ +#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */ +#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */ +#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */ +#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ +#define EXT_CSD_GP_SIZE_MULT143 /* R/W */ +#define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */ +#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ +#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ +#define EXT_CSD_HPI_MGMT161 /* R/W */ +#define EXT_CSD_RST_N_FUNCTION162 /* R/W */ +#define EXT_CSD_BKOPS_EN163 /* R/W */ +#define EXT_CSD_BKOPS_START 164 /* W */ +#define EXT_CSD_SANITIZE_START165 /* W */ +#define EXT_CSD_WR_REL_PARAM166 /* RO */ +#define EXT_CSD_RPMB_MULT 168 /* RO */ +#define EXT_CSD_FW_CONFIG 169 /* R/W */ +#define EXT_CSD_BOOT_WP 173 /* R/W */ +#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ +#define EXT_CSD_PART_CONFIG 179 /* R/W */ +#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_STROBE_SUPPORT184 /* RO */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_POWER_CLASS 187 /* R/W */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_STRUCTURE 194 /* RO */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_DRIVER_STRENGTH 197 /* RO */ +#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */ +#define EXT_CSD_PART_SWITCH_TIME199 /* RO */ +#define EXT_CSD_PWR_CL_52_195 200 /* RO */ +#define EXT_CSD_PWR_CL_26_195 201 /* RO */ +#define EXT_CSD_PWR_CL_52_360 202 /* RO */ +#define EXT_CSD_PWR_CL_26_360 203 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define EXT_CSD_S_A_TIMEOUT 217 /* RO */ +#define EXT_CSD_S_C_VCCQ 219 /* RO */ +#define EXT_CSD_S_C_VCC 220 /* RO */ +#define EXT_CSD_REL_WR_SEC_C222 /* RO */ +#define EXT_CSD_HC_WP_GRP_SIZE221 /* RO */ +#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */ +#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ +#define EXT_CSD_ACC_SIZE225 /* RO */ +#define EXT_CSD_BOOT_MULT 226 /* RO */ +#define EXT_CSD_BOOT_INFO 228 /* RO */ +#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */ +#define EXT_CSD_SEC_ERASE_MULT230 /* RO */ +#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ +#define EXT_CSD_TRIM_MULT 232 /* RO */ +#define EXT_CSD_PWR_CL_200_195236 /* RO */ +#define EXT_CSD_PWR_CL_200_360237 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */ +#define EXT_CSD_BKOPS_STATUS246 /* RO */ +#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ +#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ +#define EXT_CSD_CACHE_SIZE249 /* RO, 4 bytes */ +#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */ +#define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */ +#define EXT_CSD_PRE_EOL_INFO267 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */ +#define EXT_CSD_CMDQ_DEPTH307 /* RO */ +#define EXT_CSD_CMDQ_SUPPORT308 /* RO */ +#define EXT_CSD_SUPPORTED_MODE493 /* RO */ +#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ +#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ +#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ +#define EXT_CSD_MAX_PACKED_READS 501 /* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ +#define EXT_CSD_HPI_FEATURES503 /* RO */ +#define EXT_CSD_S_CMD_SET 504 /* RO */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_WR_REL_PARAM_EN (1 << 2) +#define EXT_CSD_WR_REL_PARAM_EN_RPMB_REL_WR (1 << 4) + +#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) +#define EXT_CSD_PART_CONFIG_ACC_DEFAULT (0x0) +#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) + +#define EXT_CSD_PART_CONFIG_EN_MASK (0x7 << 3) +#define EXT_CSD_PART_CONFIG_EN_BOOT0 (0x1 << 3) +#define EXT_CSD_PART_CONFIG_EN_USER (0x7 << 3) + #endif diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bc9d913..a26695b 100644 --- a/hw/sd/s
[PATCH v3 17/21] sd: emmc: Subtract bootarea size from blk
From: Joel Stanley The userdata size is derived from the file the user passes on the command line, but we must take into account the boot areas. Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater --- hw/sd/sd.c | 5 + 1 file changed, 5 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d311477..5135a64 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -657,6 +657,11 @@ static void sd_reset(DeviceState *dev) } size = sect << 9; +if (sd->emmc) { +unsigned int boot_capacity = sd->ext_csd[EXT_CSD_BOOT_MULT] << 17; +size -= boot_capacity * 2; +} + sect = sd_addr_to_wpnum(size) + 1; sd->state = sd_idle_state; -- 2.7.4
[PATCH v3 04/21] sd: emmc: update OCR fields for eMMC
From: Vincent Palatin eMMC OCR register doesn't has UHS-II field and voltage fields are different. Signed-off-by: Vincent Palatin Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 27 --- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 6de414b..bc9d913 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -287,6 +287,15 @@ FIELD(OCR, UHS_II_CARD,29, 1) /* Only UHS-II */ FIELD(OCR, CARD_CAPACITY, 30, 1) /* 0:SDSC, 1:SDHC/SDXC */ FIELD(OCR, CARD_POWER_UP, 31, 1) +/* + * eMMC OCR register + */ +FIELD(EMMC_OCR, VDD_WINDOW_0, 7, 1) +FIELD(EMMC_OCR, VDD_WINDOW_1, 8, 7) +FIELD(EMMC_OCR, VDD_WINDOW_2, 15, 9) +FIELD(EMMC_OCR, ACCESS_MODE, 29, 2) +FIELD(EMMC_OCR, POWER_UP, 31, 1) + #define ACMD41_ENQUIRY_MASK 0x00ff #define ACMD41_R3_MASK (R_OCR_VDD_VOLTAGE_WIN_HI_MASK \ | R_OCR_ACCEPT_SWITCH_1V8_MASK \ @@ -296,8 +305,16 @@ FIELD(OCR, CARD_POWER_UP, 31, 1) static void sd_set_ocr(SDState *sd) { -/* All voltages OK */ -sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; +if (sd->emmc) { +/* + * Dual Voltage eMMC card + */ +sd->ocr = R_EMMC_OCR_VDD_WINDOW_0_MASK | + R_EMMC_OCR_VDD_WINDOW_2_MASK; +} else { +/* All voltages OK */ +sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; +} } static void sd_ocr_powerup(void *opaque) @@ -525,7 +542,11 @@ static void sd_response_r1_make(SDState *sd, uint8_t *response) static void sd_response_r3_make(SDState *sd, uint8_t *response) { -stl_be_p(response, sd->ocr & ACMD41_R3_MASK); +if (sd->emmc) { +stl_be_p(response, sd->ocr); +} else { +stl_be_p(response, sd->ocr & ACMD41_R3_MASK); +} } static void sd_response_r6_make(SDState *sd, uint8_t *response) -- 2.7.4
[PATCH v3 19/21] arm: xlnx-versal: Add emmc to versal
Configuring SDHCI-0 to act as eMMC controller. Signed-off-by: Sai Pavan Boddu --- include/hw/arm/xlnx-versal.h | 1 + hw/arm/xlnx-versal-virt.c| 29 + hw/arm/xlnx-versal.c | 14 -- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 2b76885..440f3b4 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -76,6 +76,7 @@ struct Versal { struct { MemoryRegion *mr_ddr; uint32_t psci_conduit; +bool has_emmc; } cfg; }; diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 8482cd6..053a322 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -46,6 +46,7 @@ struct VersalVirt { struct { bool secure; +bool has_emmc; } cfg; }; @@ -333,6 +334,13 @@ static void fdt_add_sd_nodes(VersalVirt *s) qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", 2, addr, 2, MM_PMC_SD0_SIZE); qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat)); +/* + * eMMC specific properties + */ +if (s->cfg.has_emmc && i == 0) { +qemu_fdt_setprop(s->fdt, name, "non-removable", NULL, 0); +qemu_fdt_setprop_sized_cells(s->fdt, name, "bus-width", 1, 8); +} g_free(name); } } @@ -524,11 +532,17 @@ static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) _fatal); } +static void versal_virt_set_emmc(Object *obj, bool value, Error **errp) +{ +VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj); + +s->cfg.has_emmc = value; +} + static void versal_virt_init(MachineState *machine) { VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine); int psci_conduit = QEMU_PSCI_CONDUIT_DISABLED; -int i; /* * If the user provides an Operating System to be loaded, we expect them @@ -560,6 +574,8 @@ static void versal_virt_init(MachineState *machine) _abort); object_property_set_int(OBJECT(>soc), "psci-conduit", psci_conduit, _abort); +object_property_set_bool(OBJECT(>soc), "has-emmc", s->cfg.has_emmc, + _abort); sysbus_realize(SYS_BUS_DEVICE(>soc), _fatal); fdt_create(s); @@ -581,10 +597,12 @@ static void versal_virt_init(MachineState *machine) memory_region_add_subregion_overlap(get_system_memory(), 0, >soc.fpd.apu.mr, 0); -/* Plugin SD cards. */ -for (i = 0; i < ARRAY_SIZE(s->soc.pmc.iou.sd); i++) { -sd_plugin_card(>soc.pmc.iou.sd[i], drive_get_next(IF_SD)); +if (!s->cfg.has_emmc) { +sd_plugin_card(>soc.pmc.iou.sd[0], +drive_get_next(IF_SD)); } +/* Plugin SD cards. */ +sd_plugin_card(>soc.pmc.iou.sd[1], drive_get_next(IF_SD)); s->binfo.ram_size = machine->ram_size; s->binfo.loader_start = 0x0; @@ -621,6 +639,9 @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data) mc->default_cpus = XLNX_VERSAL_NR_ACPUS; mc->no_cdrom = true; mc->default_ram_id = "ddr"; +object_class_property_add_bool(oc, "emmc", +NULL, versal_virt_set_emmc); + } static const TypeInfo versal_virt_machine_init_typeinfo = { diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 628e77e..6ca2c8f 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -230,6 +230,9 @@ static void versal_create_admas(Versal *s, qemu_irq *pic) } #define SDHCI_CAPABILITIES 0x280737ec6481 /* Same as on ZynqMP. */ +#define SDHCI_EMMC_CAPS ((SDHCI_CAPABILITIES & ~(3 << 30)) | \ + (1 << 30)) + static void versal_create_sds(Versal *s, qemu_irq *pic) { int i; @@ -242,11 +245,17 @@ static void versal_create_sds(Versal *s, qemu_irq *pic) TYPE_SYSBUS_SDHCI); dev = DEVICE(>pmc.iou.sd[i]); +dev->id = g_strdup_printf("sdhci%d", i); object_property_set_uint(OBJECT(dev), "sd-spec-version", 3, _fatal); -object_property_set_uint(OBJECT(dev), "capareg", SDHCI_CAPABILITIES, +object_property_set_uint(OBJECT(dev), "capareg", SDHCI_EMMC_CAPS, _fatal); -object_property_set_uint(OBJECT(dev), "uhs", UHS_I, _fatal); +/* + * UHS is not applicable for eMMC + */ +if (!s->cfg.has_emmc || i == 1) { +object_property_set_uint(OBJECT(dev), "uhs", UHS_I, _fatal); +} sysbus_realize(SYS_BUS_DEVICE(dev), _fatal); mr = sys
[PATCH v3 21/21] docs: arm: xlnx-versal-virt: Add eMMC support documentation
Add details of eMMC specific machine property and example for passing eMMC device. Signed-off-by: Sai Pavan Boddu --- docs/system/arm/xlnx-versal-virt.rst | 14 ++ 1 file changed, 14 insertions(+) diff --git a/docs/system/arm/xlnx-versal-virt.rst b/docs/system/arm/xlnx-versal-virt.rst index 2602d0f..d1099fa 100644 --- a/docs/system/arm/xlnx-versal-virt.rst +++ b/docs/system/arm/xlnx-versal-virt.rst @@ -29,6 +29,7 @@ Implemented devices: - 2 GEMs (Cadence MACB Ethernet MACs) - 8 ADMA (Xilinx zDMA) channels - 2 SD Controllers +* SDHCI0 can be configured as eMMC - OCM (256KB of On Chip Memory) - DDR memory @@ -43,6 +44,19 @@ Other differences between the hardware and the QEMU model: - QEMU provides 8 virtio-mmio virtio transports; these start at address ``0xa000`` and have IRQs from 111 and upwards. +Enabling eMMC +""""""""""""" +In order to enable eMMC pass the following machine property "emmc=on". +ex: +"-M xlnx-versal-virt,emmc=on" + +Above switch would configure SDHCI0 to accept eMMC. More details on eMMC +emulation can be found in docs/devel/emmc.txt. + +Below is the command to pass eMMC device. +"-drive file=emmc.img,if=none,id=emmc,format=raw + -device emmc,drive=emmc,id=emmc0,bus=/sdhci0/sd-bus" + Running """"""" If the user provides an Operating System to be loaded, we expect users -- 2.7.4
[PATCH v3 00/21] eMMC support
Hi, This patch series add support for eMMC cards. This work was previosly submitted by Vincent, rebased few changes on top. Cedric & Joel has helped to added boot partition access support. I expect them to make a follow-up series to use it with aspeed machines. Present series adds eMMC support to Versal SOC. Initial patch series version is RFC Changes for V2: Split Patch 1 Add comments for eMMC Erase commands Added documentation about eMMC and Versal-virt board. Make eMMC optional for xlnx-versal-virt machines Changes for V3: Revome addition of EMMC drive flag Add TYPE_EMMC device Add id strings for shci instances Update versal doc with eMMC example Fix signed-off-by lines for few patches Cédric Le Goater (1): sd: sdmmc-internal: Add command string for SEND_OP_CMD Joel Stanley (2): sd: emmc: Support boot area in emmc image sd: emmc: Subtract bootarea size from blk Sai Pavan Boddu (14): sd: sd: Remove usage of tabs in the file sd: emmc: Add support for eMMC cards sd: emmc: Dont not update CARD_CAPACITY for eMMC cards sd: emmc: Update CMD1 definition for eMMC sd: emmc: support idle state in CMD2 sd: emmc: Add mmc switch function support sd: emmc: add CMD21 tuning sequence sd: emmc: Make ACMD41 illegal for mmc sd: emmc: Add support for emmc erase sd: emmc: Update CID structure for eMMC sd: sdhci: Support eMMC devices arm: xlnx-versal: Add emmc to versal docs: devel: emmc: Add a doc for emmc card emulation docs: arm: xlnx-versal-virt: Add eMMC support documentation Vincent Palatin (4): sd: emmc: Update SET_RELATIVE_ADDR command sd: emmc: update OCR fields for eMMC sd: emmc: Add support for EXT_CSD & CSD for eMMC sd: emmc: Update CMD8 to send EXT_CSD register docs/devel/emmc.txt | 16 + docs/system/arm/xlnx-versal-virt.rst | 14 + hw/sd/sdmmc-internal.h | 97 ++ include/hw/arm/xlnx-versal.h | 1 + include/hw/sd/sd.h | 2 + hw/arm/xlnx-versal-virt.c| 29 +- hw/arm/xlnx-versal.c | 14 +- hw/sd/sd.c | 563 ++- hw/sd/sdhci.c| 4 - hw/sd/sdmmc-internal.c | 2 +- 10 files changed, 594 insertions(+), 148 deletions(-) create mode 100644 docs/devel/emmc.txt -- 2.7.4
[PATCH v3 10/21] sd: emmc: support idle state in CMD2
eMMC is expected to be in idle-state post CMD1. Ready state is an intermediate stage which we don't come across in Device identification mode. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis --- hw/sd/sd.c | 4 1 file changed, 4 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 054ad1e..8a7d0de 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1059,6 +1059,10 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (sd->spi) goto bad_cmd; switch (sd->state) { +case sd_idle_state: +if (!sd->emmc) { +break; +} case sd_ready_state: sd->state = sd_identification_state; return sd_r2_i; -- 2.7.4
[PATCH v3 12/21] sd: emmc: add CMD21 tuning sequence
eMMC cards support tuning sequence for entering HS200 mode. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 47 +++ 1 file changed, 47 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bf963ec..174c28e 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1386,6 +1386,14 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; +case 21:/* CMD21: mmc SEND TUNING_BLOCK */ +if (sd->emmc && (sd->state == sd_transfer_state)) { +sd->state = sd_sendingdata_state; +sd->data_offset = 0; +return sd_r1; +} +break; + case 23:/* CMD23: SET_BLOCK_COUNT */ if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { break; @@ -2120,6 +2128,30 @@ static const uint8_t sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = { 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, }; +#define EXCSD_BUS_WIDTH_OFFSET 183 +#define BUS_WIDTH_8_MASK0x4 +#define BUS_WIDTH_4_MASK0x2 +#define MMC_TUNING_BLOCK_SIZE 128 + +static const uint8_t mmc_tunning_block_pattern[128] = { + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, + 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, + 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, + 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, + 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, + 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, + 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, + 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, + 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, + 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, + 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, +}; + uint8_t sd_read_byte(SDState *sd) { /* TODO: Append CRCs */ @@ -2213,6 +2245,21 @@ uint8_t sd_read_byte(SDState *sd) ret = sd_tuning_block_pattern[sd->data_offset++]; break; +case 21:/* CMD21: SEND_TUNNING_BLOCK (MMC) */ +if (sd->data_offset >= MMC_TUNING_BLOCK_SIZE - 1) { +sd->state = sd_transfer_state; +} +if (sd->ext_csd[EXCSD_BUS_WIDTH_OFFSET] & BUS_WIDTH_8_MASK) { +ret = mmc_tunning_block_pattern[sd->data_offset++]; +} else { +/* Return LSB Nibbles of two byte from the 8bit tuning block + * for 4bit mode + */ +ret = mmc_tunning_block_pattern[sd->data_offset++] & 0x0F; +ret |= (mmc_tunning_block_pattern[sd->data_offset++] & 0x0F) << 4; +} +break; + case 22:/* ACMD22: SEND_NUM_WR_BLOCKS */ ret = sd->data[sd->data_offset ++]; -- 2.7.4
[PATCH v3 20/21] docs: devel: emmc: Add a doc for emmc card emulation
Add few simple steps to create emmc card with boot and user data partitions. Signed-off-by: Sai Pavan Boddu --- docs/devel/emmc.txt | 16 1 file changed, 16 insertions(+) create mode 100644 docs/devel/emmc.txt diff --git a/docs/devel/emmc.txt b/docs/devel/emmc.txt new file mode 100644 index 000..2d098fe --- /dev/null +++ b/docs/devel/emmc.txt @@ -0,0 +1,16 @@ + +eMMC block emulation + + +Any eMMC devices has 3 kinds of partitions Boot, RPMB and User data. We +are supporting Boot and User data partitions. Boot area partitions are +expected to be 1MB size as hard coded in EXT_CSD register. + +Below is the example of combining two 1MB bootarea partition and +user data partitions. + + cat mmc-bootarea0.bin mmc-bootarea1.bin image.wic > mmc.img + qemu-img resize mmc.img 4G + +Note: mmc-bootarea0/1 are just raw paritions. User data can have +partition tables. -- 2.7.4
[PATCH v3 06/21] sd: emmc: Update CMD8 to send EXT_CSD register
From: Vincent Palatin Sends the EXT_CSD register as response to CMD8. Signed-off-by: Vincent Palatin Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 52 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a26695b..181e7e2 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1141,24 +1141,37 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; -case 8: /* CMD8: SEND_IF_COND */ -if (sd->spec_version < SD_PHY_SPECv2_00_VERS) { -break; -} -if (sd->state != sd_idle_state) { -break; -} -sd->vhs = 0; - -/* No response if not exactly one VHS bit is set. */ -if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) { -return sd->spi ? sd_r7 : sd_r0; -} +case 8:/* CMD8: SEND_IF_COND / SEND_EXT_CSD */ +if (sd->emmc) { +switch (sd->state) { +case sd_transfer_state: +/* MMC : Sends the EXT_CSD register as a Block of data */ +sd->state = sd_sendingdata_state; +memcpy(sd->data, sd->ext_csd, sizeof(sd->ext_csd)); +sd->data_start = addr; +sd->data_offset = 0; +return sd_r1; +default: +break; +} +} else { +if (sd->spec_version < SD_PHY_SPECv2_00_VERS) { +break; +} +if (sd->state != sd_idle_state) { +break; +} +sd->vhs = 0; -/* Accept. */ -sd->vhs = req.arg; -return sd_r7; +/* No response if not exactly one VHS bit is set. */ +if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) { +return sd->spi ? sd_r7 : sd_r0; +} +/* Accept. */ +sd->vhs = req.arg; +return sd_r7; +} case 9: /* CMD9: SEND_CSD */ switch (sd->state) { case sd_standby_state: @@ -2081,6 +2094,13 @@ uint8_t sd_read_byte(SDState *sd) sd->state = sd_transfer_state; break; +case 8: /* CMD8: SEND_EXT_CSD on MMC */ +ret = sd->data[sd->data_offset++]; +if (sd->data_offset >= sizeof(sd->ext_csd)) { +sd->state = sd_transfer_state; +} +break; + case 9: /* CMD9: SEND_CSD */ case 10:/* CMD10: SEND_CID */ ret = sd->data[sd->data_offset ++]; -- 2.7.4
[PATCH v3 13/21] sd: emmc: Make ACMD41 illegal for mmc
ACMD41 is not applicable for eMMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 174c28e..09c1222 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1737,6 +1737,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd, break; case 41:/* ACMD41: SD_APP_OP_COND */ +if (sd->emmc) { +break; +} if (sd->spi) { /* SEND_OP_CMD */ sd->state = sd_transfer_state; -- 2.7.4
[PATCH v3 01/21] sd: sd: Remove usage of tabs in the file
Set tabstop as 4 and used expandtabs Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 190 ++--- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 8517dbc..74b9162 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -332,39 +332,39 @@ static void sd_set_scr(SDState *sd) sd->scr[7] = 0x00; } -#define MID0xaa -#define OID"XY" -#define PNM"QEMU!" -#define PRV0x01 -#define MDT_YR 2006 -#define MDT_MON2 +#define MID 0xaa +#define OID "XY" +#define PNM "QEMU!" +#define PRV 0x01 +#define MDT_YR 2006 +#define MDT_MON 2 static void sd_set_cid(SDState *sd) { -sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ -sd->cid[1] = OID[0]; /* OEM/Application ID (OID) */ +sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ +sd->cid[1] = OID[0];/* OEM/Application ID (OID) */ sd->cid[2] = OID[1]; -sd->cid[3] = PNM[0]; /* Fake product name (PNM) */ +sd->cid[3] = PNM[0];/* Fake product name (PNM) */ sd->cid[4] = PNM[1]; sd->cid[5] = PNM[2]; sd->cid[6] = PNM[3]; sd->cid[7] = PNM[4]; -sd->cid[8] = PRV; /* Fake product revision (PRV) */ -sd->cid[9] = 0xde; /* Fake serial number (PSN) */ +sd->cid[8] = PRV; /* Fake product revision (PRV) */ +sd->cid[9] = 0xde; /* Fake serial number (PSN) */ sd->cid[10] = 0xad; sd->cid[11] = 0xbe; sd->cid[12] = 0xef; -sd->cid[13] = 0x00 | /* Manufacture date (MDT) */ +sd->cid[13] = 0x00 |/* Manufacture date (MDT) */ ((MDT_YR - 2000) / 10); sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; } -#define HWBLOCK_SHIFT 9 /* 512 bytes */ -#define SECTOR_SHIFT 5 /* 16 kilobytes */ -#define WPGROUP_SHIFT 7 /* 2 megs */ -#define CMULT_SHIFT9 /* 512 times HWBLOCK_SIZE */ -#define WPGROUP_SIZE (1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) +#define HWBLOCK_SHIFT 9 /* 512 bytes */ +#define SECTOR_SHIFT5 /* 16 kilobytes */ +#define WPGROUP_SHIFT 7 /* 2 megs */ +#define CMULT_SHIFT 9 /* 512 times HWBLOCK_SIZE */ +#define WPGROUP_SIZE(1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) static const uint8_t sd_csd_rw_mask[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -385,31 +385,31 @@ static void sd_set_csd(SDState *sd, uint64_t size) csize = (size >> (CMULT_SHIFT + hwblock_shift)) - 1; if (size <= SDSC_MAX_CAPACITY) { /* Standard Capacity SD */ -sd->csd[0] = 0x00; /* CSD structure */ -sd->csd[1] = 0x26; /* Data read access-time-1 */ -sd->csd[2] = 0x00; /* Data read access-time-2 */ +sd->csd[0] = 0x00; /* CSD structure */ +sd->csd[1] = 0x26; /* Data read access-time-1 */ +sd->csd[2] = 0x00; /* Data read access-time-2 */ sd->csd[3] = 0x32; /* Max. data transfer rate: 25 MHz */ -sd->csd[4] = 0x5f; /* Card Command Classes */ -sd->csd[5] = 0x50 |/* Max. read data block length */ +sd->csd[4] = 0x5f; /* Card Command Classes */ +sd->csd[5] = 0x50 | /* Max. read data block length */ hwblock_shift; -sd->csd[6] = 0xe0 |/* Partial block for read allowed */ +sd->csd[6] = 0xe0 | /* Partial block for read allowed */ ((csize >> 10) & 0x03); -sd->csd[7] = 0x00 |/* Device size */ +sd->csd[7] = 0x00 | /* Device size */ ((csize >> 2) & 0xff); -sd->csd[8] = 0x3f |/* Max. read current */ +sd->csd[8] = 0x3f | /* Max. read current */ ((csize << 6) & 0xc0); -sd->csd[9] = 0xfc |/* Max. write current */ +sd->csd[9] = 0xfc | /* Max. write current */ ((CMULT_SHIFT - 2) >> 1); -sd->csd[10] = 0x40 | /* Erase sector size */ +sd->csd[10] = 0x40 |/* Erase sector size */ (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1); -sd->csd[11] = 0x00 | /* Write protect group size */ +sd->csd[11] = 0x00 |/* Write protect group size */ ((sectsize << 7) & 0x80) | wpsize; -sd->csd[12] = 0x90 | /* Write speed factor */ +sd->csd[12] = 0x90 |/* Write speed factor */ (hwblock_shift >> 2); -sd->csd[13] = 0x20 | /* Max. write data block length */ +sd->csd[13] = 0x20 |/* Max. write data block length */ ((hwblock_shift << 6) &am
[PATCH v3 11/21] sd: emmc: Add mmc switch function support
switch operation in eMMC card updates the ext_csd register to request changes in card operations. Here we implement similar sequence but requests are mostly dummy and make no change. Implement SWITCH_ERROR if the write operation extends goes beyond length of ext_csd. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 56 ++-- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 8a7d0de..bf963ec 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -523,6 +523,7 @@ static void sd_set_rca(SDState *sd, uint16_t value) FIELD(CSR, AKE_SEQ_ERROR, 3, 1) FIELD(CSR, APP_CMD, 5, 1) FIELD(CSR, FX_EVENT,6, 1) +FIELD(CSR, SWITCH_ERROR,7, 1) FIELD(CSR, READY_FOR_DATA, 8, 1) FIELD(CSR, CURRENT_STATE, 9, 4) FIELD(CSR, ERASE_RESET,13, 1) @@ -886,6 +887,43 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) return ret; } +enum { +MMC_CMD6_ACCESS_COMMAND_SET = 0, +MMC_CMD6_ACCESS_SET_BITS, +MMC_CMD6_ACCESS_CLEAR_BITS, +MMC_CMD6_ACCESS_WRITE_BYTE, +}; + +static void mmc_function_switch(SDState *sd, uint32_t arg) +{ +uint32_t access = extract32(arg, 24, 2); +uint32_t index = extract32(arg, 16, 8); +uint32_t value = extract32(arg, 8, 8); +uint8_t b = sd->ext_csd[index]; + +switch (access) { +case MMC_CMD6_ACCESS_COMMAND_SET: +qemu_log_mask(LOG_UNIMP, "MMC Command set switching not supported\n"); +return; +case MMC_CMD6_ACCESS_SET_BITS: +b |= value; +break; +case MMC_CMD6_ACCESS_CLEAR_BITS: +b &= ~value; +break; +case MMC_CMD6_ACCESS_WRITE_BYTE: +b = value; +break; +} + +if (index >= 192) { +sd->card_status |= R_CSR_SWITCH_ERROR_MASK; +return; +} + +sd->ext_csd[index] = b; +} + static void sd_function_switch(SDState *sd, uint32_t arg) { int i, mode, new_func; @@ -1105,12 +1143,18 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 6: /* CMD6: SWITCH_FUNCTION */ switch (sd->mode) { case sd_data_transfer_mode: -sd_function_switch(sd, req.arg); -sd->state = sd_sendingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; - +if (sd->emmc) { +sd->state = sd_programming_state; +mmc_function_switch(sd, req.arg); +sd->state = sd_transfer_state; +return sd_r1b; +} else { +sd_function_switch(sd, req.arg); +sd->state = sd_sendingdata_state; +sd->data_start = 0; +sd->data_offset = 0; +return sd_r1; +} default: break; } -- 2.7.4
[PATCH v3 03/21] sd: emmc: Update SET_RELATIVE_ADDR command
From: Vincent Palatin Change SET_RELATIVE_ADDR command to assign relative address as requested by user. Signed-off-by: Vincent Palatin Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater [spb: Split original patch series] Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 12 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a23af6d..6de414b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -436,9 +436,13 @@ static void sd_set_csd(SDState *sd, uint64_t size) sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1; } -static void sd_set_rca(SDState *sd) +static void sd_set_rca(SDState *sd, uint16_t value) { -sd->rca += 0x4567; +if (sd->emmc) { +sd->rca = value; +} else { +sd->rca += 0x4567; +} } FIELD(CSR, AKE_SEQ_ERROR, 3, 1) @@ -984,8 +988,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case sd_identification_state: case sd_standby_state: sd->state = sd_standby_state; -sd_set_rca(sd); -return sd_r6; +sd_set_rca(sd, req.arg >> 16); +return sd->emmc ? sd_r1 : sd_r6; default: break; -- 2.7.4
[PATCH v3 08/21] sd: emmc: Dont not update CARD_CAPACITY for eMMC cards
OCR.CARD_CAPACITY field is only valid for sd cards, So skip it for eMMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis --- hw/sd/sd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 181e7e2..2612135 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -328,7 +328,8 @@ static void sd_ocr_powerup(void *opaque) /* card power-up OK */ sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_POWER_UP, 1); -if (sd->size > SDSC_MAX_CAPACITY) { +/* eMMC supports only Byte mode */ +if (!sd->emmc && sd->size > SDSC_MAX_CAPACITY) { sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_CAPACITY, 1); } } -- 2.7.4
[PATCH v3 15/21] sd: emmc: Update CID structure for eMMC
CID structure is little different for eMMC, w.r.t to product name and manufacturing date. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 47 ++- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bba0446..08b77ad 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -365,23 +365,36 @@ static void sd_set_scr(SDState *sd) static void sd_set_cid(SDState *sd) { -sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ -sd->cid[1] = OID[0];/* OEM/Application ID (OID) */ -sd->cid[2] = OID[1]; -sd->cid[3] = PNM[0];/* Fake product name (PNM) */ -sd->cid[4] = PNM[1]; -sd->cid[5] = PNM[2]; -sd->cid[6] = PNM[3]; -sd->cid[7] = PNM[4]; -sd->cid[8] = PRV; /* Fake product revision (PRV) */ -sd->cid[9] = 0xde; /* Fake serial number (PSN) */ -sd->cid[10] = 0xad; -sd->cid[11] = 0xbe; -sd->cid[12] = 0xef; -sd->cid[13] = 0x00 |/* Manufacture date (MDT) */ -((MDT_YR - 2000) / 10); -sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; -sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; +if (sd->emmc) { +sd->cid[0] = MID; +sd->cid[1] = 0x1; /* CBX */ +sd->cid[2] = OID[0];/* OEM/Application ID (OID) */ +sd->cid[8] = 0x0; +sd->cid[9] = PRV;/* Fake product revision (PRV) */ +sd->cid[10] = 0xde; /* Fake serial number (PSN) */ +sd->cid[11] = 0xad; +sd->cid[12] = 0xbe; +sd->cid[13] = 0xef; +sd->cid[14] = ((MDT_YR - 1997) % 0x10); /* MDT */ +} else { +sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ +sd->cid[1] = OID[0];/* OEM/Application ID (OID) */ +sd->cid[2] = OID[1]; +sd->cid[8] = PRV; /* Fake product revision (PRV) */ +sd->cid[9] = 0xde; /* Fake serial number (PSN) */ +sd->cid[10] = 0xad; +sd->cid[11] = 0xbe; +sd->cid[12] = 0xef; +sd->cid[13] = 0x00 |/* Manufacture date (MDT) */ +((MDT_YR - 2000) / 10); +sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; + } + sd->cid[3] = PNM[0];/* Fake product name (PNM) 48bit */ + sd->cid[4] = PNM[1]; + sd->cid[5] = PNM[2]; + sd->cid[6] = PNM[3]; + sd->cid[7] = PNM[4]; + sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; } #define HWBLOCK_SHIFT 9 /* 512 bytes */ -- 2.7.4
[PATCH v3 09/21] sd: emmc: Update CMD1 definition for eMMC
Add support to Power up the card and send response r3 in case of eMMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis --- hw/sd/sd.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 2612135..054ad1e 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1041,8 +1041,16 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 1: /* CMD1: SEND_OP_CMD */ -if (!sd->spi) +/* MMC: Powerup & send r3 + * SD: send r1 in spi mode + */ +if (sd->emmc) { +sd_ocr_powerup(sd); +return sd->state == sd_idle_state ? + sd_r3 : sd_r0; +} else if (!sd->spi) { goto bad_cmd; +} sd->state = sd_transfer_state; return sd_r1; -- 2.7.4
[PATCH v3 07/21] sd: sdmmc-internal: Add command string for SEND_OP_CMD
From: Cédric Le Goater This adds extra info to trace log. Signed-off-by: Sai Pavan Boddu --- hw/sd/sdmmc-internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd/sdmmc-internal.c b/hw/sd/sdmmc-internal.c index 2053def..8648a78 100644 --- a/hw/sd/sdmmc-internal.c +++ b/hw/sd/sdmmc-internal.c @@ -14,7 +14,7 @@ const char *sd_cmd_name(uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [0]= "GO_IDLE_STATE", + [0]= "GO_IDLE_STATE", [1]= "SEND_OP_CMD", [2]= "ALL_SEND_CID",[3]= "SEND_RELATIVE_ADDR", [4]= "SET_DSR", [5]= "IO_SEND_OP_COND", [6]= "SWITCH_FUNC", [7]= "SELECT/DESELECT_CARD", -- 2.7.4
[PATCH v3 02/21] sd: emmc: Add support for eMMC cards
Add eMMC device built on top of SD card. Signed-off-by: Sai Pavan Boddu --- include/hw/sd/sd.h | 2 ++ hw/sd/sd.c | 20 2 files changed, 22 insertions(+) diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index 05ef9b7..b402dad 100644 --- a/include/hw/sd/sd.h +++ b/include/hw/sd/sd.h @@ -90,6 +90,8 @@ typedef struct { } SDRequest; +#define TYPE_EMMC "emmc" +OBJECT_DECLARE_SIMPLE_TYPE(EMMCState, EMMC) #define TYPE_SD_CARD "sd-card" OBJECT_DECLARE_TYPE(SDState, SDCardClass, SD_CARD) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 74b9162..a23af6d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -108,6 +108,7 @@ struct SDState { uint8_t spec_version; BlockBackend *blk; bool spi; +bool emmc; /* Runtime changeables */ @@ -143,6 +144,10 @@ struct SDState { bool cmd_line; }; +struct EMMCState { +SDState parent; +}; + static void sd_realize(DeviceState *dev, Error **errp); static const char *sd_state_name(enum SDCardStates state) @@ -2105,6 +2110,13 @@ static void sd_instance_init(Object *obj) sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd); } +static void emmc_instance_init(Object *obj) +{ +SDState *sd = SD_CARD(obj); + +sd->emmc = true; +} + static void sd_instance_finalize(Object *obj) { SDState *sd = SD_CARD(obj); @@ -2213,9 +2225,17 @@ static const TypeInfo sd_info = { .instance_finalize = sd_instance_finalize, }; +static const TypeInfo emmc_info = { +.name = TYPE_EMMC, +.parent = TYPE_SD_CARD, +.instance_size = sizeof(EMMCState), +.instance_init = emmc_instance_init, +}; + static void sd_register_types(void) { type_register_static(_info); +type_register_static(_info); } type_init(sd_register_types) -- 2.7.4
RE: [PATCH v2 01/22] block: add eMMC block device type
Hi Cedric, > -Original Message- > From: Cédric Le Goater > Sent: Wednesday, February 24, 2021 7:25 PM > To: Stefan Hajnoczi ; Sai Pavan Boddu > > Cc: Philippe Mathieu-Daudé ; Markus Armbruster > ; Kevin Wolf ; Max Reitz > ; Vladimir Sementsov-Ogievskiy > ; Eric Blake ; Joel Stanley > ; Vincent Palatin ; Dr. David Alan > Gilbert ; Thomas Huth ; Peter > Maydell ; Alistair Francis > ; Edgar Iglesias ; Luc Michel > ; Paolo Bonzini ; qemu- > de...@nongnu.org; qemu-bl...@nongnu.org > Subject: Re: [PATCH v2 01/22] block: add eMMC block device type > > On 2/24/21 12:40 PM, Stefan Hajnoczi wrote: > > On Tue, Feb 23, 2021 at 05:35:20PM +, Sai Pavan Boddu wrote: > >> Hi Philippe, > >> > >>> -Original Message- > >>> From: Philippe Mathieu-Daudé > >>> Sent: Monday, February 22, 2021 5:34 PM > >>> To: Sai Pavan Boddu ; Markus Armbruster > >>> ; Kevin Wolf ; Max Reitz > >>> ; Vladimir Sementsov-Ogievskiy > >>> ; Eric Blake ; Joel > >>> Stanley ; Cédric Le Goater ; Vincent > >>> Palatin ; Dr. David Alan Gilbert > >>> ; Thomas Huth ; Stefan > >>> Hajnoczi ; Peter Maydell > >>> ; Alistair Francis > >>> ; Edgar Iglesias ; Luc > >>> Michel ; Paolo Bonzini > >>> > >>> Cc: Sai Pavan Boddu ; qemu-devel@nongnu.org; > >>> qemu- bl...@nongnu.org > >>> Subject: Re: [PATCH v2 01/22] block: add eMMC block device type > >>> > >>> On 2/22/21 9:20 AM, Sai Pavan Boddu wrote: > >>>> From: Vincent Palatin > >>>> > >>>> Add new block device type. > >>>> > >>>> Signed-off-by: Vincent Palatin > >>>> [SPB: Rebased over 5.1 version] > >>>> Signed-off-by: Sai Pavan Boddu > >>>> Signed-off-by: Joel Stanley > >>>> Signed-off-by: Cédric Le Goater > >>>> Reviewed-by: Alistair Francis > >>>> --- > >>>> include/sysemu/blockdev.h | 1 + > >>>> blockdev.c| 1 + > >>>> 2 files changed, 2 insertions(+) > >>>> > >>>> diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h > >>>> index 3b5fcda..eefae9f 100644 > >>>> --- a/include/sysemu/blockdev.h > >>>> +++ b/include/sysemu/blockdev.h > >>>> @@ -24,6 +24,7 @@ typedef enum { > >>>> */ > >>>> IF_NONE = 0, > >>>> IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, > >>>> IF_VIRTIO, IF_XEN, > >>>> +IF_EMMC, > >>>> IF_COUNT > >>>> } BlockInterfaceType; > >>>> > >>>> diff --git a/blockdev.c b/blockdev.c index cd438e6..390d43c 100644 > >>>> --- a/blockdev.c > >>>> +++ b/blockdev.c > >>>> @@ -83,6 +83,7 @@ static const char *const if_name[IF_COUNT] = { > >>>> [IF_SD] = "sd", > >>>> [IF_VIRTIO] = "virtio", > >>>> [IF_XEN] = "xen", > >>>> +[IF_EMMC] = "emmc", > >>>> }; > >>> > >>> We don't need to introduce support for the legacy -drive magic. > >>> > >>> -device should be enough for this device, right? > >> [Sai Pavan Boddu] I was seeing to use -device for emmc. But I see we > anyway need blockdev support for this, which would require us the use -drive. > >> > >> Can you give some pointers, how to approach this ? > > > > It is probably not necessary to add a new IF_ constant. Would this work: > > > > -drive if=none,id=emmc0,file=test.img,format=raw > > -device emmc,...,drive=emmc0 > > > > Or the more modern: > > > > -blockdev node-name=emmc0,driver=file,filename=test.img > > -device emmc,...,drive=emmc0 > > > > ? > > > > (The syntax might need small tweaks but is shows the general idea.) > > Yes. This is better. > > We could have an "emmc" device inheriting from "sd-card". The "emmc" > property would not be necessary anymore and may be, we could cleanup up > some parts doing : > > if (sd->emmc) { /* eMMC */ > ... > } else { > > } > > with SDCardClass handlers. the SWITCH_FUNCTION command is a good > candidate, CMD8 also. [Sai Pavan Boddu] Nice, this approach looks clean. But we still may be depending on emmc property. Not sure! I would get back with v3, your review on those patches would be great. Thanks & Regards, Sai Pavan > > C.
RE: [PATCH v2 01/22] block: add eMMC block device type
Hi Stefan > -Original Message- > From: Stefan Hajnoczi > Sent: Wednesday, February 24, 2021 5:10 PM > To: Sai Pavan Boddu > Cc: Philippe Mathieu-Daudé ; Markus Armbruster > ; Kevin Wolf ; Max Reitz > ; Vladimir Sementsov-Ogievskiy > ; Eric Blake ; Joel Stanley > ; Cédric Le Goater ; Vincent Palatin > ; Dr. David Alan Gilbert ; > Thomas Huth ; Peter Maydell > ; Alistair Francis ; Edgar > Iglesias ; Luc Michel ; Paolo > Bonzini ; qemu-devel@nongnu.org; qemu- > bl...@nongnu.org > Subject: Re: [PATCH v2 01/22] block: add eMMC block device type > > On Tue, Feb 23, 2021 at 05:35:20PM +, Sai Pavan Boddu wrote: > > Hi Philippe, > > > > > -Original Message- > > > From: Philippe Mathieu-Daudé > > > Sent: Monday, February 22, 2021 5:34 PM > > > To: Sai Pavan Boddu ; Markus Armbruster > > > ; Kevin Wolf ; Max Reitz > > > ; Vladimir Sementsov-Ogievskiy > > > ; Eric Blake ; Joel > > > Stanley ; Cédric Le Goater ; Vincent > > > Palatin ; Dr. David Alan Gilbert > > > ; Thomas Huth ; Stefan > > > Hajnoczi ; Peter Maydell > > > ; Alistair Francis > > > ; Edgar Iglesias ; Luc > > > Michel ; Paolo Bonzini > > > > > > Cc: Sai Pavan Boddu ; qemu-devel@nongnu.org; > > > qemu- bl...@nongnu.org > > > Subject: Re: [PATCH v2 01/22] block: add eMMC block device type > > > > > > On 2/22/21 9:20 AM, Sai Pavan Boddu wrote: > > > > From: Vincent Palatin > > > > > > > > Add new block device type. > > > > > > > > Signed-off-by: Vincent Palatin > > > > [SPB: Rebased over 5.1 version] > > > > Signed-off-by: Sai Pavan Boddu > > > > Signed-off-by: Joel Stanley > > > > Signed-off-by: Cédric Le Goater > > > > Reviewed-by: Alistair Francis > > > > --- > > > > include/sysemu/blockdev.h | 1 + > > > > blockdev.c| 1 + > > > > 2 files changed, 2 insertions(+) > > > > > > > > diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h > > > > index 3b5fcda..eefae9f 100644 > > > > --- a/include/sysemu/blockdev.h > > > > +++ b/include/sysemu/blockdev.h > > > > @@ -24,6 +24,7 @@ typedef enum { > > > > */ > > > > IF_NONE = 0, > > > > IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, > > > > IF_VIRTIO, IF_XEN, > > > > +IF_EMMC, > > > > IF_COUNT > > > > } BlockInterfaceType; > > > > > > > > diff --git a/blockdev.c b/blockdev.c index cd438e6..390d43c 100644 > > > > --- a/blockdev.c > > > > +++ b/blockdev.c > > > > @@ -83,6 +83,7 @@ static const char *const if_name[IF_COUNT] = { > > > > [IF_SD] = "sd", > > > > [IF_VIRTIO] = "virtio", > > > > [IF_XEN] = "xen", > > > > +[IF_EMMC] = "emmc", > > > > }; > > > > > > We don't need to introduce support for the legacy -drive magic. > > > > > > -device should be enough for this device, right? > > [Sai Pavan Boddu] I was seeing to use -device for emmc. But I see we anyway > need blockdev support for this, which would require us the use -drive. > > > > Can you give some pointers, how to approach this ? > > It is probably not necessary to add a new IF_ constant. Would this work: > > -drive if=none,id=emmc0,file=test.img,format=raw > -device emmc,...,drive=emmc0 [Sai Pavan Boddu] Great, this works for me. > > Or the more modern: > > -blockdev node-name=emmc0,driver=file,filename=test.img > -device emmc,...,drive=emmc0 [Sai Pavan Boddu] Thanks, I would try to follow the modern approach then! Regards, Sai Pavan > > ? > > (The syntax might need small tweaks but is shows the general idea.) > > Stefan
RE: [PATCH v2 01/22] block: add eMMC block device type
Hi Philippe, > -Original Message- > From: Philippe Mathieu-Daudé > Sent: Monday, February 22, 2021 5:34 PM > To: Sai Pavan Boddu ; Markus Armbruster > ; Kevin Wolf ; Max Reitz > ; Vladimir Sementsov-Ogievskiy > ; Eric Blake ; Joel Stanley > ; Cédric Le Goater ; Vincent Palatin > ; Dr. David Alan Gilbert ; > Thomas Huth ; Stefan Hajnoczi ; > Peter Maydell ; Alistair Francis > ; Edgar Iglesias ; Luc Michel > ; Paolo Bonzini > Cc: Sai Pavan Boddu ; qemu-devel@nongnu.org; qemu- > bl...@nongnu.org > Subject: Re: [PATCH v2 01/22] block: add eMMC block device type > > On 2/22/21 9:20 AM, Sai Pavan Boddu wrote: > > From: Vincent Palatin > > > > Add new block device type. > > > > Signed-off-by: Vincent Palatin > > [SPB: Rebased over 5.1 version] > > Signed-off-by: Sai Pavan Boddu > > Signed-off-by: Joel Stanley > > Signed-off-by: Cédric Le Goater > > Reviewed-by: Alistair Francis > > --- > > include/sysemu/blockdev.h | 1 + > > blockdev.c| 1 + > > 2 files changed, 2 insertions(+) > > > > diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h > > index 3b5fcda..eefae9f 100644 > > --- a/include/sysemu/blockdev.h > > +++ b/include/sysemu/blockdev.h > > @@ -24,6 +24,7 @@ typedef enum { > > */ > > IF_NONE = 0, > > IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, > > IF_XEN, > > +IF_EMMC, > > IF_COUNT > > } BlockInterfaceType; > > > > diff --git a/blockdev.c b/blockdev.c > > index cd438e6..390d43c 100644 > > --- a/blockdev.c > > +++ b/blockdev.c > > @@ -83,6 +83,7 @@ static const char *const if_name[IF_COUNT] = { > > [IF_SD] = "sd", > > [IF_VIRTIO] = "virtio", > > [IF_XEN] = "xen", > > +[IF_EMMC] = "emmc", > > }; > > We don't need to introduce support for the legacy -drive magic. > > -device should be enough for this device, right? [Sai Pavan Boddu] I was seeing to use -device for emmc. But I see we anyway need blockdev support for this, which would require us the use -drive. Can you give some pointers, how to approach this ? Regards, Sai Pavan
RE: [PATCH v2 01/22] block: add eMMC block device type
Hi Philippe, > -Original Message- > From: Philippe Mathieu-Daudé > Sent: Monday, February 22, 2021 6:54 PM > To: Dr. David Alan Gilbert ; Markus Armbruster > > Cc: Sai Pavan Boddu ; Kevin Wolf ; > Max Reitz ; Vladimir Sementsov-Ogievskiy > ; Eric Blake ; Joel Stanley > ; Cédric Le Goater ; Vincent Palatin > ; Thomas Huth ; Stefan > Hajnoczi ; Peter Maydell ; > Alistair Francis ; Edgar Iglesias > ; > Luc Michel ; Paolo Bonzini > ; Sai Pavan Boddu ; qemu- > de...@nongnu.org; qemu-bl...@nongnu.org > Subject: Re: [PATCH v2 01/22] block: add eMMC block device type > > On 2/22/21 2:16 PM, Dr. David Alan Gilbert wrote: > > * Markus Armbruster (arm...@redhat.com) wrote: > >> Philippe Mathieu-Daudé writes: > >> > >>> On 2/22/21 9:20 AM, Sai Pavan Boddu wrote: > >>>> From: Vincent Palatin > >>>> > >>>> Add new block device type. > >>>> > >>>> Signed-off-by: Vincent Palatin > >>>> [SPB: Rebased over 5.1 version] > >>>> Signed-off-by: Sai Pavan Boddu > >>>> Signed-off-by: Joel Stanley > >>>> Signed-off-by: Cédric Le Goater > >>>> Reviewed-by: Alistair Francis > >>>> --- > >>>> include/sysemu/blockdev.h | 1 + > >>>> blockdev.c| 1 + > >>>> 2 files changed, 2 insertions(+) > >>>> > >>>> diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h > >>>> index 3b5fcda..eefae9f 100644 > >>>> --- a/include/sysemu/blockdev.h > >>>> +++ b/include/sysemu/blockdev.h > >>>> @@ -24,6 +24,7 @@ typedef enum { > >>>> */ > >>>> IF_NONE = 0, > >>>> IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, > >>>> IF_VIRTIO, IF_XEN, > >>>> +IF_EMMC, > >>>> IF_COUNT > >>>> } BlockInterfaceType; > >>>> > >>>> diff --git a/blockdev.c b/blockdev.c index cd438e6..390d43c 100644 > >>>> --- a/blockdev.c > >>>> +++ b/blockdev.c > >>>> @@ -83,6 +83,7 @@ static const char *const if_name[IF_COUNT] = { > >>>> [IF_SD] = "sd", > >>>> [IF_VIRTIO] = "virtio", > >>>> [IF_XEN] = "xen", > >>>> +[IF_EMMC] = "emmc", > >>>> }; > >>> > >>> We don't need to introduce support for the legacy -drive magic. > >>> > >>> -device should be enough for this device, right? > >> > >> External interface extensions need rationale: why do we want / need it? > >> The commit message neglects to provide one. > >> > >> Even more so when the interface in question is in a state like -drive > >> is. > > > > I wouldn't be too nasty about -drive; for me I still find it the > > easiest way to start a VM. > > But eMMC isn't a bus where you can plug drives, it is soldered on-board and is > mmio mapped to a fixed address. I don't see the point of having a drive > interface for it... [Sai Pavan Boddu] Yeah, this makes sense but having a drive would be a simple implementation without disturbing much in the sd card emulation code. And its just easy to use, just as how sd cards are inserted. I need to see, how easy it would be with -device. Thanks, Sai Pavan
RE: [PATCH v2 04/22] sd: emmc: update OCR fields for eMMC
Hi Cedric > -Original Message- > From: Cédric Le Goater > Sent: Monday, February 22, 2021 3:22 PM > To: Sai Pavan Boddu ; Markus Armbruster > ; Kevin Wolf ; Max Reitz > ; Vladimir Sementsov-Ogievskiy > ; Eric Blake ; Joel Stanley > ; Vincent Palatin ; Dr. David Alan > Gilbert ; Thomas Huth ; Stefan > Hajnoczi ; Peter Maydell ; > Alistair Francis ; Edgar Iglesias > ; > Luc Michel ; Paolo Bonzini > > Cc: qemu-bl...@nongnu.org; qemu-devel@nongnu.org; Sai Pavan Boddu > > Subject: Re: [PATCH v2 04/22] sd: emmc: update OCR fields for eMMC > > On 2/22/21 9:20 AM, Sai Pavan Boddu wrote: > > From: Vincent Palatin > > > > eMMC OCR register doesn't has UHS-II field and voltage fields are > > different. > > Can a patch be "From" a person without a "Signed-off-by" of the same person ? [Sai Pavan Boddu] No I should not be like this. My mistake, I would respin the series with corrections. Few other patches may have this after the split I did. Regards, Sai Pavan > > C. > > > Signed-off-by: Sai Pavan Boddu > > > > --- > > hw/sd/sd.c | 27 --- > > 1 file changed, 24 insertions(+), 3 deletions(-) > > > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > > index 42ee49c..430bea5 100644 > > --- a/hw/sd/sd.c > > +++ b/hw/sd/sd.c > > @@ -283,6 +283,15 @@ FIELD(OCR, UHS_II_CARD,29, 1) /* Only > UHS-II */ > > FIELD(OCR, CARD_CAPACITY, 30, 1) /* 0:SDSC, 1:SDHC/SDXC */ > > FIELD(OCR, CARD_POWER_UP, 31, 1) > > > > +/* > > + * eMMC OCR register > > + */ > > +FIELD(EMMC_OCR, VDD_WINDOW_0, 7, 1) > > +FIELD(EMMC_OCR, VDD_WINDOW_1, 8, 7) > > +FIELD(EMMC_OCR, VDD_WINDOW_2, 15, 9) > > +FIELD(EMMC_OCR, ACCESS_MODE, 29, 2) > > +FIELD(EMMC_OCR, POWER_UP, 31, 1) > > + > > #define ACMD41_ENQUIRY_MASK 0x00ff > > #define ACMD41_R3_MASK (R_OCR_VDD_VOLTAGE_WIN_HI_MASK \ > > | R_OCR_ACCEPT_SWITCH_1V8_MASK \ > > @@ -292,8 +301,16 @@ FIELD(OCR, CARD_POWER_UP, 31, 1) > > > > static void sd_set_ocr(SDState *sd) > > { > > -/* All voltages OK */ > > -sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; > > +if (sd->emmc) { > > +/* > > + * Dual Voltage eMMC card > > + */ > > +sd->ocr = R_EMMC_OCR_VDD_WINDOW_0_MASK | > > + R_EMMC_OCR_VDD_WINDOW_2_MASK; > > +} else { > > +/* All voltages OK */ > > +sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; > > +} > > } > > > > static void sd_ocr_powerup(void *opaque) @@ -521,7 +538,11 @@ static > > void sd_response_r1_make(SDState *sd, uint8_t *response) > > > > static void sd_response_r3_make(SDState *sd, uint8_t *response) { > > -stl_be_p(response, sd->ocr & ACMD41_R3_MASK); > > +if (sd->emmc) { > > +stl_be_p(response, sd->ocr); > > +} else { > > +stl_be_p(response, sd->ocr & ACMD41_R3_MASK); > > +} > > } > > > > static void sd_response_r6_make(SDState *sd, uint8_t *response) > >
[PATCH v2 19/22] sd: sdhci: Support eMMC devices
Embedded device slots should be allowed as support of eMMC is available. Signed-off-by: Sai Pavan Boddu --- hw/sd/sdhci.c | 4 1 file changed, 4 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 8ffa539..771212a 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -99,10 +99,6 @@ static void sdhci_check_capareg(SDHCIState *s, Error **errp) msk = FIELD_DP64(msk, SDHC_CAPAB, ASYNC_INT, 0); val = FIELD_EX64(s->capareg, SDHC_CAPAB, SLOT_TYPE); -if (val) { -error_setg(errp, "slot-type not supported"); -return; -} trace_sdhci_capareg("slot type", val); msk = FIELD_DP64(msk, SDHC_CAPAB, SLOT_TYPE, 0); -- 2.7.4
[PATCH v2 14/22] sd: emmc: Add support for emmc erase
Add CMD35 and CMD36 which sets the erase start and end. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index df82b61..6d2ef2b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1544,6 +1544,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Erase commands (Class 5) */ case 32:/* CMD32: ERASE_WR_BLK_START */ +case 35:/* CMD35: ERASE_GROUP_START */ switch (sd->state) { case sd_transfer_state: sd->erase_start = req.arg; @@ -1555,6 +1556,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 33:/* CMD33: ERASE_WR_BLK_END */ +case 36:/* CMD36: ERASE_GROUP_END */ switch (sd->state) { case sd_transfer_state: sd->erase_end = req.arg; -- 2.7.4
[PATCH v2 06/22] sd: emmc: Update CMD8 to send EXT_CSD register
From: Vincent Palatin Sends the EXT_CSD register as response to CMD8. Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 52 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 4c211ba..a4f93b5 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1133,24 +1133,37 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; -case 8: /* CMD8: SEND_IF_COND */ -if (sd->spec_version < SD_PHY_SPECv2_00_VERS) { -break; -} -if (sd->state != sd_idle_state) { -break; -} -sd->vhs = 0; - -/* No response if not exactly one VHS bit is set. */ -if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) { -return sd->spi ? sd_r7 : sd_r0; -} +case 8:/* CMD8: SEND_IF_COND / SEND_EXT_CSD */ +if (sd->emmc) { +switch (sd->state) { +case sd_transfer_state: +/* MMC : Sends the EXT_CSD register as a Block of data */ +sd->state = sd_sendingdata_state; +memcpy(sd->data, sd->ext_csd, sizeof(sd->ext_csd)); +sd->data_start = addr; +sd->data_offset = 0; +return sd_r1; +default: +break; +} +} else { +if (sd->spec_version < SD_PHY_SPECv2_00_VERS) { +break; +} +if (sd->state != sd_idle_state) { +break; +} +sd->vhs = 0; -/* Accept. */ -sd->vhs = req.arg; -return sd_r7; +/* No response if not exactly one VHS bit is set. */ +if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) { +return sd->spi ? sd_r7 : sd_r0; +} +/* Accept. */ +sd->vhs = req.arg; +return sd_r7; +} case 9: /* CMD9: SEND_CSD */ switch (sd->state) { case sd_standby_state: @@ -2073,6 +2086,13 @@ uint8_t sd_read_byte(SDState *sd) sd->state = sd_transfer_state; break; +case 8: /* CMD8: SEND_EXT_CSD on MMC */ +ret = sd->data[sd->data_offset++]; +if (sd->data_offset >= sizeof(sd->ext_csd)) { +sd->state = sd_transfer_state; +} +break; + case 9: /* CMD9: SEND_CSD */ case 10:/* CMD10: SEND_CID */ ret = sd->data[sd->data_offset ++]; -- 2.7.4
[PATCH v2 08/22] sd: emmc: Dont not update CARD_CAPACITY for eMMC cards
OCR.CARD_CAPACITY field is only valid for sd cards, So skip it for eMMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis --- hw/sd/sd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a4f93b5..9835f52 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -324,7 +324,8 @@ static void sd_ocr_powerup(void *opaque) /* card power-up OK */ sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_POWER_UP, 1); -if (sd->size > SDSC_MAX_CAPACITY) { +/* eMMC supports only Byte mode */ +if (!sd->emmc && sd->size > SDSC_MAX_CAPACITY) { sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_CAPACITY, 1); } } -- 2.7.4
[PATCH v2 21/22] docs: devel: emmc: Add a doc for emmc card emulation
Add few simple steps to create emmc card with boot and user data partitions. Signed-off-by: Sai Pavan Boddu --- docs/devel/emmc.txt | 16 1 file changed, 16 insertions(+) create mode 100644 docs/devel/emmc.txt diff --git a/docs/devel/emmc.txt b/docs/devel/emmc.txt new file mode 100644 index 000..2d098fe --- /dev/null +++ b/docs/devel/emmc.txt @@ -0,0 +1,16 @@ + +eMMC block emulation + + +Any eMMC devices has 3 kinds of partitions Boot, RPMB and User data. We +are supporting Boot and User data partitions. Boot area partitions are +expected to be 1MB size as hard coded in EXT_CSD register. + +Below is the example of combining two 1MB bootarea partition and +user data partitions. + + cat mmc-bootarea0.bin mmc-bootarea1.bin image.wic > mmc.img + qemu-img resize mmc.img 4G + +Note: mmc-bootarea0/1 are just raw paritions. User data can have +partition tables. -- 2.7.4
[PATCH v2 10/22] sd: emmc: support idle state in CMD2
eMMC is expected to be in idle-state post CMD1. Ready state is an intermediate stage which we don't come across in Device identification mode. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis --- hw/sd/sd.c | 4 1 file changed, 4 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 8bc8d5d..ae5c5e8 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1051,6 +1051,10 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (sd->spi) goto bad_cmd; switch (sd->state) { +case sd_idle_state: +if (!sd->emmc) { +break; +} case sd_ready_state: sd->state = sd_identification_state; return sd_r2_i; -- 2.7.4
[PATCH v2 17/22] sd: emmc: Support boot area in emmc image
From: Joel Stanley This assumes a specially constructued image: dd if=/dev/zero of=mmc-bootarea.img count=2 bs=1M dd if=u-boot-spl.bin of=mmc-bootarea.img conv=notrunc dd if=u-boot.bin of=mmc-bootarea.img conv=notrunc count=64 bs=1K cat mmc-bootarea.img obmc-phosphor-image.wic > mmc.img truncate --size 16GB mmc.img truncate --size 128MB mmc-bootarea.img Signed-off-by: Joel Stanley [clg: - changes on the definition names ] Signed-off-by: Cédric Le Goater [spb: use data_start property to access right emmc partition, Clean up PARTITION_ENABLE support as incomplete, Fix commit message to be generic.] Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 40 1 file changed, 40 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 60799aa..ab29e54 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1040,6 +1040,34 @@ static void sd_lock_command(SDState *sd) sd->card_status &= ~CARD_IS_LOCKED; } +/* + * This requires a disk image that has two boot partitions inserted at the + * beginning of it. The size of the boot partitions are configured in the + * ext_csd structure, which is hardcoded in qemu. They are currently set to + * 1MB each. + */ +static uint32_t sd_bootpart_offset(SDState *sd) +{ +unsigned int access = sd->ext_csd[EXT_CSD_PART_CONFIG] & +EXT_CSD_PART_CONFIG_ACC_MASK; +unsigned int boot_capacity = sd->ext_csd[EXT_CSD_BOOT_MULT] << 17; + +if (!sd->emmc) { +return 0; +} + +switch (access) { +case EXT_CSD_PART_CONFIG_ACC_DEFAULT: +return boot_capacity * 2; +case EXT_CSD_PART_CONFIG_ACC_BOOT0: +return 0; +case EXT_CSD_PART_CONFIG_ACC_BOOT0 + 1: +return boot_capacity * 1; +default: + g_assert_not_reached(); +} +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint32_t rca = 0x; @@ -1355,6 +1383,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_sendingdata_state; sd->data_start = addr; sd->data_offset = 0; @@ -1374,6 +1405,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_sendingdata_state; sd->data_start = addr; sd->data_offset = 0; @@ -1430,6 +1464,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_receivingdata_state; sd->data_start = addr; sd->data_offset = 0; @@ -1460,6 +1497,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_receivingdata_state; sd->data_start = addr; sd->data_offset = 0; -- 2.7.4
[PATCH v2 22/22] docs: arm: xlnx-versal-virt: Add eMMC support documentation
Add details of eMMC specific machine property. Signed-off-by: Sai Pavan Boddu --- docs/system/arm/xlnx-versal-virt.rst | 10 ++ 1 file changed, 10 insertions(+) diff --git a/docs/system/arm/xlnx-versal-virt.rst b/docs/system/arm/xlnx-versal-virt.rst index 2602d0f..a48a88d 100644 --- a/docs/system/arm/xlnx-versal-virt.rst +++ b/docs/system/arm/xlnx-versal-virt.rst @@ -29,6 +29,7 @@ Implemented devices: - 2 GEMs (Cadence MACB Ethernet MACs) - 8 ADMA (Xilinx zDMA) channels - 2 SD Controllers +* SDHCI0 can be configured as eMMC - OCM (256KB of On Chip Memory) - DDR memory @@ -43,6 +44,15 @@ Other differences between the hardware and the QEMU model: - QEMU provides 8 virtio-mmio virtio transports; these start at address ``0xa000`` and have IRQs from 111 and upwards. +Enabling eMMC +""""""""""""" +In order to enable eMMC pass the following machine property "emmc=on". +ex: +"-M xlnx-versal-virt,emmc=on" + +Above switch would configure SDHCI0 to accept eMMC card. More details on eMMC +emulation can be found in docs/devel/emmc.txt. + Running """"""" If the user provides an Operating System to be loaded, we expect users -- 2.7.4
[PATCH v2 16/22] sd: emmc: Add Extended CSD register definitions
From: Cédric Le Goater Add user friendly macros for EXT_CSD register. Signed-off-by: Cédric Le Goater [spb: Rebased over versal emmc series, updated commit message] Signed-off-by: Sai Pavan Boddu --- hw/sd/sdmmc-internal.h | 97 ++ hw/sd/sd.c | 54 +++- 2 files changed, 126 insertions(+), 25 deletions(-) diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h index d8bf17d..7ab7b4d 100644 --- a/hw/sd/sdmmc-internal.h +++ b/hw/sd/sdmmc-internal.h @@ -37,4 +37,101 @@ const char *sd_cmd_name(uint8_t cmd); */ const char *sd_acmd_name(uint8_t cmd); +/* + * EXT_CSD fields + */ + +#define EXT_CSD_CMDQ_MODE_EN15 /* R/W */ +#define EXT_CSD_FLUSH_CACHE 32 /* W */ +#define EXT_CSD_CACHE_CTRL33 /* R/W */ +#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ +#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */ +#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */ +#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */ +#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */ +#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ +#define EXT_CSD_GP_SIZE_MULT143 /* R/W */ +#define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */ +#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ +#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ +#define EXT_CSD_HPI_MGMT161 /* R/W */ +#define EXT_CSD_RST_N_FUNCTION162 /* R/W */ +#define EXT_CSD_BKOPS_EN163 /* R/W */ +#define EXT_CSD_BKOPS_START 164 /* W */ +#define EXT_CSD_SANITIZE_START165 /* W */ +#define EXT_CSD_WR_REL_PARAM166 /* RO */ +#define EXT_CSD_RPMB_MULT 168 /* RO */ +#define EXT_CSD_FW_CONFIG 169 /* R/W */ +#define EXT_CSD_BOOT_WP 173 /* R/W */ +#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ +#define EXT_CSD_PART_CONFIG 179 /* R/W */ +#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_STROBE_SUPPORT184 /* RO */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_POWER_CLASS 187 /* R/W */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_STRUCTURE 194 /* RO */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_DRIVER_STRENGTH 197 /* RO */ +#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */ +#define EXT_CSD_PART_SWITCH_TIME199 /* RO */ +#define EXT_CSD_PWR_CL_52_195 200 /* RO */ +#define EXT_CSD_PWR_CL_26_195 201 /* RO */ +#define EXT_CSD_PWR_CL_52_360 202 /* RO */ +#define EXT_CSD_PWR_CL_26_360 203 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define EXT_CSD_S_A_TIMEOUT 217 /* RO */ +#define EXT_CSD_S_C_VCCQ 219 /* RO */ +#define EXT_CSD_S_C_VCC 220 /* RO */ +#define EXT_CSD_REL_WR_SEC_C222 /* RO */ +#define EXT_CSD_HC_WP_GRP_SIZE221 /* RO */ +#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */ +#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ +#define EXT_CSD_ACC_SIZE225 /* RO */ +#define EXT_CSD_BOOT_MULT 226 /* RO */ +#define EXT_CSD_BOOT_INFO 228 /* RO */ +#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */ +#define EXT_CSD_SEC_ERASE_MULT230 /* RO */ +#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ +#define EXT_CSD_TRIM_MULT 232 /* RO */ +#define EXT_CSD_PWR_CL_200_195236 /* RO */ +#define EXT_CSD_PWR_CL_200_360237 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */ +#define EXT_CSD_BKOPS_STATUS246 /* RO */ +#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ +#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ +#define EXT_CSD_CACHE_SIZE249 /* RO, 4 bytes */ +#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */ +#define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */ +#define EXT_CSD_PRE_EOL_INFO267 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */ +#define EXT_CSD_CMDQ_DEPTH307 /* RO */ +#define EXT_CSD_CMDQ_SUPPORT308 /* RO */ +#define EXT_CSD_SUPPORTED_MODE493 /* RO */ +#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ +#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ +#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ +#define EXT_CSD_MAX_PACKED_READS 501 /* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ +#define EXT_CSD_HPI_FEATURES503 /* RO */ +#define EXT_CSD_S_CMD_SET 504 /* RO */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_WR_REL_PARAM_EN (1 << 2) +#define EXT_CSD_WR_REL_PARAM_EN_RPMB_REL_WR (1 << 4) + +#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) +#define EXT_CSD_PART_CONFIG_ACC_DEFAULT (0x0) +#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) + +#define EXT_CSD_PART_CONFIG_EN_MASK (0x7 << 3) +#define EXT_CSD_PART_CONFIG_EN_BOOT0 (0x1 << 3) +#define EXT_CSD_PART_CONFIG_EN_USER (0x7 << 3) + #endif diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 3c24810..60799aa 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -409,41 +409,45 @@ static void mmc_set_ext_
[PATCH v2 05/22] sd: emmc: Add support for EXT_CSD & CSD for eMMC
From: Vincent Palatin eMMC CSD is similar to SD with an option to refer EXT_CSD for larger devices. Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 57 +++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 430bea5..4c211ba 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -135,6 +135,7 @@ struct SDState { uint64_t data_start; uint32_t data_offset; uint8_t data[512]; +uint8_t ext_csd[512]; qemu_irq readonly_cb; qemu_irq inserted_cb; QEMUTimer *ocr_power_timer; @@ -389,6 +390,51 @@ static const uint8_t sd_csd_rw_mask[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, }; +static void mmc_set_ext_csd(SDState *sd, uint64_t size) +{ +uint32_t sectcount = size >> HWBLOCK_SHIFT; + +memset(sd->ext_csd, 0, sizeof(sd->ext_csd)); +sd->ext_csd[504] = 0x1; /* supported command sets */ +sd->ext_csd[503] = 0x1; /* HPI features */ +sd->ext_csd[502] = 0x1; /* Background operations support */ +sd->ext_csd[241] = 0xA; /* 1st initialization time after partitioning */ +sd->ext_csd[232] = 0x1; /* Trim multiplier */ +sd->ext_csd[231] = 0x15; /* Secure feature support */ +sd->ext_csd[230] = 0x96; /* Secure erase support */ +sd->ext_csd[229] = 0x96; /* Secure TRIM multiplier */ +sd->ext_csd[228] = 0x7; /* Boot information */ +sd->ext_csd[226] = 0x8; /* Boot partition size */ +sd->ext_csd[225] = 0x6; /* Access size */ +sd->ext_csd[224] = 0x4; /* HC Erase unit size */ +sd->ext_csd[223] = 0x1; /* HC erase timeout */ +sd->ext_csd[222] = 0x1; /* Reliable write sector count */ +sd->ext_csd[221] = 0x4; /* HC write protect group size */ +sd->ext_csd[220] = 0x8; /* Sleep current VCC */ +sd->ext_csd[219] = 0x7; /* Sleep current VCCQ */ +sd->ext_csd[217] = 0x11; /* Sleep/Awake timeout */ +sd->ext_csd[215] = (sectcount >> 24) & 0xff; /* Sector count */ +sd->ext_csd[214] = (sectcount >> 16) & 0xff; /* ... */ +sd->ext_csd[213] = (sectcount >> 8) & 0xff; /* ... */ +sd->ext_csd[212] = (sectcount & 0xff); /* ... */ +sd->ext_csd[210] = 0xa; /* Min write perf for 8bit@52Mhz */ +sd->ext_csd[209] = 0xa; /* Min read perf for 8bit@52Mhz */ +sd->ext_csd[208] = 0xa; /* Min write perf for 4bit@52Mhz */ +sd->ext_csd[207] = 0xa; /* Min read perf for 4bit@52Mhz */ +sd->ext_csd[206] = 0xa; /* Min write perf for 4bit@26Mhz */ +sd->ext_csd[205] = 0xa; /* Min read perf for 4bit@26Mhz */ +sd->ext_csd[199] = 0x1; /* Partition switching timing */ +sd->ext_csd[198] = 0x1; /* Out-of-interrupt busy timing */ +sd->ext_csd[196] = 0xFF; /* Card type */ +sd->ext_csd[194] = 0x2; /* CSD Structure version */ +sd->ext_csd[192] = 0x5; /* Extended CSD revision */ +sd->ext_csd[168] = 0x1; /* RPMB size */ +sd->ext_csd[160] = 0x3; /* Partinioning support */ +sd->ext_csd[159] = 0x00; /* Max enhanced area size */ +sd->ext_csd[158] = 0x00; /* ... */ +sd->ext_csd[157] = 0xEC; /* ... */ +} + static void sd_set_csd(SDState *sd, uint64_t size) { int hwblock_shift = HWBLOCK_SHIFT; @@ -402,8 +448,11 @@ static void sd_set_csd(SDState *sd, uint64_t size) } csize = (size >> (CMULT_SHIFT + hwblock_shift)) - 1; -if (size <= SDSC_MAX_CAPACITY) { /* Standard Capacity SD */ -sd->csd[0] = 0x00; /* CSD structure */ +if (size <= SDSC_MAX_CAPACITY || sd->emmc) { /* Standard Capacity SD */ +if (sd->emmc && size >= SDSC_MAX_CAPACITY) { +csize = 0xfff; +} +sd->csd[0] = sd->emmc ? 0xd0 : 0x00; /* CSD structure */ sd->csd[1] = 0x26; /* Data read access-time-1 */ sd->csd[2] = 0x00; /* Data read access-time-2 */ sd->csd[3] = 0x32; /* Max. data transfer rate: 25 MHz */ @@ -447,6 +496,10 @@ static void sd_set_csd(SDState *sd, uint64_t size) sd->csd[14] = 0x00; } sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1; + +if (sd->emmc) { +mmc_set_ext_csd(sd, size); +} } static void sd_set_rca(SDState *sd, uint16_t value) -- 2.7.4
[PATCH v2 11/22] sd: emmc: Add mmc switch function support
switch operation in eMMC card updates the ext_csd register to request changes in card operations. Here we implement similar sequence but requests are mostly dummy and make no change. Implement SWITCH_ERROR if the write operation extends goes beyond length of ext_csd. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 56 ++-- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index ae5c5e8..e50d40b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -515,6 +515,7 @@ static void sd_set_rca(SDState *sd, uint16_t value) FIELD(CSR, AKE_SEQ_ERROR, 3, 1) FIELD(CSR, APP_CMD, 5, 1) FIELD(CSR, FX_EVENT,6, 1) +FIELD(CSR, SWITCH_ERROR,7, 1) FIELD(CSR, READY_FOR_DATA, 8, 1) FIELD(CSR, CURRENT_STATE, 9, 4) FIELD(CSR, ERASE_RESET,13, 1) @@ -878,6 +879,43 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) return ret; } +enum { +MMC_CMD6_ACCESS_COMMAND_SET = 0, +MMC_CMD6_ACCESS_SET_BITS, +MMC_CMD6_ACCESS_CLEAR_BITS, +MMC_CMD6_ACCESS_WRITE_BYTE, +}; + +static void mmc_function_switch(SDState *sd, uint32_t arg) +{ +uint32_t access = extract32(arg, 24, 2); +uint32_t index = extract32(arg, 16, 8); +uint32_t value = extract32(arg, 8, 8); +uint8_t b = sd->ext_csd[index]; + +switch (access) { +case MMC_CMD6_ACCESS_COMMAND_SET: +qemu_log_mask(LOG_UNIMP, "MMC Command set switching not supported\n"); +return; +case MMC_CMD6_ACCESS_SET_BITS: +b |= value; +break; +case MMC_CMD6_ACCESS_CLEAR_BITS: +b &= ~value; +break; +case MMC_CMD6_ACCESS_WRITE_BYTE: +b = value; +break; +} + +if (index >= 192) { +sd->card_status |= R_CSR_SWITCH_ERROR_MASK; +return; +} + +sd->ext_csd[index] = b; +} + static void sd_function_switch(SDState *sd, uint32_t arg) { int i, mode, new_func; @@ -1097,12 +1135,18 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 6: /* CMD6: SWITCH_FUNCTION */ switch (sd->mode) { case sd_data_transfer_mode: -sd_function_switch(sd, req.arg); -sd->state = sd_sendingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; - +if (sd->emmc) { +sd->state = sd_programming_state; +mmc_function_switch(sd, req.arg); +sd->state = sd_transfer_state; +return sd_r1b; +} else { +sd_function_switch(sd, req.arg); +sd->state = sd_sendingdata_state; +sd->data_start = 0; +sd->data_offset = 0; +return sd_r1; +} default: break; } -- 2.7.4
[PATCH v2 07/22] sd: sdmmc-internal: Add command string for SEND_OP_CMD
From: Cédric Le Goater This adds extra info to trace log. Signed-off-by: Sai Pavan Boddu --- hw/sd/sdmmc-internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd/sdmmc-internal.c b/hw/sd/sdmmc-internal.c index 2053def..8648a78 100644 --- a/hw/sd/sdmmc-internal.c +++ b/hw/sd/sdmmc-internal.c @@ -14,7 +14,7 @@ const char *sd_cmd_name(uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [0]= "GO_IDLE_STATE", + [0]= "GO_IDLE_STATE", [1]= "SEND_OP_CMD", [2]= "ALL_SEND_CID",[3]= "SEND_RELATIVE_ADDR", [4]= "SET_DSR", [5]= "IO_SEND_OP_COND", [6]= "SWITCH_FUNC", [7]= "SELECT/DESELECT_CARD", -- 2.7.4
[PATCH v2 01/22] block: add eMMC block device type
From: Vincent Palatin Add new block device type. Signed-off-by: Vincent Palatin [SPB: Rebased over 5.1 version] Signed-off-by: Sai Pavan Boddu Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater Reviewed-by: Alistair Francis --- include/sysemu/blockdev.h | 1 + blockdev.c| 1 + 2 files changed, 2 insertions(+) diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h index 3b5fcda..eefae9f 100644 --- a/include/sysemu/blockdev.h +++ b/include/sysemu/blockdev.h @@ -24,6 +24,7 @@ typedef enum { */ IF_NONE = 0, IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN, +IF_EMMC, IF_COUNT } BlockInterfaceType; diff --git a/blockdev.c b/blockdev.c index cd438e6..390d43c 100644 --- a/blockdev.c +++ b/blockdev.c @@ -83,6 +83,7 @@ static const char *const if_name[IF_COUNT] = { [IF_SD] = "sd", [IF_VIRTIO] = "virtio", [IF_XEN] = "xen", +[IF_EMMC] = "emmc", }; static int if_max_devs[IF_COUNT] = { -- 2.7.4
[PATCH v2 12/22] sd: emmc: add CMD21 tuning sequence
eMMC cards support tuning sequence for entering HS200 mode. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 47 +++ 1 file changed, 47 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index e50d40b..d702027 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1378,6 +1378,14 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; +case 21:/* CMD21: mmc SEND TUNING_BLOCK */ +if (sd->emmc && (sd->state == sd_transfer_state)) { +sd->state = sd_sendingdata_state; +sd->data_offset = 0; +return sd_r1; +} +break; + case 23:/* CMD23: SET_BLOCK_COUNT */ if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { break; @@ -2112,6 +2120,30 @@ static const uint8_t sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = { 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, }; +#define EXCSD_BUS_WIDTH_OFFSET 183 +#define BUS_WIDTH_8_MASK0x4 +#define BUS_WIDTH_4_MASK0x2 +#define MMC_TUNING_BLOCK_SIZE 128 + +static const uint8_t mmc_tunning_block_pattern[128] = { + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, + 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, + 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, + 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, + 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, + 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, + 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, + 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, + 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, + 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, + 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, +}; + uint8_t sd_read_byte(SDState *sd) { /* TODO: Append CRCs */ @@ -2205,6 +2237,21 @@ uint8_t sd_read_byte(SDState *sd) ret = sd_tuning_block_pattern[sd->data_offset++]; break; +case 21:/* CMD21: SEND_TUNNING_BLOCK (MMC) */ +if (sd->data_offset >= MMC_TUNING_BLOCK_SIZE - 1) { +sd->state = sd_transfer_state; +} +if (sd->ext_csd[EXCSD_BUS_WIDTH_OFFSET] & BUS_WIDTH_8_MASK) { +ret = mmc_tunning_block_pattern[sd->data_offset++]; +} else { +/* Return LSB Nibbles of two byte from the 8bit tuning block + * for 4bit mode + */ +ret = mmc_tunning_block_pattern[sd->data_offset++] & 0x0F; +ret |= (mmc_tunning_block_pattern[sd->data_offset++] & 0x0F) << 4; +} +break; + case 22:/* ACMD22: SEND_NUM_WR_BLOCKS */ ret = sd->data[sd->data_offset ++]; -- 2.7.4
[PATCH v2 13/22] sd: emmc: Make ACMD41 illegal for mmc
ACMD41 is not applicable for eMMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d702027..df82b61 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1729,6 +1729,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd, break; case 41:/* ACMD41: SD_APP_OP_COND */ +if (sd->emmc) { +break; +} if (sd->spi) { /* SEND_OP_CMD */ sd->state = sd_transfer_state; -- 2.7.4
[PATCH v2 15/22] sd: emmc: Update CID structure for eMMC
CID structure is little different for eMMC, w.r.t to product name and manufacturing date. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 47 ++- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 6d2ef2b..3c24810 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -361,23 +361,36 @@ static void sd_set_scr(SDState *sd) static void sd_set_cid(SDState *sd) { -sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ -sd->cid[1] = OID[0];/* OEM/Application ID (OID) */ -sd->cid[2] = OID[1]; -sd->cid[3] = PNM[0];/* Fake product name (PNM) */ -sd->cid[4] = PNM[1]; -sd->cid[5] = PNM[2]; -sd->cid[6] = PNM[3]; -sd->cid[7] = PNM[4]; -sd->cid[8] = PRV; /* Fake product revision (PRV) */ -sd->cid[9] = 0xde; /* Fake serial number (PSN) */ -sd->cid[10] = 0xad; -sd->cid[11] = 0xbe; -sd->cid[12] = 0xef; -sd->cid[13] = 0x00 |/* Manufacture date (MDT) */ -((MDT_YR - 2000) / 10); -sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; -sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; +if (sd->emmc) { +sd->cid[0] = MID; +sd->cid[1] = 0x1; /* CBX */ +sd->cid[2] = OID[0];/* OEM/Application ID (OID) */ +sd->cid[8] = 0x0; +sd->cid[9] = PRV;/* Fake product revision (PRV) */ +sd->cid[10] = 0xde; /* Fake serial number (PSN) */ +sd->cid[11] = 0xad; +sd->cid[12] = 0xbe; +sd->cid[13] = 0xef; +sd->cid[14] = ((MDT_YR - 1997) % 0x10); /* MDT */ +} else { +sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ +sd->cid[1] = OID[0];/* OEM/Application ID (OID) */ +sd->cid[2] = OID[1]; +sd->cid[8] = PRV; /* Fake product revision (PRV) */ +sd->cid[9] = 0xde; /* Fake serial number (PSN) */ +sd->cid[10] = 0xad; +sd->cid[11] = 0xbe; +sd->cid[12] = 0xef; +sd->cid[13] = 0x00 |/* Manufacture date (MDT) */ +((MDT_YR - 2000) / 10); +sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; + } + sd->cid[3] = PNM[0];/* Fake product name (PNM) 48bit */ + sd->cid[4] = PNM[1]; + sd->cid[5] = PNM[2]; + sd->cid[6] = PNM[3]; + sd->cid[7] = PNM[4]; + sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; } #define HWBLOCK_SHIFT 9 /* 512 bytes */ -- 2.7.4
[PATCH v2 20/22] arm: xlnx-versal: Add emmc to versal
Configuring SDHCI-0 to act as eMMC controller. Signed-off-by: Sai Pavan Boddu --- include/hw/arm/xlnx-versal.h | 1 + hw/arm/xlnx-versal-virt.c| 30 +- hw/arm/xlnx-versal.c | 13 +++-- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 2b76885..440f3b4 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -76,6 +76,7 @@ struct Versal { struct { MemoryRegion *mr_ddr; uint32_t psci_conduit; +bool has_emmc; } cfg; }; diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 8482cd6..273e0c7 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -46,6 +46,7 @@ struct VersalVirt { struct { bool secure; +bool has_emmc; } cfg; }; @@ -333,6 +334,13 @@ static void fdt_add_sd_nodes(VersalVirt *s) qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", 2, addr, 2, MM_PMC_SD0_SIZE); qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat)); +/* + * eMMC specific properties + */ +if (s->cfg.has_emmc && i == 0) { +qemu_fdt_setprop(s->fdt, name, "non-removable", NULL, 0); +qemu_fdt_setprop_sized_cells(s->fdt, name, "bus-width", 1, 8); +} g_free(name); } } @@ -512,7 +520,7 @@ static void create_virtio_regions(VersalVirt *s) } } -static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) +static void sd_plugin_card(SDHCIState *sd, DriveInfo *di, bool emmc) { BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL; DeviceState *card; @@ -520,15 +528,22 @@ static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) card = qdev_new(TYPE_SD_CARD); object_property_add_child(OBJECT(sd), "card[*]", OBJECT(card)); qdev_prop_set_drive_err(card, "drive", blk, _fatal); +object_property_set_bool(OBJECT(card), "emmc", emmc, _fatal); qdev_realize_and_unref(card, qdev_get_child_bus(DEVICE(sd), "sd-bus"), _fatal); } +static void versal_virt_set_emmc(Object *obj, bool value, Error **errp) +{ +VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj); + +s->cfg.has_emmc = value; +} + static void versal_virt_init(MachineState *machine) { VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine); int psci_conduit = QEMU_PSCI_CONDUIT_DISABLED; -int i; /* * If the user provides an Operating System to be loaded, we expect them @@ -560,6 +575,8 @@ static void versal_virt_init(MachineState *machine) _abort); object_property_set_int(OBJECT(>soc), "psci-conduit", psci_conduit, _abort); +object_property_set_bool(OBJECT(>soc), "has-emmc", s->cfg.has_emmc, + _abort); sysbus_realize(SYS_BUS_DEVICE(>soc), _fatal); fdt_create(s); @@ -581,10 +598,10 @@ static void versal_virt_init(MachineState *machine) memory_region_add_subregion_overlap(get_system_memory(), 0, >soc.fpd.apu.mr, 0); +sd_plugin_card(>soc.pmc.iou.sd[0], +drive_get_next(s->cfg.has_emmc ? IF_EMMC : IF_SD), s->cfg.has_emmc); /* Plugin SD cards. */ -for (i = 0; i < ARRAY_SIZE(s->soc.pmc.iou.sd); i++) { -sd_plugin_card(>soc.pmc.iou.sd[i], drive_get_next(IF_SD)); -} +sd_plugin_card(>soc.pmc.iou.sd[1], drive_get_next(IF_SD), false); s->binfo.ram_size = machine->ram_size; s->binfo.loader_start = 0x0; @@ -621,6 +638,9 @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data) mc->default_cpus = XLNX_VERSAL_NR_ACPUS; mc->no_cdrom = true; mc->default_ram_id = "ddr"; +object_class_property_add_bool(oc, "emmc", +NULL, versal_virt_set_emmc); + } static const TypeInfo versal_virt_machine_init_typeinfo = { diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 628e77e..67ed1af 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -230,6 +230,9 @@ static void versal_create_admas(Versal *s, qemu_irq *pic) } #define SDHCI_CAPABILITIES 0x280737ec6481 /* Same as on ZynqMP. */ +#define SDHCI_EMMC_CAPS ((SDHCI_CAPABILITIES & ~(3 << 30)) | \ + (1 << 30)) + static void versal_create_sds(Versal *s, qemu_irq *pic) { int i; @@ -244,9 +247,14 @@ static void versal_create_sds(Versal *s, qemu_irq *pic) object_property_set_uint(OBJECT(dev), "sd-spec-version", 3, _fatal); -object_property_set_uint(OBJECT(dev), "capareg", SDHCI_CAPABILITIES, +
[PATCH v2 09/22] sd: emmc: Update CMD1 definition for eMMC
Add support to Power up the card and send response r3 in case of eMMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis --- hw/sd/sd.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 9835f52..8bc8d5d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1033,8 +1033,16 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 1: /* CMD1: SEND_OP_CMD */ -if (!sd->spi) +/* MMC: Powerup & send r3 + * SD: send r1 in spi mode + */ +if (sd->emmc) { +sd_ocr_powerup(sd); +return sd->state == sd_idle_state ? + sd_r3 : sd_r0; +} else if (!sd->spi) { goto bad_cmd; +} sd->state = sd_transfer_state; return sd_r1; -- 2.7.4
[PATCH v2 03/22] sd: emmc: Add support for eMMC cards
From: Vincent Palatin This patch adds support for eMMC cards, change SET_RELATIVE_ADDR command to assign relative address as requested by user. Signed-off-by: Vincent Palatin Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater [spb: Split original patch series] Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 14 ++ 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 74b9162..42ee49c 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -108,6 +108,7 @@ struct SDState { uint8_t spec_version; BlockBackend *blk; bool spi; +bool emmc; /* Runtime changeables */ @@ -431,9 +432,13 @@ static void sd_set_csd(SDState *sd, uint64_t size) sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1; } -static void sd_set_rca(SDState *sd) +static void sd_set_rca(SDState *sd, uint16_t value) { -sd->rca += 0x4567; +if (sd->emmc) { +sd->rca = value; +} else { +sd->rca += 0x4567; +} } FIELD(CSR, AKE_SEQ_ERROR, 3, 1) @@ -979,8 +984,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case sd_identification_state: case sd_standby_state: sd->state = sd_standby_state; -sd_set_rca(sd); -return sd_r6; +sd_set_rca(sd, req.arg >> 16); +return sd->emmc ? sd_r1 : sd_r6; default: break; @@ -2176,6 +2181,7 @@ static Property sd_properties[] = { * board to ensure that ssi transfers only occur when the chip select * is asserted. */ DEFINE_PROP_BOOL("spi", SDState, spi, false), +DEFINE_PROP_BOOL("emmc", SDState, emmc, false), DEFINE_PROP_END_OF_LIST() }; -- 2.7.4
[PATCH v2 02/22] sd: sd: Remove usage of tabs in the file
Set tabstop as 4 and used expandtabs Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 190 ++--- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 8517dbc..74b9162 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -332,39 +332,39 @@ static void sd_set_scr(SDState *sd) sd->scr[7] = 0x00; } -#define MID0xaa -#define OID"XY" -#define PNM"QEMU!" -#define PRV0x01 -#define MDT_YR 2006 -#define MDT_MON2 +#define MID 0xaa +#define OID "XY" +#define PNM "QEMU!" +#define PRV 0x01 +#define MDT_YR 2006 +#define MDT_MON 2 static void sd_set_cid(SDState *sd) { -sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ -sd->cid[1] = OID[0]; /* OEM/Application ID (OID) */ +sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ +sd->cid[1] = OID[0];/* OEM/Application ID (OID) */ sd->cid[2] = OID[1]; -sd->cid[3] = PNM[0]; /* Fake product name (PNM) */ +sd->cid[3] = PNM[0];/* Fake product name (PNM) */ sd->cid[4] = PNM[1]; sd->cid[5] = PNM[2]; sd->cid[6] = PNM[3]; sd->cid[7] = PNM[4]; -sd->cid[8] = PRV; /* Fake product revision (PRV) */ -sd->cid[9] = 0xde; /* Fake serial number (PSN) */ +sd->cid[8] = PRV; /* Fake product revision (PRV) */ +sd->cid[9] = 0xde; /* Fake serial number (PSN) */ sd->cid[10] = 0xad; sd->cid[11] = 0xbe; sd->cid[12] = 0xef; -sd->cid[13] = 0x00 | /* Manufacture date (MDT) */ +sd->cid[13] = 0x00 |/* Manufacture date (MDT) */ ((MDT_YR - 2000) / 10); sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; } -#define HWBLOCK_SHIFT 9 /* 512 bytes */ -#define SECTOR_SHIFT 5 /* 16 kilobytes */ -#define WPGROUP_SHIFT 7 /* 2 megs */ -#define CMULT_SHIFT9 /* 512 times HWBLOCK_SIZE */ -#define WPGROUP_SIZE (1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) +#define HWBLOCK_SHIFT 9 /* 512 bytes */ +#define SECTOR_SHIFT5 /* 16 kilobytes */ +#define WPGROUP_SHIFT 7 /* 2 megs */ +#define CMULT_SHIFT 9 /* 512 times HWBLOCK_SIZE */ +#define WPGROUP_SIZE(1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) static const uint8_t sd_csd_rw_mask[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -385,31 +385,31 @@ static void sd_set_csd(SDState *sd, uint64_t size) csize = (size >> (CMULT_SHIFT + hwblock_shift)) - 1; if (size <= SDSC_MAX_CAPACITY) { /* Standard Capacity SD */ -sd->csd[0] = 0x00; /* CSD structure */ -sd->csd[1] = 0x26; /* Data read access-time-1 */ -sd->csd[2] = 0x00; /* Data read access-time-2 */ +sd->csd[0] = 0x00; /* CSD structure */ +sd->csd[1] = 0x26; /* Data read access-time-1 */ +sd->csd[2] = 0x00; /* Data read access-time-2 */ sd->csd[3] = 0x32; /* Max. data transfer rate: 25 MHz */ -sd->csd[4] = 0x5f; /* Card Command Classes */ -sd->csd[5] = 0x50 |/* Max. read data block length */ +sd->csd[4] = 0x5f; /* Card Command Classes */ +sd->csd[5] = 0x50 | /* Max. read data block length */ hwblock_shift; -sd->csd[6] = 0xe0 |/* Partial block for read allowed */ +sd->csd[6] = 0xe0 | /* Partial block for read allowed */ ((csize >> 10) & 0x03); -sd->csd[7] = 0x00 |/* Device size */ +sd->csd[7] = 0x00 | /* Device size */ ((csize >> 2) & 0xff); -sd->csd[8] = 0x3f |/* Max. read current */ +sd->csd[8] = 0x3f | /* Max. read current */ ((csize << 6) & 0xc0); -sd->csd[9] = 0xfc |/* Max. write current */ +sd->csd[9] = 0xfc | /* Max. write current */ ((CMULT_SHIFT - 2) >> 1); -sd->csd[10] = 0x40 | /* Erase sector size */ +sd->csd[10] = 0x40 |/* Erase sector size */ (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1); -sd->csd[11] = 0x00 | /* Write protect group size */ +sd->csd[11] = 0x00 |/* Write protect group size */ ((sectsize << 7) & 0x80) | wpsize; -sd->csd[12] = 0x90 | /* Write speed factor */ +sd->csd[12] = 0x90 |/* Write speed factor */ (hwblock_shift >> 2); -sd->csd[13] = 0x20 | /* Max. write data block length */ +sd->csd[13] = 0x20 |/* Max. write data block length */ ((hwblock_shift << 6) &am
[PATCH v2 18/22] sd: emmc: Subtract bootarea size from blk
From: Joel Stanley The userdata size is derived from the file the user passes on the command line, but we must take into account the boot areas. Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater --- hw/sd/sd.c | 5 + 1 file changed, 5 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index ab29e54..a0b4507 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -653,6 +653,11 @@ static void sd_reset(DeviceState *dev) } size = sect << 9; +if (sd->emmc) { +unsigned int boot_capacity = sd->ext_csd[EXT_CSD_BOOT_MULT] << 17; +size -= boot_capacity * 2; +} + sect = sd_addr_to_wpnum(size) + 1; sd->state = sd_idle_state; -- 2.7.4
[PATCH v2 04/22] sd: emmc: update OCR fields for eMMC
From: Vincent Palatin eMMC OCR register doesn't has UHS-II field and voltage fields are different. Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 27 --- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 42ee49c..430bea5 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -283,6 +283,15 @@ FIELD(OCR, UHS_II_CARD,29, 1) /* Only UHS-II */ FIELD(OCR, CARD_CAPACITY, 30, 1) /* 0:SDSC, 1:SDHC/SDXC */ FIELD(OCR, CARD_POWER_UP, 31, 1) +/* + * eMMC OCR register + */ +FIELD(EMMC_OCR, VDD_WINDOW_0, 7, 1) +FIELD(EMMC_OCR, VDD_WINDOW_1, 8, 7) +FIELD(EMMC_OCR, VDD_WINDOW_2, 15, 9) +FIELD(EMMC_OCR, ACCESS_MODE, 29, 2) +FIELD(EMMC_OCR, POWER_UP, 31, 1) + #define ACMD41_ENQUIRY_MASK 0x00ff #define ACMD41_R3_MASK (R_OCR_VDD_VOLTAGE_WIN_HI_MASK \ | R_OCR_ACCEPT_SWITCH_1V8_MASK \ @@ -292,8 +301,16 @@ FIELD(OCR, CARD_POWER_UP, 31, 1) static void sd_set_ocr(SDState *sd) { -/* All voltages OK */ -sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; +if (sd->emmc) { +/* + * Dual Voltage eMMC card + */ +sd->ocr = R_EMMC_OCR_VDD_WINDOW_0_MASK | + R_EMMC_OCR_VDD_WINDOW_2_MASK; +} else { +/* All voltages OK */ +sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; +} } static void sd_ocr_powerup(void *opaque) @@ -521,7 +538,11 @@ static void sd_response_r1_make(SDState *sd, uint8_t *response) static void sd_response_r3_make(SDState *sd, uint8_t *response) { -stl_be_p(response, sd->ocr & ACMD41_R3_MASK); +if (sd->emmc) { +stl_be_p(response, sd->ocr); +} else { +stl_be_p(response, sd->ocr & ACMD41_R3_MASK); +} } static void sd_response_r6_make(SDState *sd, uint8_t *response) -- 2.7.4
[PATCH v2 00/22] eMMC support
Hi, This patch series add support for eMMC cards. This work was previosly submitted by Vincent, rebased few changes on top. Cedric & Joel has helped to added boot partition access support. I expect them to make a follow-up series to use it with aspeed machines. Present series adds eMMC support to Versal SOC. Initial patch series version is RFC Changes for V2: Split Patch 1 Add comments for eMMC Erase commands Added documentation about eMMC and Versal-virt board. Make eMMC optional for xlnx-versal-virt machines Regards, Sai Pavan Cédric Le Goater (2): sd: sdmmc-internal: Add command string for SEND_OP_CMD sd: emmc: Add Extended CSD register definitions Joel Stanley (2): sd: emmc: Support boot area in emmc image sd: emmc: Subtract bootarea size from blk Sai Pavan Boddu (13): sd: sd: Remove usage of tabs in the file sd: emmc: Dont not update CARD_CAPACITY for eMMC cards sd: emmc: Update CMD1 definition for eMMC sd: emmc: support idle state in CMD2 sd: emmc: Add mmc switch function support sd: emmc: add CMD21 tuning sequence sd: emmc: Make ACMD41 illegal for mmc sd: emmc: Add support for emmc erase sd: emmc: Update CID structure for eMMC sd: sdhci: Support eMMC devices arm: xlnx-versal: Add emmc to versal docs: devel: emmc: Add a doc for emmc card emulation docs: arm: xlnx-versal-virt: Add eMMC support documentation Vincent Palatin (5): block: add eMMC block device type sd: emmc: Add support for eMMC cards sd: emmc: update OCR fields for eMMC sd: emmc: Add support for EXT_CSD & CSD for eMMC sd: emmc: Update CMD8 to send EXT_CSD register docs/devel/emmc.txt | 16 + docs/system/arm/xlnx-versal-virt.rst | 10 + hw/sd/sdmmc-internal.h | 97 +++ include/hw/arm/xlnx-versal.h | 1 + include/sysemu/blockdev.h| 1 + blockdev.c | 1 + hw/arm/xlnx-versal-virt.c| 30 +- hw/arm/xlnx-versal.c | 13 +- hw/sd/sd.c | 545 ++- hw/sd/sdhci.c| 4 - hw/sd/sdmmc-internal.c | 2 +- 11 files changed, 571 insertions(+), 149 deletions(-) create mode 100644 docs/devel/emmc.txt -- 2.7.4
RE: [RFC PATCH 11/15] sd: emmc: Add Extended CSD register definitions
Hi Luc, > -Original Message- > From: Luc Michel > Sent: Saturday, February 13, 2021 6:26 PM > To: Sai Pavan Boddu ; Markus Armbruster > ; Kevin Wolf ; Max Reitz > ; Vladimir Sementsov-Ogievskiy > ; Eric Blake ; Joel Stanley > ; Cédric Le Goater ; Vincent Palatin > ; Dr. David Alan Gilbert ; > Thomas Huth ; Stefan Hajnoczi ; > Peter Maydell ; Alistair Francis > ; Edgar Iglesias ; Paolo Bonzini > > Cc: qemu-bl...@nongnu.org; qemu-devel@nongnu.org; Sai Pavan Boddu > > Subject: Re: [RFC PATCH 11/15] sd: emmc: Add Extended CSD register > definitions > > On 2/11/21 9:17 AM, Sai Pavan Boddu wrote: > > From: Cédric Le Goater > > > > Add user friendly macros for EXT_CSD register. > > > Signed-off-by: Cédric Le Goater > > [spb: Rebased over versal emmc series, > >updated commit message] > > Signed-off-by: Sai Pavan Boddu > > Hi, > > If Cédric agrees, maybe you can squash this commit into patch 2, and add the > missing register definitions? [Sai Pavan Boddu] Yeah, that would be nice. I will leave @Cédric Le Goater comment here. > > Also, can you set diff.orderFile = script/git.orderfile in your git config > for your > QEMU repo? It makes the review process a bit easier. [Sai Pavan Boddu] Ok, I would configure this. Thanks ! Regards, Sai Pavan > > Thanks! > > -- > Luc > > > --- > > hw/sd/sd.c | 54 +++- > > hw/sd/sdmmc-internal.h | 97 > ++ > > 2 files changed, 126 insertions(+), 25 deletions(-) > > > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > > index 45311fa..54fba7b 100644 > > --- a/hw/sd/sd.c > > +++ b/hw/sd/sd.c > > @@ -398,41 +398,45 @@ static void mmc_set_ext_csd(SDState *sd, uint64_t > size) > > uint32_t sectcount = size >> HWBLOCK_SHIFT; > > > > memset(sd->ext_csd, 0, 512); > > -sd->ext_csd[504] = 0x1; /* supported command sets */ > > -sd->ext_csd[503] = 0x1; /* HPI features */ > > -sd->ext_csd[502] = 0x1; /* Background operations support */ > > +sd->ext_csd[EXT_CSD_S_CMD_SET] = 0x1; /* supported command sets */ > > +sd->ext_csd[EXT_CSD_HPI_FEATURES] = 0x3; /* HPI features */ > > +sd->ext_csd[EXT_CSD_BKOPS_SUPPORT] = 0x1; /* Background operations > > + support */ > > sd->ext_csd[241] = 0xA; /* 1st initialization time after partitioning > > */ > > -sd->ext_csd[232] = 0x1; /* Trim multiplier */ > > -sd->ext_csd[231] = 0x15; /* Secure feature support */ > > -sd->ext_csd[230] = 0x96; /* Secure erase support */ > > -sd->ext_csd[229] = 0x96; /* Secure TRIM multiplier */ > > -sd->ext_csd[228] = 0x7; /* Boot information */ > > -sd->ext_csd[226] = 0x8; /* Boot partition size */ > > -sd->ext_csd[225] = 0x6; /* Access size */ > > -sd->ext_csd[224] = 0x4; /* HC Erase unit size */ > > -sd->ext_csd[223] = 0x1; /* HC erase timeout */ > > -sd->ext_csd[222] = 0x1; /* Reliable write sector count */ > > -sd->ext_csd[221] = 0x4; /* HC write protect group size */ > > -sd->ext_csd[220] = 0x8; /* Sleep current VCC */ > > -sd->ext_csd[219] = 0x7; /* Sleep current VCCQ */ > > -sd->ext_csd[217] = 0x11; /* Sleep/Awake timeout */ > > +sd->ext_csd[EXT_CSD_TRIM_MULT] = 0x1; /* Trim multiplier */ > > +sd->ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] = 0x15; /* Secure feature > > +support */ > > +sd->ext_csd[EXT_CSD_SEC_ERASE_MULT] = 0x96; /* Secure erase support > */ > > +sd->ext_csd[EXT_CSD_SEC_TRIM_MULT] = 0x96; /* Secure TRIM > multiplier */ > > +sd->ext_csd[EXT_CSD_BOOT_INFO] = 0x7; /* Boot information */ > > +sd->ext_csd[EXT_CSD_BOOT_MULT] = 0x8; /* Boot partition size. 128KB > unit */ > > +sd->ext_csd[EXT_CSD_ACC_SIZE] = 0x6; /* Access size */ > > +sd->ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] = 0x4; /* HC Erase unit size > */ > > +sd->ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] = 0x1; /* HC erase > timeout */ > > +sd->ext_csd[EXT_CSD_REL_WR_SEC_C] = 0x1; /* Reliable write sector > count */ > > +sd->ext_csd[EXT_CSD_HC_WP_GRP_SIZE] = 0x4; /* HC write protect > group size */ > > +sd->ext_csd[EXT_CSD_S_C_VCC] = 0x8; /* Sleep current VCC */ > > +sd->ext_csd[EXT_CSD_S_C_VCCQ] = 0x7; /* Sleep current VCCQ */ > > +sd->ext_csd[EXT_CSD_S_A_TIMEOUT] = 0x11; /* Sleep/Awake timeout > > + */ > >
RE: [RFC PATCH 10/15] sd: emmc: Update CID structure for eMMC
Hi Alistair > -Original Message- > From: Alistair Francis > Sent: Saturday, February 13, 2021 3:41 AM > To: Sai Pavan Boddu > Cc: Markus Armbruster ; Kevin Wolf > ; Max Reitz ; Vladimir Sementsov- > Ogievskiy ; Eric Blake ; > Joel Stanley ; Cédric Le Goater ; Vincent > Palatin ; Dr. David Alan Gilbert > ; Thomas Huth ; Stefan Hajnoczi > ; Peter Maydell ; Alistair > Francis ; Edgar Iglesias ; Luc > Michel ; Paolo Bonzini ; > Sai Pavan Boddu ; qemu-devel@nongnu.org Developers > ; Qemu-block > Subject: Re: [RFC PATCH 10/15] sd: emmc: Update CID structure for eMMC > > On Thu, Feb 11, 2021 at 12:30 AM Sai Pavan Boddu > wrote: > > > > CID structure is little different for eMMC, w.r.t to product name and > > manufacturing date. > > > > Signed-off-by: Sai Pavan Boddu > > Signed-off-by: Edgar E. Iglesias > > --- > > hw/sd/sd.c | 52 +++- > > 1 file changed, 35 insertions(+), 17 deletions(-) > > > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > > index 7aab647..45311fa 100644 > > --- a/hw/sd/sd.c > > +++ b/hw/sd/sd.c > > @@ -345,23 +345,41 @@ static void sd_set_scr(SDState *sd) > > > > static void sd_set_cid(SDState *sd) > > { > > -sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ > > -sd->cid[1] = OID[0]; /* OEM/Application ID (OID) */ > > -sd->cid[2] = OID[1]; > > -sd->cid[3] = PNM[0]; /* Fake product name (PNM) */ > > -sd->cid[4] = PNM[1]; > > -sd->cid[5] = PNM[2]; > > -sd->cid[6] = PNM[3]; > > -sd->cid[7] = PNM[4]; > > -sd->cid[8] = PRV; /* Fake product revision (PRV) */ > > -sd->cid[9] = 0xde; /* Fake serial number (PSN) */ > > -sd->cid[10] = 0xad; > > -sd->cid[11] = 0xbe; > > -sd->cid[12] = 0xef; > > -sd->cid[13] = 0x00 | /* Manufacture date (MDT) */ > > -((MDT_YR - 2000) / 10); > > -sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; > > -sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; > > +if (sd->emmc) { > > +sd->cid[0] = MID; > > +sd->cid[1] = 0x1; /* CBX */ > > +sd->cid[2] = OID[0]; /* OEM/Application ID (OID) */ > > +sd->cid[3] = PNM[0];/* Fake product name (PNM) 48bit */ > > +sd->cid[4] = PNM[1]; > > +sd->cid[5] = PNM[2]; > > +sd->cid[6] = PNM[3]; > > +sd->cid[7] = PNM[4]; > > Aren't the majority of these the same between the two cases? It's probably > cleaner to split them out then. [Sai Pavan Boddu] Yes, I would try to re-order. If I see only the PNM fields are same, rest all fields kind of moved a byte below. Regards, Sai Pavan > > Alistair > > > +sd->cid[8] = 0x0; > > +sd->cid[9] = PRV;/* Fake product revision (PRV) */ > > +sd->cid[10] = 0xde; /* Fake serial number (PSN) */ > > +sd->cid[11] = 0xad; > > +sd->cid[12] = 0xbe; > > +sd->cid[13] = 0xef; > > +sd->cid[14] = ((MDT_YR - 1997) % 0x10); /* MDT */ > > +} else { > > +sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ > > +sd->cid[1] = OID[0];/* OEM/Application ID (OID) */ > > +sd->cid[2] = OID[1]; > > +sd->cid[3] = PNM[0];/* Fake product name (PNM) 40bit */ > > +sd->cid[4] = PNM[1]; > > +sd->cid[5] = PNM[2]; > > +sd->cid[6] = PNM[3]; > > +sd->cid[7] = PNM[4]; > > +sd->cid[8] = PRV; /* Fake product revision (PRV) */ > > +sd->cid[9] = 0xde; /* Fake serial number (PSN) */ > > +sd->cid[10] = 0xad; > > +sd->cid[11] = 0xbe; > > +sd->cid[12] = 0xef; > > +sd->cid[13] = 0x00 |/* Manufacture date (MDT) */ > > +((MDT_YR - 2000) / 10); > > +sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; > > + } > > + sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; > > } > > > > #define HWBLOCK_SHIFT 9 /* 512 bytes */ > > -- > > 2.7.4 > > > >
RE: [RFC PATCH 09/15] sd: emmc: Add support for emmc erase
Hi Alistair, > -Original Message- > From: Alistair Francis > Sent: Saturday, February 13, 2021 3:38 AM > To: Sai Pavan Boddu > Cc: Markus Armbruster ; Kevin Wolf > ; Max Reitz ; Vladimir Sementsov- > Ogievskiy ; Eric Blake ; > Joel Stanley ; Cédric Le Goater ; Vincent > Palatin ; Dr. David Alan Gilbert > ; Thomas Huth ; Stefan Hajnoczi > ; Peter Maydell ; Alistair > Francis ; Edgar Iglesias ; Luc > Michel ; Paolo Bonzini ; > Sai Pavan Boddu ; qemu-devel@nongnu.org Developers > ; Qemu-block > Subject: Re: [RFC PATCH 09/15] sd: emmc: Add support for emmc erase > > On Thu, Feb 11, 2021 at 12:19 AM Sai Pavan Boddu > wrote: > > > > Add CMD35 and CMD36 which sets the erase start and end. > > > > Signed-off-by: Sai Pavan Boddu > > Signed-off-by: Edgar E. Iglesias > > --- > > hw/sd/sd.c | 2 ++ > > 1 file changed, 2 insertions(+) > > > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > > index 236f2b8..7aab647 100644 > > --- a/hw/sd/sd.c > > +++ b/hw/sd/sd.c > > @@ -1544,6 +1544,7 @@ static sd_rsp_type_t sd_normal_command(SDState > > *sd, SDRequest req) > > > > /* Erase commands (Class 5) */ > > case 32: /* CMD32: ERASE_WR_BLK_START */ > > +case 35: > > Can you comment the CMD here? [Sai Pavan Boddu] Sure I will update this. Regards, Sai Pavan > > > switch (sd->state) { > > case sd_transfer_state: > > sd->erase_start = req.arg; @@ -1555,6 +1556,7 @@ static > > sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) > > break; > > > > case 33: /* CMD33: ERASE_WR_BLK_END */ > > +case 36: > > and here? > > Alistair > > > switch (sd->state) { > > case sd_transfer_state: > > sd->erase_end = req.arg; > > -- > > 2.7.4 > > > >
[RFC PATCH 15/15] arm: xlnx-versal: Add emmc to versal
Configuring SDHCI-0 to act as eMMC controller. Signed-off-by: Sai Pavan Boddu --- hw/arm/xlnx-versal-virt.c | 16 +++- hw/arm/xlnx-versal.c | 14 -- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 8482cd6..18489e4 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -333,6 +333,13 @@ static void fdt_add_sd_nodes(VersalVirt *s) qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", 2, addr, 2, MM_PMC_SD0_SIZE); qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat)); +/* + * eMMC specific properties + */ +if (i == 0) { +qemu_fdt_setprop(s->fdt, name, "non-removable", NULL, 0); +qemu_fdt_setprop_sized_cells(s->fdt, name, "bus-width", 1, 8); +} g_free(name); } } @@ -512,7 +519,7 @@ static void create_virtio_regions(VersalVirt *s) } } -static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) +static void sd_plugin_card(SDHCIState *sd, DriveInfo *di, bool emmc) { BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL; DeviceState *card; @@ -520,6 +527,7 @@ static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) card = qdev_new(TYPE_SD_CARD); object_property_add_child(OBJECT(sd), "card[*]", OBJECT(card)); qdev_prop_set_drive_err(card, "drive", blk, _fatal); +object_property_set_bool(OBJECT(card), "emmc", emmc, _fatal); qdev_realize_and_unref(card, qdev_get_child_bus(DEVICE(sd), "sd-bus"), _fatal); } @@ -528,7 +536,6 @@ static void versal_virt_init(MachineState *machine) { VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine); int psci_conduit = QEMU_PSCI_CONDUIT_DISABLED; -int i; /* * If the user provides an Operating System to be loaded, we expect them @@ -581,10 +588,9 @@ static void versal_virt_init(MachineState *machine) memory_region_add_subregion_overlap(get_system_memory(), 0, >soc.fpd.apu.mr, 0); +sd_plugin_card(>soc.pmc.iou.sd[0], drive_get_next(IF_EMMC), true); /* Plugin SD cards. */ -for (i = 0; i < ARRAY_SIZE(s->soc.pmc.iou.sd); i++) { -sd_plugin_card(>soc.pmc.iou.sd[i], drive_get_next(IF_SD)); -} +sd_plugin_card(>soc.pmc.iou.sd[1], drive_get_next(IF_SD), false); s->binfo.ram_size = machine->ram_size; s->binfo.loader_start = 0x0; diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index b077716..3498dd9 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -230,9 +230,14 @@ static void versal_create_admas(Versal *s, qemu_irq *pic) } #define SDHCI_CAPABILITIES 0x280737ec6481 /* Same as on ZynqMP. */ +#define SDHCI0_CAPS ((SDHCI_CAPABILITIES & ~(3 << 30)) | \ + (1 << 30)) +#define SDHCI1_CAPS SDHCI_CAPABILITIES + static void versal_create_sds(Versal *s, qemu_irq *pic) { int i; +uint64_t caps[] = {SDHCI0_CAPS, SDHCI1_CAPS}; for (i = 0; i < ARRAY_SIZE(s->pmc.iou.sd); i++) { DeviceState *dev; @@ -244,9 +249,14 @@ static void versal_create_sds(Versal *s, qemu_irq *pic) object_property_set_uint(OBJECT(dev), "sd-spec-version", 3, _fatal); -object_property_set_uint(OBJECT(dev), "capareg", SDHCI_CAPABILITIES, +object_property_set_uint(OBJECT(dev), "capareg", caps[i], _fatal); -object_property_set_uint(OBJECT(dev), "uhs", UHS_I, _fatal); +/* + * UHS is not applicable for eMMC + */ +if (i == 1) { +object_property_set_uint(OBJECT(dev), "uhs", UHS_I, _fatal); +} sysbus_realize(SYS_BUS_DEVICE(dev), _fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); -- 2.7.4
[RFC PATCH 14/15] sd: sdhci: Support eMMC devices
Embedded device slots should be allowed as support of eMMC is available. Signed-off-by: Sai Pavan Boddu --- hw/sd/sdhci.c | 4 1 file changed, 4 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 8ffa539..771212a 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -99,10 +99,6 @@ static void sdhci_check_capareg(SDHCIState *s, Error **errp) msk = FIELD_DP64(msk, SDHC_CAPAB, ASYNC_INT, 0); val = FIELD_EX64(s->capareg, SDHC_CAPAB, SLOT_TYPE); -if (val) { -error_setg(errp, "slot-type not supported"); -return; -} trace_sdhci_capareg("slot type", val); msk = FIELD_DP64(msk, SDHC_CAPAB, SLOT_TYPE, 0); -- 2.7.4
[RFC PATCH 11/15] sd: emmc: Add Extended CSD register definitions
From: Cédric Le Goater Add user friendly macros for EXT_CSD register. Signed-off-by: Cédric Le Goater [spb: Rebased over versal emmc series, updated commit message] Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 54 +++- hw/sd/sdmmc-internal.h | 97 ++ 2 files changed, 126 insertions(+), 25 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 45311fa..54fba7b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -398,41 +398,45 @@ static void mmc_set_ext_csd(SDState *sd, uint64_t size) uint32_t sectcount = size >> HWBLOCK_SHIFT; memset(sd->ext_csd, 0, 512); -sd->ext_csd[504] = 0x1; /* supported command sets */ -sd->ext_csd[503] = 0x1; /* HPI features */ -sd->ext_csd[502] = 0x1; /* Background operations support */ +sd->ext_csd[EXT_CSD_S_CMD_SET] = 0x1; /* supported command sets */ +sd->ext_csd[EXT_CSD_HPI_FEATURES] = 0x3; /* HPI features */ +sd->ext_csd[EXT_CSD_BKOPS_SUPPORT] = 0x1; /* Background operations + support */ sd->ext_csd[241] = 0xA; /* 1st initialization time after partitioning */ -sd->ext_csd[232] = 0x1; /* Trim multiplier */ -sd->ext_csd[231] = 0x15; /* Secure feature support */ -sd->ext_csd[230] = 0x96; /* Secure erase support */ -sd->ext_csd[229] = 0x96; /* Secure TRIM multiplier */ -sd->ext_csd[228] = 0x7; /* Boot information */ -sd->ext_csd[226] = 0x8; /* Boot partition size */ -sd->ext_csd[225] = 0x6; /* Access size */ -sd->ext_csd[224] = 0x4; /* HC Erase unit size */ -sd->ext_csd[223] = 0x1; /* HC erase timeout */ -sd->ext_csd[222] = 0x1; /* Reliable write sector count */ -sd->ext_csd[221] = 0x4; /* HC write protect group size */ -sd->ext_csd[220] = 0x8; /* Sleep current VCC */ -sd->ext_csd[219] = 0x7; /* Sleep current VCCQ */ -sd->ext_csd[217] = 0x11; /* Sleep/Awake timeout */ +sd->ext_csd[EXT_CSD_TRIM_MULT] = 0x1; /* Trim multiplier */ +sd->ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] = 0x15; /* Secure feature +support */ +sd->ext_csd[EXT_CSD_SEC_ERASE_MULT] = 0x96; /* Secure erase support */ +sd->ext_csd[EXT_CSD_SEC_TRIM_MULT] = 0x96; /* Secure TRIM multiplier */ +sd->ext_csd[EXT_CSD_BOOT_INFO] = 0x7; /* Boot information */ +sd->ext_csd[EXT_CSD_BOOT_MULT] = 0x8; /* Boot partition size. 128KB unit */ +sd->ext_csd[EXT_CSD_ACC_SIZE] = 0x6; /* Access size */ +sd->ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] = 0x4; /* HC Erase unit size */ +sd->ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] = 0x1; /* HC erase timeout */ +sd->ext_csd[EXT_CSD_REL_WR_SEC_C] = 0x1; /* Reliable write sector count */ +sd->ext_csd[EXT_CSD_HC_WP_GRP_SIZE] = 0x4; /* HC write protect group size */ +sd->ext_csd[EXT_CSD_S_C_VCC] = 0x8; /* Sleep current VCC */ +sd->ext_csd[EXT_CSD_S_C_VCCQ] = 0x7; /* Sleep current VCCQ */ +sd->ext_csd[EXT_CSD_S_A_TIMEOUT] = 0x11; /* Sleep/Awake timeout */ sd->ext_csd[215] = (sectcount >> 24) & 0xff; /* Sector count */ sd->ext_csd[214] = (sectcount >> 16) & 0xff; /* ... */ sd->ext_csd[213] = (sectcount >> 8) & 0xff; /* ... */ -sd->ext_csd[212] = (sectcount & 0xff); /* ... */ +sd->ext_csd[EXT_CSD_SEC_CNT] = (sectcount & 0xff); /* ... */ sd->ext_csd[210] = 0xa; /* Min write perf for 8bit@52Mhz */ sd->ext_csd[209] = 0xa; /* Min read perf for 8bit@52Mhz */ sd->ext_csd[208] = 0xa; /* Min write perf for 4bit@52Mhz */ sd->ext_csd[207] = 0xa; /* Min read perf for 4bit@52Mhz */ sd->ext_csd[206] = 0xa; /* Min write perf for 4bit@26Mhz */ sd->ext_csd[205] = 0xa; /* Min read perf for 4bit@26Mhz */ -sd->ext_csd[199] = 0x1; /* Partition switching timing */ -sd->ext_csd[198] = 0x1; /* Out-of-interrupt busy timing */ -sd->ext_csd[196] = 0xFF; /* Card type */ -sd->ext_csd[194] = 0x2; /* CSD Structure version */ -sd->ext_csd[192] = 0x5; /* Extended CSD revision */ -sd->ext_csd[168] = 0x1; /* RPMB size */ -sd->ext_csd[160] = 0x3; /* Partinioning support */ +sd->ext_csd[EXT_CSD_PART_SWITCH_TIME] = 0x1; /* Partition switching +timing */ +sd->ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] = 0x1; /* Out-of-interrupt busy + timing */ +sd->ext_csd[EXT_CSD_CARD_TYPE] = 0xFF; /* Card type */ +sd->ext_csd[EXT_CSD_STRUCTURE] = 0x2; /* CSD Structure version */ +sd->ext_csd[EXT_CSD_REV] = 0x5; /* Extended CSD revision */ +sd->ext_csd[EXT_CSD_RPMB_MULT] = 0x1; /* RPMB size */ +sd->ext_csd[EXT_CSD_PARTITION_SUPPORT] = 0x3; /* Partinioning support */
[RFC PATCH 10/15] sd: emmc: Update CID structure for eMMC
CID structure is little different for eMMC, w.r.t to product name and manufacturing date. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 52 +++- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 7aab647..45311fa 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -345,23 +345,41 @@ static void sd_set_scr(SDState *sd) static void sd_set_cid(SDState *sd) { -sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ -sd->cid[1] = OID[0]; /* OEM/Application ID (OID) */ -sd->cid[2] = OID[1]; -sd->cid[3] = PNM[0]; /* Fake product name (PNM) */ -sd->cid[4] = PNM[1]; -sd->cid[5] = PNM[2]; -sd->cid[6] = PNM[3]; -sd->cid[7] = PNM[4]; -sd->cid[8] = PRV; /* Fake product revision (PRV) */ -sd->cid[9] = 0xde; /* Fake serial number (PSN) */ -sd->cid[10] = 0xad; -sd->cid[11] = 0xbe; -sd->cid[12] = 0xef; -sd->cid[13] = 0x00 | /* Manufacture date (MDT) */ -((MDT_YR - 2000) / 10); -sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; -sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; +if (sd->emmc) { +sd->cid[0] = MID; +sd->cid[1] = 0x1; /* CBX */ +sd->cid[2] = OID[0];/* OEM/Application ID (OID) */ +sd->cid[3] = PNM[0];/* Fake product name (PNM) 48bit */ +sd->cid[4] = PNM[1]; +sd->cid[5] = PNM[2]; +sd->cid[6] = PNM[3]; +sd->cid[7] = PNM[4]; +sd->cid[8] = 0x0; +sd->cid[9] = PRV;/* Fake product revision (PRV) */ +sd->cid[10] = 0xde; /* Fake serial number (PSN) */ +sd->cid[11] = 0xad; +sd->cid[12] = 0xbe; +sd->cid[13] = 0xef; +sd->cid[14] = ((MDT_YR - 1997) % 0x10); /* MDT */ +} else { +sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ +sd->cid[1] = OID[0];/* OEM/Application ID (OID) */ +sd->cid[2] = OID[1]; +sd->cid[3] = PNM[0];/* Fake product name (PNM) 40bit */ +sd->cid[4] = PNM[1]; +sd->cid[5] = PNM[2]; +sd->cid[6] = PNM[3]; +sd->cid[7] = PNM[4]; +sd->cid[8] = PRV; /* Fake product revision (PRV) */ +sd->cid[9] = 0xde; /* Fake serial number (PSN) */ +sd->cid[10] = 0xad; +sd->cid[11] = 0xbe; +sd->cid[12] = 0xef; +sd->cid[13] = 0x00 |/* Manufacture date (MDT) */ +((MDT_YR - 2000) / 10); +sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; + } + sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; } #define HWBLOCK_SHIFT 9 /* 512 bytes */ -- 2.7.4
[RFC PATCH 07/15] sd: emmc: add CMD21 tuning sequence
eMMC cards support tuning sequence for entering HS200 mode. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 47 +++ 1 file changed, 47 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 7925174..90359f6 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1378,6 +1378,14 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; +case 21:/* CMD21: mmc SEND TUNING_BLOCK */ +if (sd->emmc && (sd->state == sd_transfer_state)) { +sd->state = sd_sendingdata_state; +sd->data_offset = 0; +return sd_r1; +} +break; + case 23:/* CMD23: SET_BLOCK_COUNT */ if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { break; @@ -2112,6 +2120,30 @@ static const uint8_t sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = { 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, }; +#define EXCSD_BUS_WIDTH_OFFSET 183 +#define BUS_WIDTH_8_MASK0x4 +#define BUS_WIDTH_4_MASK0x2 +#define MMC_TUNING_BLOCK_SIZE 128 + +static const uint8_t mmc_tunning_block_pattern[128] = { + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, + 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, + 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, + 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, + 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, + 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, + 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, + 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, + 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, + 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, + 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, +}; + uint8_t sd_read_byte(SDState *sd) { /* TODO: Append CRCs */ @@ -2204,6 +2236,21 @@ uint8_t sd_read_byte(SDState *sd) ret = sd_tuning_block_pattern[sd->data_offset++]; break; +case 21:/* CMD21: SEND_TUNNING_BLOCK (MMC) */ +if (sd->data_offset >= MMC_TUNING_BLOCK_SIZE - 1) { +sd->state = sd_transfer_state; +} +if (sd->ext_csd[EXCSD_BUS_WIDTH_OFFSET] & BUS_WIDTH_8_MASK) { +ret = mmc_tunning_block_pattern[sd->data_offset++]; +} else { +/* Return LSB Nibbles of two byte from the 8bit tuning block + * for 4bit mode + */ +ret = mmc_tunning_block_pattern[sd->data_offset++] & 0x0F; +ret |= (mmc_tunning_block_pattern[sd->data_offset++] & 0x0F) << 4; +} +break; + case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ ret = sd->data[sd->data_offset ++]; -- 2.7.4
[RFC PATCH 13/15] sd: emmc: Subtract bootarea size from blk
From: Joel Stanley The userdata size is derived from the file the user passes on the command line, but we must take into account the boot areas. Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater --- hw/sd/sd.c | 5 + 1 file changed, 5 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 55c1104..a2f39c9 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -658,6 +658,11 @@ static void sd_reset(DeviceState *dev) } size = sect << 9; +if (sd->emmc) { +unsigned int boot_capacity = sd->ext_csd[EXT_CSD_BOOT_MULT] << 17; +size -= boot_capacity * 2; +} + sect = sd_addr_to_wpnum(size) + 1; sd->state = sd_idle_state; -- 2.7.4
[RFC PATCH 03/15] sd: emmc: Dont not update CARD_CAPACITY for eMMC cards
OCR.CARD_CAPACITY field is only valid for sd cards, So skip it for eMMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a75fa1c..57fff89 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -308,7 +308,8 @@ static void sd_ocr_powerup(void *opaque) /* card power-up OK */ sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_POWER_UP, 1); -if (sd->size > SDSC_MAX_CAPACITY) { +/* eMMC supports only Byte mode */ +if (!sd->emmc && sd->size > SDSC_MAX_CAPACITY) { sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_CAPACITY, 1); } } -- 2.7.4
[RFC PATCH 08/15] sd: emmc: Make ACMD41 illegal for mmc
ACMD41 is not applicable for eMMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 90359f6..236f2b8 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1729,6 +1729,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd, break; case 41: /* ACMD41: SD_APP_OP_COND */ +if (sd->emmc) { +break; +} if (sd->spi) { /* SEND_OP_CMD */ sd->state = sd_transfer_state; -- 2.7.4
[RFC PATCH 09/15] sd: emmc: Add support for emmc erase
Add CMD35 and CMD36 which sets the erase start and end. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 236f2b8..7aab647 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1544,6 +1544,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Erase commands (Class 5) */ case 32: /* CMD32: ERASE_WR_BLK_START */ +case 35: switch (sd->state) { case sd_transfer_state: sd->erase_start = req.arg; @@ -1555,6 +1556,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 33: /* CMD33: ERASE_WR_BLK_END */ +case 36: switch (sd->state) { case sd_transfer_state: sd->erase_end = req.arg; -- 2.7.4
[RFC PATCH 06/15] sd: emmc: Add mmc switch function support
switch operation in eMMC card updates the ext_csd register to request changes in card operations. Here we implement similar sequence but requests are mostly dummy and make no change. Implement SWITCH_ERROR if the write operation extends goes beyond length of ext_csd. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 56 ++-- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 69289e0..7925174 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -519,6 +519,7 @@ static void sd_set_rca(SDState *sd, uint16_t value) FIELD(CSR, AKE_SEQ_ERROR, 3, 1) FIELD(CSR, APP_CMD, 5, 1) FIELD(CSR, FX_EVENT,6, 1) +FIELD(CSR, SWITCH_ERROR,7, 1) FIELD(CSR, READY_FOR_DATA, 8, 1) FIELD(CSR, CURRENT_STATE, 9, 4) FIELD(CSR, ERASE_RESET,13, 1) @@ -878,6 +879,43 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) return ret; } +enum { +MMC_CMD6_ACCESS_COMMAND_SET = 0, +MMC_CMD6_ACCESS_SET_BITS, +MMC_CMD6_ACCESS_CLEAR_BITS, +MMC_CMD6_ACCESS_WRITE_BYTE, +}; + +static void mmc_function_switch(SDState *sd, uint32_t arg) +{ +uint32_t access = extract32(arg, 24, 2); +uint32_t index = extract32(arg, 16, 8); +uint32_t value = extract32(arg, 8, 8); +uint8_t b = sd->ext_csd[index]; + +switch (access) { +case MMC_CMD6_ACCESS_COMMAND_SET: +qemu_log_mask(LOG_UNIMP, "MMC Command set switching not supported\n"); +return; +case MMC_CMD6_ACCESS_SET_BITS: +b |= value; +break; +case MMC_CMD6_ACCESS_CLEAR_BITS: +b &= ~value; +break; +case MMC_CMD6_ACCESS_WRITE_BYTE: +b = value; +break; +} + +if (index >= 192) { +sd->card_status |= R_CSR_SWITCH_ERROR_MASK; +return; +} + +sd->ext_csd[index] = b; +} + static void sd_function_switch(SDState *sd, uint32_t arg) { int i, mode, new_func; @@ -1097,12 +1135,18 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 6:/* CMD6: SWITCH_FUNCTION */ switch (sd->mode) { case sd_data_transfer_mode: -sd_function_switch(sd, req.arg); -sd->state = sd_sendingdata_state; -sd->data_start = 0; -sd->data_offset = 0; -return sd_r1; - +if (sd->emmc) { +sd->state = sd_programming_state; +mmc_function_switch(sd, req.arg); +sd->state = sd_transfer_state; +return sd_r1b; +} else { +sd_function_switch(sd, req.arg); +sd->state = sd_sendingdata_state; +sd->data_start = 0; +sd->data_offset = 0; +return sd_r1; +} default: break; } -- 2.7.4
[RFC PATCH 02/15] sd: add eMMC support
From: Vincent Palatin The parameters mimick a real 4GB eMMC, but it can be set to various sizes. Signed-off-by: Vincent Palatin [SPB: Rebased the patch over qemu 5.1, Mark eMMC to support all timing modes] Signed-off-by: Sai Pavan Boddu Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater --- hw/sd/sd.c | 143 + hw/sd/sdmmc-internal.c | 2 +- 2 files changed, 122 insertions(+), 23 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 8517dbc..a75fa1c 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -108,6 +108,7 @@ struct SDState { uint8_t spec_version; BlockBackend *blk; bool spi; +bool emmc; /* Runtime changeables */ @@ -134,6 +135,7 @@ struct SDState { uint64_t data_start; uint32_t data_offset; uint8_t data[512]; +uint8_t ext_csd[512]; qemu_irq readonly_cb; qemu_irq inserted_cb; QEMUTimer *ocr_power_timer; @@ -287,7 +289,8 @@ FIELD(OCR, CARD_POWER_UP, 31, 1) | R_OCR_ACCEPT_SWITCH_1V8_MASK \ | R_OCR_UHS_II_CARD_MASK \ | R_OCR_CARD_CAPACITY_MASK \ - | R_OCR_CARD_POWER_UP_MASK) + | R_OCR_CARD_POWER_UP_MASK \ + | R_OCR_DUAL_VOLTAGE_CARD_MASK) static void sd_set_ocr(SDState *sd) { @@ -371,6 +374,51 @@ static const uint8_t sd_csd_rw_mask[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, }; +static void mmc_set_ext_csd(SDState *sd, uint64_t size) +{ +uint32_t sectcount = size >> HWBLOCK_SHIFT; + +memset(sd->ext_csd, 0, 512); +sd->ext_csd[504] = 0x1; /* supported command sets */ +sd->ext_csd[503] = 0x1; /* HPI features */ +sd->ext_csd[502] = 0x1; /* Background operations support */ +sd->ext_csd[241] = 0xA; /* 1st initialization time after partitioning */ +sd->ext_csd[232] = 0x1; /* Trim multiplier */ +sd->ext_csd[231] = 0x15; /* Secure feature support */ +sd->ext_csd[230] = 0x96; /* Secure erase support */ +sd->ext_csd[229] = 0x96; /* Secure TRIM multiplier */ +sd->ext_csd[228] = 0x7; /* Boot information */ +sd->ext_csd[226] = 0x8; /* Boot partition size */ +sd->ext_csd[225] = 0x6; /* Access size */ +sd->ext_csd[224] = 0x4; /* HC Erase unit size */ +sd->ext_csd[223] = 0x1; /* HC erase timeout */ +sd->ext_csd[222] = 0x1; /* Reliable write sector count */ +sd->ext_csd[221] = 0x4; /* HC write protect group size */ +sd->ext_csd[220] = 0x8; /* Sleep current VCC */ +sd->ext_csd[219] = 0x7; /* Sleep current VCCQ */ +sd->ext_csd[217] = 0x11; /* Sleep/Awake timeout */ +sd->ext_csd[215] = (sectcount >> 24) & 0xff; /* Sector count */ +sd->ext_csd[214] = (sectcount >> 16) & 0xff; /* ... */ +sd->ext_csd[213] = (sectcount >> 8) & 0xff; /* ... */ +sd->ext_csd[212] = (sectcount & 0xff); /* ... */ +sd->ext_csd[210] = 0xa; /* Min write perf for 8bit@52Mhz */ +sd->ext_csd[209] = 0xa; /* Min read perf for 8bit@52Mhz */ +sd->ext_csd[208] = 0xa; /* Min write perf for 4bit@52Mhz */ +sd->ext_csd[207] = 0xa; /* Min read perf for 4bit@52Mhz */ +sd->ext_csd[206] = 0xa; /* Min write perf for 4bit@26Mhz */ +sd->ext_csd[205] = 0xa; /* Min read perf for 4bit@26Mhz */ +sd->ext_csd[199] = 0x1; /* Partition switching timing */ +sd->ext_csd[198] = 0x1; /* Out-of-interrupt busy timing */ +sd->ext_csd[196] = 0xFF; /* Card type */ +sd->ext_csd[194] = 0x2; /* CSD Structure version */ +sd->ext_csd[192] = 0x5; /* Extended CSD revision */ +sd->ext_csd[168] = 0x1; /* RPMB size */ +sd->ext_csd[160] = 0x3; /* Partinioning support */ +sd->ext_csd[159] = 0x00; /* Max enhanced area size */ +sd->ext_csd[158] = 0x00; /* ... */ +sd->ext_csd[157] = 0xEC; /* ... */ +} + static void sd_set_csd(SDState *sd, uint64_t size) { int hwblock_shift = HWBLOCK_SHIFT; @@ -384,7 +432,34 @@ static void sd_set_csd(SDState *sd, uint64_t size) } csize = (size >> (CMULT_SHIFT + hwblock_shift)) - 1; -if (size <= SDSC_MAX_CAPACITY) { /* Standard Capacity SD */ +if (sd->emmc) { /* eMMC */ +sd->csd[0] = 0xd0; +sd->csd[1] = 0x0f; +sd->csd[2] = 0x00; +sd->csd[3] = 0x32; +sd->csd[4] = 0x0f; +if (size <= 0x8000ULL) { +/* use 1k blocks */ +uint32_t csize1k = (size >> (CMULT_SHIFT + 10)) - 1; +sd->csd[5] = 0x5a; +sd->csd[6] = 0x80 | ((csize1k >> 10) & 0xf); +sd->csd[7] = (csize1k >> 2) & 0xff; +} else { /* >= 2GB : size stored in ext CSD, block addressing */ +sd->csd[5] = 0x59; +
[RFC PATCH 05/15] sd: emmc: support idle state in CMD2
eMMC is expected to be in idle-state post CMD1. Ready state is an intermediate stage which we don't come across in Device identification mode. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 4 1 file changed, 4 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index e3738b2..69289e0 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1051,6 +1051,10 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (sd->spi) goto bad_cmd; switch (sd->state) { +case sd_idle_state: +if (!sd->emmc) { +break; +} case sd_ready_state: sd->state = sd_identification_state; return sd_r2_i; -- 2.7.4
[RFC PATCH 04/15] sd: emmc: Update CMD1 definition for eMMC
Add support to Power up the card and send response r3 in case of eMMC. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias --- hw/sd/sd.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 57fff89..e3738b2 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1033,8 +1033,16 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 1:/* CMD1: SEND_OP_CMD */ -if (!sd->spi) +/* MMC: Powerup & send r3 + * SD: send r1 in spi mode + */ +if (sd->emmc) { +sd_ocr_powerup(sd); +return sd->state == sd_idle_state ? + sd_r3 : sd_r0; +} else if (!sd->spi) { goto bad_cmd; +} sd->state = sd_transfer_state; return sd_r1; -- 2.7.4
[RFC PATCH 12/15] sd: emmc: Support boot area in emmc image
From: Joel Stanley This assumes a specially constructued image: dd if=/dev/zero of=mmc-bootarea.img count=2 bs=1M dd if=u-boot-spl.bin of=mmc-bootarea.img conv=notrunc dd if=u-boot.bin of=mmc-bootarea.img conv=notrunc count=64 bs=1K cat mmc-bootarea.img obmc-phosphor-image.wic > mmc.img truncate --size 16GB mmc.img truncate --size 128MB mmc-bootarea.img Signed-off-by: Joel Stanley [clg: - changes on the definition names ] Signed-off-by: Cédric Le Goater [spb: use data_start property to access right emmc partition, Clean up PARTITION_ENABLE support as incomplete, Fix commit message to be generic.] Signed-off-by: Sai Pavan Boddu --- hw/sd/sd.c | 40 1 file changed, 40 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 54fba7b..55c1104 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1045,6 +1045,34 @@ static void sd_lock_command(SDState *sd) sd->card_status &= ~CARD_IS_LOCKED; } +/* + * This requires a disk image that has two boot partitions inserted at the + * beginning of it. The size of the boot partitions are configured in the + * ext_csd structure, which is hardcoded in qemu. They are currently set to + * 1MB each. + */ +static uint32_t sd_bootpart_offset(SDState *sd) +{ +unsigned int access = sd->ext_csd[EXT_CSD_PART_CONFIG] & +EXT_CSD_PART_CONFIG_ACC_MASK; +unsigned int boot_capacity = sd->ext_csd[EXT_CSD_BOOT_MULT] << 17; + +if (!sd->emmc) { +return 0; +} + +switch (access) { +case EXT_CSD_PART_CONFIG_ACC_DEFAULT: +return boot_capacity * 2; +case EXT_CSD_PART_CONFIG_ACC_BOOT0: +return 0; +case EXT_CSD_PART_CONFIG_ACC_BOOT0 + 1: +return boot_capacity * 1; +default: + g_assert_not_reached(); +} +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint32_t rca = 0x; @@ -1360,6 +1388,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_sendingdata_state; sd->data_start = addr; sd->data_offset = 0; @@ -1379,6 +1410,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_sendingdata_state; sd->data_start = addr; sd->data_offset = 0; @@ -1435,6 +1469,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_receivingdata_state; sd->data_start = addr; sd->data_offset = 0; @@ -1465,6 +1502,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r1; } +if (sd->emmc) { +addr += sd_bootpart_offset(sd); +} sd->state = sd_receivingdata_state; sd->data_start = addr; sd->data_offset = 0; -- 2.7.4
[RFC PATCH 01/15] block: add eMMC block device type
From: Vincent Palatin Add new block device type. Signed-off-by: Vincent Palatin [SPB: Rebased over 5.1 version] Signed-off-by: Sai Pavan Boddu Signed-off-by: Joel Stanley Signed-off-by: Cédric Le Goater --- blockdev.c| 1 + include/sysemu/blockdev.h | 1 + 2 files changed, 2 insertions(+) diff --git a/blockdev.c b/blockdev.c index b250b9b..593ce44 100644 --- a/blockdev.c +++ b/blockdev.c @@ -83,6 +83,7 @@ static const char *const if_name[IF_COUNT] = { [IF_SD] = "sd", [IF_VIRTIO] = "virtio", [IF_XEN] = "xen", +[IF_EMMC] = "emmc", }; static int if_max_devs[IF_COUNT] = { diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h index 3b5fcda..eefae9f 100644 --- a/include/sysemu/blockdev.h +++ b/include/sysemu/blockdev.h @@ -24,6 +24,7 @@ typedef enum { */ IF_NONE = 0, IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN, +IF_EMMC, IF_COUNT } BlockInterfaceType; -- 2.7.4