|
11 | 11 | * 1) CLINT (Core Level Interruptor)
|
12 | 12 | * 2) PLIC (Platform Level Interrupt Controller)
|
13 | 13 | * 3) PRCI (Power, Reset, Clock, Interrupt)
|
14 |
| - * 4) OTP (One-Time Programmable) memory with stored serial number |
15 |
| - * 5) GEM (Gigabit Ethernet Controller) and management block |
| 14 | + * 4) GPIO (General Purpose Input/Output Controller) |
| 15 | + * 5) OTP (One-Time Programmable) memory with stored serial number |
| 16 | + * 6) GEM (Gigabit Ethernet Controller) and management block |
16 | 17 | *
|
17 | 18 | * This board currently generates devicetree dynamically that indicates at least
|
18 | 19 | * two harts and up to five harts.
|
@@ -75,6 +76,7 @@ static const struct MemmapEntry {
|
75 | 76 | [SIFIVE_U_PRCI] = { 0x10000000, 0x1000 },
|
76 | 77 | [SIFIVE_U_UART0] = { 0x10010000, 0x1000 },
|
77 | 78 | [SIFIVE_U_UART1] = { 0x10011000, 0x1000 },
|
| 79 | + [SIFIVE_U_GPIO] = { 0x10060000, 0x1000 }, |
78 | 80 | [SIFIVE_U_OTP] = { 0x10070000, 0x1000 },
|
79 | 81 | [SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 },
|
80 | 82 | [SIFIVE_U_DRAM] = { 0x80000000, 0x0 },
|
@@ -268,6 +270,28 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
268 | 270 | g_free(cells);
|
269 | 271 | g_free(nodename);
|
270 | 272 |
|
| 273 | + nodename = g_strdup_printf("/soc/gpio@%lx", |
| 274 | + (long)memmap[SIFIVE_U_GPIO].base); |
| 275 | + qemu_fdt_add_subnode(fdt, nodename); |
| 276 | + qemu_fdt_setprop_cells(fdt, nodename, "clocks", |
| 277 | + prci_phandle, PRCI_CLK_TLCLK); |
| 278 | + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 2); |
| 279 | + qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); |
| 280 | + qemu_fdt_setprop_cell(fdt, nodename, "#gpio-cells", 2); |
| 281 | + qemu_fdt_setprop(fdt, nodename, "gpio-controller", NULL, 0); |
| 282 | + qemu_fdt_setprop_cells(fdt, nodename, "reg", |
| 283 | + 0x0, memmap[SIFIVE_U_GPIO].base, |
| 284 | + 0x0, memmap[SIFIVE_U_GPIO].size); |
| 285 | + qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GPIO_IRQ0, |
| 286 | + SIFIVE_U_GPIO_IRQ1, SIFIVE_U_GPIO_IRQ2, SIFIVE_U_GPIO_IRQ3, |
| 287 | + SIFIVE_U_GPIO_IRQ4, SIFIVE_U_GPIO_IRQ5, SIFIVE_U_GPIO_IRQ6, |
| 288 | + SIFIVE_U_GPIO_IRQ7, SIFIVE_U_GPIO_IRQ8, SIFIVE_U_GPIO_IRQ9, |
| 289 | + SIFIVE_U_GPIO_IRQ10, SIFIVE_U_GPIO_IRQ11, SIFIVE_U_GPIO_IRQ12, |
| 290 | + SIFIVE_U_GPIO_IRQ13, SIFIVE_U_GPIO_IRQ14, SIFIVE_U_GPIO_IRQ15); |
| 291 | + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); |
| 292 | + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,gpio0"); |
| 293 | + g_free(nodename); |
| 294 | + |
271 | 295 | phy_phandle = phandle++;
|
272 | 296 | nodename = g_strdup_printf("/soc/ethernet@%lx",
|
273 | 297 | (long)memmap[SIFIVE_U_GEM].base);
|
@@ -515,6 +539,7 @@ static void sifive_u_soc_instance_init(Object *obj)
|
515 | 539 | object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI);
|
516 | 540 | object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP);
|
517 | 541 | object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM);
|
| 542 | + object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO); |
518 | 543 | }
|
519 | 544 |
|
520 | 545 | static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
@@ -600,6 +625,20 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
600 | 625 | sysbus_realize(SYS_BUS_DEVICE(&s->prci), &err);
|
601 | 626 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base);
|
602 | 627 |
|
| 628 | + qdev_prop_set_uint32(DEVICE(&s->gpio), "ngpio", 16); |
| 629 | + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); |
| 630 | + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_U_GPIO].base); |
| 631 | + |
| 632 | + /* Pass all GPIOs to the SOC layer so they are available to the board */ |
| 633 | + qdev_pass_gpios(DEVICE(&s->gpio), dev, NULL); |
| 634 | + |
| 635 | + /* Connect GPIO interrupts to the PLIC */ |
| 636 | + for (i = 0; i < 16; i++) { |
| 637 | + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), i, |
| 638 | + qdev_get_gpio_in(DEVICE(s->plic), |
| 639 | + SIFIVE_U_GPIO_IRQ0 + i)); |
| 640 | + } |
| 641 | + |
603 | 642 | qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial);
|
604 | 643 | sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err);
|
605 | 644 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base);
|
|
0 commit comments