On 3/9/26 13:24, Bin Meng wrote:
Add the base topology for the Phytium Pi board built around the
E2000Q SoC, with two FTC310 and two FTC664 CPUs, RAM, GICv3/ITS,
and PL011 UARTs.
Describe the CPUs as three non-uniform clusters matching the vendor
Linux device tree. Preserve the board CPU slot order so firmware
MPIDR 0x200 maps to QEMU CPU index 2.
Signed-off-by: Bin Meng <[email protected]>
---
hw/arm/Kconfig | 8 +
hw/arm/meson.build | 1 +
hw/arm/phytium_e2000.c | 406 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 415 insertions(+)
create mode 100644 hw/arm/phytium_e2000.c
+struct PhytiumE2000State {
+ MachineState parent;
+ struct arm_boot_info bootinfo;
+ DeviceState *gic;
+ MemoryRegion ram_low;
+ MemoryRegion ram_high;
+};
+static void phytium_e2000_create_gic(PhytiumE2000State *s)
+{
+ MachineState *ms = MACHINE(s);
+ SysBusDevice *gicbusdev;
+ QList *redist_region_count;
+ int i;
+
+ s->gic = qdev_new(gicv3_class_name());
+ qdev_prop_set_uint32(s->gic, "revision", 3);
+ qdev_prop_set_uint32(s->gic, "num-cpu", ms->smp.cpus);
+ qdev_prop_set_uint32(s->gic, "num-irq", PHYTIUM_E2000_NUM_IRQS + 32);
+ qdev_prop_set_bit(s->gic, "has-security-extensions", true);
+ qdev_prop_set_bit(s->gic, "has-lpi", true);
+
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, ms->smp.cpus);
+ qdev_prop_set_array(s->gic, "redist-region-count", redist_region_count);
+
+ object_property_set_link(OBJECT(s->gic), "sysmem",
+ OBJECT(get_system_memory()), &error_fatal);
+
+ gicbusdev = SYS_BUS_DEVICE(s->gic);
+ sysbus_realize_and_unref(gicbusdev, &error_fatal);
+ sysbus_mmio_map(gicbusdev, 0,
+ phytium_e2000_memmap[PHYTIUM_E2000_GIC_DIST].base);
+ sysbus_mmio_map(gicbusdev, 1,
+ phytium_e2000_memmap[PHYTIUM_E2000_GIC_REDIST].base);
+
+ for (i = 0; i < ms->smp.cpus; i++) {
+ DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
I'd rather you keep a reference in PhytiumE2000State when creating
in [*] and access the CPUs that way, not with qemu_get_cpu() (because
we plan to restrict it to accel/, as it is problematic on heterogeneous
emulation).
+ int intidbase = PHYTIUM_E2000_NUM_IRQS + i * GIC_INTERNAL;
+ static const int timer_irq[] = {
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
+ };
+
+ for (int irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
+ qdev_connect_gpio_out(cpudev, irq,
+ qdev_get_gpio_in(s->gic, intidbase + timer_irq[irq]));
+ }
+ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0,
+ qdev_get_gpio_in(s->gic, intidbase + ARCH_GIC_MAINT_IRQ));
+ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
+ qdev_get_gpio_in(s->gic, intidbase + VIRTUAL_PMU_IRQ));
+
+ sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev,
ARM_CPU_IRQ));
+ sysbus_connect_irq(gicbusdev, i + ms->smp.cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+ sysbus_connect_irq(gicbusdev, i + 2 * ms->smp.cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
+ sysbus_connect_irq(gicbusdev, i + 3 * ms->smp.cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+ }
+
+ phytium_e2000_create_its(s);
+}
+static void phytium_e2000_create_cpus(PhytiumE2000State *s)
+{
+ MachineState *ms = MACHINE(s);
+ const CPUArchIdList *possible_cpus;
+ int i;
+
+ possible_cpus = MACHINE_GET_CLASS(ms)->possible_cpu_arch_ids(ms);
+
+ for (i = 0; i < ms->smp.cpus; i++) {
+ Object *cpuobj = object_new(possible_cpus->cpus[i].type);
[*]
+ CPUState *cs;
+
+ object_property_set_int(cpuobj, "mp-affinity",
+ possible_cpus->cpus[i].arch_id,
+ &error_abort);
+ object_property_set_int(cpuobj, "cntfrq", PHYTIUM_E2000_GTIMER_HZ,
+ &error_abort);
+ if (object_property_find(cpuobj, "has_el3")) {
+ /*
+ * The generic-loader U-Boot path starts after the EL3 firmware
+ * stages that normally provide the Phytium SMC services.
+ */
+ object_property_set_bool(cpuobj, "has_el3", false, &error_abort);
+ }
+ object_property_set_link(cpuobj, "memory", OBJECT(get_system_memory()),
+ &error_abort);
+ cs = CPU(cpuobj);
+ cs->cpu_index = i;
+ qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
+ object_unref(cpuobj);
+ }
+}
+
+static void phytium_pi_init(MachineState *ms)
+{
+ PhytiumE2000State *s = PHYTIUM_PI(ms);
+ int i;
+
+ if (kvm_enabled()) {
+ error_report("phytium-pi: KVM is not supported");
Why is it relevant?
+ exit(1);
+ }
+}
Conditional to not using qemu_get_cpu():
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>