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