19a69950fSNicholas Piggin /* 29a69950fSNicholas Piggin * QEMU PowerPC PowerNV Emulation of some ChipTOD behaviour 39a69950fSNicholas Piggin * 49a69950fSNicholas Piggin * Copyright (c) 2022-2023, IBM Corporation. 59a69950fSNicholas Piggin * 69a69950fSNicholas Piggin * SPDX-License-Identifier: GPL-2.0-or-later 79a69950fSNicholas Piggin * 89a69950fSNicholas Piggin * ChipTOD (aka TOD) is a facility implemented in the nest / pervasive. The 99a69950fSNicholas Piggin * purpose is to keep time-of-day across chips and cores. 109a69950fSNicholas Piggin * 119a69950fSNicholas Piggin * There is a master chip TOD, which sends signals to slave chip TODs to 129a69950fSNicholas Piggin * keep them synchronized. There are two sets of configuration registers 139a69950fSNicholas Piggin * called primary and secondary, which can be used fail over. 149a69950fSNicholas Piggin * 159a69950fSNicholas Piggin * The chip TOD also distributes synchronisation signals to the timebase 169a69950fSNicholas Piggin * facility in each of the cores on the chip. In particular there is a 179a69950fSNicholas Piggin * feature that can move the TOD value in the ChipTOD to and from the TB. 189a69950fSNicholas Piggin * 199a69950fSNicholas Piggin * Initialisation typically brings all ChipTOD into sync (see tod_state), 209a69950fSNicholas Piggin * and then brings each core TB into sync with the ChipTODs (see timebase 219a69950fSNicholas Piggin * state and TFMR). This model is a very basic simulation of the init sequence 229a69950fSNicholas Piggin * performed by skiboot. 239a69950fSNicholas Piggin */ 249a69950fSNicholas Piggin 259a69950fSNicholas Piggin #include "qemu/osdep.h" 269a69950fSNicholas Piggin #include "sysemu/reset.h" 279a69950fSNicholas Piggin #include "target/ppc/cpu.h" 289a69950fSNicholas Piggin #include "qapi/error.h" 299a69950fSNicholas Piggin #include "qemu/log.h" 309a69950fSNicholas Piggin #include "qemu/module.h" 319a69950fSNicholas Piggin #include "hw/irq.h" 329a69950fSNicholas Piggin #include "hw/qdev-properties.h" 339a69950fSNicholas Piggin #include "hw/ppc/fdt.h" 349a69950fSNicholas Piggin #include "hw/ppc/ppc.h" 359a69950fSNicholas Piggin #include "hw/ppc/pnv.h" 369a69950fSNicholas Piggin #include "hw/ppc/pnv_chip.h" 379a69950fSNicholas Piggin #include "hw/ppc/pnv_core.h" 389a69950fSNicholas Piggin #include "hw/ppc/pnv_xscom.h" 399a69950fSNicholas Piggin #include "hw/ppc/pnv_chiptod.h" 409a69950fSNicholas Piggin #include "trace.h" 419a69950fSNicholas Piggin 429a69950fSNicholas Piggin #include <libfdt.h> 439a69950fSNicholas Piggin 449a69950fSNicholas Piggin /* TOD chip XSCOM addresses */ 459a69950fSNicholas Piggin #define TOD_M_PATH_CTRL_REG 0x00000000 /* Master Path ctrl reg */ 469a69950fSNicholas Piggin #define TOD_PRI_PORT_0_CTRL_REG 0x00000001 /* Primary port0 ctrl reg */ 479a69950fSNicholas Piggin #define TOD_PRI_PORT_1_CTRL_REG 0x00000002 /* Primary port1 ctrl reg */ 489a69950fSNicholas Piggin #define TOD_SEC_PORT_0_CTRL_REG 0x00000003 /* Secondary p0 ctrl reg */ 499a69950fSNicholas Piggin #define TOD_SEC_PORT_1_CTRL_REG 0x00000004 /* Secondary p1 ctrl reg */ 509a69950fSNicholas Piggin #define TOD_S_PATH_CTRL_REG 0x00000005 /* Slave Path ctrl reg */ 519a69950fSNicholas Piggin #define TOD_I_PATH_CTRL_REG 0x00000006 /* Internal Path ctrl reg */ 529a69950fSNicholas Piggin 539a69950fSNicholas Piggin /* -- TOD primary/secondary master/slave control register -- */ 549a69950fSNicholas Piggin #define TOD_PSS_MSS_CTRL_REG 0x00000007 559a69950fSNicholas Piggin 569a69950fSNicholas Piggin /* -- TOD primary/secondary master/slave status register -- */ 579a69950fSNicholas Piggin #define TOD_PSS_MSS_STATUS_REG 0x00000008 589a69950fSNicholas Piggin 599a69950fSNicholas Piggin /* TOD chip XSCOM addresses */ 609a69950fSNicholas Piggin #define TOD_CHIP_CTRL_REG 0x00000010 /* Chip control reg */ 619a69950fSNicholas Piggin 629a69950fSNicholas Piggin #define TOD_TX_TTYPE_0_REG 0x00000011 639a69950fSNicholas Piggin #define TOD_TX_TTYPE_1_REG 0x00000012 /* PSS switch reg */ 649a69950fSNicholas Piggin #define TOD_TX_TTYPE_2_REG 0x00000013 /* Enable step checkers */ 659a69950fSNicholas Piggin #define TOD_TX_TTYPE_3_REG 0x00000014 /* Request TOD reg */ 669a69950fSNicholas Piggin #define TOD_TX_TTYPE_4_REG 0x00000015 /* Send TOD reg */ 679a69950fSNicholas Piggin #define TOD_TX_TTYPE_5_REG 0x00000016 /* Invalidate TOD reg */ 689a69950fSNicholas Piggin 699a69950fSNicholas Piggin #define TOD_MOVE_TOD_TO_TB_REG 0x00000017 709a69950fSNicholas Piggin #define TOD_LOAD_TOD_MOD_REG 0x00000018 719a69950fSNicholas Piggin #define TOD_LOAD_TOD_REG 0x00000021 729a69950fSNicholas Piggin #define TOD_START_TOD_REG 0x00000022 739a69950fSNicholas Piggin #define TOD_FSM_REG 0x00000024 749a69950fSNicholas Piggin 759a69950fSNicholas Piggin #define TOD_TX_TTYPE_CTRL_REG 0x00000027 /* TX TTYPE Control reg */ 769a69950fSNicholas Piggin #define TOD_TX_TTYPE_PIB_SLAVE_ADDR PPC_BITMASK(26, 31) 779a69950fSNicholas Piggin 789a69950fSNicholas Piggin /* -- TOD Error interrupt register -- */ 799a69950fSNicholas Piggin #define TOD_ERROR_REG 0x00000030 809a69950fSNicholas Piggin 819a69950fSNicholas Piggin /* PC unit PIB address which recieves the timebase transfer from TOD */ 829a69950fSNicholas Piggin #define PC_TOD 0x4A3 839a69950fSNicholas Piggin 849a69950fSNicholas Piggin /* 859a69950fSNicholas Piggin * The TOD FSM: 869a69950fSNicholas Piggin * - The reset state is 0 error. 879a69950fSNicholas Piggin * - A hardware error detected will transition to state 0 from any state. 889a69950fSNicholas Piggin * - LOAD_TOD_MOD and TTYPE5 will transition to state 7 from any state. 899a69950fSNicholas Piggin * 909a69950fSNicholas Piggin * | state | action | new | 919a69950fSNicholas Piggin * |------------+------------------------------+-----| 929a69950fSNicholas Piggin * | 0 error | LOAD_TOD_MOD | 7 | 939a69950fSNicholas Piggin * | 0 error | Recv TTYPE5 (invalidate TOD) | 7 | 949a69950fSNicholas Piggin * | 7 not_set | LOAD_TOD (bit-63 = 0) | 2 | 959a69950fSNicholas Piggin * | 7 not_set | LOAD_TOD (bit-63 = 1) | 1 | 969a69950fSNicholas Piggin * | 7 not_set | Recv TTYPE4 (send TOD) | 2 | 979a69950fSNicholas Piggin * | 2 running | | | 989a69950fSNicholas Piggin * | 1 stopped | START_TOD | 2 | 999a69950fSNicholas Piggin * 1009a69950fSNicholas Piggin * Note the hardware has additional states but they relate to the sending 1019a69950fSNicholas Piggin * and receiving and waiting on synchronisation signals between chips and 1029a69950fSNicholas Piggin * are not described or modeled here. 1039a69950fSNicholas Piggin */ 1049a69950fSNicholas Piggin 1059a69950fSNicholas Piggin static uint64_t pnv_chiptod_xscom_read(void *opaque, hwaddr addr, 1069a69950fSNicholas Piggin unsigned size) 1079a69950fSNicholas Piggin { 1089a69950fSNicholas Piggin PnvChipTOD *chiptod = PNV_CHIPTOD(opaque); 1099a69950fSNicholas Piggin uint32_t offset = addr >> 3; 1109a69950fSNicholas Piggin uint64_t val = 0; 1119a69950fSNicholas Piggin 1129a69950fSNicholas Piggin switch (offset) { 1139a69950fSNicholas Piggin case TOD_PSS_MSS_STATUS_REG: 1149a69950fSNicholas Piggin /* 1159a69950fSNicholas Piggin * ChipTOD does not support configurations other than primary 1169a69950fSNicholas Piggin * master, does not support errors, etc. 1179a69950fSNicholas Piggin */ 1189a69950fSNicholas Piggin val |= PPC_BITMASK(6, 10); /* STEP checker validity */ 1199a69950fSNicholas Piggin val |= PPC_BIT(12); /* Primary config master path select */ 1209a69950fSNicholas Piggin if (chiptod->tod_state == tod_running) { 1219a69950fSNicholas Piggin val |= PPC_BIT(20); /* Is running */ 1229a69950fSNicholas Piggin } 1239a69950fSNicholas Piggin val |= PPC_BIT(21); /* Is using primary config */ 1249a69950fSNicholas Piggin val |= PPC_BIT(26); /* Is using master path select */ 1259a69950fSNicholas Piggin 1269a69950fSNicholas Piggin if (chiptod->primary) { 1279a69950fSNicholas Piggin val |= PPC_BIT(23); /* Is active master */ 1289a69950fSNicholas Piggin } else if (chiptod->secondary) { 1299a69950fSNicholas Piggin val |= PPC_BIT(24); /* Is backup master */ 1309a69950fSNicholas Piggin } else { 1319a69950fSNicholas Piggin val |= PPC_BIT(25); /* Is slave (should backup master set this?) */ 1329a69950fSNicholas Piggin } 1339a69950fSNicholas Piggin break; 1349a69950fSNicholas Piggin case TOD_PSS_MSS_CTRL_REG: 1359a69950fSNicholas Piggin val = chiptod->pss_mss_ctrl_reg; 1369a69950fSNicholas Piggin break; 1379a69950fSNicholas Piggin case TOD_TX_TTYPE_CTRL_REG: 1389a69950fSNicholas Piggin val = 0; 1399a69950fSNicholas Piggin break; 1409a69950fSNicholas Piggin case TOD_ERROR_REG: 1419a69950fSNicholas Piggin val = chiptod->tod_error; 1429a69950fSNicholas Piggin break; 1439a69950fSNicholas Piggin case TOD_FSM_REG: 1449a69950fSNicholas Piggin if (chiptod->tod_state == tod_running) { 1459a69950fSNicholas Piggin val |= PPC_BIT(4); 1469a69950fSNicholas Piggin } 1479a69950fSNicholas Piggin break; 1489a69950fSNicholas Piggin default: 1499a69950fSNicholas Piggin qemu_log_mask(LOG_UNIMP, "pnv_chiptod: unimplemented register: Ox%" 1509a69950fSNicholas Piggin HWADDR_PRIx "\n", addr >> 3); 1519a69950fSNicholas Piggin } 1529a69950fSNicholas Piggin 1539a69950fSNicholas Piggin trace_pnv_chiptod_xscom_read(addr >> 3, val); 1549a69950fSNicholas Piggin 1559a69950fSNicholas Piggin return val; 1569a69950fSNicholas Piggin } 1579a69950fSNicholas Piggin 1589a69950fSNicholas Piggin static void chiptod_receive_ttype(PnvChipTOD *chiptod, uint32_t trigger) 1599a69950fSNicholas Piggin { 1609a69950fSNicholas Piggin switch (trigger) { 1619a69950fSNicholas Piggin case TOD_TX_TTYPE_4_REG: 1629a69950fSNicholas Piggin if (chiptod->tod_state != tod_not_set) { 1639a69950fSNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: received TTYPE4 in " 1649a69950fSNicholas Piggin " state %d, should be in 7 (TOD_NOT_SET)\n", 1659a69950fSNicholas Piggin chiptod->tod_state); 1669a69950fSNicholas Piggin } else { 1679a69950fSNicholas Piggin chiptod->tod_state = tod_running; 1689a69950fSNicholas Piggin } 1699a69950fSNicholas Piggin break; 1709a69950fSNicholas Piggin case TOD_TX_TTYPE_5_REG: 1719a69950fSNicholas Piggin /* Works from any state */ 1729a69950fSNicholas Piggin chiptod->tod_state = tod_not_set; 1739a69950fSNicholas Piggin break; 1749a69950fSNicholas Piggin default: 1759a69950fSNicholas Piggin qemu_log_mask(LOG_UNIMP, "pnv_chiptod: received unimplemented " 1769a69950fSNicholas Piggin " TTYPE %u\n", trigger); 1779a69950fSNicholas Piggin break; 1789a69950fSNicholas Piggin } 1799a69950fSNicholas Piggin } 1809a69950fSNicholas Piggin 1819a69950fSNicholas Piggin static void chiptod_power9_broadcast_ttype(PnvChipTOD *sender, 1829a69950fSNicholas Piggin uint32_t trigger) 1839a69950fSNicholas Piggin { 1849a69950fSNicholas Piggin PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); 1859a69950fSNicholas Piggin int i; 1869a69950fSNicholas Piggin 1879a69950fSNicholas Piggin for (i = 0; i < pnv->num_chips; i++) { 1889a69950fSNicholas Piggin Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]); 1899a69950fSNicholas Piggin PnvChipTOD *chiptod = &chip9->chiptod; 1909a69950fSNicholas Piggin 1919a69950fSNicholas Piggin if (chiptod != sender) { 1929a69950fSNicholas Piggin chiptod_receive_ttype(chiptod, trigger); 1939a69950fSNicholas Piggin } 1949a69950fSNicholas Piggin } 1959a69950fSNicholas Piggin } 1969a69950fSNicholas Piggin 1979a69950fSNicholas Piggin static void chiptod_power10_broadcast_ttype(PnvChipTOD *sender, 1989a69950fSNicholas Piggin uint32_t trigger) 1999a69950fSNicholas Piggin { 2009a69950fSNicholas Piggin PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); 2019a69950fSNicholas Piggin int i; 2029a69950fSNicholas Piggin 2039a69950fSNicholas Piggin for (i = 0; i < pnv->num_chips; i++) { 2049a69950fSNicholas Piggin Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]); 2059a69950fSNicholas Piggin PnvChipTOD *chiptod = &chip10->chiptod; 2069a69950fSNicholas Piggin 2079a69950fSNicholas Piggin if (chiptod != sender) { 2089a69950fSNicholas Piggin chiptod_receive_ttype(chiptod, trigger); 2099a69950fSNicholas Piggin } 2109a69950fSNicholas Piggin } 2119a69950fSNicholas Piggin } 2129a69950fSNicholas Piggin 213*cde2ba34SNicholas Piggin static PnvCore *pnv_chip_get_core_by_xscom_base(PnvChip *chip, 214*cde2ba34SNicholas Piggin uint32_t xscom_base) 215*cde2ba34SNicholas Piggin { 216*cde2ba34SNicholas Piggin PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 217*cde2ba34SNicholas Piggin int i; 218*cde2ba34SNicholas Piggin 219*cde2ba34SNicholas Piggin for (i = 0; i < chip->nr_cores; i++) { 220*cde2ba34SNicholas Piggin PnvCore *pc = chip->cores[i]; 221*cde2ba34SNicholas Piggin CPUCore *cc = CPU_CORE(pc); 222*cde2ba34SNicholas Piggin int core_hwid = cc->core_id; 223*cde2ba34SNicholas Piggin 224*cde2ba34SNicholas Piggin if (pcc->xscom_core_base(chip, core_hwid) == xscom_base) { 225*cde2ba34SNicholas Piggin return pc; 226*cde2ba34SNicholas Piggin } 227*cde2ba34SNicholas Piggin } 228*cde2ba34SNicholas Piggin return NULL; 229*cde2ba34SNicholas Piggin } 230*cde2ba34SNicholas Piggin 231*cde2ba34SNicholas Piggin static PnvCore *chiptod_power9_tx_ttype_target(PnvChipTOD *chiptod, 232*cde2ba34SNicholas Piggin uint64_t val) 233*cde2ba34SNicholas Piggin { 234*cde2ba34SNicholas Piggin /* 235*cde2ba34SNicholas Piggin * skiboot uses Core ID for P9, though SCOM should work too. 236*cde2ba34SNicholas Piggin */ 237*cde2ba34SNicholas Piggin if (val & PPC_BIT(35)) { /* SCOM addressing */ 238*cde2ba34SNicholas Piggin uint32_t addr = val >> 32; 239*cde2ba34SNicholas Piggin uint32_t reg = addr & 0xfff; 240*cde2ba34SNicholas Piggin 241*cde2ba34SNicholas Piggin if (reg != PC_TOD) { 242*cde2ba34SNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: SCOM addressing: " 243*cde2ba34SNicholas Piggin "unimplemented slave register 0x%" PRIx32 "\n", reg); 244*cde2ba34SNicholas Piggin return NULL; 245*cde2ba34SNicholas Piggin } 246*cde2ba34SNicholas Piggin 247*cde2ba34SNicholas Piggin return pnv_chip_get_core_by_xscom_base(chiptod->chip, addr & ~0xfff); 248*cde2ba34SNicholas Piggin 249*cde2ba34SNicholas Piggin } else { /* Core ID addressing */ 250*cde2ba34SNicholas Piggin uint32_t core_id = GETFIELD(TOD_TX_TTYPE_PIB_SLAVE_ADDR, val) & 0x1f; 251*cde2ba34SNicholas Piggin return pnv_chip_find_core(chiptod->chip, core_id); 252*cde2ba34SNicholas Piggin } 253*cde2ba34SNicholas Piggin } 254*cde2ba34SNicholas Piggin 255*cde2ba34SNicholas Piggin static PnvCore *chiptod_power10_tx_ttype_target(PnvChipTOD *chiptod, 256*cde2ba34SNicholas Piggin uint64_t val) 257*cde2ba34SNicholas Piggin { 258*cde2ba34SNicholas Piggin /* 259*cde2ba34SNicholas Piggin * skiboot uses SCOM for P10 because Core ID was unable to be made to 260*cde2ba34SNicholas Piggin * work correctly. For this reason only SCOM addressing is implemented. 261*cde2ba34SNicholas Piggin */ 262*cde2ba34SNicholas Piggin if (val & PPC_BIT(35)) { /* SCOM addressing */ 263*cde2ba34SNicholas Piggin uint32_t addr = val >> 32; 264*cde2ba34SNicholas Piggin uint32_t reg = addr & 0xfff; 265*cde2ba34SNicholas Piggin 266*cde2ba34SNicholas Piggin if (reg != PC_TOD) { 267*cde2ba34SNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: SCOM addressing: " 268*cde2ba34SNicholas Piggin "unimplemented slave register 0x%" PRIx32 "\n", reg); 269*cde2ba34SNicholas Piggin return NULL; 270*cde2ba34SNicholas Piggin } 271*cde2ba34SNicholas Piggin 272*cde2ba34SNicholas Piggin /* 273*cde2ba34SNicholas Piggin * This may not deal with P10 big-core addressing at the moment. 274*cde2ba34SNicholas Piggin * The big-core code in skiboot syncs small cores, but it targets 275*cde2ba34SNicholas Piggin * the even PIR (first small-core) when syncing second small-core. 276*cde2ba34SNicholas Piggin */ 277*cde2ba34SNicholas Piggin return pnv_chip_get_core_by_xscom_base(chiptod->chip, addr & ~0xfff); 278*cde2ba34SNicholas Piggin 279*cde2ba34SNicholas Piggin } else { /* Core ID addressing */ 280*cde2ba34SNicholas Piggin qemu_log_mask(LOG_UNIMP, "pnv_chiptod: TX TTYPE Core ID " 281*cde2ba34SNicholas Piggin "addressing is not implemented for POWER10\n"); 282*cde2ba34SNicholas Piggin return NULL; 283*cde2ba34SNicholas Piggin } 284*cde2ba34SNicholas Piggin } 285*cde2ba34SNicholas Piggin 2869a69950fSNicholas Piggin static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr, 2879a69950fSNicholas Piggin uint64_t val, unsigned size) 2889a69950fSNicholas Piggin { 2899a69950fSNicholas Piggin PnvChipTOD *chiptod = PNV_CHIPTOD(opaque); 2909a69950fSNicholas Piggin PnvChipTODClass *pctc = PNV_CHIPTOD_GET_CLASS(chiptod); 2919a69950fSNicholas Piggin uint32_t offset = addr >> 3; 2929a69950fSNicholas Piggin 2939a69950fSNicholas Piggin trace_pnv_chiptod_xscom_write(addr >> 3, val); 2949a69950fSNicholas Piggin 2959a69950fSNicholas Piggin switch (offset) { 2969a69950fSNicholas Piggin case TOD_PSS_MSS_CTRL_REG: 2979a69950fSNicholas Piggin /* Is this correct? */ 2989a69950fSNicholas Piggin if (chiptod->primary) { 2999a69950fSNicholas Piggin val |= PPC_BIT(1); /* TOD is master */ 3009a69950fSNicholas Piggin } else { 3019a69950fSNicholas Piggin val &= ~PPC_BIT(1); 3029a69950fSNicholas Piggin } 3039a69950fSNicholas Piggin val |= PPC_BIT(2); /* Drawer is master (don't simulate multi-drawer) */ 3049a69950fSNicholas Piggin chiptod->pss_mss_ctrl_reg = val & PPC_BITMASK(0, 31); 3059a69950fSNicholas Piggin break; 3069a69950fSNicholas Piggin 307*cde2ba34SNicholas Piggin case TOD_TX_TTYPE_CTRL_REG: 308*cde2ba34SNicholas Piggin /* 309*cde2ba34SNicholas Piggin * This register sets the target of the TOD value transfer initiated 310*cde2ba34SNicholas Piggin * by TOD_MOVE_TOD_TO_TB. The TOD is able to send the address to 311*cde2ba34SNicholas Piggin * any target register, though in practice only the PC TOD register 312*cde2ba34SNicholas Piggin * should be used. ChipTOD has a "SCOM addressing" mode which fully 313*cde2ba34SNicholas Piggin * specifies the SCOM address, and a core-ID mode which uses the 314*cde2ba34SNicholas Piggin * core ID to target the PC TOD for a given core. 315*cde2ba34SNicholas Piggin */ 316*cde2ba34SNicholas Piggin chiptod->slave_pc_target = pctc->tx_ttype_target(chiptod, val); 317*cde2ba34SNicholas Piggin if (!chiptod->slave_pc_target) { 318*cde2ba34SNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg" 319*cde2ba34SNicholas Piggin " TOD_TX_TTYPE_CTRL_REG val 0x%" PRIx64 320*cde2ba34SNicholas Piggin " invalid slave address\n", val); 321*cde2ba34SNicholas Piggin } 322*cde2ba34SNicholas Piggin break; 3239a69950fSNicholas Piggin case TOD_ERROR_REG: 3249a69950fSNicholas Piggin chiptod->tod_error &= ~val; 3259a69950fSNicholas Piggin break; 3269a69950fSNicholas Piggin case TOD_LOAD_TOD_MOD_REG: 3279a69950fSNicholas Piggin if (!(val & PPC_BIT(0))) { 3289a69950fSNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg" 3299a69950fSNicholas Piggin " TOD_LOAD_TOD_MOD_REG with bad val 0x%" PRIx64"\n", 3309a69950fSNicholas Piggin val); 3319a69950fSNicholas Piggin } else { 3329a69950fSNicholas Piggin chiptod->tod_state = tod_not_set; 3339a69950fSNicholas Piggin } 3349a69950fSNicholas Piggin break; 3359a69950fSNicholas Piggin case TOD_LOAD_TOD_REG: 3369a69950fSNicholas Piggin if (chiptod->tod_state != tod_not_set) { 3379a69950fSNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: LOAD_TOG_REG in " 3389a69950fSNicholas Piggin " state %d, should be in 7 (TOD_NOT_SET)\n", 3399a69950fSNicholas Piggin chiptod->tod_state); 3409a69950fSNicholas Piggin } else { 3419a69950fSNicholas Piggin if (val & PPC_BIT(63)) { 3429a69950fSNicholas Piggin chiptod->tod_state = tod_stopped; 3439a69950fSNicholas Piggin } else { 3449a69950fSNicholas Piggin chiptod->tod_state = tod_running; 3459a69950fSNicholas Piggin } 3469a69950fSNicholas Piggin } 3479a69950fSNicholas Piggin break; 348*cde2ba34SNicholas Piggin 349*cde2ba34SNicholas Piggin case TOD_MOVE_TOD_TO_TB_REG: 350*cde2ba34SNicholas Piggin /* 351*cde2ba34SNicholas Piggin * XXX: it should be a cleaner model to have this drive a SCOM 352*cde2ba34SNicholas Piggin * transaction to the target address, and implement the state machine 353*cde2ba34SNicholas Piggin * in the PnvCore. For now, this hack makes things work. 354*cde2ba34SNicholas Piggin */ 355*cde2ba34SNicholas Piggin if (chiptod->tod_state != tod_running) { 356*cde2ba34SNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg" 357*cde2ba34SNicholas Piggin " TOD_MOVE_TOD_TO_TB_REG in bad state %d\n", 358*cde2ba34SNicholas Piggin chiptod->tod_state); 359*cde2ba34SNicholas Piggin } else if (!(val & PPC_BIT(0))) { 360*cde2ba34SNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg" 361*cde2ba34SNicholas Piggin " TOD_MOVE_TOD_TO_TB_REG with bad val 0x%" PRIx64"\n", 362*cde2ba34SNicholas Piggin val); 363*cde2ba34SNicholas Piggin } else if (chiptod->slave_pc_target == NULL) { 364*cde2ba34SNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg" 365*cde2ba34SNicholas Piggin " TOD_MOVE_TOD_TO_TB_REG with no slave target\n"); 366*cde2ba34SNicholas Piggin } else { 367*cde2ba34SNicholas Piggin PowerPCCPU *cpu = chiptod->slave_pc_target->threads[0]; 368*cde2ba34SNicholas Piggin CPUPPCState *env = &cpu->env; 369*cde2ba34SNicholas Piggin 370*cde2ba34SNicholas Piggin /* 371*cde2ba34SNicholas Piggin * Moving TOD to TB will set the TB of all threads in a 372*cde2ba34SNicholas Piggin * core, so skiboot only does this once per thread0, so 373*cde2ba34SNicholas Piggin * that is where we keep the timebase state machine. 374*cde2ba34SNicholas Piggin * 375*cde2ba34SNicholas Piggin * It is likely possible for TBST to be driven from other 376*cde2ba34SNicholas Piggin * threads in the core, but for now we only implement it for 377*cde2ba34SNicholas Piggin * thread 0. 378*cde2ba34SNicholas Piggin */ 379*cde2ba34SNicholas Piggin 380*cde2ba34SNicholas Piggin if (env->pnv_tod_tbst.tb_ready_for_tod) { 381*cde2ba34SNicholas Piggin env->pnv_tod_tbst.tod_sent_to_tb = 1; 382*cde2ba34SNicholas Piggin } else { 383*cde2ba34SNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg" 384*cde2ba34SNicholas Piggin " TOD_MOVE_TOD_TO_TB_REG with TB not ready to" 385*cde2ba34SNicholas Piggin " receive TOD\n"); 386*cde2ba34SNicholas Piggin } 387*cde2ba34SNicholas Piggin } 388*cde2ba34SNicholas Piggin break; 3899a69950fSNicholas Piggin case TOD_START_TOD_REG: 3909a69950fSNicholas Piggin if (chiptod->tod_state != tod_stopped) { 3919a69950fSNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: LOAD_TOG_REG in " 3929a69950fSNicholas Piggin " state %d, should be in 1 (TOD_STOPPED)\n", 3939a69950fSNicholas Piggin chiptod->tod_state); 3949a69950fSNicholas Piggin } else { 3959a69950fSNicholas Piggin chiptod->tod_state = tod_running; 3969a69950fSNicholas Piggin } 3979a69950fSNicholas Piggin break; 3989a69950fSNicholas Piggin case TOD_TX_TTYPE_4_REG: 3999a69950fSNicholas Piggin case TOD_TX_TTYPE_5_REG: 4009a69950fSNicholas Piggin pctc->broadcast_ttype(chiptod, offset); 4019a69950fSNicholas Piggin break; 4029a69950fSNicholas Piggin default: 4039a69950fSNicholas Piggin qemu_log_mask(LOG_UNIMP, "pnv_chiptod: unimplemented register: Ox%" 4049a69950fSNicholas Piggin HWADDR_PRIx "\n", addr >> 3); 4059a69950fSNicholas Piggin } 4069a69950fSNicholas Piggin } 4079a69950fSNicholas Piggin 4089a69950fSNicholas Piggin static const MemoryRegionOps pnv_chiptod_xscom_ops = { 4099a69950fSNicholas Piggin .read = pnv_chiptod_xscom_read, 4109a69950fSNicholas Piggin .write = pnv_chiptod_xscom_write, 4119a69950fSNicholas Piggin .valid.min_access_size = 8, 4129a69950fSNicholas Piggin .valid.max_access_size = 8, 4139a69950fSNicholas Piggin .impl.min_access_size = 8, 4149a69950fSNicholas Piggin .impl.max_access_size = 8, 4159a69950fSNicholas Piggin .endianness = DEVICE_BIG_ENDIAN, 4169a69950fSNicholas Piggin }; 4179a69950fSNicholas Piggin 4189a69950fSNicholas Piggin static int pnv_chiptod_dt_xscom(PnvXScomInterface *dev, void *fdt, 4199a69950fSNicholas Piggin int xscom_offset, 4209a69950fSNicholas Piggin const char compat[], size_t compat_size) 4219a69950fSNicholas Piggin { 4229a69950fSNicholas Piggin PnvChipTOD *chiptod = PNV_CHIPTOD(dev); 4239a69950fSNicholas Piggin g_autofree char *name = NULL; 4249a69950fSNicholas Piggin int offset; 4259a69950fSNicholas Piggin uint32_t chiptod_pcba = PNV9_XSCOM_CHIPTOD_BASE; 4269a69950fSNicholas Piggin uint32_t reg[] = { 4279a69950fSNicholas Piggin cpu_to_be32(chiptod_pcba), 4289a69950fSNicholas Piggin cpu_to_be32(PNV9_XSCOM_CHIPTOD_SIZE) 4299a69950fSNicholas Piggin }; 4309a69950fSNicholas Piggin 4319a69950fSNicholas Piggin name = g_strdup_printf("chiptod@%x", chiptod_pcba); 4329a69950fSNicholas Piggin offset = fdt_add_subnode(fdt, xscom_offset, name); 4339a69950fSNicholas Piggin _FDT(offset); 4349a69950fSNicholas Piggin 4359a69950fSNicholas Piggin if (chiptod->primary) { 4369a69950fSNicholas Piggin _FDT((fdt_setprop(fdt, offset, "primary", NULL, 0))); 4379a69950fSNicholas Piggin } else if (chiptod->secondary) { 4389a69950fSNicholas Piggin _FDT((fdt_setprop(fdt, offset, "secondary", NULL, 0))); 4399a69950fSNicholas Piggin } 4409a69950fSNicholas Piggin 4419a69950fSNicholas Piggin _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); 4429a69950fSNicholas Piggin _FDT((fdt_setprop(fdt, offset, "compatible", compat, compat_size))); 4439a69950fSNicholas Piggin return 0; 4449a69950fSNicholas Piggin } 4459a69950fSNicholas Piggin 4469a69950fSNicholas Piggin static int pnv_chiptod_power9_dt_xscom(PnvXScomInterface *dev, void *fdt, 4479a69950fSNicholas Piggin int xscom_offset) 4489a69950fSNicholas Piggin { 4499a69950fSNicholas Piggin const char compat[] = "ibm,power-chiptod\0ibm,power9-chiptod"; 4509a69950fSNicholas Piggin 4519a69950fSNicholas Piggin return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat)); 4529a69950fSNicholas Piggin } 4539a69950fSNicholas Piggin 4549a69950fSNicholas Piggin static Property pnv_chiptod_properties[] = { 4559a69950fSNicholas Piggin DEFINE_PROP_BOOL("primary", PnvChipTOD, primary, false), 4569a69950fSNicholas Piggin DEFINE_PROP_BOOL("secondary", PnvChipTOD, secondary, false), 4579a69950fSNicholas Piggin DEFINE_PROP_LINK("chip", PnvChipTOD , chip, TYPE_PNV_CHIP, PnvChip *), 4589a69950fSNicholas Piggin DEFINE_PROP_END_OF_LIST(), 4599a69950fSNicholas Piggin }; 4609a69950fSNicholas Piggin 4619a69950fSNicholas Piggin static void pnv_chiptod_power9_class_init(ObjectClass *klass, void *data) 4629a69950fSNicholas Piggin { 4639a69950fSNicholas Piggin PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass); 4649a69950fSNicholas Piggin DeviceClass *dc = DEVICE_CLASS(klass); 4659a69950fSNicholas Piggin PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); 4669a69950fSNicholas Piggin 4679a69950fSNicholas Piggin dc->desc = "PowerNV ChipTOD Controller (POWER9)"; 4689a69950fSNicholas Piggin device_class_set_props(dc, pnv_chiptod_properties); 4699a69950fSNicholas Piggin 4709a69950fSNicholas Piggin xdc->dt_xscom = pnv_chiptod_power9_dt_xscom; 4719a69950fSNicholas Piggin 4729a69950fSNicholas Piggin pctc->broadcast_ttype = chiptod_power9_broadcast_ttype; 473*cde2ba34SNicholas Piggin pctc->tx_ttype_target = chiptod_power9_tx_ttype_target; 4749a69950fSNicholas Piggin 4759a69950fSNicholas Piggin pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE; 4769a69950fSNicholas Piggin } 4779a69950fSNicholas Piggin 4789a69950fSNicholas Piggin static const TypeInfo pnv_chiptod_power9_type_info = { 4799a69950fSNicholas Piggin .name = TYPE_PNV9_CHIPTOD, 4809a69950fSNicholas Piggin .parent = TYPE_PNV_CHIPTOD, 4819a69950fSNicholas Piggin .instance_size = sizeof(PnvChipTOD), 4829a69950fSNicholas Piggin .class_init = pnv_chiptod_power9_class_init, 4839a69950fSNicholas Piggin .interfaces = (InterfaceInfo[]) { 4849a69950fSNicholas Piggin { TYPE_PNV_XSCOM_INTERFACE }, 4859a69950fSNicholas Piggin { } 4869a69950fSNicholas Piggin } 4879a69950fSNicholas Piggin }; 4889a69950fSNicholas Piggin 4899a69950fSNicholas Piggin static int pnv_chiptod_power10_dt_xscom(PnvXScomInterface *dev, void *fdt, 4909a69950fSNicholas Piggin int xscom_offset) 4919a69950fSNicholas Piggin { 4929a69950fSNicholas Piggin const char compat[] = "ibm,power-chiptod\0ibm,power10-chiptod"; 4939a69950fSNicholas Piggin 4949a69950fSNicholas Piggin return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat)); 4959a69950fSNicholas Piggin } 4969a69950fSNicholas Piggin 4979a69950fSNicholas Piggin static void pnv_chiptod_power10_class_init(ObjectClass *klass, void *data) 4989a69950fSNicholas Piggin { 4999a69950fSNicholas Piggin PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass); 5009a69950fSNicholas Piggin DeviceClass *dc = DEVICE_CLASS(klass); 5019a69950fSNicholas Piggin PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); 5029a69950fSNicholas Piggin 5039a69950fSNicholas Piggin dc->desc = "PowerNV ChipTOD Controller (POWER10)"; 5049a69950fSNicholas Piggin device_class_set_props(dc, pnv_chiptod_properties); 5059a69950fSNicholas Piggin 5069a69950fSNicholas Piggin xdc->dt_xscom = pnv_chiptod_power10_dt_xscom; 5079a69950fSNicholas Piggin 5089a69950fSNicholas Piggin pctc->broadcast_ttype = chiptod_power10_broadcast_ttype; 509*cde2ba34SNicholas Piggin pctc->tx_ttype_target = chiptod_power10_tx_ttype_target; 5109a69950fSNicholas Piggin 5119a69950fSNicholas Piggin pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE; 5129a69950fSNicholas Piggin } 5139a69950fSNicholas Piggin 5149a69950fSNicholas Piggin static const TypeInfo pnv_chiptod_power10_type_info = { 5159a69950fSNicholas Piggin .name = TYPE_PNV10_CHIPTOD, 5169a69950fSNicholas Piggin .parent = TYPE_PNV_CHIPTOD, 5179a69950fSNicholas Piggin .instance_size = sizeof(PnvChipTOD), 5189a69950fSNicholas Piggin .class_init = pnv_chiptod_power10_class_init, 5199a69950fSNicholas Piggin .interfaces = (InterfaceInfo[]) { 5209a69950fSNicholas Piggin { TYPE_PNV_XSCOM_INTERFACE }, 5219a69950fSNicholas Piggin { } 5229a69950fSNicholas Piggin } 5239a69950fSNicholas Piggin }; 5249a69950fSNicholas Piggin 5259a69950fSNicholas Piggin static void pnv_chiptod_reset(void *dev) 5269a69950fSNicholas Piggin { 5279a69950fSNicholas Piggin PnvChipTOD *chiptod = PNV_CHIPTOD(dev); 5289a69950fSNicholas Piggin 5299a69950fSNicholas Piggin chiptod->pss_mss_ctrl_reg = 0; 5309a69950fSNicholas Piggin if (chiptod->primary) { 5319a69950fSNicholas Piggin chiptod->pss_mss_ctrl_reg |= PPC_BIT(1); /* TOD is master */ 5329a69950fSNicholas Piggin } 5339a69950fSNicholas Piggin /* Drawer is master (we do not simulate multi-drawer) */ 5349a69950fSNicholas Piggin chiptod->pss_mss_ctrl_reg |= PPC_BIT(2); 5359a69950fSNicholas Piggin 5369a69950fSNicholas Piggin chiptod->tod_error = 0; 5379a69950fSNicholas Piggin chiptod->tod_state = tod_error; 5389a69950fSNicholas Piggin } 5399a69950fSNicholas Piggin 5409a69950fSNicholas Piggin static void pnv_chiptod_realize(DeviceState *dev, Error **errp) 5419a69950fSNicholas Piggin { 5429a69950fSNicholas Piggin PnvChipTOD *chiptod = PNV_CHIPTOD(dev); 5439a69950fSNicholas Piggin PnvChipTODClass *pctc = PNV_CHIPTOD_GET_CLASS(chiptod); 5449a69950fSNicholas Piggin 5459a69950fSNicholas Piggin /* XScom regions for ChipTOD registers */ 5469a69950fSNicholas Piggin pnv_xscom_region_init(&chiptod->xscom_regs, OBJECT(dev), 5479a69950fSNicholas Piggin &pnv_chiptod_xscom_ops, chiptod, "xscom-chiptod", 5489a69950fSNicholas Piggin pctc->xscom_size); 5499a69950fSNicholas Piggin 5509a69950fSNicholas Piggin qemu_register_reset(pnv_chiptod_reset, chiptod); 5519a69950fSNicholas Piggin } 5529a69950fSNicholas Piggin 5539a69950fSNicholas Piggin static void pnv_chiptod_unrealize(DeviceState *dev) 5549a69950fSNicholas Piggin { 5559a69950fSNicholas Piggin PnvChipTOD *chiptod = PNV_CHIPTOD(dev); 5569a69950fSNicholas Piggin 5579a69950fSNicholas Piggin qemu_unregister_reset(pnv_chiptod_reset, chiptod); 5589a69950fSNicholas Piggin } 5599a69950fSNicholas Piggin 5609a69950fSNicholas Piggin static void pnv_chiptod_class_init(ObjectClass *klass, void *data) 5619a69950fSNicholas Piggin { 5629a69950fSNicholas Piggin DeviceClass *dc = DEVICE_CLASS(klass); 5639a69950fSNicholas Piggin 5649a69950fSNicholas Piggin dc->realize = pnv_chiptod_realize; 5659a69950fSNicholas Piggin dc->unrealize = pnv_chiptod_unrealize; 5669a69950fSNicholas Piggin dc->desc = "PowerNV ChipTOD Controller"; 5679a69950fSNicholas Piggin dc->user_creatable = false; 5689a69950fSNicholas Piggin } 5699a69950fSNicholas Piggin 5709a69950fSNicholas Piggin static const TypeInfo pnv_chiptod_type_info = { 5719a69950fSNicholas Piggin .name = TYPE_PNV_CHIPTOD, 5729a69950fSNicholas Piggin .parent = TYPE_DEVICE, 5739a69950fSNicholas Piggin .instance_size = sizeof(PnvChipTOD), 5749a69950fSNicholas Piggin .class_init = pnv_chiptod_class_init, 5759a69950fSNicholas Piggin .class_size = sizeof(PnvChipTODClass), 5769a69950fSNicholas Piggin .abstract = true, 5779a69950fSNicholas Piggin }; 5789a69950fSNicholas Piggin 5799a69950fSNicholas Piggin static void pnv_chiptod_register_types(void) 5809a69950fSNicholas Piggin { 5819a69950fSNicholas Piggin type_register_static(&pnv_chiptod_type_info); 5829a69950fSNicholas Piggin type_register_static(&pnv_chiptod_power9_type_info); 5839a69950fSNicholas Piggin type_register_static(&pnv_chiptod_power10_type_info); 5849a69950fSNicholas Piggin } 5859a69950fSNicholas Piggin 5869a69950fSNicholas Piggin type_init(pnv_chiptod_register_types); 587