Skip to content
This repository was archived by the owner on Apr 13, 2019. It is now read-only.

Commit 0047527

Browse files
committed
riscv: virt machine: multiple UARTs
Attach up to 16 serial devices, densely packed in the memory map and registered in the FDT. To ensure that BBL continues to find the default one, we register it last so that it ends up at the top of the fdt.
1 parent 79fe4f4 commit 0047527

File tree

2 files changed

+85
-43
lines changed

2 files changed

+85
-43
lines changed

hw/riscv/virt.c

+84-42
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
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+
4753
static const struct MemmapEntry {
4854
hwaddr base;
4955
hwaddr size;
@@ -59,7 +65,7 @@ static const struct MemmapEntry {
5965
};
6066

6167
static 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+
225255
static 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

include/hw/riscv/virt.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ enum {
4242
};
4343

4444
enum {
45-
UART0_IRQ = 10,
45+
UART0_IRQ = 10, /* up to 25, inclusive */
4646
VIRTIO_IRQ = 1, /* 1 to 8 */
4747
VIRTIO_COUNT = 8,
4848
VIRTIO_NDEV = 10

0 commit comments

Comments
 (0)