2 * QEMU PowerPC PowerNV CPU Core model
4 * Copyright (c) 2016, IBM Corporation.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "sysemu/reset.h"
22 #include "qapi/error.h"
24 #include "qemu/module.h"
25 #include "target/ppc/cpu.h"
26 #include "hw/ppc/ppc.h"
27 #include "hw/ppc/pnv.h"
28 #include "hw/ppc/pnv_chip.h"
29 #include "hw/ppc/pnv_core.h"
30 #include "hw/ppc/pnv_xscom.h"
31 #include "hw/ppc/xics.h"
32 #include "hw/qdev-properties.h"
33 #include "helper_regs.h"
35 static const char *pnv_core_cpu_typename(PnvCore
*pc
)
37 const char *core_type
= object_class_get_name(object_get_class(OBJECT(pc
)));
38 int len
= strlen(core_type
) - strlen(PNV_CORE_TYPE_SUFFIX
);
39 char *s
= g_strdup_printf(POWERPC_CPU_TYPE_NAME("%.*s"), len
, core_type
);
40 const char *cpu_type
= object_class_get_name(object_class_by_name(s
));
45 static void pnv_core_cpu_reset(PnvCore
*pc
, PowerPCCPU
*cpu
)
47 CPUState
*cs
= CPU(cpu
);
48 CPUPPCState
*env
= &cpu
->env
;
49 PnvChipClass
*pcc
= PNV_CHIP_GET_CLASS(pc
->chip
);
54 * the skiboot firmware elects a primary thread to initialize the
55 * system and it can be any.
57 env
->gpr
[3] = PNV_FDT_ADDR
;
59 env
->msr
|= MSR_HVB
; /* Hypervisor mode */
60 env
->spr
[SPR_HRMOR
] = pc
->hrmor
;
61 hreg_compute_hflags(env
);
62 ppc_maybe_interrupt(env
);
64 cpu_ppc_tb_reset(env
);
66 pcc
->intc_reset(pc
->chip
, cpu
);
70 * These values are read by the PowerNV HW monitors under Linux
72 #define PNV_XSCOM_EX_DTS_RESULT0 0x50000
73 #define PNV_XSCOM_EX_DTS_RESULT1 0x50001
75 static uint64_t pnv_core_power8_xscom_read(void *opaque
, hwaddr addr
,
78 uint32_t offset
= addr
>> 3;
81 /* The result should be 38 C */
83 case PNV_XSCOM_EX_DTS_RESULT0
:
84 val
= 0x26f024f023f0000ull
;
86 case PNV_XSCOM_EX_DTS_RESULT1
:
87 val
= 0x24f000000000000ull
;
90 qemu_log_mask(LOG_UNIMP
, "%s: unimp read 0x%08x\n", __func__
,
97 static void pnv_core_power8_xscom_write(void *opaque
, hwaddr addr
, uint64_t val
,
100 uint32_t offset
= addr
>> 3;
102 qemu_log_mask(LOG_UNIMP
, "%s: unimp write 0x%08x\n", __func__
,
106 static const MemoryRegionOps pnv_core_power8_xscom_ops
= {
107 .read
= pnv_core_power8_xscom_read
,
108 .write
= pnv_core_power8_xscom_write
,
109 .valid
.min_access_size
= 8,
110 .valid
.max_access_size
= 8,
111 .impl
.min_access_size
= 8,
112 .impl
.max_access_size
= 8,
113 .endianness
= DEVICE_BIG_ENDIAN
,
118 * POWER9 core controls
120 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
121 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
123 #define PNV9_XSCOM_EC_CORE_THREAD_STATE 0x10ab3
125 static uint64_t pnv_core_power9_xscom_read(void *opaque
, hwaddr addr
,
128 uint32_t offset
= addr
>> 3;
131 /* The result should be 38 C */
133 case PNV_XSCOM_EX_DTS_RESULT0
:
134 val
= 0x26f024f023f0000ull
;
136 case PNV_XSCOM_EX_DTS_RESULT1
:
137 val
= 0x24f000000000000ull
;
139 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP
:
140 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR
:
143 case PNV9_XSCOM_EC_CORE_THREAD_STATE
:
147 qemu_log_mask(LOG_UNIMP
, "%s: unimp read 0x%08x\n", __func__
,
154 static void pnv_core_power9_xscom_write(void *opaque
, hwaddr addr
, uint64_t val
,
157 uint32_t offset
= addr
>> 3;
160 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP
:
161 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR
:
164 qemu_log_mask(LOG_UNIMP
, "%s: unimp write 0x%08x\n", __func__
,
169 static const MemoryRegionOps pnv_core_power9_xscom_ops
= {
170 .read
= pnv_core_power9_xscom_read
,
171 .write
= pnv_core_power9_xscom_write
,
172 .valid
.min_access_size
= 8,
173 .valid
.max_access_size
= 8,
174 .impl
.min_access_size
= 8,
175 .impl
.max_access_size
= 8,
176 .endianness
= DEVICE_BIG_ENDIAN
,
180 * POWER10 core controls
183 #define PNV10_XSCOM_EC_CORE_THREAD_STATE 0x412
185 static uint64_t pnv_core_power10_xscom_read(void *opaque
, hwaddr addr
,
188 uint32_t offset
= addr
>> 3;
192 case PNV10_XSCOM_EC_CORE_THREAD_STATE
:
196 qemu_log_mask(LOG_UNIMP
, "%s: unimp read 0x%08x\n", __func__
,
203 static void pnv_core_power10_xscom_write(void *opaque
, hwaddr addr
,
204 uint64_t val
, unsigned int width
)
206 uint32_t offset
= addr
>> 3;
210 qemu_log_mask(LOG_UNIMP
, "%s: unimp write 0x%08x\n", __func__
,
215 static const MemoryRegionOps pnv_core_power10_xscom_ops
= {
216 .read
= pnv_core_power10_xscom_read
,
217 .write
= pnv_core_power10_xscom_write
,
218 .valid
.min_access_size
= 8,
219 .valid
.max_access_size
= 8,
220 .impl
.min_access_size
= 8,
221 .impl
.max_access_size
= 8,
222 .endianness
= DEVICE_BIG_ENDIAN
,
225 static void pnv_core_cpu_realize(PnvCore
*pc
, PowerPCCPU
*cpu
, Error
**errp
,
228 CPUPPCState
*env
= &cpu
->env
;
230 ppc_spr_t
*pir
= &env
->spr_cb
[SPR_PIR
];
231 ppc_spr_t
*tir
= &env
->spr_cb
[SPR_TIR
];
232 Error
*local_err
= NULL
;
233 PnvChipClass
*pcc
= PNV_CHIP_GET_CLASS(pc
->chip
);
235 if (!qdev_realize(DEVICE(cpu
), NULL
, errp
)) {
239 pcc
->intc_create(pc
->chip
, cpu
, &local_err
);
241 error_propagate(errp
, local_err
);
245 core_pir
= object_property_get_uint(OBJECT(pc
), "pir", &error_abort
);
247 tir
->default_value
= thread_index
;
248 pir
->default_value
= core_pir
+ thread_index
;
250 /* Set time-base frequency to 512 MHz */
251 cpu_ppc_tb_init(env
, PNV_TIMEBASE_FREQ
);
254 static void pnv_core_reset(void *dev
)
256 CPUCore
*cc
= CPU_CORE(dev
);
257 PnvCore
*pc
= PNV_CORE(dev
);
260 for (i
= 0; i
< cc
->nr_threads
; i
++) {
261 pnv_core_cpu_reset(pc
, pc
->threads
[i
]);
265 static void pnv_core_realize(DeviceState
*dev
, Error
**errp
)
267 PnvCore
*pc
= PNV_CORE(OBJECT(dev
));
268 PnvCoreClass
*pcc
= PNV_CORE_GET_CLASS(pc
);
269 CPUCore
*cc
= CPU_CORE(OBJECT(dev
));
270 const char *typename
= pnv_core_cpu_typename(pc
);
271 Error
*local_err
= NULL
;
278 pc
->threads
= g_new(PowerPCCPU
*, cc
->nr_threads
);
279 for (i
= 0; i
< cc
->nr_threads
; i
++) {
282 obj
= object_new(typename
);
283 cpu
= POWERPC_CPU(obj
);
285 pc
->threads
[i
] = POWERPC_CPU(obj
);
287 snprintf(name
, sizeof(name
), "thread[%d]", i
);
288 object_property_add_child(OBJECT(pc
), name
, obj
);
290 cpu
->machine_data
= g_new0(PnvCPUState
, 1);
295 for (j
= 0; j
< cc
->nr_threads
; j
++) {
296 pnv_core_cpu_realize(pc
, pc
->threads
[j
], &local_err
, j
);
302 snprintf(name
, sizeof(name
), "xscom-core.%d", cc
->core_id
);
303 pnv_xscom_region_init(&pc
->xscom_regs
, OBJECT(dev
), pcc
->xscom_ops
,
304 pc
, name
, pcc
->xscom_size
);
306 qemu_register_reset(pnv_core_reset
, pc
);
311 obj
= OBJECT(pc
->threads
[i
]);
312 object_unparent(obj
);
315 error_propagate(errp
, local_err
);
318 static void pnv_core_cpu_unrealize(PnvCore
*pc
, PowerPCCPU
*cpu
)
320 PnvCPUState
*pnv_cpu
= pnv_cpu_state(cpu
);
321 PnvChipClass
*pcc
= PNV_CHIP_GET_CLASS(pc
->chip
);
323 pcc
->intc_destroy(pc
->chip
, cpu
);
324 cpu_remove_sync(CPU(cpu
));
325 cpu
->machine_data
= NULL
;
327 object_unparent(OBJECT(cpu
));
330 static void pnv_core_unrealize(DeviceState
*dev
)
332 PnvCore
*pc
= PNV_CORE(dev
);
333 CPUCore
*cc
= CPU_CORE(dev
);
336 qemu_unregister_reset(pnv_core_reset
, pc
);
338 for (i
= 0; i
< cc
->nr_threads
; i
++) {
339 pnv_core_cpu_unrealize(pc
, pc
->threads
[i
]);
344 static Property pnv_core_properties
[] = {
345 DEFINE_PROP_UINT32("pir", PnvCore
, pir
, 0),
346 DEFINE_PROP_UINT64("hrmor", PnvCore
, hrmor
, 0),
347 DEFINE_PROP_LINK("chip", PnvCore
, chip
, TYPE_PNV_CHIP
, PnvChip
*),
348 DEFINE_PROP_END_OF_LIST(),
351 static void pnv_core_power8_class_init(ObjectClass
*oc
, void *data
)
353 PnvCoreClass
*pcc
= PNV_CORE_CLASS(oc
);
355 pcc
->xscom_ops
= &pnv_core_power8_xscom_ops
;
356 pcc
->xscom_size
= PNV_XSCOM_EX_SIZE
;
359 static void pnv_core_power9_class_init(ObjectClass
*oc
, void *data
)
361 PnvCoreClass
*pcc
= PNV_CORE_CLASS(oc
);
363 pcc
->xscom_ops
= &pnv_core_power9_xscom_ops
;
364 pcc
->xscom_size
= PNV_XSCOM_EX_SIZE
;
367 static void pnv_core_power10_class_init(ObjectClass
*oc
, void *data
)
369 PnvCoreClass
*pcc
= PNV_CORE_CLASS(oc
);
371 pcc
->xscom_ops
= &pnv_core_power10_xscom_ops
;
372 pcc
->xscom_size
= PNV10_XSCOM_EC_SIZE
;
375 static void pnv_core_class_init(ObjectClass
*oc
, void *data
)
377 DeviceClass
*dc
= DEVICE_CLASS(oc
);
379 dc
->realize
= pnv_core_realize
;
380 dc
->unrealize
= pnv_core_unrealize
;
381 device_class_set_props(dc
, pnv_core_properties
);
382 dc
->user_creatable
= false;
385 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
387 .parent = TYPE_PNV_CORE, \
388 .name = PNV_CORE_TYPE_NAME(cpu_model), \
389 .class_init = pnv_core_##family##_class_init, \
392 static const TypeInfo pnv_core_infos
[] = {
394 .name
= TYPE_PNV_CORE
,
395 .parent
= TYPE_CPU_CORE
,
396 .instance_size
= sizeof(PnvCore
),
397 .class_size
= sizeof(PnvCoreClass
),
398 .class_init
= pnv_core_class_init
,
401 DEFINE_PNV_CORE_TYPE(power8
, "power8e_v2.1"),
402 DEFINE_PNV_CORE_TYPE(power8
, "power8_v2.0"),
403 DEFINE_PNV_CORE_TYPE(power8
, "power8nvl_v1.0"),
404 DEFINE_PNV_CORE_TYPE(power9
, "power9_v2.2"),
405 DEFINE_PNV_CORE_TYPE(power10
, "power10_v2.0"),
408 DEFINE_TYPES(pnv_core_infos
)
414 #define P9X_EX_NCU_SPEC_BAR 0x11010
416 static uint64_t pnv_quad_power9_xscom_read(void *opaque
, hwaddr addr
,
419 uint32_t offset
= addr
>> 3;
423 case P9X_EX_NCU_SPEC_BAR
:
424 case P9X_EX_NCU_SPEC_BAR
+ 0x400: /* Second EX */
428 qemu_log_mask(LOG_UNIMP
, "%s: unimp read 0x%08x\n", __func__
,
435 static void pnv_quad_power9_xscom_write(void *opaque
, hwaddr addr
, uint64_t val
,
438 uint32_t offset
= addr
>> 3;
441 case P9X_EX_NCU_SPEC_BAR
:
442 case P9X_EX_NCU_SPEC_BAR
+ 0x400: /* Second EX */
445 qemu_log_mask(LOG_UNIMP
, "%s: unimp write 0x%08x\n", __func__
,
450 static const MemoryRegionOps pnv_quad_power9_xscom_ops
= {
451 .read
= pnv_quad_power9_xscom_read
,
452 .write
= pnv_quad_power9_xscom_write
,
453 .valid
.min_access_size
= 8,
454 .valid
.max_access_size
= 8,
455 .impl
.min_access_size
= 8,
456 .impl
.max_access_size
= 8,
457 .endianness
= DEVICE_BIG_ENDIAN
,
464 static uint64_t pnv_quad_power10_xscom_read(void *opaque
, hwaddr addr
,
467 uint32_t offset
= addr
>> 3;
472 qemu_log_mask(LOG_UNIMP
, "%s: unimp read 0x%08x\n", __func__
,
479 static void pnv_quad_power10_xscom_write(void *opaque
, hwaddr addr
,
480 uint64_t val
, unsigned int width
)
482 uint32_t offset
= addr
>> 3;
486 qemu_log_mask(LOG_UNIMP
, "%s: unimp write 0x%08x\n", __func__
,
491 static const MemoryRegionOps pnv_quad_power10_xscom_ops
= {
492 .read
= pnv_quad_power10_xscom_read
,
493 .write
= pnv_quad_power10_xscom_write
,
494 .valid
.min_access_size
= 8,
495 .valid
.max_access_size
= 8,
496 .impl
.min_access_size
= 8,
497 .impl
.max_access_size
= 8,
498 .endianness
= DEVICE_BIG_ENDIAN
,
501 #define P10_QME_SPWU_HYP 0x83c
502 #define P10_QME_SSH_HYP 0x82c
504 static uint64_t pnv_qme_power10_xscom_read(void *opaque
, hwaddr addr
,
507 uint32_t offset
= addr
>> 3;
511 * Forth nibble selects the core within a quad, mask it to process read
514 switch (offset
& ~0xf000) {
515 case P10_QME_SPWU_HYP
:
516 case P10_QME_SSH_HYP
:
519 qemu_log_mask(LOG_UNIMP
, "%s: unimp read 0x%08x\n", __func__
,
526 static void pnv_qme_power10_xscom_write(void *opaque
, hwaddr addr
,
527 uint64_t val
, unsigned int width
)
529 uint32_t offset
= addr
>> 3;
533 qemu_log_mask(LOG_UNIMP
, "%s: unimp write 0x%08x\n", __func__
,
538 static const MemoryRegionOps pnv_qme_power10_xscom_ops
= {
539 .read
= pnv_qme_power10_xscom_read
,
540 .write
= pnv_qme_power10_xscom_write
,
541 .valid
.min_access_size
= 8,
542 .valid
.max_access_size
= 8,
543 .impl
.min_access_size
= 8,
544 .impl
.max_access_size
= 8,
545 .endianness
= DEVICE_BIG_ENDIAN
,
548 static void pnv_quad_power9_realize(DeviceState
*dev
, Error
**errp
)
550 PnvQuad
*eq
= PNV_QUAD(dev
);
551 PnvQuadClass
*pqc
= PNV_QUAD_GET_CLASS(eq
);
554 snprintf(name
, sizeof(name
), "xscom-quad.%d", eq
->quad_id
);
555 pnv_xscom_region_init(&eq
->xscom_regs
, OBJECT(dev
),
561 static void pnv_quad_power10_realize(DeviceState
*dev
, Error
**errp
)
563 PnvQuad
*eq
= PNV_QUAD(dev
);
564 PnvQuadClass
*pqc
= PNV_QUAD_GET_CLASS(eq
);
567 snprintf(name
, sizeof(name
), "xscom-quad.%d", eq
->quad_id
);
568 pnv_xscom_region_init(&eq
->xscom_regs
, OBJECT(dev
),
573 snprintf(name
, sizeof(name
), "xscom-qme.%d", eq
->quad_id
);
574 pnv_xscom_region_init(&eq
->xscom_qme_regs
, OBJECT(dev
),
577 pqc
->xscom_qme_size
);
580 static Property pnv_quad_properties
[] = {
581 DEFINE_PROP_UINT32("quad-id", PnvQuad
, quad_id
, 0),
582 DEFINE_PROP_END_OF_LIST(),
585 static void pnv_quad_power9_class_init(ObjectClass
*oc
, void *data
)
587 PnvQuadClass
*pqc
= PNV_QUAD_CLASS(oc
);
588 DeviceClass
*dc
= DEVICE_CLASS(oc
);
590 dc
->realize
= pnv_quad_power9_realize
;
592 pqc
->xscom_ops
= &pnv_quad_power9_xscom_ops
;
593 pqc
->xscom_size
= PNV9_XSCOM_EQ_SIZE
;
596 static void pnv_quad_power10_class_init(ObjectClass
*oc
, void *data
)
598 PnvQuadClass
*pqc
= PNV_QUAD_CLASS(oc
);
599 DeviceClass
*dc
= DEVICE_CLASS(oc
);
601 dc
->realize
= pnv_quad_power10_realize
;
603 pqc
->xscom_ops
= &pnv_quad_power10_xscom_ops
;
604 pqc
->xscom_size
= PNV10_XSCOM_EQ_SIZE
;
606 pqc
->xscom_qme_ops
= &pnv_qme_power10_xscom_ops
;
607 pqc
->xscom_qme_size
= PNV10_XSCOM_QME_SIZE
;
610 static void pnv_quad_class_init(ObjectClass
*oc
, void *data
)
612 DeviceClass
*dc
= DEVICE_CLASS(oc
);
614 device_class_set_props(dc
, pnv_quad_properties
);
615 dc
->user_creatable
= false;
618 static const TypeInfo pnv_quad_infos
[] = {
620 .name
= TYPE_PNV_QUAD
,
621 .parent
= TYPE_DEVICE
,
622 .instance_size
= sizeof(PnvQuad
),
623 .class_size
= sizeof(PnvQuadClass
),
624 .class_init
= pnv_quad_class_init
,
628 .parent
= TYPE_PNV_QUAD
,
629 .name
= PNV_QUAD_TYPE_NAME("power9"),
630 .class_init
= pnv_quad_power9_class_init
,
633 .parent
= TYPE_PNV_QUAD
,
634 .name
= PNV_QUAD_TYPE_NAME("power10"),
635 .class_init
= pnv_quad_power10_class_init
,
639 DEFINE_TYPES(pnv_quad_infos
);