]>
Commit | Line | Data |
---|---|---|
56f6e31e BM |
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) | |
8f2ac39d | 14 | * 3) MMUARTs (Multi-Mode UART) |
898dc008 | 15 | * 4) Cadence eMMC/SDHC controller and an SD card connected to it |
7124e27b | 16 | * 5) SiFive Platform DMA (Direct Memory Access Controller) |
47374b07 | 17 | * 6) GEM (Gigabit Ethernet MAC Controller) |
933f73f1 | 18 | * 7) DMC (DDR Memory Controller) |
e35d6179 | 19 | * 8) IOSCB modules |
56f6e31e BM |
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" | |
56f6e31e BM |
39 | #include "qemu/units.h" |
40 | #include "qemu/cutils.h" | |
41 | #include "qapi/error.h" | |
42 | #include "hw/boards.h" | |
56f6e31e BM |
43 | #include "hw/loader.h" |
44 | #include "hw/sysbus.h" | |
8f2ac39d | 45 | #include "chardev/char.h" |
56f6e31e BM |
46 | #include "hw/cpu/cluster.h" |
47 | #include "target/riscv/cpu.h" | |
48 | #include "hw/misc/unimp.h" | |
49 | #include "hw/riscv/boot.h" | |
50 | #include "hw/riscv/riscv_hart.h" | |
56f6e31e | 51 | #include "hw/riscv/microchip_pfsoc.h" |
cc63a182 | 52 | #include "hw/intc/riscv_aclint.h" |
84fcf3c1 | 53 | #include "hw/intc/sifive_plic.h" |
143897b5 | 54 | #include "sysemu/device_tree.h" |
8f2ac39d | 55 | #include "sysemu/sysemu.h" |
56f6e31e BM |
56 | |
57 | /* | |
58 | * The BIOS image used by this machine is called Hart Software Services (HSS). | |
59 | * See https://github.com/polarfire-soc/hart-software-services | |
60 | */ | |
61 | #define BIOS_FILENAME "hss.bin" | |
62 | #define RESET_VECTOR 0x20220000 | |
63 | ||
a47ef6e9 BM |
64 | /* CLINT timebase frequency */ |
65 | #define CLINT_TIMEBASE_FREQ 1000000 | |
66 | ||
47374b07 BM |
67 | /* GEM version */ |
68 | #define GEM_REVISION 0x0107010c | |
69 | ||
08b86e3b BM |
70 | /* |
71 | * The complete description of the whole PolarFire SoC memory map is scattered | |
72 | * in different documents. There are several places to look at for memory maps: | |
73 | * | |
74 | * 1 Chapter 11 "MSS Memory Map", in the doc "UG0880: PolarFire SoC FPGA | |
75 | * Microprocessor Subsystem (MSS) User Guide", which can be downloaded from | |
76 | * https://www.microsemi.com/document-portal/doc_download/ | |
77 | * 1244570-ug0880-polarfire-soc-fpga-microprocessor-subsystem-mss-user-guide, | |
78 | * describes the whole picture of the PolarFire SoC memory map. | |
79 | * | |
80 | * 2 A zip file for PolarFire soC memory map, which can be downloaded from | |
81 | * https://www.microsemi.com/document-portal/doc_download/ | |
82 | * 1244581-polarfire-soc-register-map, contains the following 2 major parts: | |
83 | * - Register Map/PF_SoC_RegMap_V1_1/pfsoc_regmap.htm | |
84 | * describes the complete integrated peripherals memory map | |
85 | * - Register Map/PF_SoC_RegMap_V1_1/MPFS250T/mpfs250t_ioscb_memmap_dri.htm | |
86 | * describes the complete IOSCB modules memory maps | |
87 | */ | |
73261285 | 88 | static const MemMapEntry microchip_pfsoc_memmap[] = { |
8d32e374 CD |
89 | [MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 }, |
90 | [MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 }, | |
91 | [MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 }, | |
92 | [MICROCHIP_PFSOC_BUSERR_UNIT0] = { 0x1700000, 0x1000 }, | |
93 | [MICROCHIP_PFSOC_BUSERR_UNIT1] = { 0x1701000, 0x1000 }, | |
94 | [MICROCHIP_PFSOC_BUSERR_UNIT2] = { 0x1702000, 0x1000 }, | |
95 | [MICROCHIP_PFSOC_BUSERR_UNIT3] = { 0x1703000, 0x1000 }, | |
96 | [MICROCHIP_PFSOC_BUSERR_UNIT4] = { 0x1704000, 0x1000 }, | |
97 | [MICROCHIP_PFSOC_CLINT] = { 0x2000000, 0x10000 }, | |
98 | [MICROCHIP_PFSOC_L2CC] = { 0x2010000, 0x1000 }, | |
99 | [MICROCHIP_PFSOC_DMA] = { 0x3000000, 0x100000 }, | |
100 | [MICROCHIP_PFSOC_L2LIM] = { 0x8000000, 0x2000000 }, | |
101 | [MICROCHIP_PFSOC_PLIC] = { 0xc000000, 0x4000000 }, | |
102 | [MICROCHIP_PFSOC_MMUART0] = { 0x20000000, 0x1000 }, | |
103 | [MICROCHIP_PFSOC_WDOG0] = { 0x20001000, 0x1000 }, | |
104 | [MICROCHIP_PFSOC_SYSREG] = { 0x20002000, 0x2000 }, | |
105 | [MICROCHIP_PFSOC_AXISW] = { 0x20004000, 0x1000 }, | |
106 | [MICROCHIP_PFSOC_MPUCFG] = { 0x20005000, 0x1000 }, | |
107 | [MICROCHIP_PFSOC_FMETER] = { 0x20006000, 0x1000 }, | |
108 | [MICROCHIP_PFSOC_DDR_SGMII_PHY] = { 0x20007000, 0x1000 }, | |
109 | [MICROCHIP_PFSOC_EMMC_SD] = { 0x20008000, 0x1000 }, | |
110 | [MICROCHIP_PFSOC_DDR_CFG] = { 0x20080000, 0x40000 }, | |
111 | [MICROCHIP_PFSOC_MMUART1] = { 0x20100000, 0x1000 }, | |
112 | [MICROCHIP_PFSOC_MMUART2] = { 0x20102000, 0x1000 }, | |
113 | [MICROCHIP_PFSOC_MMUART3] = { 0x20104000, 0x1000 }, | |
114 | [MICROCHIP_PFSOC_MMUART4] = { 0x20106000, 0x1000 }, | |
115 | [MICROCHIP_PFSOC_WDOG1] = { 0x20101000, 0x1000 }, | |
116 | [MICROCHIP_PFSOC_WDOG2] = { 0x20103000, 0x1000 }, | |
117 | [MICROCHIP_PFSOC_WDOG3] = { 0x20105000, 0x1000 }, | |
118 | [MICROCHIP_PFSOC_WDOG4] = { 0x20106000, 0x1000 }, | |
119 | [MICROCHIP_PFSOC_SPI0] = { 0x20108000, 0x1000 }, | |
120 | [MICROCHIP_PFSOC_SPI1] = { 0x20109000, 0x1000 }, | |
121 | [MICROCHIP_PFSOC_I2C0] = { 0x2010a000, 0x1000 }, | |
122 | [MICROCHIP_PFSOC_I2C1] = { 0x2010b000, 0x1000 }, | |
123 | [MICROCHIP_PFSOC_CAN0] = { 0x2010c000, 0x1000 }, | |
124 | [MICROCHIP_PFSOC_CAN1] = { 0x2010d000, 0x1000 }, | |
125 | [MICROCHIP_PFSOC_GEM0] = { 0x20110000, 0x2000 }, | |
126 | [MICROCHIP_PFSOC_GEM1] = { 0x20112000, 0x2000 }, | |
127 | [MICROCHIP_PFSOC_GPIO0] = { 0x20120000, 0x1000 }, | |
128 | [MICROCHIP_PFSOC_GPIO1] = { 0x20121000, 0x1000 }, | |
129 | [MICROCHIP_PFSOC_GPIO2] = { 0x20122000, 0x1000 }, | |
130 | [MICROCHIP_PFSOC_RTC] = { 0x20124000, 0x1000 }, | |
131 | [MICROCHIP_PFSOC_ENVM_CFG] = { 0x20200000, 0x1000 }, | |
132 | [MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 }, | |
133 | [MICROCHIP_PFSOC_USB] = { 0x20201000, 0x1000 }, | |
134 | [MICROCHIP_PFSOC_QSPI_XIP] = { 0x21000000, 0x1000000 }, | |
135 | [MICROCHIP_PFSOC_IOSCB] = { 0x30000000, 0x10000000 }, | |
136 | [MICROCHIP_PFSOC_FABRIC_FIC0] = { 0x2000000000, 0x1000000000 }, | |
137 | [MICROCHIP_PFSOC_FABRIC_FIC1] = { 0x3000000000, 0x1000000000 }, | |
138 | [MICROCHIP_PFSOC_FABRIC_FIC3] = { 0x40000000, 0x20000000 }, | |
139 | [MICROCHIP_PFSOC_DRAM_LO] = { 0x80000000, 0x40000000 }, | |
140 | [MICROCHIP_PFSOC_DRAM_LO_ALIAS] = { 0xc0000000, 0x40000000 }, | |
141 | [MICROCHIP_PFSOC_DRAM_HI] = { 0x1000000000, 0x0 }, | |
142 | [MICROCHIP_PFSOC_DRAM_HI_ALIAS] = { 0x1400000000, 0x0 }, | |
143 | ||
56f6e31e BM |
144 | }; |
145 | ||
146 | static void microchip_pfsoc_soc_instance_init(Object *obj) | |
147 | { | |
148 | MachineState *ms = MACHINE(qdev_get_machine()); | |
149 | MicrochipPFSoCState *s = MICROCHIP_PFSOC(obj); | |
150 | ||
151 | object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER); | |
152 | qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0); | |
153 | ||
154 | object_initialize_child(OBJECT(&s->e_cluster), "e-cpus", &s->e_cpus, | |
155 | TYPE_RISCV_HART_ARRAY); | |
156 | qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1); | |
157 | qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0); | |
158 | qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", | |
159 | TYPE_RISCV_CPU_SIFIVE_E51); | |
160 | qdev_prop_set_uint64(DEVICE(&s->e_cpus), "resetvec", RESET_VECTOR); | |
161 | ||
162 | object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER); | |
163 | qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1); | |
164 | ||
165 | object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", &s->u_cpus, | |
166 | TYPE_RISCV_HART_ARRAY); | |
167 | qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1); | |
168 | qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1); | |
169 | qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", | |
170 | TYPE_RISCV_CPU_SIFIVE_U54); | |
171 | qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", RESET_VECTOR); | |
898dc008 | 172 | |
7124e27b BM |
173 | object_initialize_child(obj, "dma-controller", &s->dma, |
174 | TYPE_SIFIVE_PDMA); | |
175 | ||
cdd58c70 BM |
176 | object_initialize_child(obj, "sysreg", &s->sysreg, |
177 | TYPE_MCHP_PFSOC_SYSREG); | |
178 | ||
933f73f1 BM |
179 | object_initialize_child(obj, "ddr-sgmii-phy", &s->ddr_sgmii_phy, |
180 | TYPE_MCHP_PFSOC_DDR_SGMII_PHY); | |
181 | object_initialize_child(obj, "ddr-cfg", &s->ddr_cfg, | |
182 | TYPE_MCHP_PFSOC_DDR_CFG); | |
183 | ||
47374b07 BM |
184 | object_initialize_child(obj, "gem0", &s->gem0, TYPE_CADENCE_GEM); |
185 | object_initialize_child(obj, "gem1", &s->gem1, TYPE_CADENCE_GEM); | |
186 | ||
898dc008 BM |
187 | object_initialize_child(obj, "sd-controller", &s->sdhci, |
188 | TYPE_CADENCE_SDHCI); | |
e35d6179 BM |
189 | |
190 | object_initialize_child(obj, "ioscb", &s->ioscb, TYPE_MCHP_PFSOC_IOSCB); | |
56f6e31e BM |
191 | } |
192 | ||
193 | static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) | |
194 | { | |
195 | MachineState *ms = MACHINE(qdev_get_machine()); | |
196 | MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev); | |
73261285 | 197 | const MemMapEntry *memmap = microchip_pfsoc_memmap; |
56f6e31e | 198 | MemoryRegion *system_memory = get_system_memory(); |
27c22b2d | 199 | MemoryRegion *rsvd0_mem = g_new(MemoryRegion, 1); |
56f6e31e BM |
200 | MemoryRegion *e51_dtim_mem = g_new(MemoryRegion, 1); |
201 | MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1); | |
202 | MemoryRegion *envm_data = g_new(MemoryRegion, 1); | |
dfc973ec | 203 | MemoryRegion *qspi_xip_mem = g_new(MemoryRegion, 1); |
56f6e31e | 204 | char *plic_hart_config; |
47374b07 | 205 | NICInfo *nd; |
56f6e31e BM |
206 | int i; |
207 | ||
208 | sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort); | |
209 | sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort); | |
210 | /* | |
211 | * The cluster must be realized after the RISC-V hart array container, | |
212 | * as the container's CPU object is only created on realize, and the | |
213 | * CPU must exist and have been parented into the cluster before the | |
214 | * cluster is realized. | |
215 | */ | |
216 | qdev_realize(DEVICE(&s->e_cluster), NULL, &error_abort); | |
217 | qdev_realize(DEVICE(&s->u_cluster), NULL, &error_abort); | |
218 | ||
27c22b2d BM |
219 | /* Reserved Memory at address 0 */ |
220 | memory_region_init_ram(rsvd0_mem, NULL, "microchip.pfsoc.rsvd0_mem", | |
221 | memmap[MICROCHIP_PFSOC_RSVD0].size, &error_fatal); | |
222 | memory_region_add_subregion(system_memory, | |
223 | memmap[MICROCHIP_PFSOC_RSVD0].base, | |
224 | rsvd0_mem); | |
225 | ||
56f6e31e BM |
226 | /* E51 DTIM */ |
227 | memory_region_init_ram(e51_dtim_mem, NULL, "microchip.pfsoc.e51_dtim_mem", | |
228 | memmap[MICROCHIP_PFSOC_E51_DTIM].size, &error_fatal); | |
229 | memory_region_add_subregion(system_memory, | |
230 | memmap[MICROCHIP_PFSOC_E51_DTIM].base, | |
231 | e51_dtim_mem); | |
232 | ||
233 | /* Bus Error Units */ | |
234 | create_unimplemented_device("microchip.pfsoc.buserr_unit0_mem", | |
235 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT0].base, | |
236 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT0].size); | |
237 | create_unimplemented_device("microchip.pfsoc.buserr_unit1_mem", | |
238 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT1].base, | |
239 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT1].size); | |
240 | create_unimplemented_device("microchip.pfsoc.buserr_unit2_mem", | |
241 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT2].base, | |
242 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT2].size); | |
243 | create_unimplemented_device("microchip.pfsoc.buserr_unit3_mem", | |
244 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT3].base, | |
245 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT3].size); | |
246 | create_unimplemented_device("microchip.pfsoc.buserr_unit4_mem", | |
247 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].base, | |
248 | memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size); | |
249 | ||
250 | /* CLINT */ | |
b8fb878a AP |
251 | riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base, |
252 | 0, ms->smp.cpus, false); | |
253 | riscv_aclint_mtimer_create( | |
254 | memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE, | |
255 | RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus, | |
256 | RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, | |
a47ef6e9 | 257 | CLINT_TIMEBASE_FREQ, false); |
56f6e31e BM |
258 | |
259 | /* L2 cache controller */ | |
260 | create_unimplemented_device("microchip.pfsoc.l2cc", | |
261 | memmap[MICROCHIP_PFSOC_L2CC].base, memmap[MICROCHIP_PFSOC_L2CC].size); | |
262 | ||
263 | /* | |
264 | * Add L2-LIM at reset size. | |
265 | * This should be reduced in size as the L2 Cache Controller WayEnable | |
266 | * register is incremented. Unfortunately I don't see a nice (or any) way | |
267 | * to handle reducing or blocking out the L2 LIM while still allowing it | |
268 | * be re returned to all enabled after a reset. For the time being, just | |
269 | * leave it enabled all the time. This won't break anything, but will be | |
270 | * too generous to misbehaving guests. | |
271 | */ | |
272 | memory_region_init_ram(l2lim_mem, NULL, "microchip.pfsoc.l2lim", | |
273 | memmap[MICROCHIP_PFSOC_L2LIM].size, &error_fatal); | |
274 | memory_region_add_subregion(system_memory, | |
275 | memmap[MICROCHIP_PFSOC_L2LIM].base, | |
276 | l2lim_mem); | |
277 | ||
278 | /* create PLIC hart topology configuration string */ | |
8486eb8c | 279 | plic_hart_config = riscv_plic_hart_config_string(ms->smp.cpus); |
56f6e31e BM |
280 | |
281 | /* PLIC */ | |
282 | s->plic = sifive_plic_create(memmap[MICROCHIP_PFSOC_PLIC].base, | |
f436ecc3 | 283 | plic_hart_config, ms->smp.cpus, 0, |
56f6e31e BM |
284 | MICROCHIP_PFSOC_PLIC_NUM_SOURCES, |
285 | MICROCHIP_PFSOC_PLIC_NUM_PRIORITIES, | |
286 | MICROCHIP_PFSOC_PLIC_PRIORITY_BASE, | |
287 | MICROCHIP_PFSOC_PLIC_PENDING_BASE, | |
288 | MICROCHIP_PFSOC_PLIC_ENABLE_BASE, | |
289 | MICROCHIP_PFSOC_PLIC_ENABLE_STRIDE, | |
290 | MICROCHIP_PFSOC_PLIC_CONTEXT_BASE, | |
291 | MICROCHIP_PFSOC_PLIC_CONTEXT_STRIDE, | |
292 | memmap[MICROCHIP_PFSOC_PLIC].size); | |
293 | g_free(plic_hart_config); | |
294 | ||
7124e27b BM |
295 | /* DMA */ |
296 | sysbus_realize(SYS_BUS_DEVICE(&s->dma), errp); | |
297 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->dma), 0, | |
298 | memmap[MICROCHIP_PFSOC_DMA].base); | |
299 | for (i = 0; i < SIFIVE_PDMA_IRQS; i++) { | |
300 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), i, | |
301 | qdev_get_gpio_in(DEVICE(s->plic), | |
302 | MICROCHIP_PFSOC_DMA_IRQ0 + i)); | |
303 | } | |
304 | ||
56f6e31e | 305 | /* SYSREG */ |
cdd58c70 BM |
306 | sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), errp); |
307 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysreg), 0, | |
308 | memmap[MICROCHIP_PFSOC_SYSREG].base); | |
592f0a94 CD |
309 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->sysreg), 0, |
310 | qdev_get_gpio_in(DEVICE(s->plic), | |
311 | MICROCHIP_PFSOC_MAILBOX_IRQ)); | |
56f6e31e | 312 | |
25da6e31 CD |
313 | /* AXISW */ |
314 | create_unimplemented_device("microchip.pfsoc.axisw", | |
315 | memmap[MICROCHIP_PFSOC_AXISW].base, | |
316 | memmap[MICROCHIP_PFSOC_AXISW].size); | |
317 | ||
56f6e31e BM |
318 | /* MPUCFG */ |
319 | create_unimplemented_device("microchip.pfsoc.mpucfg", | |
320 | memmap[MICROCHIP_PFSOC_MPUCFG].base, | |
321 | memmap[MICROCHIP_PFSOC_MPUCFG].size); | |
322 | ||
25da6e31 CD |
323 | /* FMETER */ |
324 | create_unimplemented_device("microchip.pfsoc.fmeter", | |
325 | memmap[MICROCHIP_PFSOC_FMETER].base, | |
326 | memmap[MICROCHIP_PFSOC_FMETER].size); | |
327 | ||
933f73f1 BM |
328 | /* DDR SGMII PHY */ |
329 | sysbus_realize(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), errp); | |
330 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), 0, | |
331 | memmap[MICROCHIP_PFSOC_DDR_SGMII_PHY].base); | |
332 | ||
333 | /* DDR CFG */ | |
334 | sysbus_realize(SYS_BUS_DEVICE(&s->ddr_cfg), errp); | |
335 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_cfg), 0, | |
336 | memmap[MICROCHIP_PFSOC_DDR_CFG].base); | |
337 | ||
898dc008 BM |
338 | /* SDHCI */ |
339 | sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp); | |
340 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0, | |
341 | memmap[MICROCHIP_PFSOC_EMMC_SD].base); | |
342 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, | |
343 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_EMMC_SD_IRQ)); | |
344 | ||
8f2ac39d BM |
345 | /* MMUARTs */ |
346 | s->serial0 = mchp_pfsoc_mmuart_create(system_memory, | |
347 | memmap[MICROCHIP_PFSOC_MMUART0].base, | |
348 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART0_IRQ), | |
349 | serial_hd(0)); | |
350 | s->serial1 = mchp_pfsoc_mmuart_create(system_memory, | |
351 | memmap[MICROCHIP_PFSOC_MMUART1].base, | |
352 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART1_IRQ), | |
353 | serial_hd(1)); | |
354 | s->serial2 = mchp_pfsoc_mmuart_create(system_memory, | |
355 | memmap[MICROCHIP_PFSOC_MMUART2].base, | |
356 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART2_IRQ), | |
357 | serial_hd(2)); | |
358 | s->serial3 = mchp_pfsoc_mmuart_create(system_memory, | |
359 | memmap[MICROCHIP_PFSOC_MMUART3].base, | |
360 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART3_IRQ), | |
361 | serial_hd(3)); | |
362 | s->serial4 = mchp_pfsoc_mmuart_create(system_memory, | |
363 | memmap[MICROCHIP_PFSOC_MMUART4].base, | |
364 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART4_IRQ), | |
365 | serial_hd(4)); | |
366 | ||
25da6e31 CD |
367 | /* Watchdogs */ |
368 | create_unimplemented_device("microchip.pfsoc.watchdog0", | |
369 | memmap[MICROCHIP_PFSOC_WDOG0].base, | |
370 | memmap[MICROCHIP_PFSOC_WDOG0].size); | |
371 | create_unimplemented_device("microchip.pfsoc.watchdog1", | |
372 | memmap[MICROCHIP_PFSOC_WDOG1].base, | |
373 | memmap[MICROCHIP_PFSOC_WDOG1].size); | |
374 | create_unimplemented_device("microchip.pfsoc.watchdog2", | |
375 | memmap[MICROCHIP_PFSOC_WDOG2].base, | |
376 | memmap[MICROCHIP_PFSOC_WDOG2].size); | |
377 | create_unimplemented_device("microchip.pfsoc.watchdog3", | |
378 | memmap[MICROCHIP_PFSOC_WDOG3].base, | |
379 | memmap[MICROCHIP_PFSOC_WDOG3].size); | |
380 | create_unimplemented_device("microchip.pfsoc.watchdog4", | |
381 | memmap[MICROCHIP_PFSOC_WDOG4].base, | |
382 | memmap[MICROCHIP_PFSOC_WDOG4].size); | |
383 | ||
dfc973ec VW |
384 | /* SPI */ |
385 | create_unimplemented_device("microchip.pfsoc.spi0", | |
386 | memmap[MICROCHIP_PFSOC_SPI0].base, | |
387 | memmap[MICROCHIP_PFSOC_SPI0].size); | |
388 | create_unimplemented_device("microchip.pfsoc.spi1", | |
389 | memmap[MICROCHIP_PFSOC_SPI1].base, | |
390 | memmap[MICROCHIP_PFSOC_SPI1].size); | |
391 | ||
25da6e31 CD |
392 | /* I2C */ |
393 | create_unimplemented_device("microchip.pfsoc.i2c0", | |
394 | memmap[MICROCHIP_PFSOC_I2C0].base, | |
395 | memmap[MICROCHIP_PFSOC_I2C0].size); | |
90742c54 BM |
396 | create_unimplemented_device("microchip.pfsoc.i2c1", |
397 | memmap[MICROCHIP_PFSOC_I2C1].base, | |
398 | memmap[MICROCHIP_PFSOC_I2C1].size); | |
399 | ||
25da6e31 CD |
400 | /* CAN */ |
401 | create_unimplemented_device("microchip.pfsoc.can0", | |
402 | memmap[MICROCHIP_PFSOC_CAN0].base, | |
403 | memmap[MICROCHIP_PFSOC_CAN0].size); | |
404 | create_unimplemented_device("microchip.pfsoc.can1", | |
405 | memmap[MICROCHIP_PFSOC_CAN1].base, | |
406 | memmap[MICROCHIP_PFSOC_CAN1].size); | |
407 | ||
408 | /* USB */ | |
409 | create_unimplemented_device("microchip.pfsoc.usb", | |
410 | memmap[MICROCHIP_PFSOC_USB].base, | |
411 | memmap[MICROCHIP_PFSOC_USB].size); | |
412 | ||
47374b07 BM |
413 | /* GEMs */ |
414 | ||
415 | nd = &nd_table[0]; | |
416 | if (nd->used) { | |
417 | qemu_check_nic_model(nd, TYPE_CADENCE_GEM); | |
418 | qdev_set_nic_properties(DEVICE(&s->gem0), nd); | |
419 | } | |
420 | nd = &nd_table[1]; | |
421 | if (nd->used) { | |
422 | qemu_check_nic_model(nd, TYPE_CADENCE_GEM); | |
423 | qdev_set_nic_properties(DEVICE(&s->gem1), nd); | |
424 | } | |
425 | ||
426 | object_property_set_int(OBJECT(&s->gem0), "revision", GEM_REVISION, errp); | |
427 | object_property_set_int(OBJECT(&s->gem0), "phy-addr", 8, errp); | |
428 | sysbus_realize(SYS_BUS_DEVICE(&s->gem0), errp); | |
429 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem0), 0, | |
430 | memmap[MICROCHIP_PFSOC_GEM0].base); | |
431 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem0), 0, | |
432 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_GEM0_IRQ)); | |
433 | ||
434 | object_property_set_int(OBJECT(&s->gem1), "revision", GEM_REVISION, errp); | |
435 | object_property_set_int(OBJECT(&s->gem1), "phy-addr", 9, errp); | |
436 | sysbus_realize(SYS_BUS_DEVICE(&s->gem1), errp); | |
437 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem1), 0, | |
438 | memmap[MICROCHIP_PFSOC_GEM1].base); | |
439 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem1), 0, | |
440 | qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_GEM1_IRQ)); | |
441 | ||
ce908a2f BM |
442 | /* GPIOs */ |
443 | create_unimplemented_device("microchip.pfsoc.gpio0", | |
444 | memmap[MICROCHIP_PFSOC_GPIO0].base, | |
445 | memmap[MICROCHIP_PFSOC_GPIO0].size); | |
446 | create_unimplemented_device("microchip.pfsoc.gpio1", | |
447 | memmap[MICROCHIP_PFSOC_GPIO1].base, | |
448 | memmap[MICROCHIP_PFSOC_GPIO1].size); | |
449 | create_unimplemented_device("microchip.pfsoc.gpio2", | |
450 | memmap[MICROCHIP_PFSOC_GPIO2].base, | |
451 | memmap[MICROCHIP_PFSOC_GPIO2].size); | |
452 | ||
56f6e31e BM |
453 | /* eNVM */ |
454 | memory_region_init_rom(envm_data, OBJECT(dev), "microchip.pfsoc.envm.data", | |
455 | memmap[MICROCHIP_PFSOC_ENVM_DATA].size, | |
456 | &error_fatal); | |
457 | memory_region_add_subregion(system_memory, | |
458 | memmap[MICROCHIP_PFSOC_ENVM_DATA].base, | |
459 | envm_data); | |
460 | ||
e35d6179 BM |
461 | /* IOSCB */ |
462 | sysbus_realize(SYS_BUS_DEVICE(&s->ioscb), errp); | |
463 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->ioscb), 0, | |
464 | memmap[MICROCHIP_PFSOC_IOSCB].base); | |
592f0a94 CD |
465 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->ioscb), 0, |
466 | qdev_get_gpio_in(DEVICE(s->plic), | |
467 | MICROCHIP_PFSOC_MAILBOX_IRQ)); | |
dfc973ec | 468 | |
25da6e31 CD |
469 | /* FPGA Fabric */ |
470 | create_unimplemented_device("microchip.pfsoc.fabricfic3", | |
471 | memmap[MICROCHIP_PFSOC_FABRIC_FIC3].base, | |
472 | memmap[MICROCHIP_PFSOC_FABRIC_FIC3].size); | |
8d32e374 CD |
473 | /* FPGA Fabric */ |
474 | create_unimplemented_device("microchip.pfsoc.fabricfic0", | |
475 | memmap[MICROCHIP_PFSOC_FABRIC_FIC0].base, | |
476 | memmap[MICROCHIP_PFSOC_FABRIC_FIC0].size); | |
477 | /* FPGA Fabric */ | |
478 | create_unimplemented_device("microchip.pfsoc.fabricfic1", | |
479 | memmap[MICROCHIP_PFSOC_FABRIC_FIC1].base, | |
480 | memmap[MICROCHIP_PFSOC_FABRIC_FIC1].size); | |
d6150ace | 481 | |
dfc973ec VW |
482 | /* QSPI Flash */ |
483 | memory_region_init_rom(qspi_xip_mem, OBJECT(dev), | |
484 | "microchip.pfsoc.qspi_xip", | |
485 | memmap[MICROCHIP_PFSOC_QSPI_XIP].size, | |
486 | &error_fatal); | |
487 | memory_region_add_subregion(system_memory, | |
488 | memmap[MICROCHIP_PFSOC_QSPI_XIP].base, | |
489 | qspi_xip_mem); | |
56f6e31e BM |
490 | } |
491 | ||
492 | static void microchip_pfsoc_soc_class_init(ObjectClass *oc, void *data) | |
493 | { | |
494 | DeviceClass *dc = DEVICE_CLASS(oc); | |
495 | ||
496 | dc->realize = microchip_pfsoc_soc_realize; | |
497 | /* Reason: Uses serial_hds in realize function, thus can't be used twice */ | |
498 | dc->user_creatable = false; | |
499 | } | |
500 | ||
501 | static const TypeInfo microchip_pfsoc_soc_type_info = { | |
502 | .name = TYPE_MICROCHIP_PFSOC, | |
503 | .parent = TYPE_DEVICE, | |
504 | .instance_size = sizeof(MicrochipPFSoCState), | |
505 | .instance_init = microchip_pfsoc_soc_instance_init, | |
506 | .class_init = microchip_pfsoc_soc_class_init, | |
507 | }; | |
508 | ||
509 | static void microchip_pfsoc_soc_register_types(void) | |
510 | { | |
511 | type_register_static(µchip_pfsoc_soc_type_info); | |
512 | } | |
513 | ||
514 | type_init(microchip_pfsoc_soc_register_types) | |
515 | ||
516 | static void microchip_icicle_kit_machine_init(MachineState *machine) | |
517 | { | |
518 | MachineClass *mc = MACHINE_GET_CLASS(machine); | |
73261285 | 519 | const MemMapEntry *memmap = microchip_pfsoc_memmap; |
56f6e31e BM |
520 | MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(machine); |
521 | MemoryRegion *system_memory = get_system_memory(); | |
f03100d7 BM |
522 | MemoryRegion *mem_low = g_new(MemoryRegion, 1); |
523 | MemoryRegion *mem_low_alias = g_new(MemoryRegion, 1); | |
524 | MemoryRegion *mem_high = g_new(MemoryRegion, 1); | |
525 | MemoryRegion *mem_high_alias = g_new(MemoryRegion, 1); | |
d4c624f4 | 526 | uint64_t mem_low_size, mem_high_size; |
143897b5 BM |
527 | hwaddr firmware_load_addr; |
528 | const char *firmware_name; | |
529 | bool kernel_as_payload = false; | |
530 | target_ulong firmware_end_addr, kernel_start_addr; | |
531 | uint64_t kernel_entry; | |
532 | uint32_t fdt_load_addr; | |
64eaa820 | 533 | DriveInfo *dinfo = drive_get(IF_SD, 0, 0); |
56f6e31e BM |
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); | |
8f972e5b | 546 | qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); |
56f6e31e | 547 | |
d4c624f4 BM |
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 | ||
56f6e31e | 558 | /* Register RAM */ |
f03100d7 BM |
559 | memory_region_add_subregion(system_memory, |
560 | memmap[MICROCHIP_PFSOC_DRAM_LO].base, | |
561 | mem_low); | |
d4c624f4 BM |
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); | |
56f6e31e | 570 | memory_region_add_subregion(system_memory, |
f03100d7 BM |
571 | memmap[MICROCHIP_PFSOC_DRAM_LO_ALIAS].base, |
572 | mem_low_alias); | |
f03100d7 BM |
573 | memory_region_init_alias(mem_high_alias, NULL, |
574 | "microchip.icicle.kit.ram_high.alias", | |
575 | mem_high, 0, mem_high_size); | |
f03100d7 BM |
576 | memory_region_add_subregion(system_memory, |
577 | memmap[MICROCHIP_PFSOC_DRAM_HI_ALIAS].base, | |
578 | mem_high_alias); | |
56f6e31e | 579 | |
898dc008 BM |
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 | } | |
143897b5 BM |
589 | |
590 | /* | |
591 | * We follow the following table to select which payload we execute. | |
592 | * | |
593 | * -bios | -kernel | payload | |
594 | * -------+------------+-------- | |
595 | * N | N | HSS | |
596 | * Y | don't care | HSS | |
597 | * N | Y | kernel | |
598 | * | |
599 | * This ensures backwards compatibility with how we used to expose -bios | |
600 | * to users but allows them to run through direct kernel booting as well. | |
601 | * | |
602 | * When -kernel is used for direct boot, -dtb must be present to provide | |
603 | * a valid device tree for the board, as we don't generate device tree. | |
604 | */ | |
605 | ||
606 | if (machine->kernel_filename && machine->dtb) { | |
607 | int fdt_size; | |
608 | machine->fdt = load_device_tree(machine->dtb, &fdt_size); | |
609 | if (!machine->fdt) { | |
610 | error_report("load_device_tree() failed"); | |
611 | exit(1); | |
612 | } | |
613 | ||
614 | firmware_name = RISCV64_BIOS_BIN; | |
615 | firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base; | |
616 | kernel_as_payload = true; | |
617 | } | |
618 | ||
619 | if (!kernel_as_payload) { | |
620 | firmware_name = BIOS_FILENAME; | |
621 | firmware_load_addr = RESET_VECTOR; | |
622 | } | |
623 | ||
624 | /* Load the firmware */ | |
625 | firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, | |
626 | firmware_load_addr, NULL); | |
627 | ||
628 | if (kernel_as_payload) { | |
629 | kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus, | |
630 | firmware_end_addr); | |
631 | ||
632 | kernel_entry = riscv_load_kernel(machine->kernel_filename, | |
633 | kernel_start_addr, NULL); | |
634 | ||
635 | if (machine->initrd_filename) { | |
636 | hwaddr start; | |
637 | hwaddr end = riscv_load_initrd(machine->initrd_filename, | |
638 | machine->ram_size, kernel_entry, | |
639 | &start); | |
640 | qemu_fdt_setprop_cell(machine->fdt, "/chosen", | |
641 | "linux,initrd-start", start); | |
642 | qemu_fdt_setprop_cell(machine->fdt, "/chosen", | |
643 | "linux,initrd-end", end); | |
644 | } | |
645 | ||
58303fc0 | 646 | if (machine->kernel_cmdline && *machine->kernel_cmdline) { |
143897b5 BM |
647 | qemu_fdt_setprop_string(machine->fdt, "/chosen", |
648 | "bootargs", machine->kernel_cmdline); | |
649 | } | |
650 | ||
651 | /* Compute the fdt load address in dram */ | |
652 | fdt_load_addr = riscv_load_fdt(memmap[MICROCHIP_PFSOC_DRAM_LO].base, | |
653 | machine->ram_size, machine->fdt); | |
654 | /* Load the reset vector */ | |
655 | riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr, | |
656 | memmap[MICROCHIP_PFSOC_ENVM_DATA].base, | |
657 | memmap[MICROCHIP_PFSOC_ENVM_DATA].size, | |
6934f15b | 658 | kernel_entry, fdt_load_addr); |
143897b5 | 659 | } |
56f6e31e BM |
660 | } |
661 | ||
662 | static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data) | |
663 | { | |
664 | MachineClass *mc = MACHINE_CLASS(oc); | |
665 | ||
666 | mc->desc = "Microchip PolarFire SoC Icicle Kit"; | |
667 | mc->init = microchip_icicle_kit_machine_init; | |
668 | mc->max_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT + | |
669 | MICROCHIP_PFSOC_COMPUTE_CPU_COUNT; | |
670 | mc->min_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT + 1; | |
671 | mc->default_cpus = mc->min_cpus; | |
d4c624f4 | 672 | mc->default_ram_id = "microchip.icicle.kit.ram"; |
f03100d7 BM |
673 | |
674 | /* | |
675 | * Map 513 MiB high memory, the mimimum required high memory size, because | |
676 | * HSS will do memory test against the high memory address range regardless | |
677 | * of physical memory installed. | |
678 | * | |
679 | * See memory_tests() in mss_ddr.c in the HSS source code. | |
680 | */ | |
681 | mc->default_ram_size = 1537 * MiB; | |
56f6e31e BM |
682 | } |
683 | ||
684 | static const TypeInfo microchip_icicle_kit_machine_typeinfo = { | |
685 | .name = MACHINE_TYPE_NAME("microchip-icicle-kit"), | |
686 | .parent = TYPE_MACHINE, | |
687 | .class_init = microchip_icicle_kit_machine_class_init, | |
688 | .instance_size = sizeof(MicrochipIcicleKitState), | |
689 | }; | |
690 | ||
691 | static void microchip_icicle_kit_machine_init_register_types(void) | |
692 | { | |
693 | type_register_static(µchip_icicle_kit_machine_typeinfo); | |
694 | } | |
695 | ||
696 | type_init(microchip_icicle_kit_machine_init_register_types) |