11adf2470SChalapathi V /* 21adf2470SChalapathi V * QEMU PowerPC nest pervasive common chiplet model 31adf2470SChalapathi V * 41adf2470SChalapathi V * Copyright (c) 2023, IBM Corporation. 51adf2470SChalapathi V * 61adf2470SChalapathi V * SPDX-License-Identifier: GPL-2.0-or-later 71adf2470SChalapathi V */ 81adf2470SChalapathi V 91adf2470SChalapathi V #include "qemu/osdep.h" 101adf2470SChalapathi V #include "qemu/log.h" 111adf2470SChalapathi V #include "hw/qdev-properties.h" 121adf2470SChalapathi V #include "hw/ppc/pnv.h" 131adf2470SChalapathi V #include "hw/ppc/pnv_xscom.h" 141adf2470SChalapathi V #include "hw/ppc/pnv_nest_pervasive.h" 151adf2470SChalapathi V 161adf2470SChalapathi V /* 171adf2470SChalapathi V * Status, configuration, and control units in POWER chips is provided 181adf2470SChalapathi V * by the pervasive subsystem, which connects registers to the SCOM bus, 191adf2470SChalapathi V * which can be programmed by processor cores, other units on the chip, 201adf2470SChalapathi V * BMCs, or other POWER chips. 211adf2470SChalapathi V * 221adf2470SChalapathi V * A POWER10 chip is divided into logical units called chiplets. Chiplets 231adf2470SChalapathi V * are broadly divided into "core chiplets" (with the processor cores) and 241adf2470SChalapathi V * "nest chiplets" (with everything else). Each chiplet has an attachment 251adf2470SChalapathi V * to the pervasive bus (PIB) and with chiplet-specific registers. 261adf2470SChalapathi V * All nest chiplets have a common basic set of registers. 271adf2470SChalapathi V * 281adf2470SChalapathi V * This model will provide the registers functionality for common registers of 291adf2470SChalapathi V * nest unit (PB Chiplet, PCI Chiplets, MC Chiplet, PAU Chiplets) 301adf2470SChalapathi V * 311adf2470SChalapathi V * Currently this model provide the read/write functionality of chiplet control 321adf2470SChalapathi V * scom registers. 331adf2470SChalapathi V */ 341adf2470SChalapathi V 351adf2470SChalapathi V #define CPLT_CONF0 0x08 361adf2470SChalapathi V #define CPLT_CONF0_OR 0x18 371adf2470SChalapathi V #define CPLT_CONF0_CLEAR 0x28 381adf2470SChalapathi V #define CPLT_CONF1 0x09 391adf2470SChalapathi V #define CPLT_CONF1_OR 0x19 401adf2470SChalapathi V #define CPLT_CONF1_CLEAR 0x29 411adf2470SChalapathi V #define CPLT_STAT0 0x100 421adf2470SChalapathi V #define CPLT_MASK0 0x101 431adf2470SChalapathi V #define CPLT_PROTECT_MODE 0x3FE 441adf2470SChalapathi V #define CPLT_ATOMIC_CLOCK 0x3FF 451adf2470SChalapathi V 461adf2470SChalapathi V static uint64_t pnv_chiplet_ctrl_read(void *opaque, hwaddr addr, unsigned size) 471adf2470SChalapathi V { 481adf2470SChalapathi V PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE( 491adf2470SChalapathi V opaque); 501adf2470SChalapathi V uint32_t reg = addr >> 3; 511adf2470SChalapathi V uint64_t val = ~0ull; 521adf2470SChalapathi V 531adf2470SChalapathi V /* CPLT_CTRL0 to CPLT_CTRL5 */ 541adf2470SChalapathi V for (int i = 0; i < PNV_CPLT_CTRL_SIZE; i++) { 551adf2470SChalapathi V if (reg == i) { 561adf2470SChalapathi V return nest_pervasive->control_regs.cplt_ctrl[i]; 571adf2470SChalapathi V } else if ((reg == (i + 0x10)) || (reg == (i + 0x20))) { 581adf2470SChalapathi V qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring " 591adf2470SChalapathi V "xscom read at 0x%" PRIx32 "\n", 601adf2470SChalapathi V __func__, reg); 611adf2470SChalapathi V return val; 621adf2470SChalapathi V } 631adf2470SChalapathi V } 641adf2470SChalapathi V 651adf2470SChalapathi V switch (reg) { 661adf2470SChalapathi V case CPLT_CONF0: 671adf2470SChalapathi V val = nest_pervasive->control_regs.cplt_cfg0; 681adf2470SChalapathi V break; 691adf2470SChalapathi V case CPLT_CONF0_OR: 701adf2470SChalapathi V case CPLT_CONF0_CLEAR: 711adf2470SChalapathi V qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring " 721adf2470SChalapathi V "xscom read at 0x%" PRIx32 "\n", 731adf2470SChalapathi V __func__, reg); 741adf2470SChalapathi V break; 751adf2470SChalapathi V case CPLT_CONF1: 761adf2470SChalapathi V val = nest_pervasive->control_regs.cplt_cfg1; 771adf2470SChalapathi V break; 781adf2470SChalapathi V case CPLT_CONF1_OR: 791adf2470SChalapathi V case CPLT_CONF1_CLEAR: 801adf2470SChalapathi V qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring " 811adf2470SChalapathi V "xscom read at 0x%" PRIx32 "\n", 821adf2470SChalapathi V __func__, reg); 831adf2470SChalapathi V break; 841adf2470SChalapathi V case CPLT_STAT0: 851adf2470SChalapathi V val = nest_pervasive->control_regs.cplt_stat0; 861adf2470SChalapathi V break; 871adf2470SChalapathi V case CPLT_MASK0: 881adf2470SChalapathi V val = nest_pervasive->control_regs.cplt_mask0; 891adf2470SChalapathi V break; 901adf2470SChalapathi V case CPLT_PROTECT_MODE: 911adf2470SChalapathi V val = nest_pervasive->control_regs.ctrl_protect_mode; 921adf2470SChalapathi V break; 931adf2470SChalapathi V case CPLT_ATOMIC_CLOCK: 941adf2470SChalapathi V val = nest_pervasive->control_regs.ctrl_atomic_lock; 951adf2470SChalapathi V break; 961adf2470SChalapathi V default: 971adf2470SChalapathi V qemu_log_mask(LOG_UNIMP, "%s: Chiplet_control_regs: Invalid xscom " 981adf2470SChalapathi V "read at 0x%" PRIx32 "\n", __func__, reg); 991adf2470SChalapathi V } 1001adf2470SChalapathi V return val; 1011adf2470SChalapathi V } 1021adf2470SChalapathi V 1031adf2470SChalapathi V static void pnv_chiplet_ctrl_write(void *opaque, hwaddr addr, 1041adf2470SChalapathi V uint64_t val, unsigned size) 1051adf2470SChalapathi V { 1061adf2470SChalapathi V PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE( 1071adf2470SChalapathi V opaque); 1081adf2470SChalapathi V uint32_t reg = addr >> 3; 1091adf2470SChalapathi V 1101adf2470SChalapathi V /* CPLT_CTRL0 to CPLT_CTRL5 */ 1111adf2470SChalapathi V for (int i = 0; i < PNV_CPLT_CTRL_SIZE; i++) { 1121adf2470SChalapathi V if (reg == i) { 1131adf2470SChalapathi V nest_pervasive->control_regs.cplt_ctrl[i] = val; 1141adf2470SChalapathi V return; 1151adf2470SChalapathi V } else if (reg == (i + 0x10)) { 1161adf2470SChalapathi V nest_pervasive->control_regs.cplt_ctrl[i] |= val; 1171adf2470SChalapathi V return; 1181adf2470SChalapathi V } else if (reg == (i + 0x20)) { 1191adf2470SChalapathi V nest_pervasive->control_regs.cplt_ctrl[i] &= ~val; 1201adf2470SChalapathi V return; 1211adf2470SChalapathi V } 1221adf2470SChalapathi V } 1231adf2470SChalapathi V 1241adf2470SChalapathi V switch (reg) { 1251adf2470SChalapathi V case CPLT_CONF0: 1261adf2470SChalapathi V nest_pervasive->control_regs.cplt_cfg0 = val; 1271adf2470SChalapathi V break; 1281adf2470SChalapathi V case CPLT_CONF0_OR: 1291adf2470SChalapathi V nest_pervasive->control_regs.cplt_cfg0 |= val; 1301adf2470SChalapathi V break; 1311adf2470SChalapathi V case CPLT_CONF0_CLEAR: 1321adf2470SChalapathi V nest_pervasive->control_regs.cplt_cfg0 &= ~val; 1331adf2470SChalapathi V break; 1341adf2470SChalapathi V case CPLT_CONF1: 1351adf2470SChalapathi V nest_pervasive->control_regs.cplt_cfg1 = val; 1361adf2470SChalapathi V break; 1371adf2470SChalapathi V case CPLT_CONF1_OR: 1381adf2470SChalapathi V nest_pervasive->control_regs.cplt_cfg1 |= val; 1391adf2470SChalapathi V break; 1401adf2470SChalapathi V case CPLT_CONF1_CLEAR: 1411adf2470SChalapathi V nest_pervasive->control_regs.cplt_cfg1 &= ~val; 1421adf2470SChalapathi V break; 1431adf2470SChalapathi V case CPLT_STAT0: 1441adf2470SChalapathi V nest_pervasive->control_regs.cplt_stat0 = val; 1451adf2470SChalapathi V break; 1461adf2470SChalapathi V case CPLT_MASK0: 1471adf2470SChalapathi V nest_pervasive->control_regs.cplt_mask0 = val; 1481adf2470SChalapathi V break; 1491adf2470SChalapathi V case CPLT_PROTECT_MODE: 1501adf2470SChalapathi V nest_pervasive->control_regs.ctrl_protect_mode = val; 1511adf2470SChalapathi V break; 1521adf2470SChalapathi V case CPLT_ATOMIC_CLOCK: 1531adf2470SChalapathi V nest_pervasive->control_regs.ctrl_atomic_lock = val; 1541adf2470SChalapathi V break; 1551adf2470SChalapathi V default: 1561adf2470SChalapathi V qemu_log_mask(LOG_UNIMP, "%s: Chiplet_control_regs: Invalid xscom " 1571adf2470SChalapathi V "write at 0x%" PRIx32 "\n", 1581adf2470SChalapathi V __func__, reg); 1591adf2470SChalapathi V } 1601adf2470SChalapathi V } 1611adf2470SChalapathi V 1621adf2470SChalapathi V static const MemoryRegionOps pnv_nest_pervasive_control_xscom_ops = { 1631adf2470SChalapathi V .read = pnv_chiplet_ctrl_read, 1641adf2470SChalapathi V .write = pnv_chiplet_ctrl_write, 1651adf2470SChalapathi V .valid.min_access_size = 8, 1661adf2470SChalapathi V .valid.max_access_size = 8, 1671adf2470SChalapathi V .impl.min_access_size = 8, 1681adf2470SChalapathi V .impl.max_access_size = 8, 1691adf2470SChalapathi V .endianness = DEVICE_BIG_ENDIAN, 1701adf2470SChalapathi V }; 1711adf2470SChalapathi V 1721adf2470SChalapathi V static void pnv_nest_pervasive_realize(DeviceState *dev, Error **errp) 1731adf2470SChalapathi V { 1741adf2470SChalapathi V PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE(dev); 1751adf2470SChalapathi V 1761adf2470SChalapathi V /* Chiplet control scoms */ 1771adf2470SChalapathi V pnv_xscom_region_init(&nest_pervasive->xscom_ctrl_regs_mr, 1781adf2470SChalapathi V OBJECT(nest_pervasive), 1791adf2470SChalapathi V &pnv_nest_pervasive_control_xscom_ops, 180*5e398149SNicholas Piggin nest_pervasive, "xscom-pervasive-control", 1811adf2470SChalapathi V PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE); 1821adf2470SChalapathi V } 1831adf2470SChalapathi V 1841adf2470SChalapathi V static void pnv_nest_pervasive_class_init(ObjectClass *klass, void *data) 1851adf2470SChalapathi V { 1861adf2470SChalapathi V DeviceClass *dc = DEVICE_CLASS(klass); 1871adf2470SChalapathi V 1881adf2470SChalapathi V dc->desc = "PowerNV nest pervasive chiplet"; 1891adf2470SChalapathi V dc->realize = pnv_nest_pervasive_realize; 1901adf2470SChalapathi V } 1911adf2470SChalapathi V 1921adf2470SChalapathi V static const TypeInfo pnv_nest_pervasive_info = { 1931adf2470SChalapathi V .name = TYPE_PNV_NEST_CHIPLET_PERVASIVE, 1941adf2470SChalapathi V .parent = TYPE_DEVICE, 1951adf2470SChalapathi V .instance_size = sizeof(PnvNestChipletPervasive), 1961adf2470SChalapathi V .class_init = pnv_nest_pervasive_class_init, 1971adf2470SChalapathi V .interfaces = (InterfaceInfo[]) { 1981adf2470SChalapathi V { TYPE_PNV_XSCOM_INTERFACE }, 1991adf2470SChalapathi V { } 2001adf2470SChalapathi V } 2011adf2470SChalapathi V }; 2021adf2470SChalapathi V 2031adf2470SChalapathi V static void pnv_nest_pervasive_register_types(void) 2041adf2470SChalapathi V { 2051adf2470SChalapathi V type_register_static(&pnv_nest_pervasive_info); 2061adf2470SChalapathi V } 2071adf2470SChalapathi V 2081adf2470SChalapathi V type_init(pnv_nest_pervasive_register_types); 209