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 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 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 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 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 213 static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr, 214 uint64_t val, unsigned size) 215 { 216 PnvChipTOD *chiptod = PNV_CHIPTOD(opaque); 217 PnvChipTODClass *pctc = PNV_CHIPTOD_GET_CLASS(chiptod); 218 uint32_t offset = addr >> 3; 219 220 trace_pnv_chiptod_xscom_write(addr >> 3, val); 221 222 switch (offset) { 223 case TOD_PSS_MSS_CTRL_REG: 224 /* Is this correct? */ 225 if (chiptod->primary) { 226 val |= PPC_BIT(1); /* TOD is master */ 227 } else { 228 val &= ~PPC_BIT(1); 229 } 230 val |= PPC_BIT(2); /* Drawer is master (don't simulate multi-drawer) */ 231 chiptod->pss_mss_ctrl_reg = val & PPC_BITMASK(0, 31); 232 break; 233 234 case TOD_ERROR_REG: 235 chiptod->tod_error &= ~val; 236 break; 237 case TOD_LOAD_TOD_MOD_REG: 238 if (!(val & PPC_BIT(0))) { 239 qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg" 240 " TOD_LOAD_TOD_MOD_REG with bad val 0x%" PRIx64"\n", 241 val); 242 } else { 243 chiptod->tod_state = tod_not_set; 244 } 245 break; 246 case TOD_LOAD_TOD_REG: 247 if (chiptod->tod_state != tod_not_set) { 248 qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: LOAD_TOG_REG in " 249 " state %d, should be in 7 (TOD_NOT_SET)\n", 250 chiptod->tod_state); 251 } else { 252 if (val & PPC_BIT(63)) { 253 chiptod->tod_state = tod_stopped; 254 } else { 255 chiptod->tod_state = tod_running; 256 } 257 } 258 break; 259 case TOD_START_TOD_REG: 260 if (chiptod->tod_state != tod_stopped) { 261 qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: LOAD_TOG_REG in " 262 " state %d, should be in 1 (TOD_STOPPED)\n", 263 chiptod->tod_state); 264 } else { 265 chiptod->tod_state = tod_running; 266 } 267 break; 268 case TOD_TX_TTYPE_4_REG: 269 case TOD_TX_TTYPE_5_REG: 270 pctc->broadcast_ttype(chiptod, offset); 271 break; 272 default: 273 qemu_log_mask(LOG_UNIMP, "pnv_chiptod: unimplemented register: Ox%" 274 HWADDR_PRIx "\n", addr >> 3); 275 } 276 } 277 278 static const MemoryRegionOps pnv_chiptod_xscom_ops = { 279 .read = pnv_chiptod_xscom_read, 280 .write = pnv_chiptod_xscom_write, 281 .valid.min_access_size = 8, 282 .valid.max_access_size = 8, 283 .impl.min_access_size = 8, 284 .impl.max_access_size = 8, 285 .endianness = DEVICE_BIG_ENDIAN, 286 }; 287 288 static int pnv_chiptod_dt_xscom(PnvXScomInterface *dev, void *fdt, 289 int xscom_offset, 290 const char compat[], size_t compat_size) 291 { 292 PnvChipTOD *chiptod = PNV_CHIPTOD(dev); 293 g_autofree char *name = NULL; 294 int offset; 295 uint32_t chiptod_pcba = PNV9_XSCOM_CHIPTOD_BASE; 296 uint32_t reg[] = { 297 cpu_to_be32(chiptod_pcba), 298 cpu_to_be32(PNV9_XSCOM_CHIPTOD_SIZE) 299 }; 300 301 name = g_strdup_printf("chiptod@%x", chiptod_pcba); 302 offset = fdt_add_subnode(fdt, xscom_offset, name); 303 _FDT(offset); 304 305 if (chiptod->primary) { 306 _FDT((fdt_setprop(fdt, offset, "primary", NULL, 0))); 307 } else if (chiptod->secondary) { 308 _FDT((fdt_setprop(fdt, offset, "secondary", NULL, 0))); 309 } 310 311 _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); 312 _FDT((fdt_setprop(fdt, offset, "compatible", compat, compat_size))); 313 return 0; 314 } 315 316 static int pnv_chiptod_power9_dt_xscom(PnvXScomInterface *dev, void *fdt, 317 int xscom_offset) 318 { 319 const char compat[] = "ibm,power-chiptod\0ibm,power9-chiptod"; 320 321 return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat)); 322 } 323 324 static Property pnv_chiptod_properties[] = { 325 DEFINE_PROP_BOOL("primary", PnvChipTOD, primary, false), 326 DEFINE_PROP_BOOL("secondary", PnvChipTOD, secondary, false), 327 DEFINE_PROP_LINK("chip", PnvChipTOD , chip, TYPE_PNV_CHIP, PnvChip *), 328 DEFINE_PROP_END_OF_LIST(), 329 }; 330 331 static void pnv_chiptod_power9_class_init(ObjectClass *klass, void *data) 332 { 333 PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass); 334 DeviceClass *dc = DEVICE_CLASS(klass); 335 PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); 336 337 dc->desc = "PowerNV ChipTOD Controller (POWER9)"; 338 device_class_set_props(dc, pnv_chiptod_properties); 339 340 xdc->dt_xscom = pnv_chiptod_power9_dt_xscom; 341 342 pctc->broadcast_ttype = chiptod_power9_broadcast_ttype; 343 344 pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE; 345 } 346 347 static const TypeInfo pnv_chiptod_power9_type_info = { 348 .name = TYPE_PNV9_CHIPTOD, 349 .parent = TYPE_PNV_CHIPTOD, 350 .instance_size = sizeof(PnvChipTOD), 351 .class_init = pnv_chiptod_power9_class_init, 352 .interfaces = (InterfaceInfo[]) { 353 { TYPE_PNV_XSCOM_INTERFACE }, 354 { } 355 } 356 }; 357 358 static int pnv_chiptod_power10_dt_xscom(PnvXScomInterface *dev, void *fdt, 359 int xscom_offset) 360 { 361 const char compat[] = "ibm,power-chiptod\0ibm,power10-chiptod"; 362 363 return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat)); 364 } 365 366 static void pnv_chiptod_power10_class_init(ObjectClass *klass, void *data) 367 { 368 PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass); 369 DeviceClass *dc = DEVICE_CLASS(klass); 370 PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); 371 372 dc->desc = "PowerNV ChipTOD Controller (POWER10)"; 373 device_class_set_props(dc, pnv_chiptod_properties); 374 375 xdc->dt_xscom = pnv_chiptod_power10_dt_xscom; 376 377 pctc->broadcast_ttype = chiptod_power10_broadcast_ttype; 378 379 pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE; 380 } 381 382 static const TypeInfo pnv_chiptod_power10_type_info = { 383 .name = TYPE_PNV10_CHIPTOD, 384 .parent = TYPE_PNV_CHIPTOD, 385 .instance_size = sizeof(PnvChipTOD), 386 .class_init = pnv_chiptod_power10_class_init, 387 .interfaces = (InterfaceInfo[]) { 388 { TYPE_PNV_XSCOM_INTERFACE }, 389 { } 390 } 391 }; 392 393 static void pnv_chiptod_reset(void *dev) 394 { 395 PnvChipTOD *chiptod = PNV_CHIPTOD(dev); 396 397 chiptod->pss_mss_ctrl_reg = 0; 398 if (chiptod->primary) { 399 chiptod->pss_mss_ctrl_reg |= PPC_BIT(1); /* TOD is master */ 400 } 401 /* Drawer is master (we do not simulate multi-drawer) */ 402 chiptod->pss_mss_ctrl_reg |= PPC_BIT(2); 403 404 chiptod->tod_error = 0; 405 chiptod->tod_state = tod_error; 406 } 407 408 static void pnv_chiptod_realize(DeviceState *dev, Error **errp) 409 { 410 PnvChipTOD *chiptod = PNV_CHIPTOD(dev); 411 PnvChipTODClass *pctc = PNV_CHIPTOD_GET_CLASS(chiptod); 412 413 /* XScom regions for ChipTOD registers */ 414 pnv_xscom_region_init(&chiptod->xscom_regs, OBJECT(dev), 415 &pnv_chiptod_xscom_ops, chiptod, "xscom-chiptod", 416 pctc->xscom_size); 417 418 qemu_register_reset(pnv_chiptod_reset, chiptod); 419 } 420 421 static void pnv_chiptod_unrealize(DeviceState *dev) 422 { 423 PnvChipTOD *chiptod = PNV_CHIPTOD(dev); 424 425 qemu_unregister_reset(pnv_chiptod_reset, chiptod); 426 } 427 428 static void pnv_chiptod_class_init(ObjectClass *klass, void *data) 429 { 430 DeviceClass *dc = DEVICE_CLASS(klass); 431 432 dc->realize = pnv_chiptod_realize; 433 dc->unrealize = pnv_chiptod_unrealize; 434 dc->desc = "PowerNV ChipTOD Controller"; 435 dc->user_creatable = false; 436 } 437 438 static const TypeInfo pnv_chiptod_type_info = { 439 .name = TYPE_PNV_CHIPTOD, 440 .parent = TYPE_DEVICE, 441 .instance_size = sizeof(PnvChipTOD), 442 .class_init = pnv_chiptod_class_init, 443 .class_size = sizeof(PnvChipTODClass), 444 .abstract = true, 445 }; 446 447 static void pnv_chiptod_register_types(void) 448 { 449 type_register_static(&pnv_chiptod_type_info); 450 type_register_static(&pnv_chiptod_power9_type_info); 451 type_register_static(&pnv_chiptod_power10_type_info); 452 } 453 454 type_init(pnv_chiptod_register_types); 455