1 /*
2 * QEMU PowerPC PowerNV Emulation of some ChipTOD behaviour
3 *
4 * Copyright (c) 2022-2023, IBM Corporation.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 *
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.
10 *
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.
14 *
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.
18 *
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.
23 */
24
25 #include "qemu/osdep.h"
26 #include "sysemu/reset.h"
27 #include "target/ppc/cpu.h"
28 #include "qapi/error.h"
29 #include "qemu/log.h"
30 #include "qemu/module.h"
31 #include "hw/irq.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"
40 #include "trace.h"
41
42 #include <libfdt.h>
43
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 */
52
53 /* -- TOD primary/secondary master/slave control register -- */
54 #define TOD_PSS_MSS_CTRL_REG 0x00000007
55
56 /* -- TOD primary/secondary master/slave status register -- */
57 #define TOD_PSS_MSS_STATUS_REG 0x00000008
58
59 /* TOD chip XSCOM addresses */
60 #define TOD_CHIP_CTRL_REG 0x00000010 /* Chip control reg */
61
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 */
68
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
74
75 #define TOD_TX_TTYPE_CTRL_REG 0x00000027 /* TX TTYPE Control reg */
76 #define TOD_TX_TTYPE_PIB_SLAVE_ADDR PPC_BITMASK(26, 31)
77
78 /* -- TOD Error interrupt register -- */
79 #define TOD_ERROR_REG 0x00000030
80
81 /* PC unit PIB address which recieves the timebase transfer from TOD */
82 #define PC_TOD 0x4A3
83
84 /*
85 * The TOD FSM:
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.
89 *
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 |
97 * | 2 running | | |
98 * | 1 stopped | START_TOD | 2 |
99 *
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.
103 */
104
pnv_chiptod_xscom_read(void * opaque,hwaddr addr,unsigned size)105 static uint64_t pnv_chiptod_xscom_read(void *opaque, hwaddr addr,
106 unsigned size)
107 {
108 PnvChipTOD *chiptod = PNV_CHIPTOD(opaque);
109 uint32_t offset = addr >> 3;
110 uint64_t val = 0;
111
112 switch (offset) {
113 case TOD_PSS_MSS_STATUS_REG:
114 /*
115 * ChipTOD does not support configurations other than primary
116 * master, does not support errors, etc.
117 */
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 */
122 }
123 val |= PPC_BIT(21); /* Is using primary config */
124 val |= PPC_BIT(26); /* Is using master path select */
125
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 */
130 } else {
131 val |= PPC_BIT(25); /* Is slave (should backup master set this?) */
132 }
133 break;
134 case TOD_PSS_MSS_CTRL_REG:
135 val = chiptod->pss_mss_ctrl_reg;
136 break;
137 case TOD_TX_TTYPE_CTRL_REG:
138 val = 0;
139 break;
140 case TOD_ERROR_REG:
141 val = chiptod->tod_error;
142 break;
143 case TOD_FSM_REG:
144 if (chiptod->tod_state == tod_running) {
145 val |= PPC_BIT(4);
146 }
147 break;
148 default:
149 qemu_log_mask(LOG_UNIMP, "pnv_chiptod: unimplemented register: Ox%"
150 HWADDR_PRIx "\n", addr >> 3);
151 }
152
153 trace_pnv_chiptod_xscom_read(addr >> 3, val);
154
155 return val;
156 }
157
chiptod_receive_ttype(PnvChipTOD * chiptod,uint32_t trigger)158 static void chiptod_receive_ttype(PnvChipTOD *chiptod, uint32_t trigger)
159 {
160 switch (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",
165 chiptod->tod_state);
166 } else {
167 chiptod->tod_state = tod_running;
168 }
169 break;
170 case TOD_TX_TTYPE_5_REG:
171 /* Works from any state */
172 chiptod->tod_state = tod_not_set;
173 break;
174 default:
175 qemu_log_mask(LOG_UNIMP, "pnv_chiptod: received unimplemented "
176 " TTYPE %u\n", trigger);
177 break;
178 }
179 }
180
chiptod_power9_broadcast_ttype(PnvChipTOD * sender,uint32_t trigger)181 static void chiptod_power9_broadcast_ttype(PnvChipTOD *sender,
182 uint32_t trigger)
183 {
184 PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
185 int i;
186
187 for (i = 0; i < pnv->num_chips; i++) {
188 Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]);
189 PnvChipTOD *chiptod = &chip9->chiptod;
190
191 if (chiptod != sender) {
192 chiptod_receive_ttype(chiptod, trigger);
193 }
194 }
195 }
196
chiptod_power10_broadcast_ttype(PnvChipTOD * sender,uint32_t trigger)197 static void chiptod_power10_broadcast_ttype(PnvChipTOD *sender,
198 uint32_t trigger)
199 {
200 PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
201 int i;
202
203 for (i = 0; i < pnv->num_chips; i++) {
204 Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]);
205 PnvChipTOD *chiptod = &chip10->chiptod;
206
207 if (chiptod != sender) {
208 chiptod_receive_ttype(chiptod, trigger);
209 }
210 }
211 }
212
pnv_chip_get_core_by_xscom_base(PnvChip * chip,uint32_t xscom_base)213 static PnvCore *pnv_chip_get_core_by_xscom_base(PnvChip *chip,
214 uint32_t xscom_base)
215 {
216 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
217 int i;
218
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;
223
224 if (pcc->xscom_core_base(chip, core_hwid) == xscom_base) {
225 return pc;
226 }
227 }
228 return NULL;
229 }
230
chiptod_power9_tx_ttype_target(PnvChipTOD * chiptod,uint64_t val)231 static PnvCore *chiptod_power9_tx_ttype_target(PnvChipTOD *chiptod,
232 uint64_t val)
233 {
234 /*
235 * skiboot uses Core ID for P9, though SCOM should work too.
236 */
237 if (val & PPC_BIT(35)) { /* SCOM addressing */
238 uint32_t addr = val >> 32;
239 uint32_t reg = addr & 0xfff;
240
241 if (reg != PC_TOD) {
242 qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: SCOM addressing: "
243 "unimplemented slave register 0x%" PRIx32 "\n", reg);
244 return NULL;
245 }
246
247 return pnv_chip_get_core_by_xscom_base(chiptod->chip, addr & ~0xfff);
248
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);
252 }
253 }
254
chiptod_power10_tx_ttype_target(PnvChipTOD * chiptod,uint64_t val)255 static PnvCore *chiptod_power10_tx_ttype_target(PnvChipTOD *chiptod,
256 uint64_t val)
257 {
258 /*
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.
261 */
262 if (val & PPC_BIT(35)) { /* SCOM addressing */
263 uint32_t addr = val >> 32;
264 uint32_t reg = addr & 0xfff;
265
266 if (reg != PC_TOD) {
267 qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: SCOM addressing: "
268 "unimplemented slave register 0x%" PRIx32 "\n", reg);
269 return NULL;
270 }
271
272 /*
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.
276 */
277 return pnv_chip_get_core_by_xscom_base(chiptod->chip, addr & ~0xfff);
278
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");
282 return NULL;
283 }
284 }
285
pnv_chiptod_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)286 static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
287 uint64_t val, unsigned size)
288 {
289 PnvChipTOD *chiptod = PNV_CHIPTOD(opaque);
290 PnvChipTODClass *pctc = PNV_CHIPTOD_GET_CLASS(chiptod);
291 uint32_t offset = addr >> 3;
292
293 trace_pnv_chiptod_xscom_write(addr >> 3, val);
294
295 switch (offset) {
296 case TOD_PSS_MSS_CTRL_REG:
297 /* Is this correct? */
298 if (chiptod->primary) {
299 val |= PPC_BIT(1); /* TOD is master */
300 } else {
301 val &= ~PPC_BIT(1);
302 }
303 val |= PPC_BIT(2); /* Drawer is master (don't simulate multi-drawer) */
304 chiptod->pss_mss_ctrl_reg = val & PPC_BITMASK(0, 31);
305 break;
306
307 case TOD_TX_TTYPE_CTRL_REG:
308 /*
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.
315 */
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);
321 }
322 break;
323 case TOD_ERROR_REG:
324 chiptod->tod_error &= ~val;
325 break;
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",
330 val);
331 } else {
332 chiptod->tod_state = tod_not_set;
333 }
334 break;
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",
339 chiptod->tod_state);
340 } else {
341 if (val & PPC_BIT(63)) {
342 chiptod->tod_state = tod_stopped;
343 } else {
344 chiptod->tod_state = tod_running;
345 }
346 }
347 break;
348
349 case TOD_MOVE_TOD_TO_TB_REG:
350 /*
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.
354 */
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",
358 chiptod->tod_state);
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",
362 val);
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");
366 } else {
367 PowerPCCPU *cpu = chiptod->slave_pc_target->threads[0];
368 CPUPPCState *env = &cpu->env;
369
370 /*
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.
374 *
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
377 * thread 0.
378 */
379
380 if (env->pnv_tod_tbst.tb_ready_for_tod) {
381 env->pnv_tod_tbst.tod_sent_to_tb = 1;
382 } else {
383 qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg"
384 " TOD_MOVE_TOD_TO_TB_REG with TB not ready to"
385 " receive TOD\n");
386 }
387 }
388 break;
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",
393 chiptod->tod_state);
394 } else {
395 chiptod->tod_state = tod_running;
396 }
397 break;
398 case TOD_TX_TTYPE_4_REG:
399 case TOD_TX_TTYPE_5_REG:
400 pctc->broadcast_ttype(chiptod, offset);
401 break;
402 default:
403 qemu_log_mask(LOG_UNIMP, "pnv_chiptod: unimplemented register: Ox%"
404 HWADDR_PRIx "\n", addr >> 3);
405 }
406 }
407
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,
416 };
417
pnv_chiptod_dt_xscom(PnvXScomInterface * dev,void * fdt,int xscom_offset,const char compat[],size_t compat_size)418 static int pnv_chiptod_dt_xscom(PnvXScomInterface *dev, void *fdt,
419 int xscom_offset,
420 const char compat[], size_t compat_size)
421 {
422 PnvChipTOD *chiptod = PNV_CHIPTOD(dev);
423 g_autofree char *name = NULL;
424 int offset;
425 uint32_t chiptod_pcba = PNV9_XSCOM_CHIPTOD_BASE;
426 uint32_t reg[] = {
427 cpu_to_be32(chiptod_pcba),
428 cpu_to_be32(PNV9_XSCOM_CHIPTOD_SIZE)
429 };
430
431 name = g_strdup_printf("chiptod@%x", chiptod_pcba);
432 offset = fdt_add_subnode(fdt, xscom_offset, name);
433 _FDT(offset);
434
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)));
439 }
440
441 _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
442 _FDT((fdt_setprop(fdt, offset, "compatible", compat, compat_size)));
443 return 0;
444 }
445
pnv_chiptod_power9_dt_xscom(PnvXScomInterface * dev,void * fdt,int xscom_offset)446 static int pnv_chiptod_power9_dt_xscom(PnvXScomInterface *dev, void *fdt,
447 int xscom_offset)
448 {
449 const char compat[] = "ibm,power-chiptod\0ibm,power9-chiptod";
450
451 return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat));
452 }
453
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(),
459 };
460
pnv_chiptod_power9_class_init(ObjectClass * klass,void * data)461 static void pnv_chiptod_power9_class_init(ObjectClass *klass, void *data)
462 {
463 PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass);
464 DeviceClass *dc = DEVICE_CLASS(klass);
465 PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
466
467 dc->desc = "PowerNV ChipTOD Controller (POWER9)";
468 device_class_set_props(dc, pnv_chiptod_properties);
469
470 xdc->dt_xscom = pnv_chiptod_power9_dt_xscom;
471
472 pctc->broadcast_ttype = chiptod_power9_broadcast_ttype;
473 pctc->tx_ttype_target = chiptod_power9_tx_ttype_target;
474
475 pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE;
476 }
477
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 },
485 { }
486 }
487 };
488
pnv_chiptod_power10_dt_xscom(PnvXScomInterface * dev,void * fdt,int xscom_offset)489 static int pnv_chiptod_power10_dt_xscom(PnvXScomInterface *dev, void *fdt,
490 int xscom_offset)
491 {
492 const char compat[] = "ibm,power-chiptod\0ibm,power10-chiptod";
493
494 return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat));
495 }
496
pnv_chiptod_power10_class_init(ObjectClass * klass,void * data)497 static void pnv_chiptod_power10_class_init(ObjectClass *klass, void *data)
498 {
499 PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass);
500 DeviceClass *dc = DEVICE_CLASS(klass);
501 PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
502
503 dc->desc = "PowerNV ChipTOD Controller (POWER10)";
504 device_class_set_props(dc, pnv_chiptod_properties);
505
506 xdc->dt_xscom = pnv_chiptod_power10_dt_xscom;
507
508 pctc->broadcast_ttype = chiptod_power10_broadcast_ttype;
509 pctc->tx_ttype_target = chiptod_power10_tx_ttype_target;
510
511 pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE;
512 }
513
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 },
521 { }
522 }
523 };
524
pnv_chiptod_reset(void * dev)525 static void pnv_chiptod_reset(void *dev)
526 {
527 PnvChipTOD *chiptod = PNV_CHIPTOD(dev);
528
529 chiptod->pss_mss_ctrl_reg = 0;
530 if (chiptod->primary) {
531 chiptod->pss_mss_ctrl_reg |= PPC_BIT(1); /* TOD is master */
532 }
533 /* Drawer is master (we do not simulate multi-drawer) */
534 chiptod->pss_mss_ctrl_reg |= PPC_BIT(2);
535
536 chiptod->tod_error = 0;
537 chiptod->tod_state = tod_error;
538 }
539
pnv_chiptod_realize(DeviceState * dev,Error ** errp)540 static void pnv_chiptod_realize(DeviceState *dev, Error **errp)
541 {
542 PnvChipTOD *chiptod = PNV_CHIPTOD(dev);
543 PnvChipTODClass *pctc = PNV_CHIPTOD_GET_CLASS(chiptod);
544
545 /* XScom regions for ChipTOD registers */
546 pnv_xscom_region_init(&chiptod->xscom_regs, OBJECT(dev),
547 &pnv_chiptod_xscom_ops, chiptod, "xscom-chiptod",
548 pctc->xscom_size);
549
550 qemu_register_reset(pnv_chiptod_reset, chiptod);
551 }
552
pnv_chiptod_unrealize(DeviceState * dev)553 static void pnv_chiptod_unrealize(DeviceState *dev)
554 {
555 PnvChipTOD *chiptod = PNV_CHIPTOD(dev);
556
557 qemu_unregister_reset(pnv_chiptod_reset, chiptod);
558 }
559
pnv_chiptod_class_init(ObjectClass * klass,void * data)560 static void pnv_chiptod_class_init(ObjectClass *klass, void *data)
561 {
562 DeviceClass *dc = DEVICE_CLASS(klass);
563
564 dc->realize = pnv_chiptod_realize;
565 dc->unrealize = pnv_chiptod_unrealize;
566 dc->desc = "PowerNV ChipTOD Controller";
567 dc->user_creatable = false;
568 }
569
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),
576 .abstract = true,
577 };
578
pnv_chiptod_register_types(void)579 static void pnv_chiptod_register_types(void)
580 {
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);
584 }
585
586 type_init(pnv_chiptod_register_types);
587