diff mbox series

[RFC,12/14] hw/arm/bcm2836: Add the BCM2838 which uses a GICv2

Message ID 20190904171315.8354-13-f4bug@amsat.org (mailing list archive)
State New, archived
Headers show
Series hw/arm: Add the Raspberry Pi 4B | expand

Commit Message

Philippe Mathieu-Daudé Sept. 4, 2019, 5:13 p.m. UTC
The BCM2838 is improvement of the BCM2837:
- Cortex-A72 instead of the A53
- peripheral block and local soc controller are mapped differently,
- GICv2
- PCIe block
- exhanced MMU to address over 4GiB of SDRAM

See https://www.raspberrypi.org/forums/viewtopic.php?t=244479&start=25
and https://patchwork.kernel.org/patch/11053097/

This patch starts mapping the GICv2 but interrupt lines are NOT
wired (yet).

This is enough to start running the Ubuntu kernel8.img from [1].

Extract the kernel with:

  $ mkdir bootpart
  $ guestfish \
      --ro \
      -a ubuntu-18.04.3-preinstalled-server-arm64+raspi4.img \
      -m /dev/sda1
  Welcome to guestfish, the guest filesystem shell for
  editing virtual machine filesystems and disk images.

  ><fs> ls /
  COPYING.linux
  LICENCE.broadcom
  System.map
  armstub8-gic.bin
  bcm2710-rpi-3-b-plus.dtb
  bcm2710-rpi-3-b.dtb
  bcm2710-rpi-cm3.dtb
  bcm2711-rpi-4-b.dtb
  bcm2837-rpi-3-b-plus.dtb
  bcm2837-rpi-3-b.dtb
  cmdline.txt
  config.txt
  fixup4.dat
  fixup4cd.dat
  fixup4db.dat
  fixup4x.dat
  kernel8.img
  overlays
  start4.elf
  start4cd.elf
  start4db.elf
  start4x.elf
  ><fs> copy-out / bootpart/
  ><fs> q

Then some progress can be noticed running:

  $ qemu-system-aarch64 -d unimp,guest_errors,int,in_asm \
      -M raspi4 \
      -kernel bootpart/kernel8.img \
      -dtb bootpart/bcm2711-rpi-4-b.dtb \
      -initrd bootpart/boot/initrd.img \
      -append \
         "earlycon=pl011,0xfe201000 console=ttyAMA0 console=tty1 loglevel=8"

Not very interesting, but it runs until configuring the GIC.
(remove 'in_asm' if too verbose).

TODO:

- wire IRQs to the GIC :)

- map the SPI bootrom from [3] (boot sequence: [4])

- per [2] we could try booting without using the GIC, adding "enable_gic=0"
  in config.txt. this variable is parsed by the firmware:

  $ fgrep -r enable_gic bootpart
  Binary file bootpart/start4x.elf matches
  Binary file bootpart/start4.elf matches
  Binary file bootpart/start4db.elf matches
  Binary file bootpart/start4cd.elf matches
  bootpart/config.txt:enable_gic=1

  the stub [5] doesn't seem to check a register for it.
  maybe it falls back to kernel7l?

- decompile start4.elf to check how 'enable_gic' is used
  using vc4 toolchain from [6]

[1] https://github.com/TheRemote/Ubuntu-Server-raspi4-unofficial/releases
[2] https://jamesachambers.com/raspberry-pi-ubuntu-server-18-04-2-installation-guide/
[3] https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md
[4] https://raspberrypi.stackexchange.com/questions/10442/what-is-the-boot-sequence
[5] https://github.com/raspberrypi/tools/commit/7f4a937e1bacbc111a22552169bc890b4bb26a94#diff-8c41083e9fa0c98f1c3015e11b897444
[6] https://github.com/christinaa/rpi-open-firmware

Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 hw/arm/bcm2836.c         | 75 ++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/bcm2836.h |  3 ++
 2 files changed, 78 insertions(+)

Comments

Luc Michel Sept. 5, 2019, 8:41 a.m. UTC | #1
Hi Philippe,

On 9/4/19 7:13 PM, Philippe Mathieu-Daudé wrote:
> The BCM2838 is improvement of the BCM2837:
> - Cortex-A72 instead of the A53
> - peripheral block and local soc controller are mapped differently,
> - GICv2
> - PCIe block
> - exhanced MMU to address over 4GiB of SDRAM
> 
> See https://www.raspberrypi.org/forums/viewtopic.php?t=244479&start=25
> and https://patchwork.kernel.org/patch/11053097/
> 
> This patch starts mapping the GICv2 but interrupt lines are NOT
> wired (yet).
> 
> This is enough to start running the Ubuntu kernel8.img from [1].
> 
> Extract the kernel with:
> 
>    $ mkdir bootpart
>    $ guestfish \
>        --ro \
>        -a ubuntu-18.04.3-preinstalled-server-arm64+raspi4.img \
>        -m /dev/sda1
>    Welcome to guestfish, the guest filesystem shell for
>    editing virtual machine filesystems and disk images.
> 
>    ><fs> ls /
>    COPYING.linux
>    LICENCE.broadcom
>    System.map
>    armstub8-gic.bin
>    bcm2710-rpi-3-b-plus.dtb
>    bcm2710-rpi-3-b.dtb
>    bcm2710-rpi-cm3.dtb
>    bcm2711-rpi-4-b.dtb
>    bcm2837-rpi-3-b-plus.dtb
>    bcm2837-rpi-3-b.dtb
>    cmdline.txt
>    config.txt
>    fixup4.dat
>    fixup4cd.dat
>    fixup4db.dat
>    fixup4x.dat
>    kernel8.img
>    overlays
>    start4.elf
>    start4cd.elf
>    start4db.elf
>    start4x.elf
>    ><fs> copy-out / bootpart/
>    ><fs> q
> 
> Then some progress can be noticed running:
> 
>    $ qemu-system-aarch64 -d unimp,guest_errors,int,in_asm \
>        -M raspi4 \
>        -kernel bootpart/kernel8.img \
>        -dtb bootpart/bcm2711-rpi-4-b.dtb \
>        -initrd bootpart/boot/initrd.img \
>        -append \
>           "earlycon=pl011,0xfe201000 console=ttyAMA0 console=tty1 loglevel=8"
> 
> Not very interesting, but it runs until configuring the GIC.
> (remove 'in_asm' if too verbose).
> 
> TODO:
> 
> - wire IRQs to the GIC :)
> 
> - map the SPI bootrom from [3] (boot sequence: [4])
> 
> - per [2] we could try booting without using the GIC, adding "enable_gic=0"
>    in config.txt. this variable is parsed by the firmware:
> 
>    $ fgrep -r enable_gic bootpart
>    Binary file bootpart/start4x.elf matches
>    Binary file bootpart/start4.elf matches
>    Binary file bootpart/start4db.elf matches
>    Binary file bootpart/start4cd.elf matches
>    bootpart/config.txt:enable_gic=1
> 
>    the stub [5] doesn't seem to check a register for it.
>    maybe it falls back to kernel7l?
> 
> - decompile start4.elf to check how 'enable_gic' is used
>    using vc4 toolchain from [6]
> 
> [1] https://github.com/TheRemote/Ubuntu-Server-raspi4-unofficial/releases
> [2] https://jamesachambers.com/raspberry-pi-ubuntu-server-18-04-2-installation-guide/
> [3] https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md
> [4] https://raspberrypi.stackexchange.com/questions/10442/what-is-the-boot-sequence
> [5] https://github.com/raspberrypi/tools/commit/7f4a937e1bacbc111a22552169bc890b4bb26a94#diff-8c41083e9fa0c98f1c3015e11b897444
> [6] https://github.com/christinaa/rpi-open-firmware
> 
> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>   hw/arm/bcm2836.c         | 75 ++++++++++++++++++++++++++++++++++++++++
>   include/hw/arm/bcm2836.h |  3 ++
>   2 files changed, 78 insertions(+)
> 
> diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
> index 019e67b906..d89d7cd71d 100644
> --- a/hw/arm/bcm2836.c
> +++ b/hw/arm/bcm2836.c
> @@ -21,6 +21,7 @@ struct BCM283XInfo {
>       const char *cpu_type;
>       hwaddr peri_base; /* Peripheral base address seen by the CPU */
>       hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
> +    hwaddr gic_base;
>       int clusterid;
>   };
>   
> @@ -40,9 +41,25 @@ static const BCM283XInfo bcm283x_socs[] = {
>           .ctrl_base = 0x40000000,
>           .clusterid = 0x0,
>       },
> +    {
> +        .name = TYPE_BCM2838,
> +        .cpu_type = ARM_CPU_TYPE_NAME("cortex-a72"),
> +        .peri_base = 0xfe000000,
> +        .ctrl_base = 0xff800000,
> +        .gic_base = 0x40000,
> +    },
>   #endif
>   };
>   
> +#define GIC_NUM_IRQS                256
> +
> +#define GIC_BASE_OFS                0x0000
> +#define GIC_DIST_OFS                0x1000
> +#define GIC_CPU_OFS                 0x2000
> +#define GIC_VIFACE_THIS_OFS         0x4000
> +#define GIC_VIFACE_OTHER_OFS(cpu)  (0x5000 + (cpu) * 0x200)
> +#define GIC_VCPU_OFS                0x6000
> +
>   static void bcm2836_init(Object *obj)
>   {
>       BCM283XState *s = BCM283X(obj);
> @@ -55,6 +72,11 @@ static void bcm2836_init(Object *obj)
>                                   info->cpu_type, &error_abort, NULL);
>       }
>   
> +    if (info->gic_base) {
> +        sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic),
> +                              TYPE_ARM_GIC);
> +    }
> +
>       sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control),
>                             TYPE_BCM2836_CONTROL);
>   
> @@ -115,6 +137,59 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
>   
>       sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base);
>   
> +    /* bcm2838 GICv2 */
> +    if (info->gic_base) {
> +        object_property_set_uint(OBJECT(&s->gic), 2, "revision", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +
> +        object_property_set_uint(OBJECT(&s->gic),
> +                                 BCM283X_NCPUS, "num-cpu", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +
> +        object_property_set_uint(OBJECT(&s->gic),
> +                                 32 + GIC_NUM_IRQS, "num-irq", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +
> +        object_property_set_bool(OBJECT(&s->gic),
> +                                 true, "has-virtualization-extensions", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +
> +        object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +
> +        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0,
> +                        info->ctrl_base + info->gic_base + GIC_DIST_OFS);
> +        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1,
> +                        info->ctrl_base + info->gic_base + GIC_CPU_OFS);
> +        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 2,
> +                        info->ctrl_base + info->gic_base + GIC_VIFACE_THIS_OFS);
> +        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 3,
> +                        info->ctrl_base + info->gic_base + GIC_VCPU_OFS);
> +
> +        for (n = 0; n < BCM283X_NCPUS; n++) {
> +            sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 4 + n,
> +                            info->ctrl_base + info->gic_base
> +                            + GIC_VIFACE_OTHER_OFS(n));> +        }
> +
> +        /* TODO wire IRQs!!! */

I think as a bare minimum, you must wire:
  - the ARM generic timer IRQs going out of all the CPUs, into their
respective PPI. Looking at [1], they seem to be connected to the usual
PPIs (at least we have the same mapping in the vexpress, the xynqmp and
the virt board).
  - The PMU interrupts
  - Possibly the GICv2 maintenance interrupt, but I can't find the IRQ
number in the DTS. This is related to the virtualization extension. It
should not prevent Linux from booting if it's not connected (I think KVM
does not even use the GICv2 maintenance interrupts anyway).
  - Finally, Connect the four GICv2 output (irq, fiq, virq, vfiq) to
their respective CPU inputs.


[1]
https://github.com/raspberrypi/linux/blob/rpi-5.3.y/arch/arm/boot/dts/bcm2838.dtsi


Here is a snippet of the virt board, quickly adapted foc this SoC (I
didn't test it):

#define BCM2838_ARCH_TIMER_VIRT_IRQ   11
#define BCM2838_ARCH_TIMER_S_EL1_IRQ  13
#define BCM2838_ARCH_TIMER_NS_EL1_IRQ 14
#define BCM2838_ARCH_TIMER_NS_EL2_IRQ 10

#define BCM2838_PMU_SPI_BASE          16
[...]

 for (i = 0; i < BCM283X_NCPUS; i++) {
        DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
        int ppibase = GIC_NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
        int irq;

        /* Mapping from the output timer irq lines from the CPU to the
         * GIC PPI inputs.
         */
        const int timer_irq[] = {
            [GTIMER_PHYS] = BCM2838_ARCH_TIMER_NS_EL1_IRQ,
            [GTIMER_VIRT] = BCM2838_ARCH_TIMER_VIRT_IRQ,
            [GTIMER_HYP]  = BCM2838_ARCH_TIMER_NS_EL2_IRQ,
            [GTIMER_SEC]  = BCM2838_ARCH_TIMER_S_EL1_IRQ,
        };

        for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
            qdev_connect_gpio_out(cpudev, irq,
                                  qdev_get_gpio_in(gicdev,
                                                   ppibase +
timer_irq[irq]));
        }

        /* I don't know the maintenance IRQ number for the this SoC */
#if 0
        qemu_irq irq = qdev_get_gpio_in(gicdev,
                                        ppibase + ARCH_GIC_MAINT_IRQ);
        sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i + 4 *
smp_cpus, irq);
#endif

        /* PMU interrupt */
        qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
                                    qdev_get_gpio_in(gicdev,
BCM2838_PMU_SPI_BASE + i));

        /* Connect the GICv2 outputs to the CPU */
        sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i,
                           qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
        sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i + smp_cpus,
                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
        sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i + 2 *
smp_cpus,
                           qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
        sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i + 3 *
smp_cpus,
                           qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
    }



HTH!
Philippe Mathieu-Daudé Sept. 9, 2019, 5:10 p.m. UTC | #2
Hi Luc,

On 9/5/19 10:41 AM, Luc Michel wrote:
> On 9/4/19 7:13 PM, Philippe Mathieu-Daudé wrote:
>> The BCM2838 is improvement of the BCM2837:
>> - Cortex-A72 instead of the A53
>> - peripheral block and local soc controller are mapped differently,
>> - GICv2
>> - PCIe block
>> - exhanced MMU to address over 4GiB of SDRAM
>>
>> See https://www.raspberrypi.org/forums/viewtopic.php?t=244479&start=25
>> and https://patchwork.kernel.org/patch/11053097/
>>
>> This patch starts mapping the GICv2 but interrupt lines are NOT
>> wired (yet).
>>
>> This is enough to start running the Ubuntu kernel8.img from [1].
>>
>> Extract the kernel with:
>>
>>    $ mkdir bootpart
>>    $ guestfish \
>>        --ro \
>>        -a ubuntu-18.04.3-preinstalled-server-arm64+raspi4.img \
>>        -m /dev/sda1
>>    Welcome to guestfish, the guest filesystem shell for
>>    editing virtual machine filesystems and disk images.
>>
>>    ><fs> ls /
>>    COPYING.linux
>>    LICENCE.broadcom
>>    System.map
>>    armstub8-gic.bin
>>    bcm2710-rpi-3-b-plus.dtb
>>    bcm2710-rpi-3-b.dtb
>>    bcm2710-rpi-cm3.dtb
>>    bcm2711-rpi-4-b.dtb
>>    bcm2837-rpi-3-b-plus.dtb
>>    bcm2837-rpi-3-b.dtb
>>    cmdline.txt
>>    config.txt
>>    fixup4.dat
>>    fixup4cd.dat
>>    fixup4db.dat
>>    fixup4x.dat
>>    kernel8.img
>>    overlays
>>    start4.elf
>>    start4cd.elf
>>    start4db.elf
>>    start4x.elf
>>    ><fs> copy-out / bootpart/
>>    ><fs> q
>>
>> Then some progress can be noticed running:
>>
>>    $ qemu-system-aarch64 -d unimp,guest_errors,int,in_asm \
>>        -M raspi4 \
>>        -kernel bootpart/kernel8.img \
>>        -dtb bootpart/bcm2711-rpi-4-b.dtb \
>>        -initrd bootpart/boot/initrd.img \
>>        -append \
>>           "earlycon=pl011,0xfe201000 console=ttyAMA0 console=tty1 loglevel=8"
>>
>> Not very interesting, but it runs until configuring the GIC.
>> (remove 'in_asm' if too verbose).
>>
>> TODO:
>>
>> - wire IRQs to the GIC :)
>>
>> - map the SPI bootrom from [3] (boot sequence: [4])
>>
>> - per [2] we could try booting without using the GIC, adding "enable_gic=0"
>>    in config.txt. this variable is parsed by the firmware:
>>
>>    $ fgrep -r enable_gic bootpart
>>    Binary file bootpart/start4x.elf matches
>>    Binary file bootpart/start4.elf matches
>>    Binary file bootpart/start4db.elf matches
>>    Binary file bootpart/start4cd.elf matches
>>    bootpart/config.txt:enable_gic=1
>>
>>    the stub [5] doesn't seem to check a register for it.
>>    maybe it falls back to kernel7l?
>>
>> - decompile start4.elf to check how 'enable_gic' is used
>>    using vc4 toolchain from [6]
>>
>> [1] https://github.com/TheRemote/Ubuntu-Server-raspi4-unofficial/releases
>> [2] https://jamesachambers.com/raspberry-pi-ubuntu-server-18-04-2-installation-guide/
>> [3] https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md
>> [4] https://raspberrypi.stackexchange.com/questions/10442/what-is-the-boot-sequence
>> [5] https://github.com/raspberrypi/tools/commit/7f4a937e1bacbc111a22552169bc890b4bb26a94#diff-8c41083e9fa0c98f1c3015e11b897444
>> [6] https://github.com/christinaa/rpi-open-firmware
>>
>> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>> ---
>>   hw/arm/bcm2836.c         | 75 ++++++++++++++++++++++++++++++++++++++++
>>   include/hw/arm/bcm2836.h |  3 ++
>>   2 files changed, 78 insertions(+)
>>
>> diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
>> index 019e67b906..d89d7cd71d 100644
>> --- a/hw/arm/bcm2836.c
>> +++ b/hw/arm/bcm2836.c
>> @@ -21,6 +21,7 @@ struct BCM283XInfo {
>>       const char *cpu_type;
>>       hwaddr peri_base; /* Peripheral base address seen by the CPU */
>>       hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
>> +    hwaddr gic_base;
>>       int clusterid;
>>   };
>>   
>> @@ -40,9 +41,25 @@ static const BCM283XInfo bcm283x_socs[] = {
>>           .ctrl_base = 0x40000000,
>>           .clusterid = 0x0,
>>       },
>> +    {
>> +        .name = TYPE_BCM2838,
>> +        .cpu_type = ARM_CPU_TYPE_NAME("cortex-a72"),
>> +        .peri_base = 0xfe000000,
>> +        .ctrl_base = 0xff800000,
>> +        .gic_base = 0x40000,
>> +    },
>>   #endif
>>   };
>>   
>> +#define GIC_NUM_IRQS                256
>> +
>> +#define GIC_BASE_OFS                0x0000
>> +#define GIC_DIST_OFS                0x1000
>> +#define GIC_CPU_OFS                 0x2000
>> +#define GIC_VIFACE_THIS_OFS         0x4000
>> +#define GIC_VIFACE_OTHER_OFS(cpu)  (0x5000 + (cpu) * 0x200)
>> +#define GIC_VCPU_OFS                0x6000
>> +
>>   static void bcm2836_init(Object *obj)
>>   {
>>       BCM283XState *s = BCM283X(obj);
>> @@ -55,6 +72,11 @@ static void bcm2836_init(Object *obj)
>>                                   info->cpu_type, &error_abort, NULL);
>>       }
>>   
>> +    if (info->gic_base) {
>> +        sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic),
>> +                              TYPE_ARM_GIC);
>> +    }
>> +
>>       sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control),
>>                             TYPE_BCM2836_CONTROL);
>>   
>> @@ -115,6 +137,59 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
>>   
>>       sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base);
>>   
>> +    /* bcm2838 GICv2 */
>> +    if (info->gic_base) {
>> +        object_property_set_uint(OBJECT(&s->gic), 2, "revision", &err);
>> +        if (err) {
>> +            error_propagate(errp, err);
>> +            return;
>> +        }
>> +
>> +        object_property_set_uint(OBJECT(&s->gic),
>> +                                 BCM283X_NCPUS, "num-cpu", &err);
>> +        if (err) {
>> +            error_propagate(errp, err);
>> +            return;
>> +        }
>> +
>> +        object_property_set_uint(OBJECT(&s->gic),
>> +                                 32 + GIC_NUM_IRQS, "num-irq", &err);
>> +        if (err) {
>> +            error_propagate(errp, err);
>> +            return;
>> +        }
>> +
>> +        object_property_set_bool(OBJECT(&s->gic),
>> +                                 true, "has-virtualization-extensions", &err);
>> +        if (err) {
>> +            error_propagate(errp, err);
>> +            return;
>> +        }
>> +
>> +        object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
>> +        if (err) {
>> +            error_propagate(errp, err);
>> +            return;
>> +        }
>> +
>> +        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0,
>> +                        info->ctrl_base + info->gic_base + GIC_DIST_OFS);
>> +        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1,
>> +                        info->ctrl_base + info->gic_base + GIC_CPU_OFS);
>> +        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 2,
>> +                        info->ctrl_base + info->gic_base + GIC_VIFACE_THIS_OFS);
>> +        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 3,
>> +                        info->ctrl_base + info->gic_base + GIC_VCPU_OFS);
>> +
>> +        for (n = 0; n < BCM283X_NCPUS; n++) {
>> +            sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 4 + n,
>> +                            info->ctrl_base + info->gic_base
>> +                            + GIC_VIFACE_OTHER_OFS(n));> +        }
>> +
>> +        /* TODO wire IRQs!!! */
> 
> I think as a bare minimum, you must wire:
>   - the ARM generic timer IRQs going out of all the CPUs, into their
> respective PPI. Looking at [1], they seem to be connected to the usual
> PPIs (at least we have the same mapping in the vexpress, the xynqmp and
> the virt board).

Done :)

>   - The PMU interrupts

Still TODO.

>   - Possibly the GICv2 maintenance interrupt, but I can't find the IRQ
> number in the DTS. This is related to the virtualization extension. It
> should not prevent Linux from booting if it's not connected (I think KVM
> does not even use the GICv2 maintenance interrupts anyway).

Done, this is a GIC-400 so it is fixed as PPI IRQ#9 :)

>   - Finally, Connect the four GICv2 output (irq, fiq, virq, vfiq) to
> their respective CPU inputs.

Done.

> [1]
> https://github.com/raspberrypi/linux/blob/rpi-5.3.y/arch/arm/boot/dts/bcm2838.dtsi
> 
> 
> Here is a snippet of the virt board, quickly adapted foc this SoC (I
> didn't test it):

Thanks! It helped :)

> #define BCM2838_ARCH_TIMER_VIRT_IRQ   11
> #define BCM2838_ARCH_TIMER_S_EL1_IRQ  13
> #define BCM2838_ARCH_TIMER_NS_EL1_IRQ 14
> #define BCM2838_ARCH_TIMER_NS_EL2_IRQ 10
> 
> #define BCM2838_PMU_SPI_BASE          16
> [...]
> 
>  for (i = 0; i < BCM283X_NCPUS; i++) {
>         DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
>         int ppibase = GIC_NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
>         int irq;
> 
>         /* Mapping from the output timer irq lines from the CPU to the
>          * GIC PPI inputs.
>          */
>         const int timer_irq[] = {
>             [GTIMER_PHYS] = BCM2838_ARCH_TIMER_NS_EL1_IRQ,
>             [GTIMER_VIRT] = BCM2838_ARCH_TIMER_VIRT_IRQ,
>             [GTIMER_HYP]  = BCM2838_ARCH_TIMER_NS_EL2_IRQ,
>             [GTIMER_SEC]  = BCM2838_ARCH_TIMER_S_EL1_IRQ,
>         };
> 
>         for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
>             qdev_connect_gpio_out(cpudev, irq,
>                                   qdev_get_gpio_in(gicdev,
>                                                    ppibase +
> timer_irq[irq]));
>         }
> 
>         /* I don't know the maintenance IRQ number for the this SoC */
> #if 0
>         qemu_irq irq = qdev_get_gpio_in(gicdev,
>                                         ppibase + ARCH_GIC_MAINT_IRQ);
>         sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i + 4 *
> smp_cpus, irq);
> #endif
> 
>         /* PMU interrupt */
>         qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
>                                     qdev_get_gpio_in(gicdev,
> BCM2838_PMU_SPI_BASE + i));
> 
>         /* Connect the GICv2 outputs to the CPU */
>         sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i,
>                            qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
>         sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i + smp_cpus,
>                            qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
>         sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i + 2 *
> smp_cpus,
>                            qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
>         sysbus_connect_irq(SYS_BUS_DEVICE(gicbusdevs->gic), i + 3 *
> smp_cpus,
>                            qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
>     }

With this and few other changes I get some hopeful kernel output:

[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd083]
[    0.000000] Linux version 4.19.67-v8+ (james@james-ubuntu2) (gcc
version 9.1.0 (GCC)) #1 SMP PREEMPT Mon Aug 26 21:26:31 MDT 2019
[    0.000000] Machine model: Raspberry Pi 4 Model B
[    0.000000] earlycon: pl11 at MMIO 0x00000000fe201000 (options '')
[    0.000000] bootconsole [pl11] enabled
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: UEFI not found.
[    0.000000] cma: Reserved 8 MiB at 0x000000003b800000
[    0.000000] On node 0 totalpages: 245760
[    0.000000]   DMA32 zone: 3840 pages used for memmap
[    0.000000]   DMA32 zone: 0 pages reserved
[    0.000000]   DMA32 zone: 245760 pages, LIFO batch:63
[    0.000000] random: get_random_bytes called from
start_kernel+0xa0/0x46c with crng_init=0
[    0.000000] percpu: Embedded 24 pages/cpu s57368 r8192 d32744 u98304
[    0.000000] pcpu-alloc: s57368 r8192 d32744 u98304 alloc=24*4096
[    0.000000] pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3
[    0.000000] Detected PIPT I-cache on CPU0
[    0.000000] CPU features: enabling workaround for EL2 vector hardening
[    0.000000] CPU features: detected: Kernel page table isolation (KPTI)
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 241920
[    0.000000] Kernel command line: rw earlycon=pl011,0xfe201000
console=ttyAMA0 loglevel=8 root=/dev/mmcblk0p2 fsck.repair=yes
net.ifnames=0 rootwait rdinit=/sbin/init
[    0.000000] Dentry cache hash table entries: 131072 (order: 8,
1048576 bytes)
[    0.000000] Inode-cache hash table entries: 65536 (order: 7, 524288
bytes)
[    0.000000] Memory: 923932K/983040K available (8060K kernel code,
966K rwdata, 2560K rodata, 960K init, 916K bss, 50916K reserved, 8192K
cma-reserved)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
[    0.000000] ftrace: allocating 28504 entries in 112 pages
[    0.000000] rcu: Preemptible hierarchical RCU implementation.
[    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=64 to
nr_cpu_ids=4.
[    0.000000]  Tasks RCU enabled.
[    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
[    0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
[    0.000000] GIC: Using split EOI/Deactivate mode
[    0.000000] arch_timer: cp15 timer(s) running at 54.00MHz (phys).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff
max_cycles: 0xc743ce346, max_idle_ns: 440795203123 ns
[    0.001377] sched_clock: 56 bits at 54MHz, resolution 18ns, wraps
every 4398046511102ns
[    0.070247] Console: colour dummy device 80x25
[    0.085191] Calibrating delay loop (skipped), value calculated using
timer frequency.. 108.00 BogoMIPS (lpj=216000)
[    0.087407] pid_max: default: 32768 minimum: 301
[    0.118255] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
[    0.120037] Mountpoint-cache hash table entries: 2048 (order: 2,
16384 bytes)
[    0.462960] ASID allocator initialised with 32768 entries
[    0.475367] rcu: Hierarchical SRCU implementation.
[    0.540749] EFI services will not be available.
[    0.563715] smp: Bringing up secondary CPUs ...
[    0.624297] Detected PIPT I-cache on CPU1
[    0.628830] CPU1: Booted secondary processor 0x0000000001 [0x410fd083]
[    0.698386] Detected PIPT I-cache on CPU2
[    0.699334] CPU2: Booted secondary processor 0x0000000002 [0x410fd083]
[    0.752144] Detected PIPT I-cache on CPU3
[    0.753057] CPU3: Booted secondary processor 0x0000000003 [0x410fd083]
[    0.759037] smp: Brought up 1 node, 4 CPUs
[    0.762310] SMP: Total of 4 processors activated.
[    0.763888] CPU features: detected: 32-bit EL0 Support
[    0.819489] CPU: All CPU(s) started at EL2
[    0.826062] alternatives: patching kernel code
[    0.948345] devtmpfs: initialized
[    1.235286] Enabled cp15_barrier support
[    1.237025] Enabled setend support
[    1.253695] clocksource: jiffies: mask: 0xffffffff max_cycles:
0xffffffff, max_idle_ns: 7645041785100000 ns
[    1.255510] futex hash table entries: 1024 (order: 4, 65536 bytes)
[    1.275781] pinctrl core: initialized pinctrl subsystem
[    1.347547] DMI not present or invalid.
[    1.378896] NET: Registered protocol family 16
[    1.439424] cpuidle: using governor menu
[    1.450693] vdso: 2 pages (1 code @ (____ptrval____), 1 data @
(____ptrval____))
[    1.452529] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.

Regards.

Phil.
diff mbox series

Patch

diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 019e67b906..d89d7cd71d 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -21,6 +21,7 @@  struct BCM283XInfo {
     const char *cpu_type;
     hwaddr peri_base; /* Peripheral base address seen by the CPU */
     hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
+    hwaddr gic_base;
     int clusterid;
 };
 
@@ -40,9 +41,25 @@  static const BCM283XInfo bcm283x_socs[] = {
         .ctrl_base = 0x40000000,
         .clusterid = 0x0,
     },
+    {
+        .name = TYPE_BCM2838,
+        .cpu_type = ARM_CPU_TYPE_NAME("cortex-a72"),
+        .peri_base = 0xfe000000,
+        .ctrl_base = 0xff800000,
+        .gic_base = 0x40000,
+    },
 #endif
 };
 
+#define GIC_NUM_IRQS                256
+
+#define GIC_BASE_OFS                0x0000
+#define GIC_DIST_OFS                0x1000
+#define GIC_CPU_OFS                 0x2000
+#define GIC_VIFACE_THIS_OFS         0x4000
+#define GIC_VIFACE_OTHER_OFS(cpu)  (0x5000 + (cpu) * 0x200)
+#define GIC_VCPU_OFS                0x6000
+
 static void bcm2836_init(Object *obj)
 {
     BCM283XState *s = BCM283X(obj);
@@ -55,6 +72,11 @@  static void bcm2836_init(Object *obj)
                                 info->cpu_type, &error_abort, NULL);
     }
 
+    if (info->gic_base) {
+        sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic),
+                              TYPE_ARM_GIC);
+    }
+
     sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control),
                           TYPE_BCM2836_CONTROL);
 
@@ -115,6 +137,59 @@  static void bcm2836_realize(DeviceState *dev, Error **errp)
 
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base);
 
+    /* bcm2838 GICv2 */
+    if (info->gic_base) {
+        object_property_set_uint(OBJECT(&s->gic), 2, "revision", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+
+        object_property_set_uint(OBJECT(&s->gic),
+                                 BCM283X_NCPUS, "num-cpu", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+
+        object_property_set_uint(OBJECT(&s->gic),
+                                 32 + GIC_NUM_IRQS, "num-irq", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+
+        object_property_set_bool(OBJECT(&s->gic),
+                                 true, "has-virtualization-extensions", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+
+        object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0,
+                        info->ctrl_base + info->gic_base + GIC_DIST_OFS);
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1,
+                        info->ctrl_base + info->gic_base + GIC_CPU_OFS);
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 2,
+                        info->ctrl_base + info->gic_base + GIC_VIFACE_THIS_OFS);
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 3,
+                        info->ctrl_base + info->gic_base + GIC_VCPU_OFS);
+
+        for (n = 0; n < BCM283X_NCPUS; n++) {
+            sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 4 + n,
+                            info->ctrl_base + info->gic_base
+                            + GIC_VIFACE_OTHER_OFS(n));
+        }
+
+        /* TODO wire IRQs!!! */
+    }
+
     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
index 97187f72be..31c8fb90bd 100644
--- a/include/hw/arm/bcm2836.h
+++ b/include/hw/arm/bcm2836.h
@@ -13,6 +13,7 @@ 
 
 #include "hw/arm/bcm2835_peripherals.h"
 #include "hw/intc/bcm2836_control.h"
+#include "hw/intc/arm_gic.h"
 #include "target/arm/cpu.h"
 
 #define TYPE_BCM283X "bcm283x"
@@ -26,6 +27,7 @@ 
  */
 #define TYPE_BCM2836 "bcm2836"
 #define TYPE_BCM2837 "bcm2837"
+#define TYPE_BCM2838 "bcm2838"
 
 typedef struct BCM283XState {
     /*< private >*/
@@ -36,6 +38,7 @@  typedef struct BCM283XState {
     uint32_t enabled_cpus;
 
     ARMCPU cpus[BCM283X_NCPUS];
+    GICState gic;
     BCM2836ControlState control;
     BCM2835PeripheralState peripherals;
 } BCM283XState;