From a033d8008d1b2b35332597eacc92a1a4b14121ad Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 19 Jan 2021 11:23:05 +0800 Subject: hw/misc: sifive_u_otp: Use error_report() when block operation fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At present when blk_pread() / blk_pwrite() fails, a guest error is logged, but this is not really a guest error. Change to use error_report() instead. Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 1611026585-29971-1-git-send-email-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/misc/sifive_u_otp.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'hw') diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index b8e8b9e..18aa0bd 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -23,6 +23,7 @@ #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "hw/sysbus.h" +#include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/module.h" #include "hw/misc/sifive_u_otp.h" @@ -65,8 +66,7 @@ static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) if (blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf, SIFIVE_U_OTP_FUSE_WORD) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "read error index<%d>\n", s->pa); + error_report("read error index<%d>", s->pa); return 0xff; } @@ -169,8 +169,7 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr, if (blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "write error index<%d>\n", s->pa); + error_report("write error index<%d>", s->pa); } } @@ -260,15 +259,13 @@ static void sifive_u_otp_reset(DeviceState *dev) serial_data = s->serial; if (blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD, &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "write error index<%d>\n", index); + error_report("write error index<%d>", index); } serial_data = ~(s->serial); if (blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD, &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "write error index<%d>\n", index + 1); + error_report("write error index<%d>", index + 1); } } -- cgit v1.1 From 10509e1095c9910957c4c2b93bbf2f1833838e68 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 26 Jan 2021 13:59:59 +0800 Subject: hw/block: m25p80: Add ISSI SPI flash support This adds the ISSI SPI flash support. The number of dummy cycles in fast read, fast read dual output and fast read quad output commands is currently using the default 8. Likewise, the same default value is used for fast read dual/quad I/O command. Per the datasheet [1], the number of dummy cycles is configurable, but this is not modeled at present. For flash whose size is larger than 16 MiB, the sequence of 3-byte address along with EXTADD bit in the bank address register (BAR) is not supported. We assume that guest software always uses op codes with 4-byte address sequence. Fortunately, this is the case for both U-Boot and Linux spi-nor drivers. QPI (Quad Peripheral Interface) that supports 2-cycle instruction has different default values for dummy cycles of fast read family commands, and is unsupported at the time being. [1] http://www.issi.com/WW/pdf/25LP-WP256.pdf Signed-off-by: Bin Meng Acked-by: Alistair Francis Message-id: 20210126060007.12904-2-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/block/m25p80.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 0412d3e..ad4456b 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -412,6 +412,7 @@ typedef enum { MAN_NUMONYX, MAN_WINBOND, MAN_SST, + MAN_ISSI, MAN_GENERIC, } Manufacturer; @@ -487,6 +488,8 @@ static inline Manufacturer get_man(Flash *s) return MAN_MACRONIX; case 0xBF: return MAN_SST; + case 0x9D: + return MAN_ISSI; default: return MAN_GENERIC; } @@ -706,6 +709,9 @@ static void complete_collecting_data(Flash *s) case MAN_SPANSION: s->quad_enable = !!(s->data[1] & 0x02); break; + case MAN_ISSI: + s->quad_enable = extract32(s->data[0], 6, 1); + break; case MAN_MACRONIX: s->quad_enable = extract32(s->data[0], 6, 1); if (s->len > 1) { @@ -895,6 +901,19 @@ static void decode_fast_read_cmd(Flash *s) SPANSION_DUMMY_CLK_LEN ); break; + case MAN_ISSI: + /* + * The Fast Read instruction code is followed by address bytes and + * dummy cycles, transmitted via the SI line. + * + * The number of dummy cycles is configurable but this is currently + * unmodeled, hence the default value 8 is used. + * + * QPI (Quad Peripheral Interface) mode has different default value + * of dummy cycles, but this is unsupported at the time being. + */ + s->needed_bytes += 1; + break; default: break; } @@ -934,6 +953,16 @@ static void decode_dio_read_cmd(Flash *s) break; } break; + case MAN_ISSI: + /* + * The Fast Read Dual I/O instruction code is followed by address bytes + * and dummy cycles, transmitted via the IO1 and IO0 line. + * + * The number of dummy cycles is configurable but this is currently + * unmodeled, hence the default value 4 is used. + */ + s->needed_bytes += 1; + break; default: break; } @@ -974,6 +1003,19 @@ static void decode_qio_read_cmd(Flash *s) break; } break; + case MAN_ISSI: + /* + * The Fast Read Quad I/O instruction code is followed by address bytes + * and dummy cycles, transmitted via the IO3, IO2, IO1 and IO0 line. + * + * The number of dummy cycles is configurable but this is currently + * unmodeled, hence the default value 6 is used. + * + * QPI (Quad Peripheral Interface) mode has different default value + * of dummy cycles, but this is unsupported at the time being. + */ + s->needed_bytes += 3; + break; default: break; } @@ -1132,7 +1174,7 @@ static void decode_new_cmd(Flash *s, uint32_t value) case RDSR: s->data[0] = (!!s->write_enable) << 1; - if (get_man(s) == MAN_MACRONIX) { + if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) { s->data[0] |= (!!s->quad_enable) << 6; } if (get_man(s) == MAN_SST) { -- cgit v1.1 From 62d1076678a4c3d2385cc492283061b710bb0a60 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 26 Jan 2021 14:00:00 +0800 Subject: hw/block: m25p80: Add various ISSI flash information This updates the flash information table to include various ISSI flashes that are supported by upstream U-Boot and Linux kernel. Signed-off-by: Bin Meng Acked-by: Alistair Francis Message-id: 20210126060007.12904-3-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/block/m25p80.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'hw') diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index ad4456b..5f9471d 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -210,6 +210,19 @@ static const FlashPartInfo known_devices[] = { { INFO("640s33b", 0x898913, 0, 64 << 10, 128, 0) }, { INFO("n25q064", 0x20ba17, 0, 64 << 10, 128, 0) }, + /* ISSI */ + { INFO("is25lq040b", 0x9d4013, 0, 64 << 10, 8, ER_4K) }, + { INFO("is25lp080d", 0x9d6014, 0, 64 << 10, 16, ER_4K) }, + { INFO("is25lp016d", 0x9d6015, 0, 64 << 10, 32, ER_4K) }, + { INFO("is25lp032", 0x9d6016, 0, 64 << 10, 64, ER_4K) }, + { INFO("is25lp064", 0x9d6017, 0, 64 << 10, 128, ER_4K) }, + { INFO("is25lp128", 0x9d6018, 0, 64 << 10, 256, ER_4K) }, + { INFO("is25lp256", 0x9d6019, 0, 64 << 10, 512, ER_4K) }, + { INFO("is25wp032", 0x9d7016, 0, 64 << 10, 64, ER_4K) }, + { INFO("is25wp064", 0x9d7017, 0, 64 << 10, 128, ER_4K) }, + { INFO("is25wp128", 0x9d7018, 0, 64 << 10, 256, ER_4K) }, + { INFO("is25wp256", 0x9d7019, 0, 64 << 10, 512, ER_4K) }, + /* Macronix */ { INFO("mx25l2005a", 0xc22012, 0, 64 << 10, 4, ER_4K) }, { INFO("mx25l4005a", 0xc22013, 0, 64 << 10, 8, ER_4K) }, -- cgit v1.1 From 0694dabe9763847f3010b54ab3ec7d367d2f0ff0 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 26 Jan 2021 14:00:01 +0800 Subject: hw/ssi: Add SiFive SPI controller support This adds the SiFive SPI controller model for the FU540 SoC. The direct memory-mapped SPI flash mode is unsupported. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210126060007.12904-4-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/ssi/Kconfig | 4 + hw/ssi/meson.build | 1 + hw/ssi/sifive_spi.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 363 insertions(+) create mode 100644 hw/ssi/sifive_spi.c (limited to 'hw') diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig index 9e54a0c..7d90a02 100644 --- a/hw/ssi/Kconfig +++ b/hw/ssi/Kconfig @@ -2,6 +2,10 @@ config PL022 bool select SSI +config SIFIVE_SPI + bool + select SSI + config SSI bool diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index dee00c0..3d6bc82 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -2,6 +2,7 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c')) softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c')) softmmu_ss.add(when: 'CONFIG_PL022', if_true: files('pl022.c')) +softmmu_ss.add(when: 'CONFIG_SIFIVE_SPI', if_true: files('sifive_spi.c')) softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_SPI', if_true: files('stm32f2xx_spi.c')) softmmu_ss.add(when: 'CONFIG_XILINX_SPI', if_true: files('xilinx_spi.c')) diff --git a/hw/ssi/sifive_spi.c b/hw/ssi/sifive_spi.c new file mode 100644 index 0000000..0c9ebca --- /dev/null +++ b/hw/ssi/sifive_spi.c @@ -0,0 +1,358 @@ +/* + * QEMU model of the SiFive SPI Controller + * + * Copyright (c) 2021 Wind River Systems, Inc. + * + * Author: + * Bin Meng + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "hw/ssi/ssi.h" +#include "sysemu/sysemu.h" +#include "qemu/fifo8.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/ssi/sifive_spi.h" + +#define R_SCKDIV (0x00 / 4) +#define R_SCKMODE (0x04 / 4) +#define R_CSID (0x10 / 4) +#define R_CSDEF (0x14 / 4) +#define R_CSMODE (0x18 / 4) +#define R_DELAY0 (0x28 / 4) +#define R_DELAY1 (0x2C / 4) +#define R_FMT (0x40 / 4) +#define R_TXDATA (0x48 / 4) +#define R_RXDATA (0x4C / 4) +#define R_TXMARK (0x50 / 4) +#define R_RXMARK (0x54 / 4) +#define R_FCTRL (0x60 / 4) +#define R_FFMT (0x64 / 4) +#define R_IE (0x70 / 4) +#define R_IP (0x74 / 4) + +#define FMT_DIR (1 << 3) + +#define TXDATA_FULL (1 << 31) +#define RXDATA_EMPTY (1 << 31) + +#define IE_TXWM (1 << 0) +#define IE_RXWM (1 << 1) + +#define IP_TXWM (1 << 0) +#define IP_RXWM (1 << 1) + +#define FIFO_CAPACITY 8 + +static void sifive_spi_txfifo_reset(SiFiveSPIState *s) +{ + fifo8_reset(&s->tx_fifo); + + s->regs[R_TXDATA] &= ~TXDATA_FULL; + s->regs[R_IP] &= ~IP_TXWM; +} + +static void sifive_spi_rxfifo_reset(SiFiveSPIState *s) +{ + fifo8_reset(&s->rx_fifo); + + s->regs[R_RXDATA] |= RXDATA_EMPTY; + s->regs[R_IP] &= ~IP_RXWM; +} + +static void sifive_spi_update_cs(SiFiveSPIState *s) +{ + int i; + + for (i = 0; i < s->num_cs; i++) { + if (s->regs[R_CSDEF] & (1 << i)) { + qemu_set_irq(s->cs_lines[i], !(s->regs[R_CSMODE])); + } + } +} + +static void sifive_spi_update_irq(SiFiveSPIState *s) +{ + int level; + + if (fifo8_num_used(&s->tx_fifo) < s->regs[R_TXMARK]) { + s->regs[R_IP] |= IP_TXWM; + } else { + s->regs[R_IP] &= ~IP_TXWM; + } + + if (fifo8_num_used(&s->rx_fifo) > s->regs[R_RXMARK]) { + s->regs[R_IP] |= IP_RXWM; + } else { + s->regs[R_IP] &= ~IP_RXWM; + } + + level = s->regs[R_IP] & s->regs[R_IE] ? 1 : 0; + qemu_set_irq(s->irq, level); +} + +static void sifive_spi_reset(DeviceState *d) +{ + SiFiveSPIState *s = SIFIVE_SPI(d); + + memset(s->regs, 0, sizeof(s->regs)); + + /* The reset value is high for all implemented CS pins */ + s->regs[R_CSDEF] = (1 << s->num_cs) - 1; + + /* Populate register with their default value */ + s->regs[R_SCKDIV] = 0x03; + s->regs[R_DELAY0] = 0x1001; + s->regs[R_DELAY1] = 0x01; + + sifive_spi_txfifo_reset(s); + sifive_spi_rxfifo_reset(s); + + sifive_spi_update_cs(s); + sifive_spi_update_irq(s); +} + +static void sifive_spi_flush_txfifo(SiFiveSPIState *s) +{ + uint8_t tx; + uint8_t rx; + + while (!fifo8_is_empty(&s->tx_fifo)) { + tx = fifo8_pop(&s->tx_fifo); + rx = ssi_transfer(s->spi, tx); + + if (!fifo8_is_full(&s->rx_fifo)) { + if (!(s->regs[R_FMT] & FMT_DIR)) { + fifo8_push(&s->rx_fifo, rx); + } + } + } +} + +static bool sifive_spi_is_bad_reg(hwaddr addr, bool allow_reserved) +{ + bool bad; + + switch (addr) { + /* reserved offsets */ + case 0x08: + case 0x0C: + case 0x1C: + case 0x20: + case 0x24: + case 0x30: + case 0x34: + case 0x38: + case 0x3C: + case 0x44: + case 0x58: + case 0x5C: + case 0x68: + case 0x6C: + bad = allow_reserved ? false : true; + break; + default: + bad = false; + } + + if (addr >= (SIFIVE_SPI_REG_NUM << 2)) { + bad = true; + } + + return bad; +} + +static uint64_t sifive_spi_read(void *opaque, hwaddr addr, unsigned int size) +{ + SiFiveSPIState *s = opaque; + uint32_t r; + + if (sifive_spi_is_bad_reg(addr, true)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read at address 0x%" + HWADDR_PRIx "\n", __func__, addr); + return 0; + } + + addr >>= 2; + switch (addr) { + case R_TXDATA: + if (fifo8_is_full(&s->tx_fifo)) { + return TXDATA_FULL; + } + r = 0; + break; + + case R_RXDATA: + if (fifo8_is_empty(&s->rx_fifo)) { + return RXDATA_EMPTY; + } + r = fifo8_pop(&s->rx_fifo); + break; + + default: + r = s->regs[addr]; + break; + } + + sifive_spi_update_irq(s); + + return r; +} + +static void sifive_spi_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + SiFiveSPIState *s = opaque; + uint32_t value = val64; + + if (sifive_spi_is_bad_reg(addr, false)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write at addr=0x%" + HWADDR_PRIx " value=0x%x\n", __func__, addr, value); + return; + } + + addr >>= 2; + switch (addr) { + case R_CSID: + if (value >= s->num_cs) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csid %d\n", + __func__, value); + } else { + s->regs[R_CSID] = value; + sifive_spi_update_cs(s); + } + break; + + case R_CSDEF: + if (value >= (1 << s->num_cs)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csdef %x\n", + __func__, value); + } else { + s->regs[R_CSDEF] = value; + } + break; + + case R_CSMODE: + if (value > 3) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csmode %x\n", + __func__, value); + } else { + s->regs[R_CSMODE] = value; + sifive_spi_update_cs(s); + } + break; + + case R_TXDATA: + if (!fifo8_is_full(&s->tx_fifo)) { + fifo8_push(&s->tx_fifo, (uint8_t)value); + sifive_spi_flush_txfifo(s); + } + break; + + case R_RXDATA: + case R_IP: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid write to read-only reigster 0x%" + HWADDR_PRIx " with 0x%x\n", __func__, addr << 2, value); + break; + + case R_TXMARK: + case R_RXMARK: + if (value >= FIFO_CAPACITY) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid watermark %d\n", + __func__, value); + } else { + s->regs[addr] = value; + } + break; + + case R_FCTRL: + case R_FFMT: + qemu_log_mask(LOG_UNIMP, + "%s: direct-map flash interface unimplemented\n", + __func__); + break; + + default: + s->regs[addr] = value; + break; + } + + sifive_spi_update_irq(s); +} + +static const MemoryRegionOps sifive_spi_ops = { + .read = sifive_spi_read, + .write = sifive_spi_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static void sifive_spi_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + SiFiveSPIState *s = SIFIVE_SPI(dev); + int i; + + s->spi = ssi_create_bus(dev, "spi"); + sysbus_init_irq(sbd, &s->irq); + + s->cs_lines = g_new0(qemu_irq, s->num_cs); + for (i = 0; i < s->num_cs; i++) { + sysbus_init_irq(sbd, &s->cs_lines[i]); + } + + memory_region_init_io(&s->mmio, OBJECT(s), &sifive_spi_ops, s, + TYPE_SIFIVE_SPI, 0x1000); + sysbus_init_mmio(sbd, &s->mmio); + + fifo8_create(&s->tx_fifo, FIFO_CAPACITY); + fifo8_create(&s->rx_fifo, FIFO_CAPACITY); +} + +static Property sifive_spi_properties[] = { + DEFINE_PROP_UINT32("num-cs", SiFiveSPIState, num_cs, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sifive_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, sifive_spi_properties); + dc->reset = sifive_spi_reset; + dc->realize = sifive_spi_realize; +} + +static const TypeInfo sifive_spi_info = { + .name = TYPE_SIFIVE_SPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveSPIState), + .class_init = sifive_spi_class_init, +}; + +static void sifive_spi_register_types(void) +{ + type_register_static(&sifive_spi_info); +} + +type_init(sifive_spi_register_types) -- cgit v1.1 From 145b299139da92fb1b1048b393865bc96597d6b9 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 26 Jan 2021 14:00:02 +0800 Subject: hw/riscv: sifive_u: Add QSPI0 controller and connect a flash This adds the QSPI0 controller to the SoC, and connects an ISSI 25WP256 flash to it. The generation of corresponding device tree source fragment is also added. Since the direct memory-mapped mode is not supported by the SiFive SPI model, the property does not populate the second group which represents the memory mapped address of the SPI flash. With this commit, upstream U-Boot for the SiFive HiFive Unleashed board can boot on QEMU 'sifive_u' out of the box. This allows users to develop and test the recommended RISC-V boot flow with a real world use case: ZSBL (in QEMU) loads U-Boot SPL from SPI flash to L2LIM, then U-Boot SPL loads the payload from SPI flash that is combined with OpenSBI fw_dynamic firmware and U-Boot proper. Specify machine property `msel` to 6 to allow booting from the SPI flash. U-Boot spl is directly loaded via `-bios`, and subsequent payload is stored in the SPI flash image. Example command line: $ qemu-system-riscv64 -nographic -M sifive_u,msel=6 -smp 5 -m 8G \ -bios u-boot-spl.bin -drive file=spi-nor.img,if=mtd Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210126060007.12904-5-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/riscv/Kconfig | 2 ++ hw/riscv/sifive_u.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'hw') diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index facb0cb..6330297 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -52,9 +52,11 @@ config SIFIVE_U select SIFIVE_GPIO select SIFIVE_PDMA select SIFIVE_PLIC + select SIFIVE_SPI select SIFIVE_UART select SIFIVE_U_OTP select SIFIVE_U_PRCI + select SSI_M25P80 select UNIMP config SPIKE diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 59b61ce..43a0e98 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -15,6 +15,7 @@ * 5) OTP (One-Time Programmable) memory with stored serial number * 6) GEM (Gigabit Ethernet Controller) and management block * 7) DMA (Direct Memory Access Controller) + * 8) SPI0 connected to an SPI flash * * This board currently generates devicetree dynamically that indicates at least * two harts and up to five harts. @@ -44,6 +45,7 @@ #include "hw/char/serial.h" #include "hw/cpu/cluster.h" #include "hw/misc/unimp.h" +#include "hw/ssi/ssi.h" #include "target/riscv/cpu.h" #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_u.h" @@ -74,6 +76,7 @@ static const struct MemmapEntry { [SIFIVE_U_DEV_PRCI] = { 0x10000000, 0x1000 }, [SIFIVE_U_DEV_UART0] = { 0x10010000, 0x1000 }, [SIFIVE_U_DEV_UART1] = { 0x10011000, 0x1000 }, + [SIFIVE_U_DEV_QSPI0] = { 0x10040000, 0x1000 }, [SIFIVE_U_DEV_GPIO] = { 0x10060000, 0x1000 }, [SIFIVE_U_DEV_OTP] = { 0x10070000, 0x1000 }, [SIFIVE_U_DEV_GEM] = { 0x10090000, 0x2000 }, @@ -342,6 +345,32 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, "sifive,fu540-c000-ccache"); g_free(nodename); + nodename = g_strdup_printf("/soc/spi@%lx", + (long)memmap[SIFIVE_U_DEV_QSPI0].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_QSPI0_IRQ); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_DEV_QSPI0].base, + 0x0, memmap[SIFIVE_U_DEV_QSPI0].size); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,spi0"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/spi@%lx/flash@0", + (long)memmap[SIFIVE_U_DEV_QSPI0].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "spi-rx-bus-width", 4); + qemu_fdt_setprop_cell(fdt, nodename, "spi-tx-bus-width", 4); + qemu_fdt_setprop(fdt, nodename, "m25p,fast-read", NULL, 0); + qemu_fdt_setprop_cell(fdt, nodename, "spi-max-frequency", 50000000); + qemu_fdt_setprop_cell(fdt, nodename, "reg", 0); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "jedec,spi-nor"); + g_free(nodename); + phy_phandle = phandle++; nodename = g_strdup_printf("/soc/ethernet@%lx", (long)memmap[SIFIVE_U_DEV_GEM].base); @@ -439,6 +468,9 @@ static void sifive_u_machine_init(MachineState *machine) int i; uint32_t fdt_load_addr; uint64_t kernel_entry; + DriveInfo *dinfo; + DeviceState *flash_dev; + qemu_irq flash_cs; /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); @@ -571,6 +603,19 @@ static void sifive_u_machine_init(MachineState *machine) riscv_rom_copy_firmware_info(machine, memmap[SIFIVE_U_DEV_MROM].base, memmap[SIFIVE_U_DEV_MROM].size, sizeof(reset_vec), kernel_entry); + + /* Connect an SPI flash to SPI0 */ + flash_dev = qdev_new("is25wp256"); + dinfo = drive_get_next(IF_MTD); + if (dinfo) { + qdev_prop_set_drive_err(flash_dev, "drive", + blk_by_legacy_dinfo(dinfo), + &error_fatal); + } + qdev_realize_and_unref(flash_dev, BUS(s->soc.spi0.spi), &error_fatal); + + flash_cs = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi0), 1, flash_cs); } static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp) @@ -680,6 +725,7 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM); object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO); object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA); + object_initialize_child(obj, "spi0", &s->spi0, TYPE_SIFIVE_SPI); } static void sifive_u_soc_realize(DeviceState *dev, Error **errp) @@ -827,6 +873,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) create_unimplemented_device("riscv.sifive.u.l2cc", memmap[SIFIVE_U_DEV_L2CC].base, memmap[SIFIVE_U_DEV_L2CC].size); + + sysbus_realize(SYS_BUS_DEVICE(&s->spi0), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi0), 0, + memmap[SIFIVE_U_DEV_QSPI0].base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi0), 0, + qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI0_IRQ)); } static Property sifive_u_soc_props[] = { -- cgit v1.1 From 722f1352b6c248ead94efd77ff5726aa0cba949b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 26 Jan 2021 14:00:03 +0800 Subject: hw/riscv: sifive_u: Add QSPI2 controller and connect an SD card This adds the QSPI2 controller to the SoC, and connects an SD card to it. The generation of corresponding device tree source fragment is also added. Specify machine property `msel` to 11 to boot the same upstream U-Boot SPL and payload image for the SiFive HiFive Unleashed board. Note subsequent payload is stored in the SD card image. $ qemu-system-riscv64 -nographic -M sifive_u,msel=11 -smp 5 -m 8G \ -bios u-boot-spl.bin -drive file=sdcard.img,if=sd Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210126060007.12904-6-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/riscv/Kconfig | 1 + hw/riscv/sifive_u.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 6330297..d139074 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -57,6 +57,7 @@ config SIFIVE_U select SIFIVE_U_OTP select SIFIVE_U_PRCI select SSI_M25P80 + select SSI_SD select UNIMP config SPIKE diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 43a0e98..6c1158a 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -16,6 +16,7 @@ * 6) GEM (Gigabit Ethernet Controller) and management block * 7) DMA (Direct Memory Access Controller) * 8) SPI0 connected to an SPI flash + * 9) SPI2 connected to an SD card * * This board currently generates devicetree dynamically that indicates at least * two harts and up to five harts. @@ -77,6 +78,7 @@ static const struct MemmapEntry { [SIFIVE_U_DEV_UART0] = { 0x10010000, 0x1000 }, [SIFIVE_U_DEV_UART1] = { 0x10011000, 0x1000 }, [SIFIVE_U_DEV_QSPI0] = { 0x10040000, 0x1000 }, + [SIFIVE_U_DEV_QSPI2] = { 0x10050000, 0x1000 }, [SIFIVE_U_DEV_GPIO] = { 0x10060000, 0x1000 }, [SIFIVE_U_DEV_OTP] = { 0x10070000, 0x1000 }, [SIFIVE_U_DEV_GEM] = { 0x10090000, 0x2000 }, @@ -346,6 +348,31 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(nodename); nodename = g_strdup_printf("/soc/spi@%lx", + (long)memmap[SIFIVE_U_DEV_QSPI2].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_QSPI2_IRQ); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_DEV_QSPI2].base, + 0x0, memmap[SIFIVE_U_DEV_QSPI2].size); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,spi0"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/spi@%lx/mmc@0", + (long)memmap[SIFIVE_U_DEV_QSPI2].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop(fdt, nodename, "disable-wp", NULL, 0); + qemu_fdt_setprop_cells(fdt, nodename, "voltage-ranges", 3300, 3300); + qemu_fdt_setprop_cell(fdt, nodename, "spi-max-frequency", 20000000); + qemu_fdt_setprop_cell(fdt, nodename, "reg", 0); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "mmc-spi-slot"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/spi@%lx", (long)memmap[SIFIVE_U_DEV_QSPI0].base); qemu_fdt_add_subnode(fdt, nodename); qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0); @@ -469,8 +496,8 @@ static void sifive_u_machine_init(MachineState *machine) uint32_t fdt_load_addr; uint64_t kernel_entry; DriveInfo *dinfo; - DeviceState *flash_dev; - qemu_irq flash_cs; + DeviceState *flash_dev, *sd_dev; + qemu_irq flash_cs, sd_cs; /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); @@ -616,6 +643,12 @@ static void sifive_u_machine_init(MachineState *machine) flash_cs = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi0), 1, flash_cs); + + /* Connect an SD card to SPI2 */ + sd_dev = ssi_create_peripheral(s->soc.spi2.spi, "ssi-sd"); + + sd_cs = qdev_get_gpio_in_named(sd_dev, SSI_GPIO_CS, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi2), 1, sd_cs); } static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp) @@ -726,6 +759,7 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO); object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA); object_initialize_child(obj, "spi0", &s->spi0, TYPE_SIFIVE_SPI); + object_initialize_child(obj, "spi2", &s->spi2, TYPE_SIFIVE_SPI); } static void sifive_u_soc_realize(DeviceState *dev, Error **errp) @@ -879,6 +913,11 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_U_DEV_QSPI0].base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi0), 0, qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI0_IRQ)); + sysbus_realize(SYS_BUS_DEVICE(&s->spi2), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi2), 0, + memmap[SIFIVE_U_DEV_QSPI2].base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi2), 0, + qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI2_IRQ)); } static Property sifive_u_soc_props[] = { -- cgit v1.1 From 6b9409ba5f79b93411f32d2589fd3a3a3e4e62e2 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 20 Dec 2020 12:26:14 +0100 Subject: goldfish_rtc: re-arm the alarm after migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a migration the clock offset is updated, but we also need to re-arm the alarm if needed. Signed-off-by: Laurent Vivier Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-id: 20201220112615.933036-7-laurent@vivier.eu Signed-off-by: Alistair Francis --- hw/rtc/goldfish_rtc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw') diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 0f4e818..e07ff01 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -211,6 +211,8 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->tick_offset = s->tick_offset_vmstate - delta; + goldfish_rtc_set_alarm(s); + return 0; } -- cgit v1.1 From 732612856a8948a6ba1148322651743aa963b51c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sat, 20 Feb 2021 22:48:04 +0800 Subject: hw/riscv: Drop 'struct MemmapEntry' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is already a MemMapEntry type defined in hwaddr.h. Let's drop the RISC-V defined `struct MemmapEntry` and use the existing one. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210220144807.819-2-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/riscv/microchip_pfsoc.c | 9 +++------ hw/riscv/opentitan.c | 9 +++------ hw/riscv/sifive_e.c | 9 +++------ hw/riscv/sifive_u.c | 11 ++++------- hw/riscv/spike.c | 9 +++------ hw/riscv/virt.c | 9 +++------ 6 files changed, 19 insertions(+), 37 deletions(-) (limited to 'hw') diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index e952b49..266f1c3 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -86,10 +86,7 @@ * - Register Map/PF_SoC_RegMap_V1_1/MPFS250T/mpfs250t_ioscb_memmap_dri.htm * describes the complete IOSCB modules memory maps */ -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} microchip_pfsoc_memmap[] = { +static const MemMapEntry microchip_pfsoc_memmap[] = { [MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 }, [MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 }, [MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 }, @@ -182,7 +179,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev); - const struct MemmapEntry *memmap = microchip_pfsoc_memmap; + const MemMapEntry *memmap = microchip_pfsoc_memmap; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *rsvd0_mem = g_new(MemoryRegion, 1); MemoryRegion *e51_dtim_mem = g_new(MemoryRegion, 1); @@ -451,7 +448,7 @@ type_init(microchip_pfsoc_soc_register_types) static void microchip_icicle_kit_machine_init(MachineState *machine) { MachineClass *mc = MACHINE_GET_CLASS(machine); - const struct MemmapEntry *memmap = microchip_pfsoc_memmap; + const MemMapEntry *memmap = microchip_pfsoc_memmap; MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mem_low = g_new(MemoryRegion, 1); diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index af34569..e168bff 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -28,10 +28,7 @@ #include "qemu/units.h" #include "sysemu/sysemu.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} ibex_memmap[] = { +static const MemMapEntry ibex_memmap[] = { [IBEX_DEV_ROM] = { 0x00008000, 16 * KiB }, [IBEX_DEV_RAM] = { 0x10000000, 0x10000 }, [IBEX_DEV_FLASH] = { 0x20000000, 0x80000 }, @@ -66,7 +63,7 @@ static const struct MemmapEntry { static void opentitan_board_init(MachineState *machine) { - const struct MemmapEntry *memmap = ibex_memmap; + const MemMapEntry *memmap = ibex_memmap; OpenTitanState *s = g_new0(OpenTitanState, 1); MemoryRegion *sys_mem = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); @@ -114,7 +111,7 @@ static void lowrisc_ibex_soc_init(Object *obj) static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) { - const struct MemmapEntry *memmap = ibex_memmap; + const MemMapEntry *memmap = ibex_memmap; MachineState *ms = MACHINE(qdev_get_machine()); LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc); MemoryRegion *sys_mem = get_system_memory(); diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 59bac4c..f939bcf 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -50,10 +50,7 @@ #include "sysemu/sysemu.h" #include "exec/address-spaces.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} sifive_e_memmap[] = { +static MemMapEntry sifive_e_memmap[] = { [SIFIVE_E_DEV_DEBUG] = { 0x0, 0x1000 }, [SIFIVE_E_DEV_MROM] = { 0x1000, 0x2000 }, [SIFIVE_E_DEV_OTP] = { 0x20000, 0x2000 }, @@ -77,7 +74,7 @@ static const struct MemmapEntry { static void sifive_e_machine_init(MachineState *machine) { - const struct MemmapEntry *memmap = sifive_e_memmap; + const MemMapEntry *memmap = sifive_e_memmap; SiFiveEState *s = RISCV_E_MACHINE(machine); MemoryRegion *sys_mem = get_system_memory(); @@ -187,7 +184,7 @@ static void sifive_e_soc_init(Object *obj) static void sifive_e_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); - const struct MemmapEntry *memmap = sifive_e_memmap; + const MemMapEntry *memmap = sifive_e_memmap; SiFiveESoCState *s = RISCV_E_SOC(dev); MemoryRegion *sys_mem = get_system_memory(); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 6c1158a..7b59942 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -63,10 +63,7 @@ #include -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} sifive_u_memmap[] = { +static const MemMapEntry sifive_u_memmap[] = { [SIFIVE_U_DEV_DEBUG] = { 0x0, 0x100 }, [SIFIVE_U_DEV_MROM] = { 0x1000, 0xf000 }, [SIFIVE_U_DEV_CLINT] = { 0x2000000, 0x10000 }, @@ -91,7 +88,7 @@ static const struct MemmapEntry { #define OTP_SERIAL 1 #define GEM_REVISION 0x10070109 -static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, +static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -484,7 +481,7 @@ static void sifive_u_machine_reset(void *opaque, int n, int level) static void sifive_u_machine_init(MachineState *machine) { - const struct MemmapEntry *memmap = sifive_u_memmap; + const MemMapEntry *memmap = sifive_u_memmap; SiFiveUState *s = RISCV_U_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); @@ -766,7 +763,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); SiFiveUSoCState *s = RISCV_U_SOC(dev); - const struct MemmapEntry *memmap = sifive_u_memmap; + const MemMapEntry *memmap = sifive_u_memmap; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1); diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 56986ec..ed4ca98 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -43,16 +43,13 @@ #include "sysemu/qtest.h" #include "sysemu/sysemu.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} spike_memmap[] = { +static const MemMapEntry spike_memmap[] = { [SPIKE_MROM] = { 0x1000, 0xf000 }, [SPIKE_CLINT] = { 0x2000000, 0x10000 }, [SPIKE_DRAM] = { 0x80000000, 0x0 }, }; -static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, +static void create_fdt(SpikeState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { void *fdt; @@ -179,7 +176,7 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, static void spike_board_init(MachineState *machine) { - const struct MemmapEntry *memmap = spike_memmap; + const MemMapEntry *memmap = spike_memmap; SpikeState *s = SPIKE_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 2299b3a..cfd52bc 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -43,10 +43,7 @@ #include "hw/pci/pci.h" #include "hw/pci-host/gpex.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} virt_memmap[] = { +static const MemMapEntry virt_memmap[] = { [VIRT_DEBUG] = { 0x0, 0x100 }, [VIRT_MROM] = { 0x1000, 0xf000 }, [VIRT_TEST] = { 0x100000, 0x1000 }, @@ -170,7 +167,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, 0x1800, 0, 0, 0x7); } -static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, +static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { void *fdt; @@ -490,7 +487,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, static void virt_machine_init(MachineState *machine) { - const struct MemmapEntry *memmap = virt_memmap; + const MemMapEntry *memmap = virt_memmap; RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); -- cgit v1.1 From 2fa3c7b6eee83d3ca1bd3d69669cf2fb8a11223b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sat, 20 Feb 2021 22:48:05 +0800 Subject: hw/riscv: virt: Drop the 'link_up' parameter of gpex_pcie_init() `link_up` is never used in gpex_pcie_init(). Drop it. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210220144807.819-3-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index cfd52bc..1d05bb3 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -449,7 +449,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, hwaddr ecam_base, hwaddr ecam_size, hwaddr mmio_base, hwaddr mmio_size, hwaddr pio_base, - DeviceState *plic, bool link_up) + DeviceState *plic) { DeviceState *dev; MemoryRegion *ecam_alias, *ecam_reg; @@ -669,12 +669,12 @@ static void virt_machine_init(MachineState *machine) } gpex_pcie_init(system_memory, - memmap[VIRT_PCIE_ECAM].base, - memmap[VIRT_PCIE_ECAM].size, - memmap[VIRT_PCIE_MMIO].base, - memmap[VIRT_PCIE_MMIO].size, - memmap[VIRT_PCIE_PIO].base, - DEVICE(pcie_plic), true); + memmap[VIRT_PCIE_ECAM].base, + memmap[VIRT_PCIE_ECAM].size, + memmap[VIRT_PCIE_MMIO].base, + memmap[VIRT_PCIE_MMIO].size, + memmap[VIRT_PCIE_PIO].base, + DEVICE(pcie_plic)); serial_mm_init(system_memory, memmap[VIRT_UART0].base, 0, qdev_get_gpio_in(DEVICE(mmio_plic), UART0_IRQ), 399193, -- cgit v1.1 From cfeb8a17c88f50c2a6dbf1cd4b9a279df5a30ec9 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sat, 20 Feb 2021 22:48:06 +0800 Subject: hw/riscv: virt: Limit RAM size in a 32-bit system RV32 supports 34-bit physical address hence the maximum RAM size should be limited. Limit the RAM size to 10 GiB, which leaves some room for PCIe high mmio space. For 32-bit host, this is not needed as machine->ram_size cannot represent a RAM size that big. Use a #if size test to only do the size limitation for the 64-bit host. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210220144807.819-4-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'hw') diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 1d05bb3..c4b8f45 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -590,6 +590,16 @@ static void virt_machine_init(MachineState *machine) } } + if (riscv_is_32bit(&s->soc[0])) { +#if HOST_LONG_BITS == 64 + /* limit RAM size in a 32-bit system */ + if (machine->ram_size > 10 * GiB) { + machine->ram_size = 10 * GiB; + error_report("Limiting RAM size to 10 GiB"); + } +#endif + } + /* register system main memory (actual RAM) */ memory_region_init_ram(main_mem, NULL, "riscv_virt_board.ram", machine->ram_size, &error_fatal); -- cgit v1.1 From 19800265d407f09f333cf80dba3e975eb7bc1872 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sat, 20 Feb 2021 22:48:07 +0800 Subject: hw/riscv: virt: Map high mmio for PCIe Some peripherals require 64-bit PCI address, so let's map the high mmio space for PCIe. For RV32, the address is hardcoded to below 4 GiB from the highest accessible physical address. For RV64, the base address depends on top of RAM and is aligned to its size which is using 16 GiB for now. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210220144807.819-5-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index c4b8f45..4f0c2fb 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -59,6 +59,15 @@ static const MemMapEntry virt_memmap[] = { [VIRT_DRAM] = { 0x80000000, 0x0 }, }; +/* PCIe high mmio is fixed for RV32 */ +#define VIRT32_HIGH_PCIE_MMIO_BASE 0x300000000ULL +#define VIRT32_HIGH_PCIE_MMIO_SIZE (4 * GiB) + +/* PCIe high mmio for RV64, size is fixed but base depends on top of RAM */ +#define VIRT64_HIGH_PCIE_MMIO_SIZE (16 * GiB) + +static MemMapEntry virt_high_pcie_memmap; + #define VIRT_FLASH_SECTOR_SIZE (256 * KiB) static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s, @@ -371,7 +380,11 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, 1, FDT_PCI_RANGE_MMIO, 2, memmap[VIRT_PCIE_MMIO].base, - 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size); + 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size, + 1, FDT_PCI_RANGE_MMIO_64BIT, + 2, virt_high_pcie_memmap.base, + 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); + create_pcie_irq_map(fdt, name, plic_pcie_phandle); g_free(name); @@ -448,12 +461,14 @@ update_bootargs: static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, hwaddr ecam_base, hwaddr ecam_size, hwaddr mmio_base, hwaddr mmio_size, + hwaddr high_mmio_base, + hwaddr high_mmio_size, hwaddr pio_base, DeviceState *plic) { DeviceState *dev; MemoryRegion *ecam_alias, *ecam_reg; - MemoryRegion *mmio_alias, *mmio_reg; + MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg; qemu_irq irq; int i; @@ -473,6 +488,13 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, mmio_reg, mmio_base, mmio_size); memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias); + /* Map high MMIO space */ + high_mmio_alias = g_new0(MemoryRegion, 1); + memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high", + mmio_reg, high_mmio_base, high_mmio_size); + memory_region_add_subregion(get_system_memory(), high_mmio_base, + high_mmio_alias); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); for (i = 0; i < GPEX_NUM_IRQS; i++) { @@ -598,6 +620,13 @@ static void virt_machine_init(MachineState *machine) error_report("Limiting RAM size to 10 GiB"); } #endif + virt_high_pcie_memmap.base = VIRT32_HIGH_PCIE_MMIO_BASE; + virt_high_pcie_memmap.size = VIRT32_HIGH_PCIE_MMIO_SIZE; + } else { + virt_high_pcie_memmap.size = VIRT64_HIGH_PCIE_MMIO_SIZE; + virt_high_pcie_memmap.base = memmap[VIRT_DRAM].base + machine->ram_size; + virt_high_pcie_memmap.base = + ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size); } /* register system main memory (actual RAM) */ @@ -683,6 +712,8 @@ static void virt_machine_init(MachineState *machine) memmap[VIRT_PCIE_ECAM].size, memmap[VIRT_PCIE_MMIO].base, memmap[VIRT_PCIE_MMIO].size, + virt_high_pcie_memmap.base, + virt_high_pcie_memmap.size, memmap[VIRT_PCIE_PIO].base, DEVICE(pcie_plic)); -- cgit v1.1