| 1 | /* |
| 2 | * QEMU RISC-V Board Compatible with Microchip PolarFire SoC Icicle Kit |
| 3 | * |
| 4 | * Copyright (c) 2020 Wind River Systems, Inc. |
| 5 | * |
| 6 | * Author: |
| 7 | * Bin Meng <bin.meng@windriver.com> |
| 8 | * |
| 9 | * Provides a board compatible with the Microchip PolarFire SoC Icicle Kit |
| 10 | * |
| 11 | * 0) CLINT (Core Level Interruptor) |
| 12 | * 1) PLIC (Platform Level Interrupt Controller) |
| 13 | * 2) eNVM (Embedded Non-Volatile Memory) |
| 14 | * 3) MMUARTs (Multi-Mode UART) |
| 15 | * 4) Cadence eMMC/SDHC controller and an SD card connected to it |
| 16 | * 5) SiFive Platform DMA (Direct Memory Access Controller) |
| 17 | * 6) GEM (Gigabit Ethernet MAC Controller) |
| 18 | * 7) DMC (DDR Memory Controller) |
| 19 | * 8) IOSCB modules |
| 20 | * |
| 21 | * This board currently generates devicetree dynamically that indicates at least |
| 22 | * two harts and up to five harts. |
| 23 | * |
| 24 | * This program is free software; you can redistribute it and/or modify it |
| 25 | * under the terms and conditions of the GNU General Public License, |
| 26 | * version 2 or later, as published by the Free Software Foundation. |
| 27 | * |
| 28 | * This program is distributed in the hope it will be useful, but WITHOUT |
| 29 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 30 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 31 | * more details. |
| 32 | * |
| 33 | * You should have received a copy of the GNU General Public License along with |
| 34 | * this program. If not, see <http://www.gnu.org/licenses/>. |
| 35 | */ |
| 36 | |
| 37 | #include "qemu/osdep.h" |
| 38 | #include "qemu/error-report.h" |
| 39 | #include "qemu/units.h" |
| 40 | #include "qemu/cutils.h" |
| 41 | #include "qapi/error.h" |
| 42 | #include "qapi/visitor.h" |
| 43 | #include "hw/core/boards.h" |
| 44 | #include "hw/core/loader.h" |
| 45 | #include "hw/core/sysbus.h" |
| 46 | #include "chardev/char.h" |
| 47 | #include "hw/cpu/cluster.h" |
| 48 | #include "target/riscv/cpu.h" |
| 49 | #include "hw/misc/unimp.h" |
| 50 | #include "hw/riscv/boot.h" |
| 51 | #include "hw/riscv/riscv_hart.h" |
| 52 | #include "hw/riscv/machines-qom.h" |
| 53 | #include "hw/riscv/microchip_pfsoc.h" |
| 54 | #include "hw/intc/riscv_aclint.h" |
| 55 | #include "hw/intc/sifive_plic.h" |
| 56 | #include "system/device_tree.h" |
| 57 | #include "system/system.h" |
| 58 | |
| 59 | /* |
| 60 | * The BIOS image used by this machine is called Hart Software Services (HSS). |
| 61 | * See https://github.com/polarfire-soc/hart-software-services |
| 62 | */ |
| 63 | #define BIOS_FILENAME "hss.bin" |
| 64 | #define RESET_VECTOR 0x20220000 |
| 65 | |
| 66 | /* GEM version */ |
| 67 | #define GEM_REVISION 0x0107010c |
| 68 | |
| 69 | /* |
| 70 | * The complete description of the whole PolarFire SoC memory map is scattered |
| 71 | * in different documents. There are several places to look at for memory maps: |
| 72 | * |
| 73 | * 1 Chapter 11 "MSS Memory Map", in the doc "UG0880: PolarFire SoC FPGA |
| 74 | * Microprocessor Subsystem (MSS) User Guide", which can be downloaded from |
| 75 | * https://www.microsemi.com/document-portal/doc_download/ |
| 76 | * 1244570-ug0880-polarfire-soc-fpga-microprocessor-subsystem-mss-user-guide, |
| 77 | * describes the whole picture of the PolarFire SoC memory map. |
| 78 | * |
| 79 | * 2 A zip file for PolarFire soC memory map, which can be downloaded from |
| 80 | * https://www.microsemi.com/document-portal/doc_download/ |
| 81 | * 1244581-polarfire-soc-register-map, contains the following 2 major parts: |
| 82 | * - Register Map/PF_SoC_RegMap_V1_1/pfsoc_regmap.htm |
| 83 | * describes the complete integrated peripherals memory map |
| 84 | * - Register Map/PF_SoC_RegMap_V1_1/MPFS250T/mpfs250t_ioscb_memmap_dri.htm |
| 85 | * describes the complete IOSCB modules memory maps |
| 86 | */ |
| 87 | static const MemMapEntry microchip_pfsoc_memmap[] = { |
| 88 | [MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 }, |
| 89 | [MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 }, |
| 90 | [MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 }, |
| 91 | [MICROCHIP_PFSOC_BUSERR_UNIT0] = { 0x1700000, 0x1000 }, |
| 92 | [MICROCHIP_PFSOC_BUSERR_UNIT1] = { 0x1701000, 0x1000 }, |
| 93 | [MICROCHIP_PFSOC_BUSERR_UNIT2] = { 0x1702000, 0x1000 }, |
| 94 | [MICROCHIP_PFSOC_BUSERR_UNIT3] = { 0x1703000, 0x1000 }, |
| 95 | [MICROCHIP_PFSOC_BUSERR_UNIT4] = { 0x1704000, 0x1000 }, |
| 96 | [MICROCHIP_PFSOC_CLINT] = { 0x2000000, 0x10000 }, |
| 97 | [MICROCHIP_PFSOC_L2CC] = { 0x2010000, 0x1000 }, |
| 98 | [MICROCHIP_PFSOC_DMA] = { 0x3000000, 0x100000 }, |
| 99 | [MICROCHIP_PFSOC_L2LIM] = { 0x8000000, 0x2000000 }, |
| 100 | [MICROCHIP_PFSOC_PLIC] = { 0xc000000, 0x4000000 }, |
| 101 | [MICROCHIP_PFSOC_MMUART0] = { 0x20000000, 0x1000 }, |
| 102 | [MICROCHIP_PFSOC_WDOG0] = { 0x20001000, 0x1000 }, |
| 103 | [MICROCHIP_PFSOC_SYSREG] = { 0x20002000, 0x2000 }, |
| 104 | [MICROCHIP_PFSOC_AXISW] = { 0x20004000, 0x1000 }, |
| 105 | [MICROCHIP_PFSOC_MPUCFG] = { 0x20005000, 0x1000 }, |
| 106 | [MICROCHIP_PFSOC_FMETER] = { 0x20006000, 0x1000 }, |
| 107 | [MICROCHIP_PFSOC_DDR_SGMII_PHY] = { 0x20007000, 0x1000 }, |
| 108 | [MICROCHIP_PFSOC_EMMC_SD] = { 0x20008000, 0x1000 }, |
| 109 | [MICROCHIP_PFSOC_DDR_CFG] = { 0x20080000, 0x40000 }, |
| 110 | [MICROCHIP_PFSOC_MMUART1] = { 0x20100000, 0x1000 }, |
| 111 | [MICROCHIP_PFSOC_MMUART2] = { 0x20102000, 0x1000 }, |
| 112 | [MICROCHIP_PFSOC_MMUART3] = { 0x20104000, 0x1000 }, |
| 113 | [MICROCHIP_PFSOC_MMUART4] = { 0x20106000, 0x1000 }, |
| 114 | [MICROCHIP_PFSOC_WDOG1] = { 0x20101000, 0x1000 }, |
| 115 | [MICROCHIP_PFSOC_WDOG2] = { 0x20103000, 0x1000 }, |
| 116 | [MICROCHIP_PFSOC_WDOG3] = { 0x20105000, 0x1000 }, |
| 117 | [MICROCHIP_PFSOC_WDOG4] = { 0x20106000, 0x1000 }, |
| 118 | [MICROCHIP_PFSOC_SPI0] = { 0x20108000, 0x1000 }, |
| 119 | [MICROCHIP_PFSOC_SPI1] = { 0x20109000, 0x1000 }, |
| 120 | [MICROCHIP_PFSOC_I2C0] = { 0x2010a000, 0x1000 }, |
| 121 | [MICROCHIP_PFSOC_I2C1] = { 0x2010b000, 0x1000 }, |
| 122 | [MICROCHIP_PFSOC_CAN0] = { 0x2010c000, 0x1000 }, |
| 123 | [MICROCHIP_PFSOC_CAN1] = { 0x2010d000, 0x1000 }, |
| 124 | [MICROCHIP_PFSOC_GEM0] = { 0x20110000, 0x2000 }, |
| 125 | [MICROCHIP_PFSOC_GEM1] = { 0x20112000, 0x2000 }, |
| 126 | [MICROCHIP_PFSOC_GPIO0] = { 0x20120000, 0x1000 }, |
| 127 | [MICROCHIP_PFSOC_GPIO1] = { 0x20121000, 0x1000 }, |
| 128 | [MICROCHIP_PFSOC_GPIO2] = { 0x20122000, 0x1000 }, |
| 129 | [MICROCHIP_PFSOC_RTC] = { 0x20124000, 0x1000 }, |
| 130 | [MICROCHIP_PFSOC_ENVM_CFG] = { 0x20200000, 0x1000 }, |
| 131 | [MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 }, |
| 132 | [MICROCHIP_PFSOC_USB] = { 0x20201000, 0x1000 }, |
| 133 | [MICROCHIP_PFSOC_QSPI_XIP] = { 0x21000000, 0x1000000 }, |
| 134 | [MICROCHIP_PFSOC_IOSCB] = { 0x30000000, 0x10000000 }, |
| 135 | [MICROCHIP_PFSOC_FABRIC_FIC0] = { 0x2000000000, 0x1000000000 }, |
| 136 | [MICROCHIP_PFSOC_FABRIC_FIC1] = { 0x3000000000, 0x1000000000 }, |
| 137 | [MICROCHIP_PFSOC_FABRIC_FIC3] = { 0x40000000, 0x20000000 }, |
| 138 | [MICROCHIP_PFSOC_DRAM_LO] = { 0x80000000, 0x40000000 }, |
| 139 | [MICROCHIP_PFSOC_DRAM_LO_ALIAS] = { 0xc0000000, 0x40000000 }, |
| 140 | [MICROCHIP_PFSOC_DRAM_HI] = { 0x1000000000, 0x0 }, |
| 141 | [MICROCHIP_PFSOC_DRAM_HI_ALIAS] = { 0x1400000000, 0x0 }, |
| 142 | |
| 143 | }; |
| 144 | |
| 145 | static void microchip_pfsoc_soc_instance_init(Object *obj) |
| 146 | { |
| 147 | MicrochipPFSoCState *s = MICROCHIP_PFSOC(obj); |
| 148 | |
| 149 | object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER); |
| 150 | qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0); |
| 151 | |
| 152 | object_initialize_child(OBJECT(&s->e_cluster), "e-cpus", &s->e_cpus, |
| 153 | TYPE_RISCV_HART_ARRAY); |
| 154 | qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1); |
| 155 | qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0); |
| 156 | qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", |
| 157 | TYPE_RISCV_CPU_SIFIVE_E51); |
| 158 | qdev_prop_set_uint64(DEVICE(&s->e_cpus), "resetvec", RESET_VECTOR); |
| 159 | |
| 160 | object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER); |
| 161 | qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1); |
| 162 | |
| 163 | object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", &s->u_cpus, |
| 164 | TYPE_RISCV_HART_ARRAY); |
| 165 | /* |
| 166 | * Set the `num-harts` property later as the machine is potentially not |
| 167 | * created yet. |
| 168 | */ |
| 169 | qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1); |
| 170 | qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", |
| 171 | TYPE_RISCV_CPU_SIFIVE_U54); |
| 172 | qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", RESET_VECTOR); |
| 173 | |
| 174 | object_initialize_child(obj, "dma-controller", &s->dma, |
| 175 | TYPE_SIFIVE_PDMA); |
| 176 | |
| 177 | object_initialize_child(obj, "sysreg", &s->sysreg, |
| 178 | TYPE_MCHP_PFSOC_SYSREG); |
| 179 | |
| 180 | object_initialize_child(obj, "ddr-sgmii-phy", &s->ddr_sgmii_phy, |
| 181 | TYPE_MCHP_PFSOC_DDR_SGMII_PHY); |
| 182 | object_initialize_child(obj, "ddr-cfg", &s->ddr_cfg, |
| 183 | TYPE_MCHP_PFSOC_DDR_CFG); |
| 184 | |
| 185 | object_initialize_child(obj, "gem0", &s->gem0, TYPE_CADENCE_GEM); |
| 186 | object_initialize_child(obj, "gem1", &s->gem1, TYPE_CADENCE_GEM); |
| 187 | |
| 188 | object_initialize_child(obj, "sd-controller", &s->sdhci, |
| 189 | TYPE_CADENCE_SDHCI); |
| 190 | |
| 191 | object_initialize_child(obj, "ioscb", &s->ioscb, TYPE_MCHP_PFSOC_IOSCB); |
| 192 | } |
| 193 | |
| 194 | static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) |
| 195 | { |
| 196 | MachineState *ms = MACHINE(qdev_get_machine()); |
| 197 | MicrochipIcicleKitState *iks = MICROCHIP_ICICLE_KIT_MACHINE(ms); |
| 198 | MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev); |
| 199 | const MemMapEntry *memmap = microchip_pfsoc_memmap; |
| 200 | MemoryRegion *system_memory = get_system_memory(); |
| 201 | MemoryRegion *rsvd0_mem = g_new(MemoryRegion, 1); |
| 202 | MemoryRegion *e51_dtim_mem = g_new(MemoryRegion, 1); |
| 203 | MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1); |
| 204 | MemoryRegion *envm_data = g_new(MemoryRegion, 1); |
| 205 | MemoryRegion *qspi_xip_mem = g_new(MemoryRegion, 1); |
| 206 | char *plic_hart_config; |
| 207 | int i; |
| 208 | |
| 209 | sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort); |
| 210 | qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1); |
| 211 | sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort); |
| 212 | /* |
| 213 | * The cluster must be realized after the RISC-V hart array container, |
| 214 | * as the container's CPU object is only created on realize, and the |
| 215 | * CPU must exist and have been parented into the cluster before the |
| 216 | * cluster is realized. |
| 217 | */ |
| 218 | qdev_realize(DEVICE(&s->e_cluster), NULL, &error_abort); |
| 219 | qdev_realize(DEVICE(&s->u_cluster), NULL, &error_abort); |
| 220 | |
| 221 | /* Reserved Memory at address 0 */ |
| 222 | memory_region_init_ram(rsvd0_mem, NULL, "microchip.pfsoc.rsvd0_mem", |
| 223 | memmap[MICROCHIP_PFSOC_RSVD0].size, &error_fatal); |
| 224 | memory_region_add_subregion(system_memory, |
| 225 | memmap[MICROCHIP_PFSOC_RSVD0].base, |
| 226 | rsvd0_mem); |
| 227 | |
| 228 | /* E51 DTIM */ |
| 229 | memory_region_init_ram(e51_dtim_mem, NULL, "microchip.pfsoc.e51_dtim_mem", |
| 230 | memmap[MICROCHIP_PFSOC_E51_DTIM].size, &error_fatal); |
| 231 | memory_region_add_subregion(system_memory, |
| 232 | memmap[MICROCHIP_PFSOC_E51_DTIM].base, |
| 233 | e51_dtim_mem); |
| 234 | |
| 235 | /* Bus Error Units */ |
| 236 | create_unimplemented_device("microchip.pfsoc.buserr_unit0_mem", |
| 237 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT0].base, |
| 238 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT0].size); |
| 239 | create_unimplemented_device("microchip.pfsoc.buserr_unit1_mem", |
| 240 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT1].base, |
| 241 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT1].size); |
| 242 | create_unimplemented_device("microchip.pfsoc.buserr_unit2_mem", |
| 243 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT2].base, |
| 244 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT2].size); |
| 245 | create_unimplemented_device("microchip.pfsoc.buserr_unit3_mem", |
| 246 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT3].base, |
| 247 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT3].size); |
| 248 | create_unimplemented_device("microchip.pfsoc.buserr_unit4_mem", |
| 249 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].base, |
| 250 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size); |
| 251 | |
| 252 | /* CLINT */ |
| 253 | riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base, |
| 254 | 0, ms->smp.cpus, false); |
| 255 | riscv_aclint_mtimer_create( |
| 256 | memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE, |
| 257 | RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus, |
| 258 | RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, |
| 259 | iks->clint_timebase_freq, false); |
| 260 | |
| 261 | /* L2 cache controller */ |
| 262 | create_unimplemented_device("microchip.pfsoc.l2cc", |
| 263 | memmap[MICROCHIP_PFSOC_L2CC].base, memmap[MICROCHIP_PFSOC_L2CC].size); |
| 264 | |
| 265 | /* |
| 266 | * Add L2-LIM at reset size. |
| 267 | * This should be reduced in size as the L2 Cache Controller WayEnable |
| 268 | * register is incremented. Unfortunately I don't see a nice (or any) way |
| 269 | * to handle reducing or blocking out the L2 LIM while still allowing it |
| 270 | * be re returned to all enabled after a reset. For the time being, just |
| 271 | * leave it enabled all the time. This won't break anything, but will be |
| 272 | * too generous to misbehaving guests. |
| 273 | */ |
| 274 | memory_region_init_ram(l2lim_mem, NULL, "microchip.pfsoc.l2lim", |
| 275 | memmap[MICROCHIP_PFSOC_L2LIM].size, &error_fatal); |
| 276 | memory_region_add_subregion(system_memory, |
| 277 | memmap[MICROCHIP_PFSOC_L2LIM].base, |
| 278 | l2lim_mem); |
| 279 | |
| 280 | /* create PLIC hart topology configuration string */ |
| 281 | plic_hart_config = riscv_plic_hart_config_string(ms->smp.cpus); |
| 282 | |
| 283 | /* PLIC */ |
| 284 | s->plic = sifive_plic_create(memmap[MICROCHIP_PFSOC_PLIC].base, |
| 285 | plic_hart_config, ms->smp.cpus, 0, |
| 286 | MICROCHIP_PFSOC_PLIC_NUM_SOURCES, |
| 287 | MICROCHIP_PFSOC_PLIC_NUM_PRIORITIES, |
| 288 | MICROCHIP_PFSOC_PLIC_PRIORITY_BASE, |
| 289 | MICROCHIP_PFSOC_PLIC_PENDING_BASE, |
| 290 | MICROCHIP_PFSOC_PLIC_ENABLE_BASE, |
| 291 | MICROCHIP_PFSOC_PLIC_ENABLE_STRIDE, |
| 292 | MICROCHIP_PFSOC_PLIC_CONTEXT_BASE, |
| 293 | MICROCHIP_PFSOC_PLIC_CONTEXT_STRIDE, |
| 294 | memmap[MICROCHIP_PFSOC_PLIC].size); |
| 295 | g_free(plic_hart_config); |
| 296 | |
| 297 | /* DMA */ |
| 298 | sysbus_realize(SYS_BUS_DEVICE(&s->dma), errp); |
| 299 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->dma), 0, |
| 300 | memmap[MICROCHIP_PFSOC_DMA].base); |
| 301 | for (i = 0; i < SIFIVE_PDMA_IRQS; i++) { |
| 302 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), i, |
| 303 | qdev_get_gpio_in(DEVICE(s->plic), |
| 304 | MICROCHIP_PFSOC_DMA_IRQ0 + i)); |
| 305 | } |
| 306 | |
| 307 | /* SYSREG */ |
| 308 | sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), errp); |
| 309 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysreg), 0, |
| 310 | memmap[MICROCHIP_PFSOC_SYSREG].base); |
| 311 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->sysreg), 0, |
| 312 | qdev_get_gpio_in(DEVICE(s->plic), |
| 313 | MICROCHIP_PFSOC_MAILBOX_IRQ)); |
| 314 | |
| 315 | /* AXISW */ |
| 316 | create_unimplemented_device("microchip.pfsoc.axisw", |
| 317 | memmap[MICROCHIP_PFSOC_AXISW].base, |
| 318 | memmap[MICROCHIP_PFSOC_AXISW].size); |
| 319 | |
| 320 | /* MPUCFG */ |
| 321 | create_unimplemented_device("microchip.pfsoc.mpucfg", |
| 322 | memmap[MICROCHIP_PFSOC_MPUCFG].base, |
| 323 | memmap[MICROCHIP_PFSOC_MPUCFG].size); |
| 324 | |
| 325 | /* FMETER */ |
| 326 | create_unimplemented_device("microchip.pfsoc.fmeter", |
| 327 | memmap[MICROCHIP_PFSOC_FMETER].base, |
| 328 | memmap[MICROCHIP_PFSOC_FMETER].size); |
| 329 | |
| 330 | /* DDR SGMII PHY */ |
| 331 | sysbus_realize(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), errp); |
| 332 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), 0, |
| 333 | memmap[MICROCHIP_PFSOC_DDR_SGMII_PHY].base); |
| 334 | |
| 335 | /* DDR CFG */ |
| 336 | sysbus_realize(SYS_BUS_DEVICE(&s->ddr_cfg), errp); |
| 337 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_cfg), 0, |
| 338 | memmap[MICROCHIP_PFSOC_DDR_CFG].base); |
| 339 | |
| 340 | /* SDHCI */ |
| 341 | sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp); |
| 342 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0, |
| 343 | memmap[MICROCHIP_PFSOC_EMMC_SD].base); |
| 344 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, |
| 345 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_EMMC_SD_IRQ)); |
| 346 | |
| 347 | /* MMUARTs */ |
| 348 | s->serial0 = mchp_pfsoc_mmuart_create(system_memory, |
| 349 | memmap[MICROCHIP_PFSOC_MMUART0].base, |
| 350 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART0_IRQ), |
| 351 | serial_hd(0)); |
| 352 | s->serial1 = mchp_pfsoc_mmuart_create(system_memory, |
| 353 | memmap[MICROCHIP_PFSOC_MMUART1].base, |
| 354 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART1_IRQ), |
| 355 | serial_hd(1)); |
| 356 | s->serial2 = mchp_pfsoc_mmuart_create(system_memory, |
| 357 | memmap[MICROCHIP_PFSOC_MMUART2].base, |
| 358 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART2_IRQ), |
| 359 | serial_hd(2)); |
| 360 | s->serial3 = mchp_pfsoc_mmuart_create(system_memory, |
| 361 | memmap[MICROCHIP_PFSOC_MMUART3].base, |
| 362 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART3_IRQ), |
| 363 | serial_hd(3)); |
| 364 | s->serial4 = mchp_pfsoc_mmuart_create(system_memory, |
| 365 | memmap[MICROCHIP_PFSOC_MMUART4].base, |
| 366 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART4_IRQ), |
| 367 | serial_hd(4)); |
| 368 | |
| 369 | /* Watchdogs */ |
| 370 | create_unimplemented_device("microchip.pfsoc.watchdog0", |
| 371 | memmap[MICROCHIP_PFSOC_WDOG0].base, |
| 372 | memmap[MICROCHIP_PFSOC_WDOG0].size); |
| 373 | create_unimplemented_device("microchip.pfsoc.watchdog1", |
| 374 | memmap[MICROCHIP_PFSOC_WDOG1].base, |
| 375 | memmap[MICROCHIP_PFSOC_WDOG1].size); |
| 376 | create_unimplemented_device("microchip.pfsoc.watchdog2", |
| 377 | memmap[MICROCHIP_PFSOC_WDOG2].base, |
| 378 | memmap[MICROCHIP_PFSOC_WDOG2].size); |
| 379 | create_unimplemented_device("microchip.pfsoc.watchdog3", |
| 380 | memmap[MICROCHIP_PFSOC_WDOG3].base, |
| 381 | memmap[MICROCHIP_PFSOC_WDOG3].size); |
| 382 | create_unimplemented_device("microchip.pfsoc.watchdog4", |
| 383 | memmap[MICROCHIP_PFSOC_WDOG4].base, |
| 384 | memmap[MICROCHIP_PFSOC_WDOG4].size); |
| 385 | |
| 386 | /* SPI */ |
| 387 | create_unimplemented_device("microchip.pfsoc.spi0", |
| 388 | memmap[MICROCHIP_PFSOC_SPI0].base, |
| 389 | memmap[MICROCHIP_PFSOC_SPI0].size); |
| 390 | create_unimplemented_device("microchip.pfsoc.spi1", |
| 391 | memmap[MICROCHIP_PFSOC_SPI1].base, |
| 392 | memmap[MICROCHIP_PFSOC_SPI1].size); |
| 393 | |
| 394 | /* I2C */ |
| 395 | create_unimplemented_device("microchip.pfsoc.i2c0", |
| 396 | memmap[MICROCHIP_PFSOC_I2C0].base, |
| 397 | memmap[MICROCHIP_PFSOC_I2C0].size); |
| 398 | create_unimplemented_device("microchip.pfsoc.i2c1", |
| 399 | memmap[MICROCHIP_PFSOC_I2C1].base, |
| 400 | memmap[MICROCHIP_PFSOC_I2C1].size); |
| 401 | |
| 402 | /* CAN */ |
| 403 | create_unimplemented_device("microchip.pfsoc.can0", |
| 404 | memmap[MICROCHIP_PFSOC_CAN0].base, |
| 405 | memmap[MICROCHIP_PFSOC_CAN0].size); |
| 406 | create_unimplemented_device("microchip.pfsoc.can1", |
| 407 | memmap[MICROCHIP_PFSOC_CAN1].base, |
| 408 | memmap[MICROCHIP_PFSOC_CAN1].size); |
| 409 | |
| 410 | /* USB */ |
| 411 | create_unimplemented_device("microchip.pfsoc.usb", |
| 412 | memmap[MICROCHIP_PFSOC_USB].base, |
| 413 | memmap[MICROCHIP_PFSOC_USB].size); |
| 414 | |
| 415 | /* GEMs */ |
| 416 | qemu_configure_nic_device(DEVICE(&s->gem0), true, NULL); |
| 417 | qemu_configure_nic_device(DEVICE(&s->gem1), true, NULL); |
| 418 | |
| 419 | object_property_set_int(OBJECT(&s->gem0), "revision", GEM_REVISION, errp); |
| 420 | object_property_set_int(OBJECT(&s->gem0), "phy-addr", 8, errp); |
| 421 | object_property_set_bool(OBJECT(&s->gem0), "phy-connected", false, errp); |
| 422 | object_property_set_bool(OBJECT(&s->gem0), "pcs-enabled", true, errp); |
| 423 | |
| 424 | sysbus_realize(SYS_BUS_DEVICE(&s->gem0), errp); |
| 425 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem0), 0, |
| 426 | memmap[MICROCHIP_PFSOC_GEM0].base); |
| 427 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem0), 0, |
| 428 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_GEM0_IRQ)); |
| 429 | |
| 430 | object_property_set_int(OBJECT(&s->gem1), "revision", GEM_REVISION, errp); |
| 431 | object_property_set_int(OBJECT(&s->gem1), "phy-addr", 9, errp); |
| 432 | object_property_set_link(OBJECT(&s->gem1), "phy-consumer", |
| 433 | OBJECT(&s->gem0), errp); |
| 434 | object_property_set_bool(OBJECT(&s->gem1), "pcs-enabled", true, errp); |
| 435 | sysbus_realize(SYS_BUS_DEVICE(&s->gem1), errp); |
| 436 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem1), 0, |
| 437 | memmap[MICROCHIP_PFSOC_GEM1].base); |
| 438 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem1), 0, |
| 439 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_GEM1_IRQ)); |
| 440 | |
| 441 | /* GPIOs */ |
| 442 | create_unimplemented_device("microchip.pfsoc.gpio0", |
| 443 | memmap[MICROCHIP_PFSOC_GPIO0].base, |
| 444 | memmap[MICROCHIP_PFSOC_GPIO0].size); |
| 445 | create_unimplemented_device("microchip.pfsoc.gpio1", |
| 446 | memmap[MICROCHIP_PFSOC_GPIO1].base, |
| 447 | memmap[MICROCHIP_PFSOC_GPIO1].size); |
| 448 | create_unimplemented_device("microchip.pfsoc.gpio2", |
| 449 | memmap[MICROCHIP_PFSOC_GPIO2].base, |
| 450 | memmap[MICROCHIP_PFSOC_GPIO2].size); |
| 451 | |
| 452 | /* eNVM */ |
| 453 | memory_region_init_rom(envm_data, OBJECT(dev), "microchip.pfsoc.envm.data", |
| 454 | memmap[MICROCHIP_PFSOC_ENVM_DATA].size, |
| 455 | &error_fatal); |
| 456 | memory_region_add_subregion(system_memory, |
| 457 | memmap[MICROCHIP_PFSOC_ENVM_DATA].base, |
| 458 | envm_data); |
| 459 | |
| 460 | /* IOSCB */ |
| 461 | sysbus_realize(SYS_BUS_DEVICE(&s->ioscb), errp); |
| 462 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->ioscb), 0, |
| 463 | memmap[MICROCHIP_PFSOC_IOSCB].base); |
| 464 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->ioscb), 0, |
| 465 | qdev_get_gpio_in(DEVICE(s->plic), |
| 466 | MICROCHIP_PFSOC_MAILBOX_IRQ)); |
| 467 | |
| 468 | /* FPGA Fabric */ |
| 469 | create_unimplemented_device("microchip.pfsoc.fabricfic3", |
| 470 | memmap[MICROCHIP_PFSOC_FABRIC_FIC3].base, |
| 471 | memmap[MICROCHIP_PFSOC_FABRIC_FIC3].size); |
| 472 | /* FPGA Fabric */ |
| 473 | create_unimplemented_device("microchip.pfsoc.fabricfic0", |
| 474 | memmap[MICROCHIP_PFSOC_FABRIC_FIC0].base, |
| 475 | memmap[MICROCHIP_PFSOC_FABRIC_FIC0].size); |
| 476 | /* FPGA Fabric */ |
| 477 | create_unimplemented_device("microchip.pfsoc.fabricfic1", |
| 478 | memmap[MICROCHIP_PFSOC_FABRIC_FIC1].base, |
| 479 | memmap[MICROCHIP_PFSOC_FABRIC_FIC1].size); |
| 480 | |
| 481 | /* QSPI Flash */ |
| 482 | memory_region_init_rom(qspi_xip_mem, OBJECT(dev), |
| 483 | "microchip.pfsoc.qspi_xip", |
| 484 | memmap[MICROCHIP_PFSOC_QSPI_XIP].size, |
| 485 | &error_fatal); |
| 486 | memory_region_add_subregion(system_memory, |
| 487 | memmap[MICROCHIP_PFSOC_QSPI_XIP].base, |
| 488 | qspi_xip_mem); |
| 489 | } |
| 490 | |
| 491 | static void microchip_pfsoc_soc_class_init(ObjectClass *oc, const void *data) |
| 492 | { |
| 493 | DeviceClass *dc = DEVICE_CLASS(oc); |
| 494 | |
| 495 | dc->realize = microchip_pfsoc_soc_realize; |
| 496 | /* Reason: Uses serial_hds in realize function, thus can't be used twice */ |
| 497 | dc->user_creatable = false; |
| 498 | } |
| 499 | |
| 500 | static const TypeInfo microchip_pfsoc_soc_type_info = { |
| 501 | .name = TYPE_MICROCHIP_PFSOC, |
| 502 | .parent = TYPE_DEVICE, |
| 503 | .instance_size = sizeof(MicrochipPFSoCState), |
| 504 | .instance_init = microchip_pfsoc_soc_instance_init, |
| 505 | .class_init = microchip_pfsoc_soc_class_init, |
| 506 | }; |
| 507 | |
| 508 | static void microchip_pfsoc_soc_register_types(void) |
| 509 | { |
| 510 | type_register_static(µchip_pfsoc_soc_type_info); |
| 511 | } |
| 512 | |
| 513 | type_init(microchip_pfsoc_soc_register_types) |
| 514 | |
| 515 | static void microchip_icicle_kit_machine_init(MachineState *machine) |
| 516 | { |
| 517 | MachineClass *mc = MACHINE_GET_CLASS(machine); |
| 518 | const MemMapEntry *memmap = microchip_pfsoc_memmap; |
| 519 | MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(machine); |
| 520 | MemoryRegion *system_memory = get_system_memory(); |
| 521 | MemoryRegion *mem_low = g_new(MemoryRegion, 1); |
| 522 | MemoryRegion *mem_low_alias = g_new(MemoryRegion, 1); |
| 523 | MemoryRegion *mem_high = g_new(MemoryRegion, 1); |
| 524 | MemoryRegion *mem_high_alias = g_new(MemoryRegion, 1); |
| 525 | uint64_t mem_low_size, mem_high_size; |
| 526 | hwaddr firmware_load_addr; |
| 527 | const char *firmware_name; |
| 528 | hwaddr firmware_end_addr; |
| 529 | vaddr kernel_start_addr; |
| 530 | uint64_t kernel_entry; |
| 531 | uint64_t fdt_load_addr; |
| 532 | DriveInfo *dinfo = drive_get(IF_SD, 0, 0); |
| 533 | RISCVBootInfo boot_info; |
| 534 | |
| 535 | /* Sanity check on RAM size */ |
| 536 | if (machine->ram_size < mc->default_ram_size) { |
| 537 | char *sz = size_to_str(mc->default_ram_size); |
| 538 | error_report("Invalid RAM size, should be bigger than %s", sz); |
| 539 | g_free(sz); |
| 540 | exit(EXIT_FAILURE); |
| 541 | } |
| 542 | |
| 543 | /* Initialize SoC */ |
| 544 | object_initialize_child(OBJECT(machine), "soc", &s->soc, |
| 545 | TYPE_MICROCHIP_PFSOC); |
| 546 | qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); |
| 547 | |
| 548 | /* Split RAM into low and high regions using aliases to machine->ram */ |
| 549 | mem_low_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size; |
| 550 | mem_high_size = machine->ram_size - mem_low_size; |
| 551 | memory_region_init_alias(mem_low, NULL, |
| 552 | "microchip.icicle.kit.ram_low", machine->ram, |
| 553 | 0, mem_low_size); |
| 554 | memory_region_init_alias(mem_high, NULL, |
| 555 | "microchip.icicle.kit.ram_high", machine->ram, |
| 556 | mem_low_size, mem_high_size); |
| 557 | |
| 558 | /* Register RAM */ |
| 559 | memory_region_add_subregion(system_memory, |
| 560 | memmap[MICROCHIP_PFSOC_DRAM_LO].base, |
| 561 | mem_low); |
| 562 | memory_region_add_subregion(system_memory, |
| 563 | memmap[MICROCHIP_PFSOC_DRAM_HI].base, |
| 564 | mem_high); |
| 565 | |
| 566 | /* Create aliases for the low and high RAM regions */ |
| 567 | memory_region_init_alias(mem_low_alias, NULL, |
| 568 | "microchip.icicle.kit.ram_low.alias", |
| 569 | mem_low, 0, mem_low_size); |
| 570 | memory_region_add_subregion(system_memory, |
| 571 | memmap[MICROCHIP_PFSOC_DRAM_LO_ALIAS].base, |
| 572 | mem_low_alias); |
| 573 | memory_region_init_alias(mem_high_alias, NULL, |
| 574 | "microchip.icicle.kit.ram_high.alias", |
| 575 | mem_high, 0, mem_high_size); |
| 576 | memory_region_add_subregion(system_memory, |
| 577 | memmap[MICROCHIP_PFSOC_DRAM_HI_ALIAS].base, |
| 578 | mem_high_alias); |
| 579 | |
| 580 | /* Attach an SD card */ |
| 581 | if (dinfo) { |
| 582 | CadenceSDHCIState *sdhci = &(s->soc.sdhci); |
| 583 | DeviceState *card = qdev_new(TYPE_SD_CARD); |
| 584 | |
| 585 | qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo), |
| 586 | &error_fatal); |
| 587 | qdev_realize_and_unref(card, sdhci->bus, &error_fatal); |
| 588 | } |
| 589 | |
| 590 | /* |
| 591 | * We follow the following table to select which firmware we use. |
| 592 | * |
| 593 | * -bios | -kernel | firmware |
| 594 | * --------------+------------+-------- |
| 595 | * none | N | error |
| 596 | * none | Y | kernel |
| 597 | * NULL, default | N | BIOS_FILENAME |
| 598 | * NULL, default | Y | RISCV64_BIOS_BIN |
| 599 | * other | don't care | other |
| 600 | */ |
| 601 | if (machine->firmware && !strcmp(machine->firmware, "none")) { |
| 602 | if (!machine->kernel_filename) { |
| 603 | error_report("for -bios none, a kernel is required"); |
| 604 | exit(1); |
| 605 | } |
| 606 | |
| 607 | firmware_name = NULL; |
| 608 | firmware_load_addr = RESET_VECTOR; |
| 609 | } else if (!machine->firmware || !strcmp(machine->firmware, "default")) { |
| 610 | if (machine->kernel_filename) { |
| 611 | firmware_name = RISCV64_BIOS_BIN; |
| 612 | firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base; |
| 613 | } else { |
| 614 | firmware_name = BIOS_FILENAME; |
| 615 | firmware_load_addr = RESET_VECTOR; |
| 616 | } |
| 617 | } else { |
| 618 | firmware_name = machine->firmware; |
| 619 | firmware_load_addr = RESET_VECTOR; |
| 620 | } |
| 621 | |
| 622 | riscv_boot_info_init_discontig_mem(&boot_info, &s->soc.u_cpus, |
| 623 | memmap[MICROCHIP_PFSOC_DRAM_LO].base, |
| 624 | mem_low_size); |
| 625 | |
| 626 | /* Load the firmware if necessary */ |
| 627 | firmware_end_addr = firmware_load_addr; |
| 628 | if (firmware_name) { |
| 629 | char *filename = riscv_find_firmware(firmware_name, NULL); |
| 630 | if (filename) { |
| 631 | firmware_end_addr = riscv_load_firmware(machine, &boot_info, |
| 632 | filename, |
| 633 | &firmware_load_addr, NULL); |
| 634 | g_free(filename); |
| 635 | } |
| 636 | } |
| 637 | |
| 638 | if (machine->kernel_filename) { |
| 639 | kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info, |
| 640 | firmware_end_addr); |
| 641 | |
| 642 | riscv_load_kernel(machine, &boot_info, kernel_start_addr, |
| 643 | true, NULL); |
| 644 | kernel_entry = boot_info.image_low_addr; |
| 645 | |
| 646 | if (machine->dtb) { |
| 647 | int fdt_size; |
| 648 | machine->fdt = load_device_tree(machine->dtb, &fdt_size); |
| 649 | if (!machine->fdt) { |
| 650 | error_report("load_device_tree() failed"); |
| 651 | exit(1); |
| 652 | } |
| 653 | |
| 654 | /* Compute the FDT load address in DRAM */ |
| 655 | hwaddr kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_LO].base; |
| 656 | hwaddr kernel_ram_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size; |
| 657 | |
| 658 | if (kernel_entry - kernel_ram_base >= kernel_ram_size) { |
| 659 | kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_HI].base; |
| 660 | kernel_ram_size = mem_high_size; |
| 661 | } |
| 662 | |
| 663 | fdt_load_addr = riscv_compute_fdt_addr(kernel_ram_base, kernel_ram_size, |
| 664 | machine, &boot_info); |
| 665 | riscv_load_fdt(fdt_load_addr, machine->fdt); |
| 666 | } else { |
| 667 | warn_report_once("The QEMU microchip-icicle-kit machine does not " |
| 668 | "generate a device tree, so no device tree is " |
| 669 | "being provided to the guest."); |
| 670 | fdt_load_addr = 0; |
| 671 | } |
| 672 | |
| 673 | hwaddr start_addr; |
| 674 | if (firmware_name) { |
| 675 | start_addr = firmware_load_addr; |
| 676 | } else { |
| 677 | start_addr = kernel_entry; |
| 678 | } |
| 679 | |
| 680 | /* Load the reset vector */ |
| 681 | riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, start_addr, |
| 682 | memmap[MICROCHIP_PFSOC_ENVM_DATA].base, |
| 683 | memmap[MICROCHIP_PFSOC_ENVM_DATA].size, |
| 684 | kernel_entry, fdt_load_addr); |
| 685 | } |
| 686 | } |
| 687 | |
| 688 | static void microchip_icicle_kit_set_clint_timebase_freq(Object *obj, |
| 689 | Visitor *v, |
| 690 | const char *name, |
| 691 | void *opaque, |
| 692 | Error **errp) |
| 693 | { |
| 694 | MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj); |
| 695 | uint32_t value; |
| 696 | |
| 697 | if (!visit_type_uint32(v, name, &value, errp)) { |
| 698 | return; |
| 699 | } |
| 700 | |
| 701 | s->clint_timebase_freq = value; |
| 702 | } |
| 703 | |
| 704 | static void microchip_icicle_kit_get_clint_timebase_freq(Object *obj, |
| 705 | Visitor *v, |
| 706 | const char *name, |
| 707 | void *opaque, |
| 708 | Error **errp) |
| 709 | { |
| 710 | MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj); |
| 711 | uint32_t value = s->clint_timebase_freq; |
| 712 | |
| 713 | visit_type_uint32(v, name, &value, errp); |
| 714 | } |
| 715 | |
| 716 | static void microchip_icicle_kit_machine_instance_init(Object *obj) |
| 717 | { |
| 718 | MicrochipIcicleKitState *m = MICROCHIP_ICICLE_KIT_MACHINE(obj); |
| 719 | m->clint_timebase_freq = 1000000; |
| 720 | } |
| 721 | |
| 722 | static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, |
| 723 | const void *data) |
| 724 | { |
| 725 | MachineClass *mc = MACHINE_CLASS(oc); |
| 726 | |
| 727 | mc->desc = "Microchip PolarFire SoC Icicle Kit"; |
| 728 | mc->init = microchip_icicle_kit_machine_init; |
| 729 | mc->max_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT + |
| 730 | MICROCHIP_PFSOC_COMPUTE_CPU_COUNT; |
| 731 | mc->min_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT + 1; |
| 732 | mc->default_cpus = mc->min_cpus; |
| 733 | mc->default_ram_id = "microchip.icicle.kit.ram"; |
| 734 | mc->auto_create_sdcard = true; |
| 735 | |
| 736 | /* |
| 737 | * Map 513 MiB high memory, the minimum required high memory size, because |
| 738 | * HSS will do memory test against the high memory address range regardless |
| 739 | * of physical memory installed. |
| 740 | * |
| 741 | * See memory_tests() in mss_ddr.c in the HSS source code. |
| 742 | */ |
| 743 | mc->default_ram_size = 1537 * MiB; |
| 744 | |
| 745 | object_class_property_add(oc, "clint-timebase-frequency", "uint32_t", |
| 746 | microchip_icicle_kit_get_clint_timebase_freq, |
| 747 | microchip_icicle_kit_set_clint_timebase_freq, |
| 748 | NULL, NULL); |
| 749 | object_class_property_set_description(oc, "clint-timebase-frequency", |
| 750 | "Set CLINT timebase frequency in Hz."); |
| 751 | } |
| 752 | |
| 753 | static const TypeInfo microchip_icicle_kit_machine_typeinfo = { |
| 754 | .name = MACHINE_TYPE_NAME("microchip-icicle-kit"), |
| 755 | .parent = TYPE_MACHINE, |
| 756 | .class_init = microchip_icicle_kit_machine_class_init, |
| 757 | .instance_init = microchip_icicle_kit_machine_instance_init, |
| 758 | .instance_size = sizeof(MicrochipIcicleKitState), |
| 759 | .interfaces = riscv64_machine_interfaces, |
| 760 | }; |
| 761 | |
| 762 | static void microchip_icicle_kit_machine_init_register_types(void) |
| 763 | { |
| 764 | type_register_static(µchip_icicle_kit_machine_typeinfo); |
| 765 | } |
| 766 | |
| 767 | type_init(microchip_icicle_kit_machine_init_register_types) |