2 * QEMU PowerPC PowerNV Emulation of some ChipTOD behaviour
4 * Copyright (c) 2022-2023, IBM Corporation.
6 * SPDX-License-Identifier: GPL-2.0-or-later
8 * ChipTOD (aka TOD) is a facility implemented in the nest / pervasive. The
9 * purpose is to keep time-of-day across chips and cores.
11 * There is a master chip TOD, which sends signals to slave chip TODs to
12 * keep them synchronized. There are two sets of configuration registers
13 * called primary and secondary, which can be used fail over.
15 * The chip TOD also distributes synchronisation signals to the timebase
16 * facility in each of the cores on the chip. In particular there is a
17 * feature that can move the TOD value in the ChipTOD to and from the TB.
19 * Initialisation typically brings all ChipTOD into sync (see tod_state),
20 * and then brings each core TB into sync with the ChipTODs (see timebase
21 * state and TFMR). This model is a very basic simulation of the init sequence
22 * performed by skiboot.
25 #include "qemu/osdep.h"
26 #include "sysemu/reset.h"
27 #include "target/ppc/cpu.h"
28 #include "qapi/error.h"
30 #include "qemu/module.h"
32 #include "hw/qdev-properties.h"
33 #include "hw/ppc/fdt.h"
34 #include "hw/ppc/ppc.h"
35 #include "hw/ppc/pnv.h"
36 #include "hw/ppc/pnv_chip.h"
37 #include "hw/ppc/pnv_core.h"
38 #include "hw/ppc/pnv_xscom.h"
39 #include "hw/ppc/pnv_chiptod.h"
44 /* TOD chip XSCOM addresses */
45 #define TOD_M_PATH_CTRL_REG 0x00000000 /* Master Path ctrl reg */
46 #define TOD_PRI_PORT_0_CTRL_REG 0x00000001 /* Primary port0 ctrl reg */
47 #define TOD_PRI_PORT_1_CTRL_REG 0x00000002 /* Primary port1 ctrl reg */
48 #define TOD_SEC_PORT_0_CTRL_REG 0x00000003 /* Secondary p0 ctrl reg */
49 #define TOD_SEC_PORT_1_CTRL_REG 0x00000004 /* Secondary p1 ctrl reg */
50 #define TOD_S_PATH_CTRL_REG 0x00000005 /* Slave Path ctrl reg */
51 #define TOD_I_PATH_CTRL_REG 0x00000006 /* Internal Path ctrl reg */
53 /* -- TOD primary/secondary master/slave control register -- */
54 #define TOD_PSS_MSS_CTRL_REG 0x00000007
56 /* -- TOD primary/secondary master/slave status register -- */
57 #define TOD_PSS_MSS_STATUS_REG 0x00000008
59 /* TOD chip XSCOM addresses */
60 #define TOD_CHIP_CTRL_REG 0x00000010 /* Chip control reg */
62 #define TOD_TX_TTYPE_0_REG 0x00000011
63 #define TOD_TX_TTYPE_1_REG 0x00000012 /* PSS switch reg */
64 #define TOD_TX_TTYPE_2_REG 0x00000013 /* Enable step checkers */
65 #define TOD_TX_TTYPE_3_REG 0x00000014 /* Request TOD reg */
66 #define TOD_TX_TTYPE_4_REG 0x00000015 /* Send TOD reg */
67 #define TOD_TX_TTYPE_5_REG 0x00000016 /* Invalidate TOD reg */
69 #define TOD_MOVE_TOD_TO_TB_REG 0x00000017
70 #define TOD_LOAD_TOD_MOD_REG 0x00000018
71 #define TOD_LOAD_TOD_REG 0x00000021
72 #define TOD_START_TOD_REG 0x00000022
73 #define TOD_FSM_REG 0x00000024
75 #define TOD_TX_TTYPE_CTRL_REG 0x00000027 /* TX TTYPE Control reg */
76 #define TOD_TX_TTYPE_PIB_SLAVE_ADDR PPC_BITMASK(26, 31)
78 /* -- TOD Error interrupt register -- */
79 #define TOD_ERROR_REG 0x00000030
81 /* PC unit PIB address which recieves the timebase transfer from TOD */
86 * - The reset state is 0 error.
87 * - A hardware error detected will transition to state 0 from any state.
88 * - LOAD_TOD_MOD and TTYPE5 will transition to state 7 from any state.
90 * | state | action | new |
91 * |------------+------------------------------+-----|
92 * | 0 error | LOAD_TOD_MOD | 7 |
93 * | 0 error | Recv TTYPE5 (invalidate TOD) | 7 |
94 * | 7 not_set | LOAD_TOD (bit-63 = 0) | 2 |
95 * | 7 not_set | LOAD_TOD (bit-63 = 1) | 1 |
96 * | 7 not_set | Recv TTYPE4 (send TOD) | 2 |
98 * | 1 stopped | START_TOD | 2 |
100 * Note the hardware has additional states but they relate to the sending
101 * and receiving and waiting on synchronisation signals between chips and
102 * are not described or modeled here.
105 static uint64_t pnv_chiptod_xscom_read(void *opaque
, hwaddr addr
,
108 PnvChipTOD
*chiptod
= PNV_CHIPTOD(opaque
);
109 uint32_t offset
= addr
>> 3;
113 case TOD_PSS_MSS_STATUS_REG
:
115 * ChipTOD does not support configurations other than primary
116 * master, does not support errors, etc.
118 val
|= PPC_BITMASK(6, 10); /* STEP checker validity */
119 val
|= PPC_BIT(12); /* Primary config master path select */
120 if (chiptod
->tod_state
== tod_running
) {
121 val
|= PPC_BIT(20); /* Is running */
123 val
|= PPC_BIT(21); /* Is using primary config */
124 val
|= PPC_BIT(26); /* Is using master path select */
126 if (chiptod
->primary
) {
127 val
|= PPC_BIT(23); /* Is active master */
128 } else if (chiptod
->secondary
) {
129 val
|= PPC_BIT(24); /* Is backup master */
131 val
|= PPC_BIT(25); /* Is slave (should backup master set this?) */
134 case TOD_PSS_MSS_CTRL_REG
:
135 val
= chiptod
->pss_mss_ctrl_reg
;
137 case TOD_TX_TTYPE_CTRL_REG
:
141 val
= chiptod
->tod_error
;
144 if (chiptod
->tod_state
== tod_running
) {
149 qemu_log_mask(LOG_UNIMP
, "pnv_chiptod: unimplemented register: Ox%"
150 HWADDR_PRIx
"\n", addr
>> 3);
153 trace_pnv_chiptod_xscom_read(addr
>> 3, val
);
158 static void chiptod_receive_ttype(PnvChipTOD
*chiptod
, uint32_t trigger
)
161 case TOD_TX_TTYPE_4_REG
:
162 if (chiptod
->tod_state
!= tod_not_set
) {
163 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: received TTYPE4 in "
164 " state %d, should be in 7 (TOD_NOT_SET)\n",
167 chiptod
->tod_state
= tod_running
;
170 case TOD_TX_TTYPE_5_REG
:
171 /* Works from any state */
172 chiptod
->tod_state
= tod_not_set
;
175 qemu_log_mask(LOG_UNIMP
, "pnv_chiptod: received unimplemented "
176 " TTYPE %u\n", trigger
);
181 static void chiptod_power9_broadcast_ttype(PnvChipTOD
*sender
,
184 PnvMachineState
*pnv
= PNV_MACHINE(qdev_get_machine());
187 for (i
= 0; i
< pnv
->num_chips
; i
++) {
188 Pnv9Chip
*chip9
= PNV9_CHIP(pnv
->chips
[i
]);
189 PnvChipTOD
*chiptod
= &chip9
->chiptod
;
191 if (chiptod
!= sender
) {
192 chiptod_receive_ttype(chiptod
, trigger
);
197 static void chiptod_power10_broadcast_ttype(PnvChipTOD
*sender
,
200 PnvMachineState
*pnv
= PNV_MACHINE(qdev_get_machine());
203 for (i
= 0; i
< pnv
->num_chips
; i
++) {
204 Pnv10Chip
*chip10
= PNV10_CHIP(pnv
->chips
[i
]);
205 PnvChipTOD
*chiptod
= &chip10
->chiptod
;
207 if (chiptod
!= sender
) {
208 chiptod_receive_ttype(chiptod
, trigger
);
213 static PnvCore
*pnv_chip_get_core_by_xscom_base(PnvChip
*chip
,
216 PnvChipClass
*pcc
= PNV_CHIP_GET_CLASS(chip
);
219 for (i
= 0; i
< chip
->nr_cores
; i
++) {
220 PnvCore
*pc
= chip
->cores
[i
];
221 CPUCore
*cc
= CPU_CORE(pc
);
222 int core_hwid
= cc
->core_id
;
224 if (pcc
->xscom_core_base(chip
, core_hwid
) == xscom_base
) {
231 static PnvCore
*chiptod_power9_tx_ttype_target(PnvChipTOD
*chiptod
,
235 * skiboot uses Core ID for P9, though SCOM should work too.
237 if (val
& PPC_BIT(35)) { /* SCOM addressing */
238 uint32_t addr
= val
>> 32;
239 uint32_t reg
= addr
& 0xfff;
242 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: SCOM addressing: "
243 "unimplemented slave register 0x%" PRIx32
"\n", reg
);
247 return pnv_chip_get_core_by_xscom_base(chiptod
->chip
, addr
& ~0xfff);
249 } else { /* Core ID addressing */
250 uint32_t core_id
= GETFIELD(TOD_TX_TTYPE_PIB_SLAVE_ADDR
, val
) & 0x1f;
251 return pnv_chip_find_core(chiptod
->chip
, core_id
);
255 static PnvCore
*chiptod_power10_tx_ttype_target(PnvChipTOD
*chiptod
,
259 * skiboot uses SCOM for P10 because Core ID was unable to be made to
260 * work correctly. For this reason only SCOM addressing is implemented.
262 if (val
& PPC_BIT(35)) { /* SCOM addressing */
263 uint32_t addr
= val
>> 32;
264 uint32_t reg
= addr
& 0xfff;
267 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: SCOM addressing: "
268 "unimplemented slave register 0x%" PRIx32
"\n", reg
);
273 * This may not deal with P10 big-core addressing at the moment.
274 * The big-core code in skiboot syncs small cores, but it targets
275 * the even PIR (first small-core) when syncing second small-core.
277 return pnv_chip_get_core_by_xscom_base(chiptod
->chip
, addr
& ~0xfff);
279 } else { /* Core ID addressing */
280 qemu_log_mask(LOG_UNIMP
, "pnv_chiptod: TX TTYPE Core ID "
281 "addressing is not implemented for POWER10\n");
286 static void pnv_chiptod_xscom_write(void *opaque
, hwaddr addr
,
287 uint64_t val
, unsigned size
)
289 PnvChipTOD
*chiptod
= PNV_CHIPTOD(opaque
);
290 PnvChipTODClass
*pctc
= PNV_CHIPTOD_GET_CLASS(chiptod
);
291 uint32_t offset
= addr
>> 3;
293 trace_pnv_chiptod_xscom_write(addr
>> 3, val
);
296 case TOD_PSS_MSS_CTRL_REG
:
297 /* Is this correct? */
298 if (chiptod
->primary
) {
299 val
|= PPC_BIT(1); /* TOD is master */
303 val
|= PPC_BIT(2); /* Drawer is master (don't simulate multi-drawer) */
304 chiptod
->pss_mss_ctrl_reg
= val
& PPC_BITMASK(0, 31);
307 case TOD_TX_TTYPE_CTRL_REG
:
309 * This register sets the target of the TOD value transfer initiated
310 * by TOD_MOVE_TOD_TO_TB. The TOD is able to send the address to
311 * any target register, though in practice only the PC TOD register
312 * should be used. ChipTOD has a "SCOM addressing" mode which fully
313 * specifies the SCOM address, and a core-ID mode which uses the
314 * core ID to target the PC TOD for a given core.
316 chiptod
->slave_pc_target
= pctc
->tx_ttype_target(chiptod
, val
);
317 if (!chiptod
->slave_pc_target
) {
318 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: xscom write reg"
319 " TOD_TX_TTYPE_CTRL_REG val 0x%" PRIx64
320 " invalid slave address\n", val
);
324 chiptod
->tod_error
&= ~val
;
326 case TOD_LOAD_TOD_MOD_REG
:
327 if (!(val
& PPC_BIT(0))) {
328 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: xscom write reg"
329 " TOD_LOAD_TOD_MOD_REG with bad val 0x%" PRIx64
"\n",
332 chiptod
->tod_state
= tod_not_set
;
335 case TOD_LOAD_TOD_REG
:
336 if (chiptod
->tod_state
!= tod_not_set
) {
337 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: LOAD_TOG_REG in "
338 " state %d, should be in 7 (TOD_NOT_SET)\n",
341 if (val
& PPC_BIT(63)) {
342 chiptod
->tod_state
= tod_stopped
;
344 chiptod
->tod_state
= tod_running
;
349 case TOD_MOVE_TOD_TO_TB_REG
:
351 * XXX: it should be a cleaner model to have this drive a SCOM
352 * transaction to the target address, and implement the state machine
353 * in the PnvCore. For now, this hack makes things work.
355 if (chiptod
->tod_state
!= tod_running
) {
356 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: xscom write reg"
357 " TOD_MOVE_TOD_TO_TB_REG in bad state %d\n",
359 } else if (!(val
& PPC_BIT(0))) {
360 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: xscom write reg"
361 " TOD_MOVE_TOD_TO_TB_REG with bad val 0x%" PRIx64
"\n",
363 } else if (chiptod
->slave_pc_target
== NULL
) {
364 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: xscom write reg"
365 " TOD_MOVE_TOD_TO_TB_REG with no slave target\n");
367 PowerPCCPU
*cpu
= chiptod
->slave_pc_target
->threads
[0];
368 CPUPPCState
*env
= &cpu
->env
;
371 * Moving TOD to TB will set the TB of all threads in a
372 * core, so skiboot only does this once per thread0, so
373 * that is where we keep the timebase state machine.
375 * It is likely possible for TBST to be driven from other
376 * threads in the core, but for now we only implement it for
380 if (env
->pnv_tod_tbst
.tb_ready_for_tod
) {
381 env
->pnv_tod_tbst
.tod_sent_to_tb
= 1;
383 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: xscom write reg"
384 " TOD_MOVE_TOD_TO_TB_REG with TB not ready to"
389 case TOD_START_TOD_REG
:
390 if (chiptod
->tod_state
!= tod_stopped
) {
391 qemu_log_mask(LOG_GUEST_ERROR
, "pnv_chiptod: LOAD_TOG_REG in "
392 " state %d, should be in 1 (TOD_STOPPED)\n",
395 chiptod
->tod_state
= tod_running
;
398 case TOD_TX_TTYPE_4_REG
:
399 case TOD_TX_TTYPE_5_REG
:
400 pctc
->broadcast_ttype(chiptod
, offset
);
403 qemu_log_mask(LOG_UNIMP
, "pnv_chiptod: unimplemented register: Ox%"
404 HWADDR_PRIx
"\n", addr
>> 3);
408 static const MemoryRegionOps pnv_chiptod_xscom_ops
= {
409 .read
= pnv_chiptod_xscom_read
,
410 .write
= pnv_chiptod_xscom_write
,
411 .valid
.min_access_size
= 8,
412 .valid
.max_access_size
= 8,
413 .impl
.min_access_size
= 8,
414 .impl
.max_access_size
= 8,
415 .endianness
= DEVICE_BIG_ENDIAN
,
418 static int pnv_chiptod_dt_xscom(PnvXScomInterface
*dev
, void *fdt
,
420 const char compat
[], size_t compat_size
)
422 PnvChipTOD
*chiptod
= PNV_CHIPTOD(dev
);
423 g_autofree
char *name
= NULL
;
425 uint32_t chiptod_pcba
= PNV9_XSCOM_CHIPTOD_BASE
;
427 cpu_to_be32(chiptod_pcba
),
428 cpu_to_be32(PNV9_XSCOM_CHIPTOD_SIZE
)
431 name
= g_strdup_printf("chiptod@%x", chiptod_pcba
);
432 offset
= fdt_add_subnode(fdt
, xscom_offset
, name
);
435 if (chiptod
->primary
) {
436 _FDT((fdt_setprop(fdt
, offset
, "primary", NULL
, 0)));
437 } else if (chiptod
->secondary
) {
438 _FDT((fdt_setprop(fdt
, offset
, "secondary", NULL
, 0)));
441 _FDT((fdt_setprop(fdt
, offset
, "reg", reg
, sizeof(reg
))));
442 _FDT((fdt_setprop(fdt
, offset
, "compatible", compat
, compat_size
)));
446 static int pnv_chiptod_power9_dt_xscom(PnvXScomInterface
*dev
, void *fdt
,
449 const char compat
[] = "ibm,power-chiptod\0ibm,power9-chiptod";
451 return pnv_chiptod_dt_xscom(dev
, fdt
, xscom_offset
, compat
, sizeof(compat
));
454 static Property pnv_chiptod_properties
[] = {
455 DEFINE_PROP_BOOL("primary", PnvChipTOD
, primary
, false),
456 DEFINE_PROP_BOOL("secondary", PnvChipTOD
, secondary
, false),
457 DEFINE_PROP_LINK("chip", PnvChipTOD
, chip
, TYPE_PNV_CHIP
, PnvChip
*),
458 DEFINE_PROP_END_OF_LIST(),
461 static void pnv_chiptod_power9_class_init(ObjectClass
*klass
, void *data
)
463 PnvChipTODClass
*pctc
= PNV_CHIPTOD_CLASS(klass
);
464 DeviceClass
*dc
= DEVICE_CLASS(klass
);
465 PnvXScomInterfaceClass
*xdc
= PNV_XSCOM_INTERFACE_CLASS(klass
);
467 dc
->desc
= "PowerNV ChipTOD Controller (POWER9)";
468 device_class_set_props(dc
, pnv_chiptod_properties
);
470 xdc
->dt_xscom
= pnv_chiptod_power9_dt_xscom
;
472 pctc
->broadcast_ttype
= chiptod_power9_broadcast_ttype
;
473 pctc
->tx_ttype_target
= chiptod_power9_tx_ttype_target
;
475 pctc
->xscom_size
= PNV_XSCOM_CHIPTOD_SIZE
;
478 static const TypeInfo pnv_chiptod_power9_type_info
= {
479 .name
= TYPE_PNV9_CHIPTOD
,
480 .parent
= TYPE_PNV_CHIPTOD
,
481 .instance_size
= sizeof(PnvChipTOD
),
482 .class_init
= pnv_chiptod_power9_class_init
,
483 .interfaces
= (InterfaceInfo
[]) {
484 { TYPE_PNV_XSCOM_INTERFACE
},
489 static int pnv_chiptod_power10_dt_xscom(PnvXScomInterface
*dev
, void *fdt
,
492 const char compat
[] = "ibm,power-chiptod\0ibm,power10-chiptod";
494 return pnv_chiptod_dt_xscom(dev
, fdt
, xscom_offset
, compat
, sizeof(compat
));
497 static void pnv_chiptod_power10_class_init(ObjectClass
*klass
, void *data
)
499 PnvChipTODClass
*pctc
= PNV_CHIPTOD_CLASS(klass
);
500 DeviceClass
*dc
= DEVICE_CLASS(klass
);
501 PnvXScomInterfaceClass
*xdc
= PNV_XSCOM_INTERFACE_CLASS(klass
);
503 dc
->desc
= "PowerNV ChipTOD Controller (POWER10)";
504 device_class_set_props(dc
, pnv_chiptod_properties
);
506 xdc
->dt_xscom
= pnv_chiptod_power10_dt_xscom
;
508 pctc
->broadcast_ttype
= chiptod_power10_broadcast_ttype
;
509 pctc
->tx_ttype_target
= chiptod_power10_tx_ttype_target
;
511 pctc
->xscom_size
= PNV_XSCOM_CHIPTOD_SIZE
;
514 static const TypeInfo pnv_chiptod_power10_type_info
= {
515 .name
= TYPE_PNV10_CHIPTOD
,
516 .parent
= TYPE_PNV_CHIPTOD
,
517 .instance_size
= sizeof(PnvChipTOD
),
518 .class_init
= pnv_chiptod_power10_class_init
,
519 .interfaces
= (InterfaceInfo
[]) {
520 { TYPE_PNV_XSCOM_INTERFACE
},
525 static void pnv_chiptod_reset(void *dev
)
527 PnvChipTOD
*chiptod
= PNV_CHIPTOD(dev
);
529 chiptod
->pss_mss_ctrl_reg
= 0;
530 if (chiptod
->primary
) {
531 chiptod
->pss_mss_ctrl_reg
|= PPC_BIT(1); /* TOD is master */
533 /* Drawer is master (we do not simulate multi-drawer) */
534 chiptod
->pss_mss_ctrl_reg
|= PPC_BIT(2);
536 chiptod
->tod_error
= 0;
537 chiptod
->tod_state
= tod_error
;
540 static void pnv_chiptod_realize(DeviceState
*dev
, Error
**errp
)
542 PnvChipTOD
*chiptod
= PNV_CHIPTOD(dev
);
543 PnvChipTODClass
*pctc
= PNV_CHIPTOD_GET_CLASS(chiptod
);
545 /* XScom regions for ChipTOD registers */
546 pnv_xscom_region_init(&chiptod
->xscom_regs
, OBJECT(dev
),
547 &pnv_chiptod_xscom_ops
, chiptod
, "xscom-chiptod",
550 qemu_register_reset(pnv_chiptod_reset
, chiptod
);
553 static void pnv_chiptod_unrealize(DeviceState
*dev
)
555 PnvChipTOD
*chiptod
= PNV_CHIPTOD(dev
);
557 qemu_unregister_reset(pnv_chiptod_reset
, chiptod
);
560 static void pnv_chiptod_class_init(ObjectClass
*klass
, void *data
)
562 DeviceClass
*dc
= DEVICE_CLASS(klass
);
564 dc
->realize
= pnv_chiptod_realize
;
565 dc
->unrealize
= pnv_chiptod_unrealize
;
566 dc
->desc
= "PowerNV ChipTOD Controller";
567 dc
->user_creatable
= false;
570 static const TypeInfo pnv_chiptod_type_info
= {
571 .name
= TYPE_PNV_CHIPTOD
,
572 .parent
= TYPE_DEVICE
,
573 .instance_size
= sizeof(PnvChipTOD
),
574 .class_init
= pnv_chiptod_class_init
,
575 .class_size
= sizeof(PnvChipTODClass
),
579 static void pnv_chiptod_register_types(void)
581 type_register_static(&pnv_chiptod_type_info
);
582 type_register_static(&pnv_chiptod_power9_type_info
);
583 type_register_static(&pnv_chiptod_power10_type_info
);
586 type_init(pnv_chiptod_register_types
);