/* * QEMU PowerPC N1 chiplet model * * Copyright (c) 2023, IBM Corporation. * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" #include "qemu/log.h" #include "hw/qdev-properties.h" #include "hw/ppc/pnv.h" #include "hw/ppc/pnv_xscom.h" #include "hw/ppc/pnv_n1_chiplet.h" #include "hw/ppc/pnv_nest_pervasive.h" /* * The n1 chiplet contains chiplet control unit, * PowerBus/RaceTrack/Bridge logic, nest Memory Management Unit(nMMU) * and more. * * In this model Nest1 chiplet control registers are modelled via common * nest pervasive model and few PowerBus racetrack registers are modelled. */ #define PB_SCOM_EQ0_HP_MODE2_CURR 0xe #define PB_SCOM_ES3_MODE 0x8a static uint64_t pnv_n1_chiplet_pb_scom_eq_read(void *opaque, hwaddr addr, unsigned size) { PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(opaque); uint32_t reg = addr >> 3; uint64_t val = ~0ull; switch (reg) { case PB_SCOM_EQ0_HP_MODE2_CURR: val = n1_chiplet->eq[0].hp_mode2_curr; break; default: qemu_log_mask(LOG_UNIMP, "%s: Invalid xscom read at 0x%" PRIx32 "\n", __func__, reg); } return val; } static void pnv_n1_chiplet_pb_scom_eq_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(opaque); uint32_t reg = addr >> 3; switch (reg) { case PB_SCOM_EQ0_HP_MODE2_CURR: n1_chiplet->eq[0].hp_mode2_curr = val; break; default: qemu_log_mask(LOG_UNIMP, "%s: Invalid xscom write at 0x%" PRIx32 "\n", __func__, reg); } } static const MemoryRegionOps pnv_n1_chiplet_pb_scom_eq_ops = { .read = pnv_n1_chiplet_pb_scom_eq_read, .write = pnv_n1_chiplet_pb_scom_eq_write, .valid.min_access_size = 8, .valid.max_access_size = 8, .impl.min_access_size = 8, .impl.max_access_size = 8, .endianness = DEVICE_BIG_ENDIAN, }; static uint64_t pnv_n1_chiplet_pb_scom_es_read(void *opaque, hwaddr addr, unsigned size) { PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(opaque); uint32_t reg = addr >> 3; uint64_t val = ~0ull; switch (reg) { case PB_SCOM_ES3_MODE: val = n1_chiplet->es[3].mode; break; default: qemu_log_mask(LOG_UNIMP, "%s: Invalid xscom read at 0x%" PRIx32 "\n", __func__, reg); } return val; } static void pnv_n1_chiplet_pb_scom_es_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(opaque); uint32_t reg = addr >> 3; switch (reg) { case PB_SCOM_ES3_MODE: n1_chiplet->es[3].mode = val; break; default: qemu_log_mask(LOG_UNIMP, "%s: Invalid xscom write at 0x%" PRIx32 "\n", __func__, reg); } } static const MemoryRegionOps pnv_n1_chiplet_pb_scom_es_ops = { .read = pnv_n1_chiplet_pb_scom_es_read, .write = pnv_n1_chiplet_pb_scom_es_write, .valid.min_access_size = 8, .valid.max_access_size = 8, .impl.min_access_size = 8, .impl.max_access_size = 8, .endianness = DEVICE_BIG_ENDIAN, }; static void pnv_n1_chiplet_realize(DeviceState *dev, Error **errp) { PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(dev); /* Realize nest pervasive common chiplet model */ if (!qdev_realize(DEVICE(&n1_chiplet->nest_pervasive), NULL, errp)) { return; } /* Nest1 chiplet power bus EQ xscom region */ pnv_xscom_region_init(&n1_chiplet->xscom_pb_eq_mr, OBJECT(n1_chiplet), &pnv_n1_chiplet_pb_scom_eq_ops, n1_chiplet, "xscom-n1-chiplet-pb-scom-eq", PNV10_XSCOM_N1_PB_SCOM_EQ_SIZE); /* Nest1 chiplet power bus ES xscom region */ pnv_xscom_region_init(&n1_chiplet->xscom_pb_es_mr, OBJECT(n1_chiplet), &pnv_n1_chiplet_pb_scom_es_ops, n1_chiplet, "xscom-n1-chiplet-pb-scom-es", PNV10_XSCOM_N1_PB_SCOM_ES_SIZE); } static void pnv_n1_chiplet_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->desc = "PowerNV n1 chiplet"; dc->realize = pnv_n1_chiplet_realize; } static void pnv_n1_chiplet_instance_init(Object *obj) { PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(obj); object_initialize_child(OBJECT(n1_chiplet), "nest-pervasive-common", &n1_chiplet->nest_pervasive, TYPE_PNV_NEST_CHIPLET_PERVASIVE); } static const TypeInfo pnv_n1_chiplet_info = { .name = TYPE_PNV_N1_CHIPLET, .parent = TYPE_DEVICE, .instance_init = pnv_n1_chiplet_instance_init, .instance_size = sizeof(PnvN1Chiplet), .class_init = pnv_n1_chiplet_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } }; static void pnv_n1_chiplet_register_types(void) { type_register_static(&pnv_n1_chiplet_info); } type_init(pnv_n1_chiplet_register_types);