xref: /qemu/hw/ppc/pnv_chiptod.c (revision 9a69950feb0983cde8a97f8c7d1623e81b912412)
1*9a69950fSNicholas Piggin /*
2*9a69950fSNicholas Piggin  * QEMU PowerPC PowerNV Emulation of some ChipTOD behaviour
3*9a69950fSNicholas Piggin  *
4*9a69950fSNicholas Piggin  * Copyright (c) 2022-2023, IBM Corporation.
5*9a69950fSNicholas Piggin  *
6*9a69950fSNicholas Piggin  * SPDX-License-Identifier: GPL-2.0-or-later
7*9a69950fSNicholas Piggin  *
8*9a69950fSNicholas Piggin  * ChipTOD (aka TOD) is a facility implemented in the nest / pervasive. The
9*9a69950fSNicholas Piggin  * purpose is to keep time-of-day across chips and cores.
10*9a69950fSNicholas Piggin  *
11*9a69950fSNicholas Piggin  * There is a master chip TOD, which sends signals to slave chip TODs to
12*9a69950fSNicholas Piggin  * keep them synchronized. There are two sets of configuration registers
13*9a69950fSNicholas Piggin  * called primary and secondary, which can be used fail over.
14*9a69950fSNicholas Piggin  *
15*9a69950fSNicholas Piggin  * The chip TOD also distributes synchronisation signals to the timebase
16*9a69950fSNicholas Piggin  * facility in each of the cores on the chip. In particular there is a
17*9a69950fSNicholas Piggin  * feature that can move the TOD value in the ChipTOD to and from the TB.
18*9a69950fSNicholas Piggin  *
19*9a69950fSNicholas Piggin  * Initialisation typically brings all ChipTOD into sync (see tod_state),
20*9a69950fSNicholas Piggin  * and then brings each core TB into sync with the ChipTODs (see timebase
21*9a69950fSNicholas Piggin  * state and TFMR). This model is a very basic simulation of the init sequence
22*9a69950fSNicholas Piggin  * performed by skiboot.
23*9a69950fSNicholas Piggin  */
24*9a69950fSNicholas Piggin 
25*9a69950fSNicholas Piggin #include "qemu/osdep.h"
26*9a69950fSNicholas Piggin #include "sysemu/reset.h"
27*9a69950fSNicholas Piggin #include "target/ppc/cpu.h"
28*9a69950fSNicholas Piggin #include "qapi/error.h"
29*9a69950fSNicholas Piggin #include "qemu/log.h"
30*9a69950fSNicholas Piggin #include "qemu/module.h"
31*9a69950fSNicholas Piggin #include "hw/irq.h"
32*9a69950fSNicholas Piggin #include "hw/qdev-properties.h"
33*9a69950fSNicholas Piggin #include "hw/ppc/fdt.h"
34*9a69950fSNicholas Piggin #include "hw/ppc/ppc.h"
35*9a69950fSNicholas Piggin #include "hw/ppc/pnv.h"
36*9a69950fSNicholas Piggin #include "hw/ppc/pnv_chip.h"
37*9a69950fSNicholas Piggin #include "hw/ppc/pnv_core.h"
38*9a69950fSNicholas Piggin #include "hw/ppc/pnv_xscom.h"
39*9a69950fSNicholas Piggin #include "hw/ppc/pnv_chiptod.h"
40*9a69950fSNicholas Piggin #include "trace.h"
41*9a69950fSNicholas Piggin 
42*9a69950fSNicholas Piggin #include <libfdt.h>
43*9a69950fSNicholas Piggin 
44*9a69950fSNicholas Piggin /* TOD chip XSCOM addresses */
45*9a69950fSNicholas Piggin #define TOD_M_PATH_CTRL_REG             0x00000000 /* Master Path ctrl reg */
46*9a69950fSNicholas Piggin #define TOD_PRI_PORT_0_CTRL_REG         0x00000001 /* Primary port0 ctrl reg */
47*9a69950fSNicholas Piggin #define TOD_PRI_PORT_1_CTRL_REG         0x00000002 /* Primary port1 ctrl reg */
48*9a69950fSNicholas Piggin #define TOD_SEC_PORT_0_CTRL_REG         0x00000003 /* Secondary p0 ctrl reg */
49*9a69950fSNicholas Piggin #define TOD_SEC_PORT_1_CTRL_REG         0x00000004 /* Secondary p1 ctrl reg */
50*9a69950fSNicholas Piggin #define TOD_S_PATH_CTRL_REG             0x00000005 /* Slave Path ctrl reg */
51*9a69950fSNicholas Piggin #define TOD_I_PATH_CTRL_REG             0x00000006 /* Internal Path ctrl reg */
52*9a69950fSNicholas Piggin 
53*9a69950fSNicholas Piggin /* -- TOD primary/secondary master/slave control register -- */
54*9a69950fSNicholas Piggin #define TOD_PSS_MSS_CTRL_REG            0x00000007
55*9a69950fSNicholas Piggin 
56*9a69950fSNicholas Piggin /* -- TOD primary/secondary master/slave status register -- */
57*9a69950fSNicholas Piggin #define TOD_PSS_MSS_STATUS_REG          0x00000008
58*9a69950fSNicholas Piggin 
59*9a69950fSNicholas Piggin /* TOD chip XSCOM addresses */
60*9a69950fSNicholas Piggin #define TOD_CHIP_CTRL_REG               0x00000010 /* Chip control reg */
61*9a69950fSNicholas Piggin 
62*9a69950fSNicholas Piggin #define TOD_TX_TTYPE_0_REG              0x00000011
63*9a69950fSNicholas Piggin #define TOD_TX_TTYPE_1_REG              0x00000012 /* PSS switch reg */
64*9a69950fSNicholas Piggin #define TOD_TX_TTYPE_2_REG              0x00000013 /* Enable step checkers */
65*9a69950fSNicholas Piggin #define TOD_TX_TTYPE_3_REG              0x00000014 /* Request TOD reg */
66*9a69950fSNicholas Piggin #define TOD_TX_TTYPE_4_REG              0x00000015 /* Send TOD reg */
67*9a69950fSNicholas Piggin #define TOD_TX_TTYPE_5_REG              0x00000016 /* Invalidate TOD reg */
68*9a69950fSNicholas Piggin 
69*9a69950fSNicholas Piggin #define TOD_MOVE_TOD_TO_TB_REG          0x00000017
70*9a69950fSNicholas Piggin #define TOD_LOAD_TOD_MOD_REG            0x00000018
71*9a69950fSNicholas Piggin #define TOD_LOAD_TOD_REG                0x00000021
72*9a69950fSNicholas Piggin #define TOD_START_TOD_REG               0x00000022
73*9a69950fSNicholas Piggin #define TOD_FSM_REG                     0x00000024
74*9a69950fSNicholas Piggin 
75*9a69950fSNicholas Piggin #define TOD_TX_TTYPE_CTRL_REG           0x00000027 /* TX TTYPE Control reg */
76*9a69950fSNicholas Piggin #define   TOD_TX_TTYPE_PIB_SLAVE_ADDR      PPC_BITMASK(26, 31)
77*9a69950fSNicholas Piggin 
78*9a69950fSNicholas Piggin /* -- TOD Error interrupt register -- */
79*9a69950fSNicholas Piggin #define TOD_ERROR_REG                   0x00000030
80*9a69950fSNicholas Piggin 
81*9a69950fSNicholas Piggin /* PC unit PIB address which recieves the timebase transfer from TOD */
82*9a69950fSNicholas Piggin #define   PC_TOD                        0x4A3
83*9a69950fSNicholas Piggin 
84*9a69950fSNicholas Piggin /*
85*9a69950fSNicholas Piggin  * The TOD FSM:
86*9a69950fSNicholas Piggin  * - The reset state is 0 error.
87*9a69950fSNicholas Piggin  * - A hardware error detected will transition to state 0 from any state.
88*9a69950fSNicholas Piggin  * - LOAD_TOD_MOD and TTYPE5 will transition to state 7 from any state.
89*9a69950fSNicholas Piggin  *
90*9a69950fSNicholas Piggin  * | state      | action                       | new |
91*9a69950fSNicholas Piggin  * |------------+------------------------------+-----|
92*9a69950fSNicholas Piggin  * | 0 error    | LOAD_TOD_MOD                 |  7  |
93*9a69950fSNicholas Piggin  * | 0 error    | Recv TTYPE5 (invalidate TOD) |  7  |
94*9a69950fSNicholas Piggin  * | 7 not_set  | LOAD_TOD (bit-63 = 0)        |  2  |
95*9a69950fSNicholas Piggin  * | 7 not_set  | LOAD_TOD (bit-63 = 1)        |  1  |
96*9a69950fSNicholas Piggin  * | 7 not_set  | Recv TTYPE4 (send TOD)       |  2  |
97*9a69950fSNicholas Piggin  * | 2 running  |                              |     |
98*9a69950fSNicholas Piggin  * | 1 stopped  | START_TOD                    |  2  |
99*9a69950fSNicholas Piggin  *
100*9a69950fSNicholas Piggin  * Note the hardware has additional states but they relate to the sending
101*9a69950fSNicholas Piggin  * and receiving and waiting on synchronisation signals between chips and
102*9a69950fSNicholas Piggin  * are not described or modeled here.
103*9a69950fSNicholas Piggin  */
104*9a69950fSNicholas Piggin 
105*9a69950fSNicholas Piggin static uint64_t pnv_chiptod_xscom_read(void *opaque, hwaddr addr,
106*9a69950fSNicholas Piggin                                           unsigned size)
107*9a69950fSNicholas Piggin {
108*9a69950fSNicholas Piggin     PnvChipTOD *chiptod = PNV_CHIPTOD(opaque);
109*9a69950fSNicholas Piggin     uint32_t offset = addr >> 3;
110*9a69950fSNicholas Piggin     uint64_t val = 0;
111*9a69950fSNicholas Piggin 
112*9a69950fSNicholas Piggin     switch (offset) {
113*9a69950fSNicholas Piggin     case TOD_PSS_MSS_STATUS_REG:
114*9a69950fSNicholas Piggin         /*
115*9a69950fSNicholas Piggin          * ChipTOD does not support configurations other than primary
116*9a69950fSNicholas Piggin          * master, does not support errors, etc.
117*9a69950fSNicholas Piggin          */
118*9a69950fSNicholas Piggin         val |= PPC_BITMASK(6, 10); /* STEP checker validity */
119*9a69950fSNicholas Piggin         val |= PPC_BIT(12); /* Primary config master path select */
120*9a69950fSNicholas Piggin         if (chiptod->tod_state == tod_running) {
121*9a69950fSNicholas Piggin             val |= PPC_BIT(20); /* Is running */
122*9a69950fSNicholas Piggin         }
123*9a69950fSNicholas Piggin         val |= PPC_BIT(21); /* Is using primary config */
124*9a69950fSNicholas Piggin         val |= PPC_BIT(26); /* Is using master path select */
125*9a69950fSNicholas Piggin 
126*9a69950fSNicholas Piggin         if (chiptod->primary) {
127*9a69950fSNicholas Piggin             val |= PPC_BIT(23); /* Is active master */
128*9a69950fSNicholas Piggin         } else if (chiptod->secondary) {
129*9a69950fSNicholas Piggin             val |= PPC_BIT(24); /* Is backup master */
130*9a69950fSNicholas Piggin         } else {
131*9a69950fSNicholas Piggin             val |= PPC_BIT(25); /* Is slave (should backup master set this?) */
132*9a69950fSNicholas Piggin         }
133*9a69950fSNicholas Piggin         break;
134*9a69950fSNicholas Piggin     case TOD_PSS_MSS_CTRL_REG:
135*9a69950fSNicholas Piggin         val = chiptod->pss_mss_ctrl_reg;
136*9a69950fSNicholas Piggin         break;
137*9a69950fSNicholas Piggin     case TOD_TX_TTYPE_CTRL_REG:
138*9a69950fSNicholas Piggin         val = 0;
139*9a69950fSNicholas Piggin         break;
140*9a69950fSNicholas Piggin     case TOD_ERROR_REG:
141*9a69950fSNicholas Piggin         val = chiptod->tod_error;
142*9a69950fSNicholas Piggin         break;
143*9a69950fSNicholas Piggin     case TOD_FSM_REG:
144*9a69950fSNicholas Piggin         if (chiptod->tod_state == tod_running) {
145*9a69950fSNicholas Piggin             val |= PPC_BIT(4);
146*9a69950fSNicholas Piggin         }
147*9a69950fSNicholas Piggin         break;
148*9a69950fSNicholas Piggin     default:
149*9a69950fSNicholas Piggin         qemu_log_mask(LOG_UNIMP, "pnv_chiptod: unimplemented register: Ox%"
150*9a69950fSNicholas Piggin                       HWADDR_PRIx "\n", addr >> 3);
151*9a69950fSNicholas Piggin     }
152*9a69950fSNicholas Piggin 
153*9a69950fSNicholas Piggin     trace_pnv_chiptod_xscom_read(addr >> 3, val);
154*9a69950fSNicholas Piggin 
155*9a69950fSNicholas Piggin     return val;
156*9a69950fSNicholas Piggin }
157*9a69950fSNicholas Piggin 
158*9a69950fSNicholas Piggin static void chiptod_receive_ttype(PnvChipTOD *chiptod, uint32_t trigger)
159*9a69950fSNicholas Piggin {
160*9a69950fSNicholas Piggin     switch (trigger) {
161*9a69950fSNicholas Piggin     case TOD_TX_TTYPE_4_REG:
162*9a69950fSNicholas Piggin         if (chiptod->tod_state != tod_not_set) {
163*9a69950fSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: received TTYPE4 in "
164*9a69950fSNicholas Piggin                           " state %d, should be in 7 (TOD_NOT_SET)\n",
165*9a69950fSNicholas Piggin                           chiptod->tod_state);
166*9a69950fSNicholas Piggin         } else {
167*9a69950fSNicholas Piggin             chiptod->tod_state = tod_running;
168*9a69950fSNicholas Piggin         }
169*9a69950fSNicholas Piggin         break;
170*9a69950fSNicholas Piggin     case TOD_TX_TTYPE_5_REG:
171*9a69950fSNicholas Piggin         /* Works from any state */
172*9a69950fSNicholas Piggin         chiptod->tod_state = tod_not_set;
173*9a69950fSNicholas Piggin         break;
174*9a69950fSNicholas Piggin     default:
175*9a69950fSNicholas Piggin         qemu_log_mask(LOG_UNIMP, "pnv_chiptod: received unimplemented "
176*9a69950fSNicholas Piggin                       " TTYPE %u\n", trigger);
177*9a69950fSNicholas Piggin         break;
178*9a69950fSNicholas Piggin     }
179*9a69950fSNicholas Piggin }
180*9a69950fSNicholas Piggin 
181*9a69950fSNicholas Piggin static void chiptod_power9_broadcast_ttype(PnvChipTOD *sender,
182*9a69950fSNicholas Piggin                                             uint32_t trigger)
183*9a69950fSNicholas Piggin {
184*9a69950fSNicholas Piggin     PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
185*9a69950fSNicholas Piggin     int i;
186*9a69950fSNicholas Piggin 
187*9a69950fSNicholas Piggin     for (i = 0; i < pnv->num_chips; i++) {
188*9a69950fSNicholas Piggin         Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]);
189*9a69950fSNicholas Piggin         PnvChipTOD *chiptod = &chip9->chiptod;
190*9a69950fSNicholas Piggin 
191*9a69950fSNicholas Piggin         if (chiptod != sender) {
192*9a69950fSNicholas Piggin             chiptod_receive_ttype(chiptod, trigger);
193*9a69950fSNicholas Piggin         }
194*9a69950fSNicholas Piggin     }
195*9a69950fSNicholas Piggin }
196*9a69950fSNicholas Piggin 
197*9a69950fSNicholas Piggin static void chiptod_power10_broadcast_ttype(PnvChipTOD *sender,
198*9a69950fSNicholas Piggin                                             uint32_t trigger)
199*9a69950fSNicholas Piggin {
200*9a69950fSNicholas Piggin     PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
201*9a69950fSNicholas Piggin     int i;
202*9a69950fSNicholas Piggin 
203*9a69950fSNicholas Piggin     for (i = 0; i < pnv->num_chips; i++) {
204*9a69950fSNicholas Piggin         Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]);
205*9a69950fSNicholas Piggin         PnvChipTOD *chiptod = &chip10->chiptod;
206*9a69950fSNicholas Piggin 
207*9a69950fSNicholas Piggin         if (chiptod != sender) {
208*9a69950fSNicholas Piggin             chiptod_receive_ttype(chiptod, trigger);
209*9a69950fSNicholas Piggin         }
210*9a69950fSNicholas Piggin     }
211*9a69950fSNicholas Piggin }
212*9a69950fSNicholas Piggin 
213*9a69950fSNicholas Piggin static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
214*9a69950fSNicholas Piggin                                     uint64_t val, unsigned size)
215*9a69950fSNicholas Piggin {
216*9a69950fSNicholas Piggin     PnvChipTOD *chiptod = PNV_CHIPTOD(opaque);
217*9a69950fSNicholas Piggin     PnvChipTODClass *pctc = PNV_CHIPTOD_GET_CLASS(chiptod);
218*9a69950fSNicholas Piggin     uint32_t offset = addr >> 3;
219*9a69950fSNicholas Piggin 
220*9a69950fSNicholas Piggin     trace_pnv_chiptod_xscom_write(addr >> 3, val);
221*9a69950fSNicholas Piggin 
222*9a69950fSNicholas Piggin     switch (offset) {
223*9a69950fSNicholas Piggin     case TOD_PSS_MSS_CTRL_REG:
224*9a69950fSNicholas Piggin         /* Is this correct? */
225*9a69950fSNicholas Piggin         if (chiptod->primary) {
226*9a69950fSNicholas Piggin             val |= PPC_BIT(1); /* TOD is master */
227*9a69950fSNicholas Piggin         } else {
228*9a69950fSNicholas Piggin             val &= ~PPC_BIT(1);
229*9a69950fSNicholas Piggin         }
230*9a69950fSNicholas Piggin         val |= PPC_BIT(2); /* Drawer is master (don't simulate multi-drawer) */
231*9a69950fSNicholas Piggin         chiptod->pss_mss_ctrl_reg = val & PPC_BITMASK(0, 31);
232*9a69950fSNicholas Piggin         break;
233*9a69950fSNicholas Piggin 
234*9a69950fSNicholas Piggin     case TOD_ERROR_REG:
235*9a69950fSNicholas Piggin         chiptod->tod_error &= ~val;
236*9a69950fSNicholas Piggin         break;
237*9a69950fSNicholas Piggin     case TOD_LOAD_TOD_MOD_REG:
238*9a69950fSNicholas Piggin         if (!(val & PPC_BIT(0))) {
239*9a69950fSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg"
240*9a69950fSNicholas Piggin                           " TOD_LOAD_TOD_MOD_REG with bad val 0x%" PRIx64"\n",
241*9a69950fSNicholas Piggin                           val);
242*9a69950fSNicholas Piggin         } else {
243*9a69950fSNicholas Piggin             chiptod->tod_state = tod_not_set;
244*9a69950fSNicholas Piggin         }
245*9a69950fSNicholas Piggin         break;
246*9a69950fSNicholas Piggin     case TOD_LOAD_TOD_REG:
247*9a69950fSNicholas Piggin         if (chiptod->tod_state != tod_not_set) {
248*9a69950fSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: LOAD_TOG_REG in "
249*9a69950fSNicholas Piggin                           " state %d, should be in 7 (TOD_NOT_SET)\n",
250*9a69950fSNicholas Piggin                           chiptod->tod_state);
251*9a69950fSNicholas Piggin         } else {
252*9a69950fSNicholas Piggin             if (val & PPC_BIT(63)) {
253*9a69950fSNicholas Piggin                 chiptod->tod_state = tod_stopped;
254*9a69950fSNicholas Piggin             } else {
255*9a69950fSNicholas Piggin                 chiptod->tod_state = tod_running;
256*9a69950fSNicholas Piggin             }
257*9a69950fSNicholas Piggin         }
258*9a69950fSNicholas Piggin         break;
259*9a69950fSNicholas Piggin     case TOD_START_TOD_REG:
260*9a69950fSNicholas Piggin         if (chiptod->tod_state != tod_stopped) {
261*9a69950fSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: LOAD_TOG_REG in "
262*9a69950fSNicholas Piggin                           " state %d, should be in 1 (TOD_STOPPED)\n",
263*9a69950fSNicholas Piggin                           chiptod->tod_state);
264*9a69950fSNicholas Piggin         } else {
265*9a69950fSNicholas Piggin             chiptod->tod_state = tod_running;
266*9a69950fSNicholas Piggin         }
267*9a69950fSNicholas Piggin         break;
268*9a69950fSNicholas Piggin     case TOD_TX_TTYPE_4_REG:
269*9a69950fSNicholas Piggin     case TOD_TX_TTYPE_5_REG:
270*9a69950fSNicholas Piggin         pctc->broadcast_ttype(chiptod, offset);
271*9a69950fSNicholas Piggin         break;
272*9a69950fSNicholas Piggin     default:
273*9a69950fSNicholas Piggin         qemu_log_mask(LOG_UNIMP, "pnv_chiptod: unimplemented register: Ox%"
274*9a69950fSNicholas Piggin                       HWADDR_PRIx "\n", addr >> 3);
275*9a69950fSNicholas Piggin     }
276*9a69950fSNicholas Piggin }
277*9a69950fSNicholas Piggin 
278*9a69950fSNicholas Piggin static const MemoryRegionOps pnv_chiptod_xscom_ops = {
279*9a69950fSNicholas Piggin     .read = pnv_chiptod_xscom_read,
280*9a69950fSNicholas Piggin     .write = pnv_chiptod_xscom_write,
281*9a69950fSNicholas Piggin     .valid.min_access_size = 8,
282*9a69950fSNicholas Piggin     .valid.max_access_size = 8,
283*9a69950fSNicholas Piggin     .impl.min_access_size = 8,
284*9a69950fSNicholas Piggin     .impl.max_access_size = 8,
285*9a69950fSNicholas Piggin     .endianness = DEVICE_BIG_ENDIAN,
286*9a69950fSNicholas Piggin };
287*9a69950fSNicholas Piggin 
288*9a69950fSNicholas Piggin static int pnv_chiptod_dt_xscom(PnvXScomInterface *dev, void *fdt,
289*9a69950fSNicholas Piggin                                 int xscom_offset,
290*9a69950fSNicholas Piggin                                 const char compat[], size_t compat_size)
291*9a69950fSNicholas Piggin {
292*9a69950fSNicholas Piggin     PnvChipTOD *chiptod = PNV_CHIPTOD(dev);
293*9a69950fSNicholas Piggin     g_autofree char *name = NULL;
294*9a69950fSNicholas Piggin     int offset;
295*9a69950fSNicholas Piggin     uint32_t chiptod_pcba = PNV9_XSCOM_CHIPTOD_BASE;
296*9a69950fSNicholas Piggin     uint32_t reg[] = {
297*9a69950fSNicholas Piggin         cpu_to_be32(chiptod_pcba),
298*9a69950fSNicholas Piggin         cpu_to_be32(PNV9_XSCOM_CHIPTOD_SIZE)
299*9a69950fSNicholas Piggin     };
300*9a69950fSNicholas Piggin 
301*9a69950fSNicholas Piggin     name = g_strdup_printf("chiptod@%x", chiptod_pcba);
302*9a69950fSNicholas Piggin     offset = fdt_add_subnode(fdt, xscom_offset, name);
303*9a69950fSNicholas Piggin     _FDT(offset);
304*9a69950fSNicholas Piggin 
305*9a69950fSNicholas Piggin     if (chiptod->primary) {
306*9a69950fSNicholas Piggin         _FDT((fdt_setprop(fdt, offset, "primary", NULL, 0)));
307*9a69950fSNicholas Piggin     } else if (chiptod->secondary) {
308*9a69950fSNicholas Piggin         _FDT((fdt_setprop(fdt, offset, "secondary", NULL, 0)));
309*9a69950fSNicholas Piggin     }
310*9a69950fSNicholas Piggin 
311*9a69950fSNicholas Piggin     _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
312*9a69950fSNicholas Piggin     _FDT((fdt_setprop(fdt, offset, "compatible", compat, compat_size)));
313*9a69950fSNicholas Piggin     return 0;
314*9a69950fSNicholas Piggin }
315*9a69950fSNicholas Piggin 
316*9a69950fSNicholas Piggin static int pnv_chiptod_power9_dt_xscom(PnvXScomInterface *dev, void *fdt,
317*9a69950fSNicholas Piggin                              int xscom_offset)
318*9a69950fSNicholas Piggin {
319*9a69950fSNicholas Piggin     const char compat[] = "ibm,power-chiptod\0ibm,power9-chiptod";
320*9a69950fSNicholas Piggin 
321*9a69950fSNicholas Piggin     return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat));
322*9a69950fSNicholas Piggin }
323*9a69950fSNicholas Piggin 
324*9a69950fSNicholas Piggin static Property pnv_chiptod_properties[] = {
325*9a69950fSNicholas Piggin     DEFINE_PROP_BOOL("primary", PnvChipTOD, primary, false),
326*9a69950fSNicholas Piggin     DEFINE_PROP_BOOL("secondary", PnvChipTOD, secondary, false),
327*9a69950fSNicholas Piggin     DEFINE_PROP_LINK("chip", PnvChipTOD , chip, TYPE_PNV_CHIP, PnvChip *),
328*9a69950fSNicholas Piggin     DEFINE_PROP_END_OF_LIST(),
329*9a69950fSNicholas Piggin };
330*9a69950fSNicholas Piggin 
331*9a69950fSNicholas Piggin static void pnv_chiptod_power9_class_init(ObjectClass *klass, void *data)
332*9a69950fSNicholas Piggin {
333*9a69950fSNicholas Piggin     PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass);
334*9a69950fSNicholas Piggin     DeviceClass *dc = DEVICE_CLASS(klass);
335*9a69950fSNicholas Piggin     PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
336*9a69950fSNicholas Piggin 
337*9a69950fSNicholas Piggin     dc->desc = "PowerNV ChipTOD Controller (POWER9)";
338*9a69950fSNicholas Piggin     device_class_set_props(dc, pnv_chiptod_properties);
339*9a69950fSNicholas Piggin 
340*9a69950fSNicholas Piggin     xdc->dt_xscom = pnv_chiptod_power9_dt_xscom;
341*9a69950fSNicholas Piggin 
342*9a69950fSNicholas Piggin     pctc->broadcast_ttype = chiptod_power9_broadcast_ttype;
343*9a69950fSNicholas Piggin 
344*9a69950fSNicholas Piggin     pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE;
345*9a69950fSNicholas Piggin }
346*9a69950fSNicholas Piggin 
347*9a69950fSNicholas Piggin static const TypeInfo pnv_chiptod_power9_type_info = {
348*9a69950fSNicholas Piggin     .name          = TYPE_PNV9_CHIPTOD,
349*9a69950fSNicholas Piggin     .parent        = TYPE_PNV_CHIPTOD,
350*9a69950fSNicholas Piggin     .instance_size = sizeof(PnvChipTOD),
351*9a69950fSNicholas Piggin     .class_init    = pnv_chiptod_power9_class_init,
352*9a69950fSNicholas Piggin     .interfaces    = (InterfaceInfo[]) {
353*9a69950fSNicholas Piggin         { TYPE_PNV_XSCOM_INTERFACE },
354*9a69950fSNicholas Piggin         { }
355*9a69950fSNicholas Piggin     }
356*9a69950fSNicholas Piggin };
357*9a69950fSNicholas Piggin 
358*9a69950fSNicholas Piggin static int pnv_chiptod_power10_dt_xscom(PnvXScomInterface *dev, void *fdt,
359*9a69950fSNicholas Piggin                              int xscom_offset)
360*9a69950fSNicholas Piggin {
361*9a69950fSNicholas Piggin     const char compat[] = "ibm,power-chiptod\0ibm,power10-chiptod";
362*9a69950fSNicholas Piggin 
363*9a69950fSNicholas Piggin     return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat));
364*9a69950fSNicholas Piggin }
365*9a69950fSNicholas Piggin 
366*9a69950fSNicholas Piggin static void pnv_chiptod_power10_class_init(ObjectClass *klass, void *data)
367*9a69950fSNicholas Piggin {
368*9a69950fSNicholas Piggin     PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass);
369*9a69950fSNicholas Piggin     DeviceClass *dc = DEVICE_CLASS(klass);
370*9a69950fSNicholas Piggin     PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
371*9a69950fSNicholas Piggin 
372*9a69950fSNicholas Piggin     dc->desc = "PowerNV ChipTOD Controller (POWER10)";
373*9a69950fSNicholas Piggin     device_class_set_props(dc, pnv_chiptod_properties);
374*9a69950fSNicholas Piggin 
375*9a69950fSNicholas Piggin     xdc->dt_xscom = pnv_chiptod_power10_dt_xscom;
376*9a69950fSNicholas Piggin 
377*9a69950fSNicholas Piggin     pctc->broadcast_ttype = chiptod_power10_broadcast_ttype;
378*9a69950fSNicholas Piggin 
379*9a69950fSNicholas Piggin     pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE;
380*9a69950fSNicholas Piggin }
381*9a69950fSNicholas Piggin 
382*9a69950fSNicholas Piggin static const TypeInfo pnv_chiptod_power10_type_info = {
383*9a69950fSNicholas Piggin     .name          = TYPE_PNV10_CHIPTOD,
384*9a69950fSNicholas Piggin     .parent        = TYPE_PNV_CHIPTOD,
385*9a69950fSNicholas Piggin     .instance_size = sizeof(PnvChipTOD),
386*9a69950fSNicholas Piggin     .class_init    = pnv_chiptod_power10_class_init,
387*9a69950fSNicholas Piggin     .interfaces    = (InterfaceInfo[]) {
388*9a69950fSNicholas Piggin         { TYPE_PNV_XSCOM_INTERFACE },
389*9a69950fSNicholas Piggin         { }
390*9a69950fSNicholas Piggin     }
391*9a69950fSNicholas Piggin };
392*9a69950fSNicholas Piggin 
393*9a69950fSNicholas Piggin static void pnv_chiptod_reset(void *dev)
394*9a69950fSNicholas Piggin {
395*9a69950fSNicholas Piggin     PnvChipTOD *chiptod = PNV_CHIPTOD(dev);
396*9a69950fSNicholas Piggin 
397*9a69950fSNicholas Piggin     chiptod->pss_mss_ctrl_reg = 0;
398*9a69950fSNicholas Piggin     if (chiptod->primary) {
399*9a69950fSNicholas Piggin         chiptod->pss_mss_ctrl_reg |= PPC_BIT(1); /* TOD is master */
400*9a69950fSNicholas Piggin     }
401*9a69950fSNicholas Piggin     /* Drawer is master (we do not simulate multi-drawer) */
402*9a69950fSNicholas Piggin     chiptod->pss_mss_ctrl_reg |= PPC_BIT(2);
403*9a69950fSNicholas Piggin 
404*9a69950fSNicholas Piggin     chiptod->tod_error = 0;
405*9a69950fSNicholas Piggin     chiptod->tod_state = tod_error;
406*9a69950fSNicholas Piggin }
407*9a69950fSNicholas Piggin 
408*9a69950fSNicholas Piggin static void pnv_chiptod_realize(DeviceState *dev, Error **errp)
409*9a69950fSNicholas Piggin {
410*9a69950fSNicholas Piggin     PnvChipTOD *chiptod = PNV_CHIPTOD(dev);
411*9a69950fSNicholas Piggin     PnvChipTODClass *pctc = PNV_CHIPTOD_GET_CLASS(chiptod);
412*9a69950fSNicholas Piggin 
413*9a69950fSNicholas Piggin     /* XScom regions for ChipTOD registers */
414*9a69950fSNicholas Piggin     pnv_xscom_region_init(&chiptod->xscom_regs, OBJECT(dev),
415*9a69950fSNicholas Piggin                           &pnv_chiptod_xscom_ops, chiptod, "xscom-chiptod",
416*9a69950fSNicholas Piggin                           pctc->xscom_size);
417*9a69950fSNicholas Piggin 
418*9a69950fSNicholas Piggin     qemu_register_reset(pnv_chiptod_reset, chiptod);
419*9a69950fSNicholas Piggin }
420*9a69950fSNicholas Piggin 
421*9a69950fSNicholas Piggin static void pnv_chiptod_unrealize(DeviceState *dev)
422*9a69950fSNicholas Piggin {
423*9a69950fSNicholas Piggin     PnvChipTOD *chiptod = PNV_CHIPTOD(dev);
424*9a69950fSNicholas Piggin 
425*9a69950fSNicholas Piggin     qemu_unregister_reset(pnv_chiptod_reset, chiptod);
426*9a69950fSNicholas Piggin }
427*9a69950fSNicholas Piggin 
428*9a69950fSNicholas Piggin static void pnv_chiptod_class_init(ObjectClass *klass, void *data)
429*9a69950fSNicholas Piggin {
430*9a69950fSNicholas Piggin     DeviceClass *dc = DEVICE_CLASS(klass);
431*9a69950fSNicholas Piggin 
432*9a69950fSNicholas Piggin     dc->realize = pnv_chiptod_realize;
433*9a69950fSNicholas Piggin     dc->unrealize = pnv_chiptod_unrealize;
434*9a69950fSNicholas Piggin     dc->desc = "PowerNV ChipTOD Controller";
435*9a69950fSNicholas Piggin     dc->user_creatable = false;
436*9a69950fSNicholas Piggin }
437*9a69950fSNicholas Piggin 
438*9a69950fSNicholas Piggin static const TypeInfo pnv_chiptod_type_info = {
439*9a69950fSNicholas Piggin     .name          = TYPE_PNV_CHIPTOD,
440*9a69950fSNicholas Piggin     .parent        = TYPE_DEVICE,
441*9a69950fSNicholas Piggin     .instance_size = sizeof(PnvChipTOD),
442*9a69950fSNicholas Piggin     .class_init    = pnv_chiptod_class_init,
443*9a69950fSNicholas Piggin     .class_size    = sizeof(PnvChipTODClass),
444*9a69950fSNicholas Piggin     .abstract      = true,
445*9a69950fSNicholas Piggin };
446*9a69950fSNicholas Piggin 
447*9a69950fSNicholas Piggin static void pnv_chiptod_register_types(void)
448*9a69950fSNicholas Piggin {
449*9a69950fSNicholas Piggin     type_register_static(&pnv_chiptod_type_info);
450*9a69950fSNicholas Piggin     type_register_static(&pnv_chiptod_power9_type_info);
451*9a69950fSNicholas Piggin     type_register_static(&pnv_chiptod_power10_type_info);
452*9a69950fSNicholas Piggin }
453*9a69950fSNicholas Piggin 
454*9a69950fSNicholas Piggin type_init(pnv_chiptod_register_types);
455