pnv_dt_lpc(chip, fdt, 0);
}
+static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
+{
+ int i;
+
+ pnv_dt_xscom(chip, fdt, 0);
+
+ for (i = 0; i < chip->nr_cores; i++) {
+ PnvCore *pnv_core = chip->cores[i];
+
+ pnv_dt_core(chip, pnv_core, fdt);
+ }
+
+ if (chip->ram_size) {
+ pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
+ }
+}
+
static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
{
uint32_t io_base = d->ioport_id;
{
const char plat_compat8[] = "qemu,powernv8\0qemu,powernv\0ibm,powernv";
const char plat_compat9[] = "qemu,powernv9\0ibm,powernv";
+ const char plat_compat10[] = "qemu,powernv10\0ibm,powernv";
PnvMachineState *pnv = PNV_MACHINE(machine);
void *fdt;
char *buf;
_FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
_FDT((fdt_setprop_string(fdt, 0, "model",
"IBM PowerNV (emulated by qemu)")));
- if (pnv_is_power9(pnv)) {
+ if (pnv_is_power10(pnv)) {
+ _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat10,
+ sizeof(plat_compat10))));
+ } else if (pnv_is_power9(pnv)) {
_FDT((fdt_setprop(fdt, 0, "compatible", plat_compat9,
sizeof(plat_compat9))));
} else {
pnv_dt_bmc_sensors(pnv->bmc, fdt);
}
- /* Create an extra node for power management on Power9 */
- if (pnv_is_power9(pnv)) {
+ /* Create an extra node for power management on Power9 and Power10 */
+ if (pnv_is_power9(pnv) || pnv_is_power10(pnv)) {
pnv_dt_power_mgt(fdt);
}
return pnv_lpc_isa_create(&chip9->lpc, false, errp);
}
+static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp)
+{
+ error_setg(errp, "No ISA bus!");
+ return NULL;
+}
+
static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
{
return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
object_property_set_bool(obj, true, "realized", &error_fatal);
}
+static void pnv_chip_power10_pic_print_info(PnvChip *chip, Monitor *mon)
+{
+ /*
+ * No interrupt controller yet
+ */;
+}
+
static void pnv_init(MachineState *machine)
{
PnvMachineState *pnv = PNV_MACHINE(machine);
return (chip->chip_id << 8) | (core_id << 2);
}
+static uint32_t pnv_chip_core_pir_p10(PnvChip *chip, uint32_t core_id)
+{
+ return (chip->chip_id << 8) | (core_id << 2);
+}
+
static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
Error **errp)
{
pnv_cpu->intc = NULL;
}
+static void pnv_chip_power10_intc_create(PnvChip *chip, PowerPCCPU *cpu,
+ Error **errp)
+{
+ PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
+
+ /* Will be defined when the interrupt controller is */
+ pnv_cpu->intc = NULL;
+}
+
+static void pnv_chip_power10_intc_reset(PnvChip *chip, PowerPCCPU *cpu)
+{
+ ;
+}
+
+static void pnv_chip_power10_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
+{
+ PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
+
+ pnv_cpu->intc = NULL;
+}
+
/*
* Allowed core identifiers on a POWER8 Processor Chip :
*
*/
#define POWER9_CORE_MASK (0xffffffffffffffull)
+
+#define POWER10_CORE_MASK (0xffffffffffffffull)
+
static void pnv_chip_power8_instance_init(Object *obj)
{
Pnv8Chip *chip8 = PNV8_CHIP(obj);
&k->parent_realize);
}
+static void pnv_chip_power10_instance_init(Object *obj)
+{
+ /*
+ * No controllers yet
+ */
+ ;
+}
+
+static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
+{
+ PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
+ PnvChip *chip = PNV_CHIP(dev);
+ Error *local_err = NULL;
+
+ /* XSCOM bridge is first */
+ pnv_xscom_realize(chip, PNV10_XSCOM_SIZE, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV10_XSCOM_BASE(chip));
+
+ pcc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+}
+
+static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PnvChipClass *k = PNV_CHIP_CLASS(klass);
+
+ k->chip_type = PNV_CHIP_POWER10;
+ k->chip_cfam_id = 0x120da04900008000ull; /* P10 DD1.0 (with NX) */
+ k->cores_mask = POWER10_CORE_MASK;
+ k->core_pir = pnv_chip_core_pir_p10;
+ k->intc_create = pnv_chip_power10_intc_create;
+ k->intc_reset = pnv_chip_power10_intc_reset;
+ k->intc_destroy = pnv_chip_power10_intc_destroy;
+ k->isa_create = pnv_chip_power10_isa_create;
+ k->dt_populate = pnv_chip_power10_dt_populate;
+ k->pic_print_info = pnv_chip_power10_pic_print_info;
+ dc->desc = "PowerNV Chip POWER10";
+
+ device_class_set_parent_realize(dc, pnv_chip_power10_realize,
+ &k->parent_realize);
+}
+
static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
{
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
&error_fatal);
/* Each core has an XSCOM MMIO region */
- if (!pnv_chip_is_power9(chip)) {
- xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
- } else {
+ if (pnv_chip_is_power10(chip)) {
+ xscom_core_base = PNV10_XSCOM_EC_BASE(core_hwid);
+ } else if (pnv_chip_is_power9(chip)) {
xscom_core_base = PNV9_XSCOM_EC_BASE(core_hwid);
+ } else {
+ xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
}
pnv_xscom_add_subregion(chip, xscom_core_base,
mc->alias = "powernv";
}
+static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v1.0");
+}
+
static void pnv_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
.parent = TYPE_PNV9_CHIP, \
}
+#define DEFINE_PNV10_CHIP_TYPE(type, class_initfn) \
+ { \
+ .name = type, \
+ .class_init = class_initfn, \
+ .parent = TYPE_PNV10_CHIP, \
+ }
+
static const TypeInfo types[] = {
+ {
+ .name = MACHINE_TYPE_NAME("powernv10"),
+ .parent = TYPE_PNV_MACHINE,
+ .class_init = pnv_machine_power10_class_init,
+ },
{
.name = MACHINE_TYPE_NAME("powernv9"),
.parent = TYPE_PNV_MACHINE,
.abstract = true,
},
+ /*
+ * P10 chip and variants
+ */
+ {
+ .name = TYPE_PNV10_CHIP,
+ .parent = TYPE_PNV_CHIP,
+ .instance_init = pnv_chip_power10_instance_init,
+ .instance_size = sizeof(Pnv10Chip),
+ },
+ DEFINE_PNV10_CHIP_TYPE(TYPE_PNV_CHIP_POWER10, pnv_chip_power10_class_init),
+
/*
* P9 chip and variants
*/
{
addr &= (PNV_XSCOM_SIZE - 1);
- if (pnv_chip_is_power9(chip)) {
- return addr >> 3;
- } else {
+ switch (PNV_CHIP_GET_CLASS(chip)->chip_type) {
+ case PNV_CHIP_POWER8E:
+ case PNV_CHIP_POWER8:
+ case PNV_CHIP_POWER8NVL:
return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
+ case PNV_CHIP_POWER9:
+ case PNV_CHIP_POWER10:
+ return addr >> 3;
+ default:
+ g_assert_not_reached();
}
}
static const char compat_p8[] = "ibm,power8-xscom\0ibm,xscom";
static const char compat_p9[] = "ibm,power9-xscom\0ibm,xscom";
+static const char compat_p10[] = "ibm,power10-xscom\0ibm,xscom";
int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
{
ForeachPopulateArgs args;
char *name;
- if (pnv_chip_is_power9(chip)) {
+ if (pnv_chip_is_power10(chip)) {
+ reg[0] = cpu_to_be64(PNV10_XSCOM_BASE(chip));
+ reg[1] = cpu_to_be64(PNV10_XSCOM_SIZE);
+ } else if (pnv_chip_is_power9(chip)) {
reg[0] = cpu_to_be64(PNV9_XSCOM_BASE(chip));
reg[1] = cpu_to_be64(PNV9_XSCOM_SIZE);
} else {
_FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
_FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
- if (pnv_chip_is_power9(chip)) {
+ if (pnv_chip_is_power10(chip)) {
+ _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p10,
+ sizeof(compat_p10))));
+ } else if (pnv_chip_is_power9(chip)) {
_FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p9,
sizeof(compat_p9))));
} else {
PNV_CHIP_POWER8, /* AKA Venice */
PNV_CHIP_POWER8NVL, /* AKA Naples */
PNV_CHIP_POWER9, /* AKA Nimbus */
+ PNV_CHIP_POWER10, /* AKA TBD */
} PnvChipType;
typedef struct PnvChip {
#define PNV9_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf)
#define PNV9_PIR2CHIP(pir) (((pir) >> 8) & 0x7f)
+#define TYPE_PNV10_CHIP "pnv10-chip"
+#define PNV10_CHIP(obj) OBJECT_CHECK(Pnv10Chip, (obj), TYPE_PNV10_CHIP)
+
+typedef struct Pnv10Chip {
+ /*< private >*/
+ PnvChip parent_obj;
+} Pnv10Chip;
+
typedef struct PnvChipClass {
/*< private >*/
SysBusDeviceClass parent_class;
#define PNV_CHIP_POWER9(obj) \
OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP_POWER9)
+#define TYPE_PNV_CHIP_POWER10 PNV_CHIP_TYPE_NAME("power10_v1.0")
+#define PNV_CHIP_POWER10(obj) \
+ OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP_POWER10)
+
/*
* This generates a HW chip id depending on an index, as found on a
* two socket system with dual chip modules :
#define PNV_FDT_ADDR 0x01000000
#define PNV_TIMEBASE_FREQ 512000000ULL
+static inline bool pnv_chip_is_power10(const PnvChip *chip)
+{
+ return PNV_CHIP_GET_CLASS(chip)->chip_type == PNV_CHIP_POWER10;
+}
+
+static inline bool pnv_is_power10(PnvMachineState *pnv)
+{
+ return pnv_chip_is_power10(pnv->chips[0]);
+}
+
/*
* BMC helpers
*/
#define PNV9_HOMER_SIZE 0x0000000000300000ull
#define PNV9_HOMER_BASE(chip) \
(0x203ffd800000ull + ((uint64_t)PNV_CHIP_INDEX(chip)) * PNV9_HOMER_SIZE)
+
+/*
+ * POWER10 MMIO base addresses - 16TB stride per chip
+ */
+#define PNV10_CHIP_BASE(chip, base) \
+ ((base) + ((uint64_t) (chip)->chip_id << 44))
+
+#define PNV10_XSCOM_SIZE 0x0000000400000000ull
+#define PNV10_XSCOM_BASE(chip) PNV10_CHIP_BASE(chip, 0x00603fc00000000ull)
+
#endif /* PPC_PNV_H */