* [PATCH 1/4] tests/qtest/libqos: add SDHCI commands
2021-09-07 23:25 [PATCH 0/4] hw/arm: Add MMC device for NPCM7XX boards Hao Wu
@ 2021-09-07 23:25 ` Hao Wu
2021-09-13 14:48 ` Peter Maydell
2021-09-07 23:25 ` [PATCH 2/4] hw/sd: add nuvoton MMC Hao Wu
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Hao Wu @ 2021-09-07 23:25 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-arm, qemu-devel, wuhaotsh, venture, Avi.Fishman, kfting,
hskinnemoen, f4bug, bin.meng, qemu-block, Shengtan Mao,
Chris Rauer
From: Shengtan Mao <stmao@google.com>
Signed-off-by: Shengtan Mao <stmao@google.com>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
Reviewed-by: Chris Rauer <crauer@google.com>
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
---
tests/qtest/libqos/meson.build | 1 +
tests/qtest/libqos/sdhci-cmd.c | 116 +++++++++++++++++++++++++++++++++
tests/qtest/libqos/sdhci-cmd.h | 70 ++++++++++++++++++++
3 files changed, 187 insertions(+)
create mode 100644 tests/qtest/libqos/sdhci-cmd.c
create mode 100644 tests/qtest/libqos/sdhci-cmd.h
diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build
index 1f5c8f1053..4af1f04787 100644
--- a/tests/qtest/libqos/meson.build
+++ b/tests/qtest/libqos/meson.build
@@ -5,6 +5,7 @@ libqos_srcs = files('../libqtest.c',
'fw_cfg.c',
'malloc.c',
'libqos.c',
+ 'sdhci-cmd.c',
# spapr
'malloc-spapr.c',
diff --git a/tests/qtest/libqos/sdhci-cmd.c b/tests/qtest/libqos/sdhci-cmd.c
new file mode 100644
index 0000000000..2d9e518341
--- /dev/null
+++ b/tests/qtest/libqos/sdhci-cmd.c
@@ -0,0 +1,116 @@
+/*
+ * MMC Host Controller Commands
+ *
+ * Copyright (c) 2021 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+#include "sdhci-cmd.h"
+#include "libqtest.h"
+
+static ssize_t read_fifo(QTestState *qts, uint64_t reg, char *msg, size_t count)
+{
+ uint32_t mask = 0xff;
+ size_t index = 0;
+ uint32_t msg_frag;
+ int size;
+ while (index < count) {
+ size = count - index;
+ if (size > 4) {
+ size = 4;
+ }
+ msg_frag = qtest_readl(qts, reg);
+ while (size > 0) {
+ msg[index] = msg_frag & mask;
+ if (msg[index++] == 0) {
+ return index;
+ }
+ msg_frag >>= 8;
+ --size;
+ }
+ }
+ return index;
+}
+
+static void write_fifo(QTestState *qts, uint64_t reg, const char *msg,
+ size_t count)
+{
+ size_t index = 0;
+ uint32_t msg_frag;
+ int size;
+ int frag_i;
+ while (index < count) {
+ size = count - index;
+ if (size > 4) {
+ size = 4;
+ }
+ msg_frag = 0;
+ frag_i = 0;
+ while (frag_i < size) {
+ msg_frag |= ((uint32_t)msg[index++]) << (frag_i * 8);
+ ++frag_i;
+ }
+ qtest_writel(qts, reg, msg_frag);
+ }
+}
+
+static void fill_block(QTestState *qts, uint64_t reg, int count)
+{
+ while (--count >= 0) {
+ qtest_writel(qts, reg, 0);
+ }
+}
+
+void sdhci_cmd_regs(QTestState *qts, uint64_t base_addr, uint16_t blksize,
+ uint16_t blkcnt, uint32_t argument, uint16_t trnmod,
+ uint16_t cmdreg)
+{
+ qtest_writew(qts, base_addr + SDHC_BLKSIZE, blksize);
+ qtest_writew(qts, base_addr + SDHC_BLKCNT, blkcnt);
+ qtest_writel(qts, base_addr + SDHC_ARGUMENT, argument);
+ qtest_writew(qts, base_addr + SDHC_TRNMOD, trnmod);
+ qtest_writew(qts, base_addr + SDHC_CMDREG, cmdreg);
+}
+
+ssize_t sdhci_read_cmd(QTestState *qts, uint64_t base_addr, char *msg,
+ size_t count)
+{
+ sdhci_cmd_regs(qts, base_addr, count, 1, 0,
+ SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN,
+ SDHC_READ_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT);
+
+ /* read sd fifo_buffer */
+ ssize_t bytes_read = read_fifo(qts, base_addr + SDHC_BDATA, msg, count);
+
+ sdhci_cmd_regs(qts, base_addr, 0, 0, 0,
+ SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN,
+ SDHC_STOP_TRANSMISSION);
+
+ return bytes_read;
+}
+
+void sdhci_write_cmd(QTestState *qts, uint64_t base_addr, const char *msg,
+ size_t count, size_t blksize)
+{
+ sdhci_cmd_regs(qts, base_addr, blksize, 1, 0,
+ SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN,
+ SDHC_WRITE_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT);
+
+ /* write to sd fifo_buffer */
+ write_fifo(qts, base_addr + SDHC_BDATA, msg, count);
+ fill_block(qts, base_addr + SDHC_BDATA, (blksize - count) / 4);
+
+ sdhci_cmd_regs(qts, base_addr, 0, 0, 0,
+ SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN,
+ SDHC_STOP_TRANSMISSION);
+}
diff --git a/tests/qtest/libqos/sdhci-cmd.h b/tests/qtest/libqos/sdhci-cmd.h
new file mode 100644
index 0000000000..64763c5a2a
--- /dev/null
+++ b/tests/qtest/libqos/sdhci-cmd.h
@@ -0,0 +1,70 @@
+/*
+ * MMC Host Controller Commands
+ *
+ * Copyright (c) 2021 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "libqtest.h"
+
+/* more details at hw/sd/sdhci-internal.h */
+#define SDHC_BLKSIZE 0x04
+#define SDHC_BLKCNT 0x06
+#define SDHC_ARGUMENT 0x08
+#define SDHC_TRNMOD 0x0C
+#define SDHC_CMDREG 0x0E
+#define SDHC_BDATA 0x20
+#define SDHC_PRNSTS 0x24
+#define SDHC_BLKGAP 0x2A
+#define SDHC_CLKCON 0x2C
+#define SDHC_SWRST 0x2F
+#define SDHC_CAPAB 0x40
+#define SDHC_MAXCURR 0x48
+#define SDHC_HCVER 0xFE
+
+/* TRNSMOD Reg */
+#define SDHC_TRNS_BLK_CNT_EN 0x0002
+#define SDHC_TRNS_READ 0x0010
+#define SDHC_TRNS_WRITE 0x0000
+#define SDHC_TRNS_MULTI 0x0020
+
+/* CMD Reg */
+#define SDHC_CMD_DATA_PRESENT (1 << 5)
+#define SDHC_ALL_SEND_CID (2 << 8)
+#define SDHC_SEND_RELATIVE_ADDR (3 << 8)
+#define SDHC_SELECT_DESELECT_CARD (7 << 8)
+#define SDHC_SEND_CSD (9 << 8)
+#define SDHC_STOP_TRANSMISSION (12 << 8)
+#define SDHC_READ_MULTIPLE_BLOCK (18 << 8)
+#define SDHC_WRITE_MULTIPLE_BLOCK (25 << 8)
+#define SDHC_APP_CMD (55 << 8)
+
+/* SWRST Reg */
+#define SDHC_RESET_ALL 0x01
+
+/* CLKCTRL Reg */
+#define SDHC_CLOCK_INT_EN 0x0001
+#define SDHC_CLOCK_INT_STABLE 0x0002
+#define SDHC_CLOCK_SDCLK_EN (1 << 2)
+
+/* Set registers needed to send commands to SD */
+void sdhci_cmd_regs(QTestState *qts, uint64_t base_addr, uint16_t blksize,
+ uint16_t blkcnt, uint32_t argument, uint16_t trnmod,
+ uint16_t cmdreg);
+
+/* Read at most 1 block of SD using non-DMA */
+ssize_t sdhci_read_cmd(QTestState *qts, uint64_t base_addr, char *msg,
+ size_t count);
+
+/* Write at most 1 block of SD using non-DMA */
+void sdhci_write_cmd(QTestState *qts, uint64_t base_addr, const char *msg,
+ size_t count, size_t blksize);
--
2.33.0.153.gba50c8fa24-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] tests/qtest/libqos: add SDHCI commands
2021-09-07 23:25 ` [PATCH 1/4] tests/qtest/libqos: add SDHCI commands Hao Wu
@ 2021-09-13 14:48 ` Peter Maydell
0 siblings, 0 replies; 9+ messages in thread
From: Peter Maydell @ 2021-09-13 14:48 UTC (permalink / raw)
To: Hao Wu
Cc: Qemu-block, Patrick Venture, Bin Meng, Havard Skinnemoen,
QEMU Developers, CS20 KFTing, qemu-arm, IS20 Avi Fishman,
Chris Rauer, Philippe Mathieu-Daudé
On Wed, 8 Sept 2021 at 00:26, Hao Wu <wuhaotsh@google.com> wrote:
>
> From: Shengtan Mao <stmao@google.com>
>
> Signed-off-by: Shengtan Mao <stmao@google.com>
> Reviewed-by: Hao Wu <wuhaotsh@google.com>
> Reviewed-by: Chris Rauer <crauer@google.com>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
I think this patch would make more sense placed later in the
series, just before the current patch 4 which is the user
of the functions added here.
-- PMM
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/4] hw/sd: add nuvoton MMC
2021-09-07 23:25 [PATCH 0/4] hw/arm: Add MMC device for NPCM7XX boards Hao Wu
2021-09-07 23:25 ` [PATCH 1/4] tests/qtest/libqos: add SDHCI commands Hao Wu
@ 2021-09-07 23:25 ` Hao Wu
2021-09-13 14:16 ` Peter Maydell
2021-09-07 23:25 ` [PATCH 3/4] hw/arm: Attach MMC to quanta-gbs-bmc Hao Wu
2021-09-07 23:25 ` [PATCH 4/4] tests/qtest: add qtests for npcm7xx sdhci Hao Wu
3 siblings, 1 reply; 9+ messages in thread
From: Hao Wu @ 2021-09-07 23:25 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-arm, qemu-devel, wuhaotsh, venture, Avi.Fishman, kfting,
hskinnemoen, f4bug, bin.meng, qemu-block, Shengtan Mao,
Chris Rauer
From: Shengtan Mao <stmao@google.com>
Signed-off-by: Shengtan Mao <stmao@google.com>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
Reviewed-by: Chris Rauer <crauer@google.com>
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
---
hw/arm/npcm7xx.c | 12 +++-
hw/sd/meson.build | 1 +
hw/sd/npcm7xx_sdhci.c | 131 ++++++++++++++++++++++++++++++++++
include/hw/arm/npcm7xx.h | 2 +
include/hw/sd/npcm7xx_sdhci.h | 65 +++++++++++++++++
5 files changed, 210 insertions(+), 1 deletion(-)
create mode 100644 hw/sd/npcm7xx_sdhci.c
create mode 100644 include/hw/sd/npcm7xx_sdhci.h
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index 2ab0080e0b..878c2208e0 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -63,6 +63,8 @@
#define NPCM7XX_ROM_BA (0xffff0000)
#define NPCM7XX_ROM_SZ (64 * KiB)
+/* SDHCI Modules */
+#define NPCM7XX_MMC_BA (0xf0842000)
/* Clock configuration values to be fixed up when bypassing bootloader */
@@ -83,6 +85,7 @@ enum NPCM7xxInterrupt {
NPCM7XX_UART3_IRQ,
NPCM7XX_EMC1RX_IRQ = 15,
NPCM7XX_EMC1TX_IRQ,
+ NPCM7XX_MMC_IRQ = 26,
NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */
NPCM7XX_TIMER1_IRQ,
NPCM7XX_TIMER2_IRQ,
@@ -443,6 +446,8 @@ static void npcm7xx_init(Object *obj)
for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
}
+
+ object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
}
static void npcm7xx_realize(DeviceState *dev, Error **errp)
@@ -707,6 +712,12 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
&error_abort);
memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom);
+ /* SDHCI */
+ sysbus_realize(SYS_BUS_DEVICE(&s->mmc), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc), 0, NPCM7XX_MMC_BA);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
+ npcm7xx_irq(s, NPCM7XX_MMC_IRQ));
+
create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB);
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
@@ -736,7 +747,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("npcm7xx.usbd[8]", 0xf0838000, 4 * KiB);
create_unimplemented_device("npcm7xx.usbd[9]", 0xf0839000, 4 * KiB);
create_unimplemented_device("npcm7xx.sd", 0xf0840000, 8 * KiB);
- create_unimplemented_device("npcm7xx.mmc", 0xf0842000, 8 * KiB);
create_unimplemented_device("npcm7xx.pcimbx", 0xf0848000, 512 * KiB);
create_unimplemented_device("npcm7xx.aes", 0xf0858000, 4 * KiB);
create_unimplemented_device("npcm7xx.des", 0xf0859000, 4 * KiB);
diff --git a/hw/sd/meson.build b/hw/sd/meson.build
index f1ce357a3b..807ca07b7c 100644
--- a/hw/sd/meson.build
+++ b/hw/sd/meson.build
@@ -9,4 +9,5 @@ softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c'))
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c'))
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_sdhci.c'))
softmmu_ss.add(when: 'CONFIG_CADENCE_SDHCI', if_true: files('cadence_sdhci.c'))
diff --git a/hw/sd/npcm7xx_sdhci.c b/hw/sd/npcm7xx_sdhci.c
new file mode 100644
index 0000000000..85cccdc485
--- /dev/null
+++ b/hw/sd/npcm7xx_sdhci.c
@@ -0,0 +1,131 @@
+/*
+ * NPCM7xx SD-3.0 / eMMC-4.51 Host Controller
+ *
+ * Copyright (c) 2021 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/sd/npcm7xx_sdhci.h"
+#include "sdhci-internal.h"
+
+static uint64_t npcm7xx_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ NPCM7xxSDHCIState *s = opaque;
+ uint64_t val = 0;
+
+ switch (addr) {
+ case NPCM7XX_PRSTVALS_0:
+ case NPCM7XX_PRSTVALS_1:
+ case NPCM7XX_PRSTVALS_2:
+ case NPCM7XX_PRSTVALS_3:
+ case NPCM7XX_PRSTVALS_4:
+ case NPCM7XX_PRSTVALS_5:
+ val = (uint64_t)s->regs.prstvals[(addr - NPCM7XX_PRSTVALS_0) / 2];
+ break;
+ case NPCM7XX_BOOTTOCTRL:
+ val = (uint64_t)s->regs.boottoctrl;
+ break;
+ default:
+ val = (uint64_t)s->sdhci.io_ops->read(&s->sdhci, addr, size);
+ }
+
+ return val;
+}
+
+static void npcm7xx_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned int size)
+{
+ NPCM7xxSDHCIState *s = opaque;
+
+ switch (addr) {
+ case NPCM7XX_BOOTTOCTRL:
+ s->regs.boottoctrl = (uint32_t)val;
+ break;
+ default:
+ s->sdhci.io_ops->write(&s->sdhci, addr, val, size);
+ }
+}
+
+static const MemoryRegionOps npcm7xx_sdhci_ops = {
+ .read = npcm7xx_sdhci_read,
+ .write = npcm7xx_sdhci_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {.min_access_size = 1, .max_access_size = 4, .unaligned = false},
+};
+
+static void npcm7xx_sdhci_realize(DeviceState *dev, Error **errp)
+{
+ NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ SysBusDevice *sbd_sdhci = SYS_BUS_DEVICE(&s->sdhci);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_sdhci_ops, s,
+ TYPE_NPCM7XX_SDHCI, 0x1000);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_realize(sbd_sdhci, errp);
+
+ /* propagate irq and "sd-bus" from generic-sdhci */
+ sysbus_pass_irq(sbd, sbd_sdhci);
+ s->bus = qdev_get_child_bus(DEVICE(sbd_sdhci), "sd-bus");
+}
+
+static void npcm7xx_sdhci_reset(DeviceState *dev)
+{
+ NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(dev);
+ device_cold_reset(DEVICE(&s->sdhci));
+ s->regs.boottoctrl = 0;
+
+ s->sdhci.prnsts = NPCM7XX_PRSNTS_RESET;
+ s->sdhci.blkgap = NPCM7XX_BLKGAP_RESET;
+ s->sdhci.capareg = NPCM7XX_CAPAB_RESET;
+ s->sdhci.maxcurr = NPCM7XX_MAXCURR_RESET;
+ s->sdhci.version = NPCM7XX_HCVER_RESET;
+
+ memset(s->regs.prstvals, 0, NPCM7XX_PRSTVALS_SIZE * sizeof(uint16_t));
+ s->regs.prstvals[0] = NPCM7XX_PRSTVALS_0_RESET;
+ s->regs.prstvals[1] = NPCM7XX_PRSTVALS_1_RESET;
+ s->regs.prstvals[3] = NPCM7XX_PRSTVALS_3_RESET;
+}
+
+static void npcm7xx_sdhci_class_init(ObjectClass *classp, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(classp);
+
+ dc->desc = "NPCM7xx SD/eMMC Host Controller";
+ dc->realize = npcm7xx_sdhci_realize;
+ dc->reset = npcm7xx_sdhci_reset;
+}
+
+static void npcm7xx_sdhci_instance_init(Object *obj)
+{
+ NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(obj);
+
+ object_initialize_child(OBJECT(s), "generic-sdhci", &s->sdhci,
+ TYPE_SYSBUS_SDHCI);
+}
+
+static TypeInfo npcm7xx_sdhci_info = {
+ .name = TYPE_NPCM7XX_SDHCI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCM7xxSDHCIState),
+ .instance_init = npcm7xx_sdhci_instance_init,
+ .class_init = npcm7xx_sdhci_class_init,
+};
+
+static void npcm7xx_sdhci_register_types(void)
+{
+ type_register_static(&npcm7xx_sdhci_info);
+}
+
+type_init(npcm7xx_sdhci_register_types)
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
index 61ecc57ab9..ce593235d9 100644
--- a/include/hw/arm/npcm7xx.h
+++ b/include/hw/arm/npcm7xx.h
@@ -35,6 +35,7 @@
#include "hw/usb/hcd-ehci.h"
#include "hw/usb/hcd-ohci.h"
#include "target/arm/cpu.h"
+#include "hw/sd/npcm7xx_sdhci.h"
#define NPCM7XX_MAX_NUM_CPUS (2)
@@ -103,6 +104,7 @@ typedef struct NPCM7xxState {
OHCISysBusState ohci;
NPCM7xxFIUState fiu[2];
NPCM7xxEMCState emc[2];
+ NPCM7xxSDHCIState mmc;
} NPCM7xxState;
#define TYPE_NPCM7XX "npcm7xx"
diff --git a/include/hw/sd/npcm7xx_sdhci.h b/include/hw/sd/npcm7xx_sdhci.h
new file mode 100644
index 0000000000..4d132f521b
--- /dev/null
+++ b/include/hw/sd/npcm7xx_sdhci.h
@@ -0,0 +1,65 @@
+/*
+ * NPCM7xx SD-3.0 / eMMC-4.51 Host Controller
+ *
+ * Copyright (c) 2021 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef NPCM7XX_SDHCI_H
+#define NPCM7XX_SDHCI_H
+
+#include "hw/sd/sdhci.h"
+#include "qom/object.h"
+
+#define TYPE_NPCM7XX_SDHCI "npcm7xx.sdhci"
+#define NPCM7XX_REG_SIZE 0x100
+
+#define NPCM7XX_PRSTVALS_SIZE 6
+#define NPCM7XX_PRSTVALS 0x60
+#define NPCM7XX_PRSTVALS_0 0x60
+#define NPCM7XX_PRSTVALS_1 0x62
+#define NPCM7XX_PRSTVALS_2 0x64
+#define NPCM7XX_PRSTVALS_3 0x66
+#define NPCM7XX_PRSTVALS_4 0x68
+#define NPCM7XX_PRSTVALS_5 0x6A
+#define NPCM7XX_BOOTTOCTRL 0x70
+
+#define NPCM7XX_PRSNTS_RESET 0x04A00000
+#define NPCM7XX_BLKGAP_RESET 0x80
+#define NPCM7XX_CAPAB_RESET 0x0100200161EE0399
+#define NPCM7XX_MAXCURR_RESET 0x0000000000000005
+#define NPCM7XX_HCVER_RESET 0x1002
+
+#define NPCM7XX_PRSTVALS_0_RESET 0x0040
+#define NPCM7XX_PRSTVALS_1_RESET 0x0001
+#define NPCM7XX_PRSTVALS_3_RESET 0x0001
+
+OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxSDHCIState, NPCM7XX_SDHCI)
+
+typedef struct NPCM7xxRegs {
+ /* Preset Values Register Field, read-only */
+ uint16_t prstvals[NPCM7XX_PRSTVALS_SIZE];
+ /* Boot Timeout Control Register, read-write */
+ uint32_t boottoctrl;
+} NPCM7xxRegisters;
+
+typedef struct NPCM7xxSDHCIState {
+ SysBusDevice parent;
+
+ MemoryRegion iomem;
+ BusState *bus;
+ NPCM7xxRegisters regs;
+
+ SDHCIState sdhci;
+} NPCM7xxSDHCIState;
+
+#endif /* NPCM7XX_SDHCI_H */
--
2.33.0.153.gba50c8fa24-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 2/4] hw/sd: add nuvoton MMC
2021-09-07 23:25 ` [PATCH 2/4] hw/sd: add nuvoton MMC Hao Wu
@ 2021-09-13 14:16 ` Peter Maydell
0 siblings, 0 replies; 9+ messages in thread
From: Peter Maydell @ 2021-09-13 14:16 UTC (permalink / raw)
To: Hao Wu
Cc: Qemu-block, Patrick Venture, Shengtan Mao, Bin Meng,
Havard Skinnemoen, QEMU Developers, CS20 KFTing, qemu-arm,
IS20 Avi Fishman, Chris Rauer, Philippe Mathieu-Daudé
On Wed, 8 Sept 2021 at 00:26, Hao Wu <wuhaotsh@google.com> wrote:
>
> From: Shengtan Mao <stmao@google.com>
>
> Signed-off-by: Shengtan Mao <stmao@google.com>
> Reviewed-by: Hao Wu <wuhaotsh@google.com>
> Reviewed-by: Chris Rauer <crauer@google.com>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> ---
> hw/arm/npcm7xx.c | 12 +++-
> hw/sd/meson.build | 1 +
> hw/sd/npcm7xx_sdhci.c | 131 ++++++++++++++++++++++++++++++++++
> include/hw/arm/npcm7xx.h | 2 +
> include/hw/sd/npcm7xx_sdhci.h | 65 +++++++++++++++++
> 5 files changed, 210 insertions(+), 1 deletion(-)
> create mode 100644 hw/sd/npcm7xx_sdhci.c
> create mode 100644 include/hw/sd/npcm7xx_sdhci.h
>
> diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
> index 2ab0080e0b..878c2208e0 100644
> --- a/hw/arm/npcm7xx.c
> +++ b/hw/arm/npcm7xx.c
> @@ -63,6 +63,8 @@
> #define NPCM7XX_ROM_BA (0xffff0000)
> #define NPCM7XX_ROM_SZ (64 * KiB)
>
> +/* SDHCI Modules */
> +#define NPCM7XX_MMC_BA (0xf0842000)
>
> /* Clock configuration values to be fixed up when bypassing bootloader */
>
> @@ -83,6 +85,7 @@ enum NPCM7xxInterrupt {
> NPCM7XX_UART3_IRQ,
> NPCM7XX_EMC1RX_IRQ = 15,
> NPCM7XX_EMC1TX_IRQ,
> + NPCM7XX_MMC_IRQ = 26,
> NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */
> NPCM7XX_TIMER1_IRQ,
> NPCM7XX_TIMER2_IRQ,
> @@ -443,6 +446,8 @@ static void npcm7xx_init(Object *obj)
> for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
> object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
> }
> +
> + object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
> }
>
> static void npcm7xx_realize(DeviceState *dev, Error **errp)
> @@ -707,6 +712,12 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
> &error_abort);
> memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom);
>
> + /* SDHCI */
> + sysbus_realize(SYS_BUS_DEVICE(&s->mmc), &error_abort);
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc), 0, NPCM7XX_MMC_BA);
> + sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
> + npcm7xx_irq(s, NPCM7XX_MMC_IRQ));
> +
> create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB);
> create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
> create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
> @@ -736,7 +747,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
> create_unimplemented_device("npcm7xx.usbd[8]", 0xf0838000, 4 * KiB);
> create_unimplemented_device("npcm7xx.usbd[9]", 0xf0839000, 4 * KiB);
> create_unimplemented_device("npcm7xx.sd", 0xf0840000, 8 * KiB);
> - create_unimplemented_device("npcm7xx.mmc", 0xf0842000, 8 * KiB);
> create_unimplemented_device("npcm7xx.pcimbx", 0xf0848000, 512 * KiB);
> create_unimplemented_device("npcm7xx.aes", 0xf0858000, 4 * KiB);
> create_unimplemented_device("npcm7xx.des", 0xf0859000, 4 * KiB);
The "add to board" code should be a separate patch from
"implement this new device".
> diff --git a/hw/sd/meson.build b/hw/sd/meson.build
> index f1ce357a3b..807ca07b7c 100644
> --- a/hw/sd/meson.build
> +++ b/hw/sd/meson.build
> @@ -9,4 +9,5 @@ softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
> softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
> softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c'))
> softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c'))
> +softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_sdhci.c'))
> softmmu_ss.add(when: 'CONFIG_CADENCE_SDHCI', if_true: files('cadence_sdhci.c'))
> diff --git a/hw/sd/npcm7xx_sdhci.c b/hw/sd/npcm7xx_sdhci.c
> new file mode 100644
> index 0000000000..85cccdc485
> --- /dev/null
> +++ b/hw/sd/npcm7xx_sdhci.c
> @@ -0,0 +1,131 @@
> +/*
> + * NPCM7xx SD-3.0 / eMMC-4.51 Host Controller
> + *
> + * Copyright (c) 2021 Google LLC
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> + * for more details.
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "hw/sd/npcm7xx_sdhci.h"
> +#include "sdhci-internal.h"
> +
> +static uint64_t npcm7xx_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
> +{
> + NPCM7xxSDHCIState *s = opaque;
> + uint64_t val = 0;
> +
> + switch (addr) {
> + case NPCM7XX_PRSTVALS_0:
> + case NPCM7XX_PRSTVALS_1:
> + case NPCM7XX_PRSTVALS_2:
> + case NPCM7XX_PRSTVALS_3:
> + case NPCM7XX_PRSTVALS_4:
> + case NPCM7XX_PRSTVALS_5:
> + val = (uint64_t)s->regs.prstvals[(addr - NPCM7XX_PRSTVALS_0) / 2];
> + break;
> + case NPCM7XX_BOOTTOCTRL:
> + val = (uint64_t)s->regs.boottoctrl;
Your MemoryRegionOps says that accesses of between 1 and 4
bytes are OK, but this code won't handle eg byte reads of the
high byte of one of these 16-bit registers. What does the
hardware require in the way of alignment ?
> + break;
> + default:
> + val = (uint64_t)s->sdhci.io_ops->read(&s->sdhci, addr, size);
I don't think all these (uint64_t) casts are necessary.
I think it would be nicer to handle the registers that
are done by the generic-sdhci object the same way that
hw/sd/cadence-sdhci.c does it -- have a container region
that the sdhci registers get mapped into at the appropriate
offset, with a fallback io ops for the ones that aren't
handled by the generic-sdhci MemoryRegion.
> + }
> +
> + return val;
> +}
> +
> +static void npcm7xx_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
> + unsigned int size)
> +{
> + NPCM7xxSDHCIState *s = opaque;
> +
> + switch (addr) {
> + case NPCM7XX_BOOTTOCTRL:
> + s->regs.boottoctrl = (uint32_t)val;
This cast isn't needed either.
> + break;
> + default:
> + s->sdhci.io_ops->write(&s->sdhci, addr, val, size);
> + }
> +}
> +
> +static const MemoryRegionOps npcm7xx_sdhci_ops = {
> + .read = npcm7xx_sdhci_read,
> + .write = npcm7xx_sdhci_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> + .valid = {.min_access_size = 1, .max_access_size = 4, .unaligned = false},
This shouldn't be all on one line;
.valid = {
.min_access_size = 1,
.max_access_size = 4,
.unaligned = false,
},
> +};
> +
> +static void npcm7xx_sdhci_realize(DeviceState *dev, Error **errp)
> +{
> + NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(dev);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> + SysBusDevice *sbd_sdhci = SYS_BUS_DEVICE(&s->sdhci);
> +
> + memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_sdhci_ops, s,
> + TYPE_NPCM7XX_SDHCI, 0x1000);
> + sysbus_init_mmio(sbd, &s->iomem);
> + sysbus_realize(sbd_sdhci, errp);
> +
> + /* propagate irq and "sd-bus" from generic-sdhci */
> + sysbus_pass_irq(sbd, sbd_sdhci);
> + s->bus = qdev_get_child_bus(DEVICE(sbd_sdhci), "sd-bus");
> +}
> +
> +static void npcm7xx_sdhci_reset(DeviceState *dev)
> +{
> + NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(dev);
> + device_cold_reset(DEVICE(&s->sdhci));
> + s->regs.boottoctrl = 0;
> +
> + s->sdhci.prnsts = NPCM7XX_PRSNTS_RESET;
> + s->sdhci.blkgap = NPCM7XX_BLKGAP_RESET;
> + s->sdhci.capareg = NPCM7XX_CAPAB_RESET;
> + s->sdhci.maxcurr = NPCM7XX_MAXCURR_RESET;
> + s->sdhci.version = NPCM7XX_HCVER_RESET;
> +
> + memset(s->regs.prstvals, 0, NPCM7XX_PRSTVALS_SIZE * sizeof(uint16_t));
Using 'sizeof(s->regs.prstvals)' allows you to avoid having
to keep the type and member count in sync here.
> + s->regs.prstvals[0] = NPCM7XX_PRSTVALS_0_RESET;
> + s->regs.prstvals[1] = NPCM7XX_PRSTVALS_1_RESET;
> + s->regs.prstvals[3] = NPCM7XX_PRSTVALS_3_RESET;
Aren't these read-only? If so, you can set them to their
correct values in the realize function and need not reinit
them in reset.
> +}
> +
> +static void npcm7xx_sdhci_class_init(ObjectClass *classp, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(classp);
> +
> + dc->desc = "NPCM7xx SD/eMMC Host Controller";
> + dc->realize = npcm7xx_sdhci_realize;
> + dc->reset = npcm7xx_sdhci_reset;
This device has at least one piece of modifiable internal
state (the boottoctrl register). So it needs a vmstate
struct for migration.
thanks
-- PMM
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/4] hw/arm: Attach MMC to quanta-gbs-bmc
2021-09-07 23:25 [PATCH 0/4] hw/arm: Add MMC device for NPCM7XX boards Hao Wu
2021-09-07 23:25 ` [PATCH 1/4] tests/qtest/libqos: add SDHCI commands Hao Wu
2021-09-07 23:25 ` [PATCH 2/4] hw/sd: add nuvoton MMC Hao Wu
@ 2021-09-07 23:25 ` Hao Wu
2021-09-13 14:40 ` Peter Maydell
2021-09-07 23:25 ` [PATCH 4/4] tests/qtest: add qtests for npcm7xx sdhci Hao Wu
3 siblings, 1 reply; 9+ messages in thread
From: Hao Wu @ 2021-09-07 23:25 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-arm, qemu-devel, wuhaotsh, venture, Avi.Fishman, kfting,
hskinnemoen, f4bug, bin.meng, qemu-block, Shengtan Mao
From: Shengtan Mao <stmao@google.com>
Signed-off-by: Shengtan Mao <stmao@google.com>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
---
hw/arm/npcm7xx_boards.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
index e5a3243995..7205483280 100644
--- a/hw/arm/npcm7xx_boards.c
+++ b/hw/arm/npcm7xx_boards.c
@@ -27,6 +27,10 @@
#include "qemu-common.h"
#include "qemu/datadir.h"
#include "qemu/units.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/block-backend.h"
+
#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7
#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff
@@ -80,6 +84,22 @@ static void npcm7xx_connect_dram(NPCM7xxState *soc, MemoryRegion *dram)
&error_abort);
}
+static void sdhci_attach_drive(SDHCIState *sdhci)
+{
+ DriveInfo *di = drive_get_next(IF_SD);
+ BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
+
+ BusState *bus = qdev_get_child_bus(DEVICE(sdhci), "sd-bus");
+ if (bus == NULL) {
+ error_report("No SD bus found in SOC object");
+ exit(1);
+ }
+
+ DeviceState *carddev = qdev_new(TYPE_SD_CARD);
+ qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
+ qdev_realize_and_unref(carddev, bus, &error_fatal);
+}
+
static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
uint32_t hw_straps)
{
@@ -354,6 +374,7 @@ static void quanta_gbs_init(MachineState *machine)
drive_get(IF_MTD, 0, 0));
quanta_gbs_i2c_init(soc);
+ sdhci_attach_drive(&soc->mmc.sdhci);
npcm7xx_load_kernel(machine, soc);
}
--
2.33.0.153.gba50c8fa24-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 3/4] hw/arm: Attach MMC to quanta-gbs-bmc
2021-09-07 23:25 ` [PATCH 3/4] hw/arm: Attach MMC to quanta-gbs-bmc Hao Wu
@ 2021-09-13 14:40 ` Peter Maydell
0 siblings, 0 replies; 9+ messages in thread
From: Peter Maydell @ 2021-09-13 14:40 UTC (permalink / raw)
To: Hao Wu
Cc: Qemu-block, Patrick Venture, Shengtan Mao, Bin Meng,
Havard Skinnemoen, QEMU Developers, CS20 KFTing, qemu-arm,
IS20 Avi Fishman, Philippe Mathieu-Daudé
On Wed, 8 Sept 2021 at 00:26, Hao Wu <wuhaotsh@google.com> wrote:
>
> From: Shengtan Mao <stmao@google.com>
>
> Signed-off-by: Shengtan Mao <stmao@google.com>
> Reviewed-by: Hao Wu <wuhaotsh@google.com>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> ---
> hw/arm/npcm7xx_boards.c | 21 +++++++++++++++++++++
> 1 file changed, 21 insertions(+)
>
> diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
> index e5a3243995..7205483280 100644
> --- a/hw/arm/npcm7xx_boards.c
> +++ b/hw/arm/npcm7xx_boards.c
> @@ -27,6 +27,10 @@
> #include "qemu-common.h"
> #include "qemu/datadir.h"
> #include "qemu/units.h"
> +#include "sysemu/blockdev.h"
> +#include "sysemu/sysemu.h"
> +#include "sysemu/block-backend.h"
> +
>
Stray extra blank line. Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/4] tests/qtest: add qtests for npcm7xx sdhci
2021-09-07 23:25 [PATCH 0/4] hw/arm: Add MMC device for NPCM7XX boards Hao Wu
` (2 preceding siblings ...)
2021-09-07 23:25 ` [PATCH 3/4] hw/arm: Attach MMC to quanta-gbs-bmc Hao Wu
@ 2021-09-07 23:25 ` Hao Wu
2021-09-13 14:47 ` Peter Maydell
3 siblings, 1 reply; 9+ messages in thread
From: Hao Wu @ 2021-09-07 23:25 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-arm, qemu-devel, wuhaotsh, venture, Avi.Fishman, kfting,
hskinnemoen, f4bug, bin.meng, qemu-block, Shengtan Mao,
Chris Rauer
From: Shengtan Mao <stmao@google.com>
Signed-off-by: Shengtan Mao <stmao@google.com>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
Reviewed-by: Chris Rauer <crauer@google.com>
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
---
tests/qtest/meson.build | 1 +
tests/qtest/npcm7xx_sdhci-test.c | 201 +++++++++++++++++++++++++++++++
2 files changed, 202 insertions(+)
create mode 100644 tests/qtest/npcm7xx_sdhci-test.c
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 757bb8499a..ef9c904779 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -157,6 +157,7 @@ qtests_npcm7xx = \
'npcm7xx_gpio-test',
'npcm7xx_pwm-test',
'npcm7xx_rng-test',
+ 'npcm7xx_sdhci-test',
'npcm7xx_smbus-test',
'npcm7xx_timer-test',
'npcm7xx_watchdog_timer-test'] + \
diff --git a/tests/qtest/npcm7xx_sdhci-test.c b/tests/qtest/npcm7xx_sdhci-test.c
new file mode 100644
index 0000000000..5c4e78fda4
--- /dev/null
+++ b/tests/qtest/npcm7xx_sdhci-test.c
@@ -0,0 +1,201 @@
+/*
+ * QTests for NPCM7xx SD-3.0 / MMC-4.51 Host Controller
+ *
+ * Copyright (c) 2021 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sd/npcm7xx_sdhci.h"
+
+#include "libqos/libqtest.h"
+#include "libqtest-single.h"
+#include "libqos/sdhci-cmd.h"
+
+#define NPCM7XX_MMC_BA 0xF0842000
+#define NPCM7XX_BLK_SIZE 512
+#define NPCM7XX_TEST_IMAGE_SIZE (1 << 30)
+
+char *sd_path;
+
+static QTestState *setup_sd_card(void)
+{
+ QTestState *qts = qtest_initf(
+ "-machine quanta-gbs-bmc "
+ "-device sd-card,drive=drive0 "
+ "-drive id=drive0,if=none,file=%s,format=raw,auto-read-only=off",
+ sd_path);
+
+ qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_SWRST, SDHC_RESET_ALL);
+ qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_CLKCON,
+ SDHC_CLOCK_SDCLK_EN | SDHC_CLOCK_INT_STABLE |
+ SDHC_CLOCK_INT_EN);
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_APP_CMD);
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x41200000, 0, (41 << 8));
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_ALL_SEND_CID);
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_SEND_RELATIVE_ADDR);
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x45670000, 0,
+ SDHC_SELECT_DESELECT_CARD);
+
+ return qts;
+}
+
+static void write_sdread(QTestState *qts, const char *msg)
+{
+ size_t len = strlen(msg);
+ char *rmsg = g_malloc(len);
+
+ /* write message to sd */
+ int fd = open(sd_path, O_WRONLY);
+ int ret = write(fd, msg, len);
+ close(fd);
+ g_assert(ret == len);
+
+ /* read message using sdhci */
+ ret = sdhci_read_cmd(qts, NPCM7XX_MMC_BA, rmsg, len);
+ g_assert(ret == len);
+ g_assert(!strcmp(rmsg, msg));
+
+ free(rmsg);
+}
+
+/* Check MMC can read values from sd */
+static void test_read_sd(void)
+{
+ QTestState *qts = setup_sd_card();
+
+ write_sdread(qts, "hello world");
+ write_sdread(qts, "goodbye");
+
+ qtest_quit(qts);
+}
+
+static void sdwrite_read(QTestState *qts, const char *msg)
+{
+ size_t len = strlen(msg);
+ char *rmsg = g_malloc(len);
+
+ /* write message using sdhci */
+ sdhci_write_cmd(qts, NPCM7XX_MMC_BA, msg, len, NPCM7XX_BLK_SIZE);
+
+ /* read message from sd */
+ int fd = open(sd_path, O_RDONLY);
+ int ret = read(fd, rmsg, len);
+ close(fd);
+ g_assert(ret == len);
+
+ g_assert(!strcmp(rmsg, msg));
+
+ free(rmsg);
+}
+
+/* Check MMC can write values to sd */
+static void test_write_sd(void)
+{
+ QTestState *qts = setup_sd_card();
+
+ sdwrite_read(qts, "hello world");
+ sdwrite_read(qts, "goodbye");
+
+ qtest_quit(qts);
+}
+
+/* Check SDHCI has correct default values. */
+static void test_reset(void)
+{
+ QTestState *qts = qtest_init("-machine quanta-gbs-bmc");
+
+ uint64_t addr = NPCM7XX_MMC_BA;
+ uint64_t end_addr = addr + NPCM7XX_REG_SIZE;
+ uint16_t prstvals_resets[] = {NPCM7XX_PRSTVALS_0_RESET,
+ NPCM7XX_PRSTVALS_1_RESET,
+ 0,
+ NPCM7XX_PRSTVALS_3_RESET,
+ 0,
+ 0};
+ int i;
+ uint32_t mask;
+ while (addr < end_addr) {
+ switch (addr - NPCM7XX_MMC_BA) {
+ case SDHC_PRNSTS:
+ /* ignores bits 20 to 24: they are changed when reading registers */
+ mask = 0x1f00000;
+ g_assert_cmphex(qtest_readl(qts, addr) | mask, ==,
+ NPCM7XX_PRSNTS_RESET | mask);
+ addr += 4;
+ break;
+ case SDHC_BLKGAP:
+ g_assert_cmphex(qtest_readb(qts, addr), ==, NPCM7XX_BLKGAP_RESET);
+ addr += 1;
+ break;
+ case SDHC_CAPAB:
+ g_assert_cmphex(qtest_readq(qts, addr), ==, NPCM7XX_CAPAB_RESET);
+ addr += 8;
+ break;
+ case SDHC_MAXCURR:
+ g_assert_cmphex(qtest_readq(qts, addr), ==, NPCM7XX_MAXCURR_RESET);
+ addr += 8;
+ break;
+ case SDHC_HCVER:
+ g_assert_cmphex(qtest_readw(qts, addr), ==, NPCM7XX_HCVER_RESET);
+ addr += 2;
+ break;
+ case NPCM7XX_PRSTVALS:
+ for (i = 0; i < NPCM7XX_PRSTVALS_SIZE; ++i) {
+ g_assert_cmphex(qtest_readw(qts, addr + 2 * i), ==,
+ prstvals_resets[i]);
+ }
+ addr += NPCM7XX_PRSTVALS_SIZE * 2;
+ break;
+ default:
+ g_assert_cmphex(qtest_readb(qts, addr), ==, 0);
+ addr += 1;
+ }
+ }
+
+ qtest_quit(qts);
+}
+
+static void drive_destroy(void)
+{
+ unlink(sd_path);
+ g_free(sd_path);
+}
+
+static void drive_create(void)
+{
+ int fd, ret;
+ sd_path = g_strdup("/tmp/qtest.XXXXXX");
+
+ /* Create a temporary raw image */
+ fd = mkstemp(sd_path);
+ g_assert_cmpint(fd, >=, 0);
+ ret = ftruncate(fd, NPCM7XX_TEST_IMAGE_SIZE);
+ g_assert_cmpint(ret, ==, 0);
+ g_message("%s", sd_path);
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ drive_create();
+
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("npcm7xx_sdhci/reset", test_reset);
+ qtest_add_func("npcm7xx_sdhci/write_sd", test_write_sd);
+ qtest_add_func("npcm7xx_sdhci/read_sd", test_read_sd);
+
+ int ret = g_test_run();
+ drive_destroy();
+ return ret;
+}
--
2.33.0.153.gba50c8fa24-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 4/4] tests/qtest: add qtests for npcm7xx sdhci
2021-09-07 23:25 ` [PATCH 4/4] tests/qtest: add qtests for npcm7xx sdhci Hao Wu
@ 2021-09-13 14:47 ` Peter Maydell
0 siblings, 0 replies; 9+ messages in thread
From: Peter Maydell @ 2021-09-13 14:47 UTC (permalink / raw)
To: Hao Wu
Cc: Qemu-block, Patrick Venture, Bin Meng, Havard Skinnemoen,
QEMU Developers, CS20 KFTing, qemu-arm, IS20 Avi Fishman,
Chris Rauer, Philippe Mathieu-Daudé
On Wed, 8 Sept 2021 at 00:26, Hao Wu <wuhaotsh@google.com> wrote:
>
> From: Shengtan Mao <stmao@google.com>
>
> Signed-off-by: Shengtan Mao <stmao@google.com>
> Reviewed-by: Hao Wu <wuhaotsh@google.com>
> Reviewed-by: Chris Rauer <crauer@google.com>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> ---
> tests/qtest/meson.build | 1 +
> tests/qtest/npcm7xx_sdhci-test.c | 201 +++++++++++++++++++++++++++++++
> 2 files changed, 202 insertions(+)
> create mode 100644 tests/qtest/npcm7xx_sdhci-test.c
>
> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index 757bb8499a..ef9c904779 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -157,6 +157,7 @@ qtests_npcm7xx = \
> 'npcm7xx_gpio-test',
> 'npcm7xx_pwm-test',
> 'npcm7xx_rng-test',
> + 'npcm7xx_sdhci-test',
> 'npcm7xx_smbus-test',
> 'npcm7xx_timer-test',
> 'npcm7xx_watchdog_timer-test'] + \
> diff --git a/tests/qtest/npcm7xx_sdhci-test.c b/tests/qtest/npcm7xx_sdhci-test.c
> new file mode 100644
> index 0000000000..5c4e78fda4
> --- /dev/null
> +++ b/tests/qtest/npcm7xx_sdhci-test.c
> @@ -0,0 +1,201 @@
> +/*
> + * QTests for NPCM7xx SD-3.0 / MMC-4.51 Host Controller
> + *
> + * Copyright (c) 2021 Google LLC
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> + * for more details.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/sd/npcm7xx_sdhci.h"
> +
> +#include "libqos/libqtest.h"
> +#include "libqtest-single.h"
> +#include "libqos/sdhci-cmd.h"
> +
> +#define NPCM7XX_MMC_BA 0xF0842000
> +#define NPCM7XX_BLK_SIZE 512
> +#define NPCM7XX_TEST_IMAGE_SIZE (1 << 30)
> +
> +char *sd_path;
should be "static".
> +
> +static QTestState *setup_sd_card(void)
> +{
> + QTestState *qts = qtest_initf(
> + "-machine quanta-gbs-bmc "
> + "-device sd-card,drive=drive0 "
> + "-drive id=drive0,if=none,file=%s,format=raw,auto-read-only=off",
> + sd_path);
> +
> + qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_SWRST, SDHC_RESET_ALL);
> + qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_CLKCON,
> + SDHC_CLOCK_SDCLK_EN | SDHC_CLOCK_INT_STABLE |
> + SDHC_CLOCK_INT_EN);
inconsistent indent
> + sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_APP_CMD);
> + sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x41200000, 0, (41 << 8));
> + sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_ALL_SEND_CID);
> + sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_SEND_RELATIVE_ADDR);
> + sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x45670000, 0,
> + SDHC_SELECT_DESELECT_CARD);
> +
> + return qts;
> +}
> +
> +static void write_sdread(QTestState *qts, const char *msg)
> +{
> + size_t len = strlen(msg);
> + char *rmsg = g_malloc(len);
> +
> + /* write message to sd */
> + int fd = open(sd_path, O_WRONLY);
> + int ret = write(fd, msg, len);
> + close(fd);
You should check the return value from open() and close()
(same again in code below)
> + g_assert(ret == len);
> +
> + /* read message using sdhci */
> + ret = sdhci_read_cmd(qts, NPCM7XX_MMC_BA, rmsg, len);
> + g_assert(ret == len);
> + g_assert(!strcmp(rmsg, msg));
> +
> + free(rmsg);
> +}
> +static void drive_create(void)
> +{
> + int fd, ret;
> + sd_path = g_strdup("/tmp/qtest.XXXXXX");
Please use a template string that gives an indication of
which test created the file. This helps subsequent debugging
of "where did this junk in my tmp directory come from?".
> +
> + /* Create a temporary raw image */
> + fd = mkstemp(sd_path);
> + g_assert_cmpint(fd, >=, 0);
> + ret = ftruncate(fd, NPCM7XX_TEST_IMAGE_SIZE);
> + g_assert_cmpint(ret, ==, 0);
> + g_message("%s", sd_path);
> + close(fd);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + drive_create();
> +
> + g_test_init(&argc, &argv, NULL);
> +
> + qtest_add_func("npcm7xx_sdhci/reset", test_reset);
> + qtest_add_func("npcm7xx_sdhci/write_sd", test_write_sd);
> + qtest_add_func("npcm7xx_sdhci/read_sd", test_read_sd);
> +
> + int ret = g_test_run();
> + drive_destroy();
> + return ret;
> +}
thanks
-- PMM
^ permalink raw reply [flat|nested] 9+ messages in thread