4444
4545#include <libfdt.h>
4646
47+ /* Each UART is given 0x100 bytes of memory map despite not needing nearly
48+ * that much. Despite that, the existing memory map still supports up to
49+ * 16 uarts, which is probably plenty.
50+ */
51+ #define MAX_UARTS 16
52+
4753static const struct MemmapEntry {
4854 hwaddr base ;
4955 hwaddr size ;
@@ -59,7 +65,7 @@ static const struct MemmapEntry {
5965};
6066
6167static void * create_fdt (RISCVVirtState * s , const struct MemmapEntry * memmap ,
62- uint64_t mem_size , const char * cmdline )
68+ uint64_t mem_size , const char * cmdline , uint32_t * out_plic_handle )
6369{
6470 void * fdt ;
6571 int cpu ;
@@ -200,28 +206,52 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
200206 qemu_fdt_setprop_cells (fdt , nodename , "reg" ,
201207 0x0 , memmap [VIRT_TEST ].base ,
202208 0x0 , memmap [VIRT_TEST ].size );
209+ g_free (nodename );
203210
204- nodename = g_strdup_printf ("/uart@%lx" ,
205- (long )memmap [VIRT_UART0 ].base );
206- qemu_fdt_add_subnode (fdt , nodename );
207- qemu_fdt_setprop_string (fdt , nodename , "compatible" , "ns16550a" );
208- qemu_fdt_setprop_cells (fdt , nodename , "reg" ,
209- 0x0 , memmap [VIRT_UART0 ].base ,
210- 0x0 , memmap [VIRT_UART0 ].size );
211- qemu_fdt_setprop_cell (fdt , nodename , "clock-frequency" , 3686400 );
212- qemu_fdt_setprop_cells (fdt , nodename , "interrupt-parent" , plic_phandle );
213- qemu_fdt_setprop_cells (fdt , nodename , "interrupts" , UART0_IRQ );
214-
211+ /* Install UART0 as /chosen/stdout-path */
212+ nodename = g_strdup_printf ("/uart@%lx" , (long )memmap [VIRT_UART0 ].base );
215213 qemu_fdt_add_subnode (fdt , "/chosen" );
216214 qemu_fdt_setprop_string (fdt , "/chosen" , "stdout-path" , nodename );
215+ g_free (nodename );
217216 if (cmdline ) {
218217 qemu_fdt_setprop_string (fdt , "/chosen" , "bootargs" , cmdline );
219218 }
220- g_free (nodename );
219+
220+ if (out_plic_handle ) {
221+ * out_plic_handle = plic_phandle ;
222+ }
221223
222224 return fdt ;
223225}
224226
227+ static void
228+ riscv_virt_serial_init (RISCVVirtState * s , const struct MemmapEntry * memmap ,
229+ MemoryRegion * system_memory , void * fdt ,
230+ uint32_t plic_phandle , int hdix , int uix )
231+ {
232+ hwaddr addr ;
233+ char * nodename ;
234+
235+ addr = memmap [VIRT_UART0 ].base + uix * memmap [VIRT_UART0 ].size ;
236+
237+ /* Wire to memory */
238+ serial_mm_init (system_memory , addr , 0 ,
239+ qdev_get_gpio_in (DEVICE (s -> plic ), UART0_IRQ + uix ), 399193 ,
240+ serial_hd (hdix ), DEVICE_LITTLE_ENDIAN );
241+
242+ /* Register with FDT */
243+ nodename = g_strdup_printf ("/uart@%lx" , (long )addr );
244+ qemu_fdt_add_subnode (fdt , nodename );
245+ qemu_fdt_setprop_string (fdt , nodename , "compatible" , "ns16550a" );
246+ qemu_fdt_setprop_cells (fdt , nodename , "reg" ,
247+ 0x0 , addr ,
248+ 0x0 , memmap [VIRT_UART0 ].size );
249+ qemu_fdt_setprop_cell (fdt , nodename , "clock-frequency" , 3686400 );
250+ qemu_fdt_setprop_cells (fdt , nodename , "interrupt-parent" , plic_phandle );
251+ qemu_fdt_setprop_cells (fdt , nodename , "interrupts" , UART0_IRQ + uix );
252+ g_free (nodename );
253+ }
254+
225255static void riscv_virt_board_init (MachineState * machine )
226256{
227257 const struct MemmapEntry * memmap = virt_memmap ;
@@ -232,8 +262,9 @@ static void riscv_virt_board_init(MachineState *machine)
232262 MemoryRegion * mask_rom = g_new (MemoryRegion , 1 );
233263 char * plic_hart_config ;
234264 size_t plic_hart_config_len ;
235- int i ;
265+ int i , j ;
236266 void * fdt ;
267+ uint32_t plic_phandle ;
237268 hwaddr firmware_entry ;
238269
239270 /* Initialize SOC */
@@ -253,7 +284,44 @@ static void riscv_virt_board_init(MachineState *machine)
253284 main_mem );
254285
255286 /* create device tree */
256- fdt = create_fdt (s , memmap , machine -> ram_size , machine -> kernel_cmdline );
287+ fdt = create_fdt (s , memmap , machine -> ram_size , machine -> kernel_cmdline ,
288+ & plic_phandle );
289+
290+ /* create PLIC hart topology configuration string */
291+ plic_hart_config_len = (strlen (VIRT_PLIC_HART_CONFIG ) + 1 ) * smp_cpus ;
292+ plic_hart_config = g_malloc0 (plic_hart_config_len );
293+ for (i = 0 ; i < smp_cpus ; i ++ ) {
294+ if (i != 0 ) {
295+ strncat (plic_hart_config , "," , plic_hart_config_len );
296+ }
297+ strncat (plic_hart_config , VIRT_PLIC_HART_CONFIG , plic_hart_config_len );
298+ plic_hart_config_len -= (strlen (VIRT_PLIC_HART_CONFIG ) + 1 );
299+ }
300+
301+ /* create PLIC */
302+ s -> plic = sifive_plic_create (memmap [VIRT_PLIC ].base ,
303+ plic_hart_config ,
304+ VIRT_PLIC_NUM_SOURCES ,
305+ VIRT_PLIC_NUM_PRIORITIES ,
306+ VIRT_PLIC_PRIORITY_BASE ,
307+ VIRT_PLIC_PENDING_BASE ,
308+ VIRT_PLIC_ENABLE_BASE ,
309+ VIRT_PLIC_ENABLE_STRIDE ,
310+ VIRT_PLIC_CONTEXT_BASE ,
311+ VIRT_PLIC_CONTEXT_STRIDE ,
312+ memmap [VIRT_PLIC ].size );
313+
314+ /* Attach UARTs */
315+ for (i = 1 , j = 1 ; (i < serial_max_hds ()) && (j < MAX_UARTS ); i ++ ) {
316+ if (serial_hd (i ) == NULL ) {
317+ continue ;
318+ }
319+ riscv_virt_serial_init (s , memmap , system_memory , fdt , plic_phandle ,
320+ i , j );
321+ j ++ ;
322+ }
323+ /* Attach the debug UART last, so BBL finds it first */
324+ riscv_virt_serial_init (s , memmap , system_memory , fdt , plic_phandle , 0 , 0 );
257325
258326 /* boot rom */
259327 memory_region_init_rom (mask_rom , NULL , "riscv_virt_board.mrom" ,
@@ -303,29 +371,7 @@ static void riscv_virt_board_init(MachineState *machine)
303371 memmap [VIRT_MROM ].base + sizeof (reset_vec ),
304372 & address_space_memory );
305373
306- /* create PLIC hart topology configuration string */
307- plic_hart_config_len = (strlen (VIRT_PLIC_HART_CONFIG ) + 1 ) * smp_cpus ;
308- plic_hart_config = g_malloc0 (plic_hart_config_len );
309- for (i = 0 ; i < smp_cpus ; i ++ ) {
310- if (i != 0 ) {
311- strncat (plic_hart_config , "," , plic_hart_config_len );
312- }
313- strncat (plic_hart_config , VIRT_PLIC_HART_CONFIG , plic_hart_config_len );
314- plic_hart_config_len -= (strlen (VIRT_PLIC_HART_CONFIG ) + 1 );
315- }
316-
317- /* MMIO */
318- s -> plic = sifive_plic_create (memmap [VIRT_PLIC ].base ,
319- plic_hart_config ,
320- VIRT_PLIC_NUM_SOURCES ,
321- VIRT_PLIC_NUM_PRIORITIES ,
322- VIRT_PLIC_PRIORITY_BASE ,
323- VIRT_PLIC_PENDING_BASE ,
324- VIRT_PLIC_ENABLE_BASE ,
325- VIRT_PLIC_ENABLE_STRIDE ,
326- VIRT_PLIC_CONTEXT_BASE ,
327- VIRT_PLIC_CONTEXT_STRIDE ,
328- memmap [VIRT_PLIC ].size );
374+ /* Other MMIO: CLINT, TEST */
329375 sifive_clint_create (memmap [VIRT_CLINT ].base ,
330376 memmap [VIRT_CLINT ].size , smp_cpus ,
331377 SIFIVE_SIP_BASE , SIFIVE_TIMECMP_BASE , SIFIVE_TIME_BASE );
@@ -337,10 +383,6 @@ static void riscv_virt_board_init(MachineState *machine)
337383 qdev_get_gpio_in (DEVICE (s -> plic ), VIRTIO_IRQ + i ));
338384 }
339385
340- serial_mm_init (system_memory , memmap [VIRT_UART0 ].base ,
341- 0 , qdev_get_gpio_in (DEVICE (s -> plic ), UART0_IRQ ), 399193 ,
342- serial_hd (0 ), DEVICE_LITTLE_ENDIAN );
343-
344386 g_free (plic_hart_config );
345387}
346388
0 commit comments