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 "qemu/log.h" 21 #include "qapi/error.h" 22 #include "exec/hwaddr.h" 23 #include "system/memory.h" 24 #include "system/cpus.h" 25 #include "hw/qdev-core.h" 26 #include "hw/qdev-properties.h" 27 #include "hw/ppc/pnv.h" 28 #include "hw/ppc/pnv_chip.h" 29 #include "hw/ppc/pnv_homer.h" 30 #include "hw/ppc/pnv_xscom.h" 31 32 /* P8 PBA BARs */ 33 #define PBA_BAR0 0x00 34 #define PBA_BAR1 0x01 35 #define PBA_BAR2 0x02 36 #define PBA_BAR3 0x03 37 #define PBA_BARMASK0 0x04 38 #define PBA_BARMASK1 0x05 39 #define PBA_BARMASK2 0x06 40 #define PBA_BARMASK3 0x07 41 42 static uint64_t pnv_homer_power8_pba_read(void *opaque, hwaddr addr, 43 unsigned size) 44 { 45 PnvHomer *homer = PNV_HOMER(opaque); 46 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); 47 uint32_t reg = addr >> 3; 48 uint64_t val = 0; 49 50 switch (reg) { 51 case PBA_BAR0: 52 val = homer->base; 53 break; 54 case PBA_BARMASK0: /* P8 homer region mask */ 55 val = (hmrc->size - 1) & 0x300000; 56 break; 57 case PBA_BAR3: /* P8 occ common area */ 58 val = PNV_OCC_COMMON_AREA_BASE; 59 break; 60 case PBA_BARMASK3: /* P8 occ common area mask */ 61 val = (PNV_OCC_COMMON_AREA_SIZE - 1) & 0x700000; 62 break; 63 default: 64 qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%" 65 HWADDR_PRIx "\n", addr >> 3); 66 } 67 return val; 68 } 69 70 static void pnv_homer_power8_pba_write(void *opaque, hwaddr addr, 71 uint64_t val, unsigned size) 72 { 73 qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%" 74 HWADDR_PRIx "\n", addr >> 3); 75 } 76 77 static const MemoryRegionOps pnv_homer_power8_pba_ops = { 78 .read = pnv_homer_power8_pba_read, 79 .write = pnv_homer_power8_pba_write, 80 .valid.min_access_size = 8, 81 .valid.max_access_size = 8, 82 .impl.min_access_size = 8, 83 .impl.max_access_size = 8, 84 .endianness = DEVICE_BIG_ENDIAN, 85 }; 86 87 static hwaddr pnv_homer_power8_get_base(PnvChip *chip) 88 { 89 return PNV_HOMER_BASE(chip); 90 } 91 92 static void pnv_homer_power8_class_init(ObjectClass *klass, const void *data) 93 { 94 PnvHomerClass *homer = PNV_HOMER_CLASS(klass); 95 96 homer->get_base = pnv_homer_power8_get_base; 97 homer->size = PNV_HOMER_SIZE; 98 homer->pba_size = PNV_XSCOM_PBA_SIZE; 99 homer->pba_ops = &pnv_homer_power8_pba_ops; 100 } 101 102 static const TypeInfo pnv_homer_power8_type_info = { 103 .name = TYPE_PNV8_HOMER, 104 .parent = TYPE_PNV_HOMER, 105 .instance_size = sizeof(PnvHomer), 106 .class_init = pnv_homer_power8_class_init, 107 }; 108 109 static uint64_t pnv_homer_power9_pba_read(void *opaque, hwaddr addr, 110 unsigned size) 111 { 112 PnvHomer *homer = PNV_HOMER(opaque); 113 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); 114 uint32_t reg = addr >> 3; 115 uint64_t val = 0; 116 117 switch (reg) { 118 case PBA_BAR0: 119 val = homer->base; 120 break; 121 case PBA_BARMASK0: /* P9 homer region mask */ 122 val = (hmrc->size - 1) & 0x300000; 123 break; 124 case PBA_BAR2: /* P9 occ common area */ 125 val = PNV9_OCC_COMMON_AREA_BASE; 126 break; 127 case PBA_BARMASK2: /* P9 occ common area size */ 128 val = (PNV9_OCC_COMMON_AREA_SIZE - 1) & 0x700000; 129 break; 130 default: 131 qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%" 132 HWADDR_PRIx "\n", addr >> 3); 133 } 134 return val; 135 } 136 137 static void pnv_homer_power9_pba_write(void *opaque, hwaddr addr, 138 uint64_t val, unsigned size) 139 { 140 qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%" 141 HWADDR_PRIx "\n", addr >> 3); 142 } 143 144 static const MemoryRegionOps pnv_homer_power9_pba_ops = { 145 .read = pnv_homer_power9_pba_read, 146 .write = pnv_homer_power9_pba_write, 147 .valid.min_access_size = 8, 148 .valid.max_access_size = 8, 149 .impl.min_access_size = 8, 150 .impl.max_access_size = 8, 151 .endianness = DEVICE_BIG_ENDIAN, 152 }; 153 154 static hwaddr pnv_homer_power9_get_base(PnvChip *chip) 155 { 156 return PNV9_HOMER_BASE(chip); 157 } 158 159 static void pnv_homer_power9_class_init(ObjectClass *klass, const void *data) 160 { 161 PnvHomerClass *homer = PNV_HOMER_CLASS(klass); 162 163 homer->get_base = pnv_homer_power9_get_base; 164 homer->size = PNV_HOMER_SIZE; 165 homer->pba_size = PNV9_XSCOM_PBA_SIZE; 166 homer->pba_ops = &pnv_homer_power9_pba_ops; 167 } 168 169 static const TypeInfo pnv_homer_power9_type_info = { 170 .name = TYPE_PNV9_HOMER, 171 .parent = TYPE_PNV_HOMER, 172 .instance_size = sizeof(PnvHomer), 173 .class_init = pnv_homer_power9_class_init, 174 }; 175 176 static uint64_t pnv_homer_power10_pba_read(void *opaque, hwaddr addr, 177 unsigned size) 178 { 179 PnvHomer *homer = PNV_HOMER(opaque); 180 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); 181 uint32_t reg = addr >> 3; 182 uint64_t val = 0; 183 184 switch (reg) { 185 case PBA_BAR0: 186 val = homer->base; 187 break; 188 case PBA_BARMASK0: /* P10 homer region mask */ 189 val = (hmrc->size - 1) & 0x300000; 190 break; 191 case PBA_BAR2: /* P10 occ common area */ 192 val = PNV10_OCC_COMMON_AREA_BASE; 193 break; 194 case PBA_BARMASK2: /* P10 occ common area size */ 195 val = (PNV10_OCC_COMMON_AREA_SIZE - 1) & 0x700000; 196 break; 197 default: 198 qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%" 199 HWADDR_PRIx "\n", addr >> 3); 200 } 201 return val; 202 } 203 204 static void pnv_homer_power10_pba_write(void *opaque, hwaddr addr, 205 uint64_t val, unsigned size) 206 { 207 qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%" 208 HWADDR_PRIx "\n", addr >> 3); 209 } 210 211 static const MemoryRegionOps pnv_homer_power10_pba_ops = { 212 .read = pnv_homer_power10_pba_read, 213 .write = pnv_homer_power10_pba_write, 214 .valid.min_access_size = 8, 215 .valid.max_access_size = 8, 216 .impl.min_access_size = 8, 217 .impl.max_access_size = 8, 218 .endianness = DEVICE_BIG_ENDIAN, 219 }; 220 221 static hwaddr pnv_homer_power10_get_base(PnvChip *chip) 222 { 223 return PNV10_HOMER_BASE(chip); 224 } 225 226 static void pnv_homer_power10_class_init(ObjectClass *klass, const void *data) 227 { 228 PnvHomerClass *homer = PNV_HOMER_CLASS(klass); 229 230 homer->get_base = pnv_homer_power10_get_base; 231 homer->size = PNV_HOMER_SIZE; 232 homer->pba_size = PNV10_XSCOM_PBA_SIZE; 233 homer->pba_ops = &pnv_homer_power10_pba_ops; 234 } 235 236 static const TypeInfo pnv_homer_power10_type_info = { 237 .name = TYPE_PNV10_HOMER, 238 .parent = TYPE_PNV_HOMER, 239 .instance_size = sizeof(PnvHomer), 240 .class_init = pnv_homer_power10_class_init, 241 }; 242 243 static void pnv_homer_realize(DeviceState *dev, Error **errp) 244 { 245 PnvHomer *homer = PNV_HOMER(dev); 246 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); 247 char homer_str[32]; 248 249 assert(homer->chip); 250 251 pnv_xscom_region_init(&homer->pba_regs, OBJECT(dev), hmrc->pba_ops, 252 homer, "xscom-pba", hmrc->pba_size); 253 254 /* Homer RAM region */ 255 homer->base = hmrc->get_base(homer->chip); 256 257 snprintf(homer_str, sizeof(homer_str), "homer-chip%d-memory", 258 homer->chip->chip_id); 259 if (!memory_region_init_ram(&homer->mem, OBJECT(homer), 260 homer_str, hmrc->size, errp)) { 261 return; 262 } 263 } 264 265 static const Property pnv_homer_properties[] = { 266 DEFINE_PROP_LINK("chip", PnvHomer, chip, TYPE_PNV_CHIP, PnvChip *), 267 }; 268 269 static void pnv_homer_class_init(ObjectClass *klass, const void *data) 270 { 271 DeviceClass *dc = DEVICE_CLASS(klass); 272 273 dc->realize = pnv_homer_realize; 274 dc->desc = "PowerNV HOMER Memory"; 275 device_class_set_props(dc, pnv_homer_properties); 276 dc->user_creatable = false; 277 } 278 279 static const TypeInfo pnv_homer_type_info = { 280 .name = TYPE_PNV_HOMER, 281 .parent = TYPE_DEVICE, 282 .instance_size = sizeof(PnvHomer), 283 .class_init = pnv_homer_class_init, 284 .class_size = sizeof(PnvHomerClass), 285 .abstract = true, 286 }; 287 288 static void pnv_homer_register_types(void) 289 { 290 type_register_static(&pnv_homer_type_info); 291 type_register_static(&pnv_homer_power8_type_info); 292 type_register_static(&pnv_homer_power9_type_info); 293 type_register_static(&pnv_homer_power10_type_info); 294 } 295 296 type_init(pnv_homer_register_types); 297