1 /* 2 * QEMU PowerPC PowerNV Emulation of a few HOMER related registers 3 * 4 * Copyright (c) 2019, IBM Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License, version 2, as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "qemu/osdep.h" 20 #include "qapi/error.h" 21 #include "exec/hwaddr.h" 22 #include "exec/memory.h" 23 #include "sysemu/cpus.h" 24 #include "hw/qdev-core.h" 25 #include "hw/qdev-properties.h" 26 #include "hw/ppc/pnv.h" 27 #include "hw/ppc/pnv_homer.h" 28 29 30 static bool core_max_array(PnvHomer *homer, hwaddr addr) 31 { 32 int i; 33 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); 34 35 for (i = 0; i <= homer->chip->nr_cores; i++) { 36 if (addr == (hmrc->core_max_base + i)) { 37 return true; 38 } 39 } 40 return false; 41 } 42 43 /* P8 Pstate table */ 44 45 #define PNV8_OCC_PSTATE_VERSION 0x1f8001 46 #define PNV8_OCC_PSTATE_MIN 0x1f8003 47 #define PNV8_OCC_PSTATE_VALID 0x1f8000 48 #define PNV8_OCC_PSTATE_THROTTLE 0x1f8002 49 #define PNV8_OCC_PSTATE_NOM 0x1f8004 50 #define PNV8_OCC_PSTATE_TURBO 0x1f8005 51 #define PNV8_OCC_PSTATE_ULTRA_TURBO 0x1f8006 52 #define PNV8_OCC_PSTATE_DATA 0x1f8008 53 #define PNV8_OCC_PSTATE_ID_ZERO 0x1f8010 54 #define PNV8_OCC_PSTATE_ID_ONE 0x1f8018 55 #define PNV8_OCC_PSTATE_ID_TWO 0x1f8020 56 #define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER 0x1f8012 57 #define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER 0x1f8013 58 #define PNV8_OCC_PSTATE_ZERO_FREQUENCY 0x1f8014 59 #define PNV8_OCC_PSTATE_ONE_FREQUENCY 0x1f801c 60 #define PNV8_OCC_PSTATE_TWO_FREQUENCY 0x1f8024 61 #define PNV8_CORE_MAX_BASE 0x1f8810 62 63 64 static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr, 65 unsigned size) 66 { 67 PnvHomer *homer = PNV_HOMER(opaque); 68 69 switch (addr) { 70 case PNV8_OCC_PSTATE_VERSION: 71 case PNV8_OCC_PSTATE_MIN: 72 case PNV8_OCC_PSTATE_ID_ZERO: 73 return 0; 74 case PNV8_OCC_PSTATE_VALID: 75 case PNV8_OCC_PSTATE_THROTTLE: 76 case PNV8_OCC_PSTATE_NOM: 77 case PNV8_OCC_PSTATE_TURBO: 78 case PNV8_OCC_PSTATE_ID_ONE: 79 case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER: 80 case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER: 81 return 1; 82 case PNV8_OCC_PSTATE_ULTRA_TURBO: 83 case PNV8_OCC_PSTATE_ID_TWO: 84 return 2; 85 case PNV8_OCC_PSTATE_DATA: 86 return 0x1000000000000000; 87 /* P8 frequency for 0, 1, and 2 pstates */ 88 case PNV8_OCC_PSTATE_ZERO_FREQUENCY: 89 case PNV8_OCC_PSTATE_ONE_FREQUENCY: 90 case PNV8_OCC_PSTATE_TWO_FREQUENCY: 91 return 3000; 92 } 93 /* pstate table core max array */ 94 if (core_max_array(homer, addr)) { 95 return 1; 96 } 97 return 0; 98 } 99 100 static void pnv_power8_homer_write(void *opaque, hwaddr addr, 101 uint64_t val, unsigned size) 102 { 103 /* callback function defined to homer write */ 104 return; 105 } 106 107 static const MemoryRegionOps pnv_power8_homer_ops = { 108 .read = pnv_power8_homer_read, 109 .write = pnv_power8_homer_write, 110 .valid.min_access_size = 1, 111 .valid.max_access_size = 8, 112 .impl.min_access_size = 1, 113 .impl.max_access_size = 8, 114 .endianness = DEVICE_BIG_ENDIAN, 115 }; 116 117 static void pnv_homer_power8_class_init(ObjectClass *klass, void *data) 118 { 119 PnvHomerClass *homer = PNV_HOMER_CLASS(klass); 120 121 homer->homer_size = PNV_HOMER_SIZE; 122 homer->homer_ops = &pnv_power8_homer_ops; 123 homer->core_max_base = PNV8_CORE_MAX_BASE; 124 } 125 126 static const TypeInfo pnv_homer_power8_type_info = { 127 .name = TYPE_PNV8_HOMER, 128 .parent = TYPE_PNV_HOMER, 129 .instance_size = sizeof(PnvHomer), 130 .class_init = pnv_homer_power8_class_init, 131 }; 132 133 /* P9 Pstate table */ 134 135 #define PNV9_OCC_PSTATE_ID_ZERO 0xe2018 136 #define PNV9_OCC_PSTATE_ID_ONE 0xe2020 137 #define PNV9_OCC_PSTATE_ID_TWO 0xe2028 138 #define PNV9_OCC_PSTATE_DATA 0xe2000 139 #define PNV9_OCC_PSTATE_DATA_AREA 0xe2008 140 #define PNV9_OCC_PSTATE_MIN 0xe2003 141 #define PNV9_OCC_PSTATE_NOM 0xe2004 142 #define PNV9_OCC_PSTATE_TURBO 0xe2005 143 #define PNV9_OCC_PSTATE_ULTRA_TURBO 0xe2818 144 #define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO 0xe2006 145 #define PNV9_OCC_PSTATE_MAJOR_VERSION 0xe2001 146 #define PNV9_OCC_OPAL_RUNTIME_DATA 0xe2b85 147 #define PNV9_CHIP_HOMER_IMAGE_POINTER 0x200008 148 #define PNV9_CHIP_HOMER_BASE 0x0 149 #define PNV9_OCC_PSTATE_ZERO_FREQUENCY 0xe201c 150 #define PNV9_OCC_PSTATE_ONE_FREQUENCY 0xe2024 151 #define PNV9_OCC_PSTATE_TWO_FREQUENCY 0xe202c 152 #define PNV9_OCC_ROLE_MASTER_OR_SLAVE 0xe2002 153 #define PNV9_CORE_MAX_BASE 0xe2819 154 155 156 static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr, 157 unsigned size) 158 { 159 PnvHomer *homer = PNV_HOMER(opaque); 160 161 switch (addr) { 162 case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO: 163 case PNV9_OCC_PSTATE_ID_ZERO: 164 return 0; 165 case PNV9_OCC_PSTATE_DATA: 166 case PNV9_OCC_ROLE_MASTER_OR_SLAVE: 167 case PNV9_OCC_PSTATE_NOM: 168 case PNV9_OCC_PSTATE_TURBO: 169 case PNV9_OCC_PSTATE_ID_ONE: 170 case PNV9_OCC_PSTATE_ULTRA_TURBO: 171 case PNV9_OCC_OPAL_RUNTIME_DATA: 172 return 1; 173 case PNV9_OCC_PSTATE_MIN: 174 case PNV9_OCC_PSTATE_ID_TWO: 175 return 2; 176 177 /* 3000 khz frequency for 0, 1, and 2 pstates */ 178 case PNV9_OCC_PSTATE_ZERO_FREQUENCY: 179 case PNV9_OCC_PSTATE_ONE_FREQUENCY: 180 case PNV9_OCC_PSTATE_TWO_FREQUENCY: 181 return 3000; 182 case PNV9_OCC_PSTATE_MAJOR_VERSION: 183 return 0x90; 184 case PNV9_CHIP_HOMER_BASE: 185 case PNV9_OCC_PSTATE_DATA_AREA: 186 case PNV9_CHIP_HOMER_IMAGE_POINTER: 187 return 0x1000000000000000; 188 } 189 /* pstate table core max array */ 190 if (core_max_array(homer, addr)) { 191 return 1; 192 } 193 return 0; 194 } 195 196 static void pnv_power9_homer_write(void *opaque, hwaddr addr, 197 uint64_t val, unsigned size) 198 { 199 /* callback function defined to homer write */ 200 return; 201 } 202 203 static const MemoryRegionOps pnv_power9_homer_ops = { 204 .read = pnv_power9_homer_read, 205 .write = pnv_power9_homer_write, 206 .valid.min_access_size = 1, 207 .valid.max_access_size = 8, 208 .impl.min_access_size = 1, 209 .impl.max_access_size = 8, 210 .endianness = DEVICE_BIG_ENDIAN, 211 }; 212 213 static void pnv_homer_power9_class_init(ObjectClass *klass, void *data) 214 { 215 PnvHomerClass *homer = PNV_HOMER_CLASS(klass); 216 217 homer->homer_size = PNV9_HOMER_SIZE; 218 homer->homer_ops = &pnv_power9_homer_ops; 219 homer->core_max_base = PNV9_CORE_MAX_BASE; 220 } 221 222 static const TypeInfo pnv_homer_power9_type_info = { 223 .name = TYPE_PNV9_HOMER, 224 .parent = TYPE_PNV_HOMER, 225 .instance_size = sizeof(PnvHomer), 226 .class_init = pnv_homer_power9_class_init, 227 }; 228 229 static void pnv_homer_realize(DeviceState *dev, Error **errp) 230 { 231 PnvHomer *homer = PNV_HOMER(dev); 232 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); 233 234 assert(homer->chip); 235 236 /* homer region */ 237 memory_region_init_io(&homer->regs, OBJECT(dev), 238 hmrc->homer_ops, homer, "homer-main-memory", 239 hmrc->homer_size); 240 } 241 242 static Property pnv_homer_properties[] = { 243 DEFINE_PROP_LINK("chip", PnvHomer, chip, TYPE_PNV_CHIP, PnvChip *), 244 DEFINE_PROP_END_OF_LIST(), 245 }; 246 247 static void pnv_homer_class_init(ObjectClass *klass, void *data) 248 { 249 DeviceClass *dc = DEVICE_CLASS(klass); 250 251 dc->realize = pnv_homer_realize; 252 dc->desc = "PowerNV HOMER Memory"; 253 dc->props = pnv_homer_properties; 254 } 255 256 static const TypeInfo pnv_homer_type_info = { 257 .name = TYPE_PNV_HOMER, 258 .parent = TYPE_DEVICE, 259 .instance_size = sizeof(PnvHomer), 260 .class_init = pnv_homer_class_init, 261 .class_size = sizeof(PnvHomerClass), 262 .abstract = true, 263 }; 264 265 static void pnv_homer_register_types(void) 266 { 267 type_register_static(&pnv_homer_type_info); 268 type_register_static(&pnv_homer_power8_type_info); 269 type_register_static(&pnv_homer_power9_type_info); 270 } 271 272 type_init(pnv_homer_register_types); 273