1 /* 2 * QEMU PowerPC nest pervasive common chiplet model 3 * 4 * Copyright (c) 2023, IBM Corporation. 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9 #include "qemu/osdep.h" 10 #include "qemu/log.h" 11 #include "hw/qdev-properties.h" 12 #include "hw/ppc/pnv.h" 13 #include "hw/ppc/pnv_xscom.h" 14 #include "hw/ppc/pnv_nest_pervasive.h" 15 16 /* 17 * Status, configuration, and control units in POWER chips is provided 18 * by the pervasive subsystem, which connects registers to the SCOM bus, 19 * which can be programmed by processor cores, other units on the chip, 20 * BMCs, or other POWER chips. 21 * 22 * A POWER10 chip is divided into logical units called chiplets. Chiplets 23 * are broadly divided into "core chiplets" (with the processor cores) and 24 * "nest chiplets" (with everything else). Each chiplet has an attachment 25 * to the pervasive bus (PIB) and with chiplet-specific registers. 26 * All nest chiplets have a common basic set of registers. 27 * 28 * This model will provide the registers functionality for common registers of 29 * nest unit (PB Chiplet, PCI Chiplets, MC Chiplet, PAU Chiplets) 30 * 31 * Currently this model provide the read/write functionality of chiplet control 32 * scom registers. 33 */ 34 35 #define CPLT_CONF0 0x08 36 #define CPLT_CONF0_OR 0x18 37 #define CPLT_CONF0_CLEAR 0x28 38 #define CPLT_CONF1 0x09 39 #define CPLT_CONF1_OR 0x19 40 #define CPLT_CONF1_CLEAR 0x29 41 #define CPLT_STAT0 0x100 42 #define CPLT_MASK0 0x101 43 #define CPLT_PROTECT_MODE 0x3FE 44 #define CPLT_ATOMIC_CLOCK 0x3FF 45 46 static uint64_t pnv_chiplet_ctrl_read(void *opaque, hwaddr addr, unsigned size) 47 { 48 PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE( 49 opaque); 50 uint32_t reg = addr >> 3; 51 uint64_t val = ~0ull; 52 53 /* CPLT_CTRL0 to CPLT_CTRL5 */ 54 for (int i = 0; i < PNV_CPLT_CTRL_SIZE; i++) { 55 if (reg == i) { 56 return nest_pervasive->control_regs.cplt_ctrl[i]; 57 } else if ((reg == (i + 0x10)) || (reg == (i + 0x20))) { 58 qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring " 59 "xscom read at 0x%" PRIx32 "\n", 60 __func__, reg); 61 return val; 62 } 63 } 64 65 switch (reg) { 66 case CPLT_CONF0: 67 val = nest_pervasive->control_regs.cplt_cfg0; 68 break; 69 case CPLT_CONF0_OR: 70 case CPLT_CONF0_CLEAR: 71 qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring " 72 "xscom read at 0x%" PRIx32 "\n", 73 __func__, reg); 74 break; 75 case CPLT_CONF1: 76 val = nest_pervasive->control_regs.cplt_cfg1; 77 break; 78 case CPLT_CONF1_OR: 79 case CPLT_CONF1_CLEAR: 80 qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring " 81 "xscom read at 0x%" PRIx32 "\n", 82 __func__, reg); 83 break; 84 case CPLT_STAT0: 85 val = nest_pervasive->control_regs.cplt_stat0; 86 break; 87 case CPLT_MASK0: 88 val = nest_pervasive->control_regs.cplt_mask0; 89 break; 90 case CPLT_PROTECT_MODE: 91 val = nest_pervasive->control_regs.ctrl_protect_mode; 92 break; 93 case CPLT_ATOMIC_CLOCK: 94 val = nest_pervasive->control_regs.ctrl_atomic_lock; 95 break; 96 default: 97 qemu_log_mask(LOG_UNIMP, "%s: Chiplet_control_regs: Invalid xscom " 98 "read at 0x%" PRIx32 "\n", __func__, reg); 99 } 100 return val; 101 } 102 103 static void pnv_chiplet_ctrl_write(void *opaque, hwaddr addr, 104 uint64_t val, unsigned size) 105 { 106 PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE( 107 opaque); 108 uint32_t reg = addr >> 3; 109 110 /* CPLT_CTRL0 to CPLT_CTRL5 */ 111 for (int i = 0; i < PNV_CPLT_CTRL_SIZE; i++) { 112 if (reg == i) { 113 nest_pervasive->control_regs.cplt_ctrl[i] = val; 114 return; 115 } else if (reg == (i + 0x10)) { 116 nest_pervasive->control_regs.cplt_ctrl[i] |= val; 117 return; 118 } else if (reg == (i + 0x20)) { 119 nest_pervasive->control_regs.cplt_ctrl[i] &= ~val; 120 return; 121 } 122 } 123 124 switch (reg) { 125 case CPLT_CONF0: 126 nest_pervasive->control_regs.cplt_cfg0 = val; 127 break; 128 case CPLT_CONF0_OR: 129 nest_pervasive->control_regs.cplt_cfg0 |= val; 130 break; 131 case CPLT_CONF0_CLEAR: 132 nest_pervasive->control_regs.cplt_cfg0 &= ~val; 133 break; 134 case CPLT_CONF1: 135 nest_pervasive->control_regs.cplt_cfg1 = val; 136 break; 137 case CPLT_CONF1_OR: 138 nest_pervasive->control_regs.cplt_cfg1 |= val; 139 break; 140 case CPLT_CONF1_CLEAR: 141 nest_pervasive->control_regs.cplt_cfg1 &= ~val; 142 break; 143 case CPLT_STAT0: 144 nest_pervasive->control_regs.cplt_stat0 = val; 145 break; 146 case CPLT_MASK0: 147 nest_pervasive->control_regs.cplt_mask0 = val; 148 break; 149 case CPLT_PROTECT_MODE: 150 nest_pervasive->control_regs.ctrl_protect_mode = val; 151 break; 152 case CPLT_ATOMIC_CLOCK: 153 nest_pervasive->control_regs.ctrl_atomic_lock = val; 154 break; 155 default: 156 qemu_log_mask(LOG_UNIMP, "%s: Chiplet_control_regs: Invalid xscom " 157 "write at 0x%" PRIx32 "\n", 158 __func__, reg); 159 } 160 } 161 162 static const MemoryRegionOps pnv_nest_pervasive_control_xscom_ops = { 163 .read = pnv_chiplet_ctrl_read, 164 .write = pnv_chiplet_ctrl_write, 165 .valid.min_access_size = 8, 166 .valid.max_access_size = 8, 167 .impl.min_access_size = 8, 168 .impl.max_access_size = 8, 169 .endianness = DEVICE_BIG_ENDIAN, 170 }; 171 172 static void pnv_nest_pervasive_realize(DeviceState *dev, Error **errp) 173 { 174 PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE(dev); 175 176 /* Chiplet control scoms */ 177 pnv_xscom_region_init(&nest_pervasive->xscom_ctrl_regs_mr, 178 OBJECT(nest_pervasive), 179 &pnv_nest_pervasive_control_xscom_ops, 180 nest_pervasive, "xscom-pervasive-control", 181 PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE); 182 } 183 184 static void pnv_nest_pervasive_class_init(ObjectClass *klass, void *data) 185 { 186 DeviceClass *dc = DEVICE_CLASS(klass); 187 188 dc->desc = "PowerNV nest pervasive chiplet"; 189 dc->realize = pnv_nest_pervasive_realize; 190 } 191 192 static const TypeInfo pnv_nest_pervasive_info = { 193 .name = TYPE_PNV_NEST_CHIPLET_PERVASIVE, 194 .parent = TYPE_DEVICE, 195 .instance_size = sizeof(PnvNestChipletPervasive), 196 .class_init = pnv_nest_pervasive_class_init, 197 .interfaces = (InterfaceInfo[]) { 198 { TYPE_PNV_XSCOM_INTERFACE }, 199 { } 200 } 201 }; 202 203 static void pnv_nest_pervasive_register_types(void) 204 { 205 type_register_static(&pnv_nest_pervasive_info); 206 } 207 208 type_init(pnv_nest_pervasive_register_types); 209