qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

riscv: sifive: Implement PRCI model for FU540

This adds a simple PRCI model for FU540 (sifive_u). It has different
register layout from the existing PRCI model for FE310 (sifive_e).

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Palmer Dabbelt <palmer@sifive.com>

authored by

Bin Meng and committed by
Palmer Dabbelt
0d952994 ef965ce2

+251
+1
hw/riscv/Makefile.objs
··· 8 8 obj-$(CONFIG_SIFIVE) += sifive_plic.o 9 9 obj-$(CONFIG_SIFIVE) += sifive_test.o 10 10 obj-$(CONFIG_SIFIVE_U) += sifive_u.o 11 + obj-$(CONFIG_SIFIVE_U) += sifive_u_prci.o 11 12 obj-$(CONFIG_SIFIVE) += sifive_uart.o 12 13 obj-$(CONFIG_SPIKE) += spike.o 13 14 obj-$(CONFIG_RISCV_VIRT) += virt.o
+169
hw/riscv/sifive_u_prci.c
··· 1 + /* 2 + * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt) 3 + * 4 + * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com> 5 + * 6 + * Simple model of the PRCI to emulate register reads made by the SDK BSP 7 + * 8 + * This program is free software; you can redistribute it and/or modify it 9 + * under the terms and conditions of the GNU General Public License, 10 + * version 2 or later, as published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope it will be useful, but WITHOUT 13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 + * more details. 16 + * 17 + * You should have received a copy of the GNU General Public License along with 18 + * this program. If not, see <http://www.gnu.org/licenses/>. 19 + */ 20 + 21 + #include "qemu/osdep.h" 22 + #include "hw/sysbus.h" 23 + #include "qemu/log.h" 24 + #include "qemu/module.h" 25 + #include "hw/riscv/sifive_u_prci.h" 26 + 27 + static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size) 28 + { 29 + SiFiveUPRCIState *s = opaque; 30 + 31 + switch (addr) { 32 + case SIFIVE_U_PRCI_HFXOSCCFG: 33 + return s->hfxosccfg; 34 + case SIFIVE_U_PRCI_COREPLLCFG0: 35 + return s->corepllcfg0; 36 + case SIFIVE_U_PRCI_DDRPLLCFG0: 37 + return s->ddrpllcfg0; 38 + case SIFIVE_U_PRCI_DDRPLLCFG1: 39 + return s->ddrpllcfg1; 40 + case SIFIVE_U_PRCI_GEMGXLPLLCFG0: 41 + return s->gemgxlpllcfg0; 42 + case SIFIVE_U_PRCI_GEMGXLPLLCFG1: 43 + return s->gemgxlpllcfg1; 44 + case SIFIVE_U_PRCI_CORECLKSEL: 45 + return s->coreclksel; 46 + case SIFIVE_U_PRCI_DEVICESRESET: 47 + return s->devicesreset; 48 + case SIFIVE_U_PRCI_CLKMUXSTATUS: 49 + return s->clkmuxstatus; 50 + } 51 + 52 + qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", 53 + __func__, addr); 54 + 55 + return 0; 56 + } 57 + 58 + static void sifive_u_prci_write(void *opaque, hwaddr addr, 59 + uint64_t val64, unsigned int size) 60 + { 61 + SiFiveUPRCIState *s = opaque; 62 + uint32_t val32 = (uint32_t)val64; 63 + 64 + switch (addr) { 65 + case SIFIVE_U_PRCI_HFXOSCCFG: 66 + s->hfxosccfg = val32; 67 + /* OSC stays ready */ 68 + s->hfxosccfg |= SIFIVE_U_PRCI_HFXOSCCFG_RDY; 69 + break; 70 + case SIFIVE_U_PRCI_COREPLLCFG0: 71 + s->corepllcfg0 = val32; 72 + /* internal feedback */ 73 + s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; 74 + /* PLL stays locked */ 75 + s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; 76 + break; 77 + case SIFIVE_U_PRCI_DDRPLLCFG0: 78 + s->ddrpllcfg0 = val32; 79 + /* internal feedback */ 80 + s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; 81 + /* PLL stays locked */ 82 + s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; 83 + break; 84 + case SIFIVE_U_PRCI_DDRPLLCFG1: 85 + s->ddrpllcfg1 = val32; 86 + break; 87 + case SIFIVE_U_PRCI_GEMGXLPLLCFG0: 88 + s->gemgxlpllcfg0 = val32; 89 + /* internal feedback */ 90 + s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; 91 + /* PLL stays locked */ 92 + s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; 93 + break; 94 + case SIFIVE_U_PRCI_GEMGXLPLLCFG1: 95 + s->gemgxlpllcfg1 = val32; 96 + break; 97 + case SIFIVE_U_PRCI_CORECLKSEL: 98 + s->coreclksel = val32; 99 + break; 100 + case SIFIVE_U_PRCI_DEVICESRESET: 101 + s->devicesreset = val32; 102 + break; 103 + case SIFIVE_U_PRCI_CLKMUXSTATUS: 104 + s->clkmuxstatus = val32; 105 + break; 106 + default: 107 + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 108 + " v=0x%x\n", __func__, addr, val32); 109 + } 110 + } 111 + 112 + static const MemoryRegionOps sifive_u_prci_ops = { 113 + .read = sifive_u_prci_read, 114 + .write = sifive_u_prci_write, 115 + .endianness = DEVICE_NATIVE_ENDIAN, 116 + .valid = { 117 + .min_access_size = 4, 118 + .max_access_size = 4 119 + } 120 + }; 121 + 122 + static void sifive_u_prci_realize(DeviceState *dev, Error **errp) 123 + { 124 + SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev); 125 + 126 + memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_prci_ops, s, 127 + TYPE_SIFIVE_U_PRCI, SIFIVE_U_PRCI_REG_SIZE); 128 + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); 129 + } 130 + 131 + static void sifive_u_prci_reset(DeviceState *dev) 132 + { 133 + SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev); 134 + 135 + /* Initialize register to power-on-reset values */ 136 + s->hfxosccfg = SIFIVE_U_PRCI_HFXOSCCFG_RDY | SIFIVE_U_PRCI_HFXOSCCFG_EN; 137 + s->corepllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | 138 + SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | 139 + SIFIVE_U_PRCI_PLLCFG0_LOCK; 140 + s->ddrpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | 141 + SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | 142 + SIFIVE_U_PRCI_PLLCFG0_LOCK; 143 + s->gemgxlpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | 144 + SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | 145 + SIFIVE_U_PRCI_PLLCFG0_LOCK; 146 + s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK; 147 + } 148 + 149 + static void sifive_u_prci_class_init(ObjectClass *klass, void *data) 150 + { 151 + DeviceClass *dc = DEVICE_CLASS(klass); 152 + 153 + dc->realize = sifive_u_prci_realize; 154 + dc->reset = sifive_u_prci_reset; 155 + } 156 + 157 + static const TypeInfo sifive_u_prci_info = { 158 + .name = TYPE_SIFIVE_U_PRCI, 159 + .parent = TYPE_SYS_BUS_DEVICE, 160 + .instance_size = sizeof(SiFiveUPRCIState), 161 + .class_init = sifive_u_prci_class_init, 162 + }; 163 + 164 + static void sifive_u_prci_register_types(void) 165 + { 166 + type_register_static(&sifive_u_prci_info); 167 + } 168 + 169 + type_init(sifive_u_prci_register_types)
+81
include/hw/riscv/sifive_u_prci.h
··· 1 + /* 2 + * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt) interface 3 + * 4 + * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms and conditions of the GNU General Public License, 8 + * version 2 or later, as published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 + * more details. 14 + * 15 + * You should have received a copy of the GNU General Public License along with 16 + * this program. If not, see <http://www.gnu.org/licenses/>. 17 + */ 18 + 19 + #ifndef HW_SIFIVE_U_PRCI_H 20 + #define HW_SIFIVE_U_PRCI_H 21 + 22 + #define SIFIVE_U_PRCI_HFXOSCCFG 0x00 23 + #define SIFIVE_U_PRCI_COREPLLCFG0 0x04 24 + #define SIFIVE_U_PRCI_DDRPLLCFG0 0x0C 25 + #define SIFIVE_U_PRCI_DDRPLLCFG1 0x10 26 + #define SIFIVE_U_PRCI_GEMGXLPLLCFG0 0x1C 27 + #define SIFIVE_U_PRCI_GEMGXLPLLCFG1 0x20 28 + #define SIFIVE_U_PRCI_CORECLKSEL 0x24 29 + #define SIFIVE_U_PRCI_DEVICESRESET 0x28 30 + #define SIFIVE_U_PRCI_CLKMUXSTATUS 0x2C 31 + 32 + /* 33 + * Current FU540-C000 manual says ready bit is at bit 29, but 34 + * freedom-u540-c000-bootloader codes (ux00prci.h) says it is at bit 31. 35 + * We have to trust the actual code that works. 36 + * 37 + * see https://github.com/sifive/freedom-u540-c000-bootloader 38 + */ 39 + 40 + #define SIFIVE_U_PRCI_HFXOSCCFG_EN (1 << 30) 41 + #define SIFIVE_U_PRCI_HFXOSCCFG_RDY (1 << 31) 42 + 43 + /* xxxPLLCFG0 register bits */ 44 + #define SIFIVE_U_PRCI_PLLCFG0_DIVR (1 << 0) 45 + #define SIFIVE_U_PRCI_PLLCFG0_DIVF (31 << 6) 46 + #define SIFIVE_U_PRCI_PLLCFG0_DIVQ (3 << 15) 47 + #define SIFIVE_U_PRCI_PLLCFG0_FSE (1 << 25) 48 + #define SIFIVE_U_PRCI_PLLCFG0_LOCK (1 << 31) 49 + 50 + /* xxxPLLCFG1 register bits */ 51 + #define SIFIVE_U_PRCI_PLLCFG1_CKE (1 << 24) 52 + 53 + /* coreclksel register bits */ 54 + #define SIFIVE_U_PRCI_CORECLKSEL_HFCLK (1 << 0) 55 + 56 + 57 + #define SIFIVE_U_PRCI_REG_SIZE 0x1000 58 + 59 + #define TYPE_SIFIVE_U_PRCI "riscv.sifive.u.prci" 60 + 61 + #define SIFIVE_U_PRCI(obj) \ 62 + OBJECT_CHECK(SiFiveUPRCIState, (obj), TYPE_SIFIVE_U_PRCI) 63 + 64 + typedef struct SiFiveUPRCIState { 65 + /*< private >*/ 66 + SysBusDevice parent_obj; 67 + 68 + /*< public >*/ 69 + MemoryRegion mmio; 70 + uint32_t hfxosccfg; 71 + uint32_t corepllcfg0; 72 + uint32_t ddrpllcfg0; 73 + uint32_t ddrpllcfg1; 74 + uint32_t gemgxlpllcfg0; 75 + uint32_t gemgxlpllcfg1; 76 + uint32_t coreclksel; 77 + uint32_t devicesreset; 78 + uint32_t clkmuxstatus; 79 + } SiFiveUPRCIState; 80 + 81 + #endif /* HW_SIFIVE_U_PRCI_H */