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 "exec/memory.h"
24 #include "sysemu/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
core_max_array(PnvHomer * homer,hwaddr addr)33 static bool core_max_array(PnvHomer *homer, hwaddr addr)
34 {
35 int i;
36 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
37
38 for (i = 0; i <= homer->chip->nr_cores; i++) {
39 if (addr == (hmrc->core_max_base + i)) {
40 return true;
41 }
42 }
43 return false;
44 }
45
46 /* P8 Pstate table */
47
48 #define PNV8_OCC_PSTATE_VERSION 0x1f8001
49 #define PNV8_OCC_PSTATE_MIN 0x1f8003
50 #define PNV8_OCC_PSTATE_VALID 0x1f8000
51 #define PNV8_OCC_PSTATE_THROTTLE 0x1f8002
52 #define PNV8_OCC_PSTATE_NOM 0x1f8004
53 #define PNV8_OCC_PSTATE_TURBO 0x1f8005
54 #define PNV8_OCC_PSTATE_ULTRA_TURBO 0x1f8006
55 #define PNV8_OCC_PSTATE_DATA 0x1f8008
56 #define PNV8_OCC_PSTATE_ID_ZERO 0x1f8010
57 #define PNV8_OCC_PSTATE_ID_ONE 0x1f8018
58 #define PNV8_OCC_PSTATE_ID_TWO 0x1f8020
59 #define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER 0x1f8012
60 #define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER 0x1f8013
61 #define PNV8_OCC_PSTATE_ZERO_FREQUENCY 0x1f8014
62 #define PNV8_OCC_PSTATE_ONE_FREQUENCY 0x1f801c
63 #define PNV8_OCC_PSTATE_TWO_FREQUENCY 0x1f8024
64 #define PNV8_CORE_MAX_BASE 0x1f8810
65
66
pnv_power8_homer_read(void * opaque,hwaddr addr,unsigned size)67 static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr,
68 unsigned size)
69 {
70 PnvHomer *homer = PNV_HOMER(opaque);
71
72 switch (addr) {
73 case PNV8_OCC_PSTATE_VERSION:
74 case PNV8_OCC_PSTATE_MIN:
75 case PNV8_OCC_PSTATE_ID_ZERO:
76 return 0;
77 case PNV8_OCC_PSTATE_VALID:
78 case PNV8_OCC_PSTATE_THROTTLE:
79 case PNV8_OCC_PSTATE_NOM:
80 case PNV8_OCC_PSTATE_TURBO:
81 case PNV8_OCC_PSTATE_ID_ONE:
82 case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER:
83 case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER:
84 return 1;
85 case PNV8_OCC_PSTATE_ULTRA_TURBO:
86 case PNV8_OCC_PSTATE_ID_TWO:
87 return 2;
88 case PNV8_OCC_PSTATE_DATA:
89 return 0x1000000000000000;
90 /* P8 frequency for 0, 1, and 2 pstates */
91 case PNV8_OCC_PSTATE_ZERO_FREQUENCY:
92 case PNV8_OCC_PSTATE_ONE_FREQUENCY:
93 case PNV8_OCC_PSTATE_TWO_FREQUENCY:
94 return 3000;
95 }
96 /* pstate table core max array */
97 if (core_max_array(homer, addr)) {
98 return 1;
99 }
100 return 0;
101 }
102
pnv_power8_homer_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)103 static void pnv_power8_homer_write(void *opaque, hwaddr addr,
104 uint64_t val, unsigned size)
105 {
106 /* callback function defined to homer write */
107 return;
108 }
109
110 static const MemoryRegionOps pnv_power8_homer_ops = {
111 .read = pnv_power8_homer_read,
112 .write = pnv_power8_homer_write,
113 .valid.min_access_size = 1,
114 .valid.max_access_size = 8,
115 .impl.min_access_size = 1,
116 .impl.max_access_size = 8,
117 .endianness = DEVICE_BIG_ENDIAN,
118 };
119
120 /* P8 PBA BARs */
121 #define PBA_BAR0 0x00
122 #define PBA_BAR1 0x01
123 #define PBA_BAR2 0x02
124 #define PBA_BAR3 0x03
125 #define PBA_BARMASK0 0x04
126 #define PBA_BARMASK1 0x05
127 #define PBA_BARMASK2 0x06
128 #define PBA_BARMASK3 0x07
129
pnv_homer_power8_pba_read(void * opaque,hwaddr addr,unsigned size)130 static uint64_t pnv_homer_power8_pba_read(void *opaque, hwaddr addr,
131 unsigned size)
132 {
133 PnvHomer *homer = PNV_HOMER(opaque);
134 PnvChip *chip = homer->chip;
135 uint32_t reg = addr >> 3;
136 uint64_t val = 0;
137
138 switch (reg) {
139 case PBA_BAR0:
140 val = PNV_HOMER_BASE(chip);
141 break;
142 case PBA_BARMASK0: /* P8 homer region mask */
143 val = (PNV_HOMER_SIZE - 1) & 0x300000;
144 break;
145 case PBA_BAR3: /* P8 occ common area */
146 val = PNV_OCC_COMMON_AREA_BASE;
147 break;
148 case PBA_BARMASK3: /* P8 occ common area mask */
149 val = (PNV_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
150 break;
151 default:
152 qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
153 HWADDR_PRIx "\n", addr >> 3);
154 }
155 return val;
156 }
157
pnv_homer_power8_pba_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)158 static void pnv_homer_power8_pba_write(void *opaque, hwaddr addr,
159 uint64_t val, unsigned size)
160 {
161 qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
162 HWADDR_PRIx "\n", addr >> 3);
163 }
164
165 static const MemoryRegionOps pnv_homer_power8_pba_ops = {
166 .read = pnv_homer_power8_pba_read,
167 .write = pnv_homer_power8_pba_write,
168 .valid.min_access_size = 8,
169 .valid.max_access_size = 8,
170 .impl.min_access_size = 8,
171 .impl.max_access_size = 8,
172 .endianness = DEVICE_BIG_ENDIAN,
173 };
174
pnv_homer_power8_class_init(ObjectClass * klass,void * data)175 static void pnv_homer_power8_class_init(ObjectClass *klass, void *data)
176 {
177 PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
178
179 homer->pba_size = PNV_XSCOM_PBA_SIZE;
180 homer->pba_ops = &pnv_homer_power8_pba_ops;
181 homer->homer_size = PNV_HOMER_SIZE;
182 homer->homer_ops = &pnv_power8_homer_ops;
183 homer->core_max_base = PNV8_CORE_MAX_BASE;
184 }
185
186 static const TypeInfo pnv_homer_power8_type_info = {
187 .name = TYPE_PNV8_HOMER,
188 .parent = TYPE_PNV_HOMER,
189 .instance_size = sizeof(PnvHomer),
190 .class_init = pnv_homer_power8_class_init,
191 };
192
193 /* P9 Pstate table */
194
195 #define PNV9_OCC_PSTATE_ID_ZERO 0xe2018
196 #define PNV9_OCC_PSTATE_ID_ONE 0xe2020
197 #define PNV9_OCC_PSTATE_ID_TWO 0xe2028
198 #define PNV9_OCC_PSTATE_DATA 0xe2000
199 #define PNV9_OCC_PSTATE_DATA_AREA 0xe2008
200 #define PNV9_OCC_PSTATE_MIN 0xe2003
201 #define PNV9_OCC_PSTATE_NOM 0xe2004
202 #define PNV9_OCC_PSTATE_TURBO 0xe2005
203 #define PNV9_OCC_PSTATE_ULTRA_TURBO 0xe2818
204 #define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO 0xe2006
205 #define PNV9_OCC_PSTATE_MAJOR_VERSION 0xe2001
206 #define PNV9_OCC_OPAL_RUNTIME_DATA 0xe2b85
207 #define PNV9_CHIP_HOMER_IMAGE_POINTER 0x200008
208 #define PNV9_CHIP_HOMER_BASE 0x0
209 #define PNV9_OCC_PSTATE_ZERO_FREQUENCY 0xe201c
210 #define PNV9_OCC_PSTATE_ONE_FREQUENCY 0xe2024
211 #define PNV9_OCC_PSTATE_TWO_FREQUENCY 0xe202c
212 #define PNV9_OCC_ROLE_MASTER_OR_SLAVE 0xe2002
213 #define PNV9_CORE_MAX_BASE 0xe2819
214
215
pnv_power9_homer_read(void * opaque,hwaddr addr,unsigned size)216 static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr,
217 unsigned size)
218 {
219 PnvHomer *homer = PNV_HOMER(opaque);
220
221 switch (addr) {
222 case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO:
223 case PNV9_OCC_PSTATE_ID_ZERO:
224 return 0;
225 case PNV9_OCC_PSTATE_DATA:
226 case PNV9_OCC_ROLE_MASTER_OR_SLAVE:
227 case PNV9_OCC_PSTATE_NOM:
228 case PNV9_OCC_PSTATE_TURBO:
229 case PNV9_OCC_PSTATE_ID_ONE:
230 case PNV9_OCC_PSTATE_ULTRA_TURBO:
231 case PNV9_OCC_OPAL_RUNTIME_DATA:
232 return 1;
233 case PNV9_OCC_PSTATE_MIN:
234 case PNV9_OCC_PSTATE_ID_TWO:
235 return 2;
236
237 /* 3000 khz frequency for 0, 1, and 2 pstates */
238 case PNV9_OCC_PSTATE_ZERO_FREQUENCY:
239 case PNV9_OCC_PSTATE_ONE_FREQUENCY:
240 case PNV9_OCC_PSTATE_TWO_FREQUENCY:
241 return 3000;
242 case PNV9_OCC_PSTATE_MAJOR_VERSION:
243 return 0x90;
244 case PNV9_CHIP_HOMER_BASE:
245 case PNV9_OCC_PSTATE_DATA_AREA:
246 case PNV9_CHIP_HOMER_IMAGE_POINTER:
247 return 0x1000000000000000;
248 }
249 /* pstate table core max array */
250 if (core_max_array(homer, addr)) {
251 return 1;
252 }
253 return 0;
254 }
255
pnv_power9_homer_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)256 static void pnv_power9_homer_write(void *opaque, hwaddr addr,
257 uint64_t val, unsigned size)
258 {
259 /* callback function defined to homer write */
260 return;
261 }
262
263 static const MemoryRegionOps pnv_power9_homer_ops = {
264 .read = pnv_power9_homer_read,
265 .write = pnv_power9_homer_write,
266 .valid.min_access_size = 1,
267 .valid.max_access_size = 8,
268 .impl.min_access_size = 1,
269 .impl.max_access_size = 8,
270 .endianness = DEVICE_BIG_ENDIAN,
271 };
272
pnv_homer_power9_pba_read(void * opaque,hwaddr addr,unsigned size)273 static uint64_t pnv_homer_power9_pba_read(void *opaque, hwaddr addr,
274 unsigned size)
275 {
276 PnvHomer *homer = PNV_HOMER(opaque);
277 PnvChip *chip = homer->chip;
278 uint32_t reg = addr >> 3;
279 uint64_t val = 0;
280
281 switch (reg) {
282 case PBA_BAR0:
283 val = PNV9_HOMER_BASE(chip);
284 break;
285 case PBA_BARMASK0: /* P9 homer region mask */
286 val = (PNV9_HOMER_SIZE - 1) & 0x300000;
287 break;
288 case PBA_BAR2: /* P9 occ common area */
289 val = PNV9_OCC_COMMON_AREA_BASE;
290 break;
291 case PBA_BARMASK2: /* P9 occ common area size */
292 val = (PNV9_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
293 break;
294 default:
295 qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
296 HWADDR_PRIx "\n", addr >> 3);
297 }
298 return val;
299 }
300
pnv_homer_power9_pba_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)301 static void pnv_homer_power9_pba_write(void *opaque, hwaddr addr,
302 uint64_t val, unsigned size)
303 {
304 qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
305 HWADDR_PRIx "\n", addr >> 3);
306 }
307
308 static const MemoryRegionOps pnv_homer_power9_pba_ops = {
309 .read = pnv_homer_power9_pba_read,
310 .write = pnv_homer_power9_pba_write,
311 .valid.min_access_size = 8,
312 .valid.max_access_size = 8,
313 .impl.min_access_size = 8,
314 .impl.max_access_size = 8,
315 .endianness = DEVICE_BIG_ENDIAN,
316 };
317
pnv_homer_power9_class_init(ObjectClass * klass,void * data)318 static void pnv_homer_power9_class_init(ObjectClass *klass, void *data)
319 {
320 PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
321
322 homer->pba_size = PNV9_XSCOM_PBA_SIZE;
323 homer->pba_ops = &pnv_homer_power9_pba_ops;
324 homer->homer_size = PNV9_HOMER_SIZE;
325 homer->homer_ops = &pnv_power9_homer_ops;
326 homer->core_max_base = PNV9_CORE_MAX_BASE;
327 }
328
329 static const TypeInfo pnv_homer_power9_type_info = {
330 .name = TYPE_PNV9_HOMER,
331 .parent = TYPE_PNV_HOMER,
332 .instance_size = sizeof(PnvHomer),
333 .class_init = pnv_homer_power9_class_init,
334 };
335
pnv_homer_power10_pba_read(void * opaque,hwaddr addr,unsigned size)336 static uint64_t pnv_homer_power10_pba_read(void *opaque, hwaddr addr,
337 unsigned size)
338 {
339 PnvHomer *homer = PNV_HOMER(opaque);
340 PnvChip *chip = homer->chip;
341 uint32_t reg = addr >> 3;
342 uint64_t val = 0;
343
344 switch (reg) {
345 case PBA_BAR0:
346 val = PNV10_HOMER_BASE(chip);
347 break;
348 case PBA_BARMASK0: /* P10 homer region mask */
349 val = (PNV10_HOMER_SIZE - 1) & 0x300000;
350 break;
351 case PBA_BAR2: /* P10 occ common area */
352 val = PNV10_OCC_COMMON_AREA_BASE;
353 break;
354 case PBA_BARMASK2: /* P10 occ common area size */
355 val = (PNV10_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
356 break;
357 default:
358 qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
359 HWADDR_PRIx "\n", addr >> 3);
360 }
361 return val;
362 }
363
pnv_homer_power10_pba_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)364 static void pnv_homer_power10_pba_write(void *opaque, hwaddr addr,
365 uint64_t val, unsigned size)
366 {
367 qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
368 HWADDR_PRIx "\n", addr >> 3);
369 }
370
371 static const MemoryRegionOps pnv_homer_power10_pba_ops = {
372 .read = pnv_homer_power10_pba_read,
373 .write = pnv_homer_power10_pba_write,
374 .valid.min_access_size = 8,
375 .valid.max_access_size = 8,
376 .impl.min_access_size = 8,
377 .impl.max_access_size = 8,
378 .endianness = DEVICE_BIG_ENDIAN,
379 };
380
pnv_homer_power10_class_init(ObjectClass * klass,void * data)381 static void pnv_homer_power10_class_init(ObjectClass *klass, void *data)
382 {
383 PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
384
385 homer->pba_size = PNV10_XSCOM_PBA_SIZE;
386 homer->pba_ops = &pnv_homer_power10_pba_ops;
387 homer->homer_size = PNV10_HOMER_SIZE;
388 homer->homer_ops = &pnv_power9_homer_ops; /* TODO */
389 homer->core_max_base = PNV9_CORE_MAX_BASE;
390 }
391
392 static const TypeInfo pnv_homer_power10_type_info = {
393 .name = TYPE_PNV10_HOMER,
394 .parent = TYPE_PNV_HOMER,
395 .instance_size = sizeof(PnvHomer),
396 .class_init = pnv_homer_power10_class_init,
397 };
398
pnv_homer_realize(DeviceState * dev,Error ** errp)399 static void pnv_homer_realize(DeviceState *dev, Error **errp)
400 {
401 PnvHomer *homer = PNV_HOMER(dev);
402 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
403
404 assert(homer->chip);
405
406 pnv_xscom_region_init(&homer->pba_regs, OBJECT(dev), hmrc->pba_ops,
407 homer, "xscom-pba", hmrc->pba_size);
408
409 /* homer region */
410 memory_region_init_io(&homer->regs, OBJECT(dev),
411 hmrc->homer_ops, homer, "homer-main-memory",
412 hmrc->homer_size);
413 }
414
415 static Property pnv_homer_properties[] = {
416 DEFINE_PROP_LINK("chip", PnvHomer, chip, TYPE_PNV_CHIP, PnvChip *),
417 DEFINE_PROP_END_OF_LIST(),
418 };
419
pnv_homer_class_init(ObjectClass * klass,void * data)420 static void pnv_homer_class_init(ObjectClass *klass, void *data)
421 {
422 DeviceClass *dc = DEVICE_CLASS(klass);
423
424 dc->realize = pnv_homer_realize;
425 dc->desc = "PowerNV HOMER Memory";
426 device_class_set_props(dc, pnv_homer_properties);
427 dc->user_creatable = false;
428 }
429
430 static const TypeInfo pnv_homer_type_info = {
431 .name = TYPE_PNV_HOMER,
432 .parent = TYPE_DEVICE,
433 .instance_size = sizeof(PnvHomer),
434 .class_init = pnv_homer_class_init,
435 .class_size = sizeof(PnvHomerClass),
436 .abstract = true,
437 };
438
pnv_homer_register_types(void)439 static void pnv_homer_register_types(void)
440 {
441 type_register_static(&pnv_homer_type_info);
442 type_register_static(&pnv_homer_power8_type_info);
443 type_register_static(&pnv_homer_power9_type_info);
444 type_register_static(&pnv_homer_power10_type_info);
445 }
446
447 type_init(pnv_homer_register_types);
448