1967b7523SCédric Le Goater /* 2967b7523SCédric Le Goater * QEMU PowerPC PowerNV XSCOM bus 3967b7523SCédric Le Goater * 4967b7523SCédric Le Goater * Copyright (c) 2016, IBM Corporation. 5967b7523SCédric Le Goater * 6967b7523SCédric Le Goater * This library is free software; you can redistribute it and/or 7967b7523SCédric Le Goater * modify it under the terms of the GNU Lesser General Public 8967b7523SCédric Le Goater * License as published by the Free Software Foundation; either 9967b7523SCédric Le Goater * version 2 of the License, or (at your option) any later version. 10967b7523SCédric Le Goater * 11967b7523SCédric Le Goater * This library is distributed in the hope that it will be useful, 12967b7523SCédric Le Goater * but WITHOUT ANY WARRANTY; without even the implied warranty of 13967b7523SCédric Le Goater * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14967b7523SCédric Le Goater * Lesser General Public License for more details. 15967b7523SCédric Le Goater * 16967b7523SCédric Le Goater * You should have received a copy of the GNU Lesser General Public 17967b7523SCédric Le Goater * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18967b7523SCédric Le Goater */ 190b8fa32fSMarkus Armbruster 20967b7523SCédric Le Goater #include "qemu/osdep.h" 21967b7523SCédric Le Goater #include "qemu/log.h" 220b8fa32fSMarkus Armbruster #include "qemu/module.h" 23b3946626SVincent Palatin #include "sysemu/hw_accel.h" 24fcf5ef2aSThomas Huth #include "target/ppc/cpu.h" 25967b7523SCédric Le Goater #include "hw/sysbus.h" 26967b7523SCédric Le Goater 27967b7523SCédric Le Goater #include "hw/ppc/fdt.h" 28967b7523SCédric Le Goater #include "hw/ppc/pnv.h" 29ec575aa0SCédric Le Goater #include "hw/ppc/pnv_xscom.h" 30967b7523SCédric Le Goater 31967b7523SCédric Le Goater #include <libfdt.h> 32967b7523SCédric Le Goater 33ce4b1b56SCédric Le Goater /* PRD registers */ 34ce4b1b56SCédric Le Goater #define PRD_P8_IPOLL_REG_MASK 0x01020013 35ce4b1b56SCédric Le Goater #define PRD_P8_IPOLL_REG_STATUS 0x01020014 36ce4b1b56SCédric Le Goater #define PRD_P9_IPOLL_REG_MASK 0x000F0033 37ce4b1b56SCédric Le Goater #define PRD_P9_IPOLL_REG_STATUS 0x000F0034 38ce4b1b56SCédric Le Goater 39967b7523SCédric Le Goater static void xscom_complete(CPUState *cs, uint64_t hmer_bits) 40967b7523SCédric Le Goater { 41967b7523SCédric Le Goater /* 42967b7523SCédric Le Goater * TODO: When the read/write comes from the monitor, NULL is 43967b7523SCédric Le Goater * passed for the cpu, and no CPU completion is generated. 44967b7523SCédric Le Goater */ 45967b7523SCédric Le Goater if (cs) { 46967b7523SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 47967b7523SCédric Le Goater CPUPPCState *env = &cpu->env; 48967b7523SCédric Le Goater 49967b7523SCédric Le Goater /* 50967b7523SCédric Le Goater * TODO: Need a CPU helper to set HMER, also handle generation 51967b7523SCédric Le Goater * of HMIs 52967b7523SCédric Le Goater */ 53967b7523SCédric Le Goater cpu_synchronize_state(cs); 54967b7523SCédric Le Goater env->spr[SPR_HMER] |= hmer_bits; 55967b7523SCédric Le Goater } 56967b7523SCédric Le Goater } 57967b7523SCédric Le Goater 58967b7523SCédric Le Goater static uint32_t pnv_xscom_pcba(PnvChip *chip, uint64_t addr) 59967b7523SCédric Le Goater { 60967b7523SCédric Le Goater addr &= (PNV_XSCOM_SIZE - 1); 61b3b066e9SCédric Le Goater 62b3b066e9SCédric Le Goater if (pnv_chip_is_power9(chip)) { 63967b7523SCédric Le Goater return addr >> 3; 64967b7523SCédric Le Goater } else { 65967b7523SCédric Le Goater return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf); 66967b7523SCédric Le Goater } 67967b7523SCédric Le Goater } 68967b7523SCédric Le Goater 69967b7523SCédric Le Goater static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba) 70967b7523SCédric Le Goater { 71967b7523SCédric Le Goater switch (pcba) { 72967b7523SCédric Le Goater case 0xf000f: 73967b7523SCédric Le Goater return PNV_CHIP_GET_CLASS(chip)->chip_cfam_id; 74bc565116SCédric Le Goater case 0x18002: /* ECID2 */ 75bc565116SCédric Le Goater return 0; 76bc565116SCédric Le Goater 77967b7523SCédric Le Goater case 0x1010c00: /* PIBAM FIR */ 78967b7523SCédric Le Goater case 0x1010c03: /* PIBAM FIR MASK */ 79bc565116SCédric Le Goater 80ce4b1b56SCédric Le Goater /* PRD registers */ 81ce4b1b56SCédric Le Goater case PRD_P8_IPOLL_REG_MASK: 82ce4b1b56SCédric Le Goater case PRD_P8_IPOLL_REG_STATUS: 83ce4b1b56SCédric Le Goater case PRD_P9_IPOLL_REG_MASK: 84ce4b1b56SCédric Le Goater case PRD_P9_IPOLL_REG_STATUS: 85ce4b1b56SCédric Le Goater 86bc565116SCédric Le Goater /* P9 xscom reset */ 87bc565116SCédric Le Goater case 0x0090018: /* Receive status reg */ 88bc565116SCédric Le Goater case 0x0090012: /* log register */ 89bc565116SCédric Le Goater case 0x0090013: /* error register */ 90bc565116SCédric Le Goater 91bc565116SCédric Le Goater /* P8 xscom reset */ 92bc565116SCédric Le Goater case 0x2020007: /* ADU stuff, log register */ 93bc565116SCédric Le Goater case 0x2020009: /* ADU stuff, error register */ 94bc565116SCédric Le Goater case 0x202000f: /* ADU stuff, receive status register*/ 95967b7523SCédric Le Goater return 0; 96967b7523SCédric Le Goater case 0x2013f00: /* PBA stuff */ 97967b7523SCédric Le Goater case 0x2013f01: /* PBA stuff */ 98967b7523SCédric Le Goater case 0x2013f02: /* PBA stuff */ 99967b7523SCédric Le Goater case 0x2013f03: /* PBA stuff */ 100967b7523SCédric Le Goater case 0x2013f04: /* PBA stuff */ 101967b7523SCédric Le Goater case 0x2013f05: /* PBA stuff */ 102967b7523SCédric Le Goater case 0x2013f06: /* PBA stuff */ 103967b7523SCédric Le Goater case 0x2013f07: /* PBA stuff */ 104967b7523SCédric Le Goater return 0; 105967b7523SCédric Le Goater case 0x2013028: /* CAPP stuff */ 106967b7523SCédric Le Goater case 0x201302a: /* CAPP stuff */ 107967b7523SCédric Le Goater case 0x2013801: /* CAPP stuff */ 108967b7523SCédric Le Goater case 0x2013802: /* CAPP stuff */ 109*45a73a19SCédric Le Goater 110*45a73a19SCédric Le Goater /* P9 CAPP regs */ 111*45a73a19SCédric Le Goater case 0x2010841: 112*45a73a19SCédric Le Goater case 0x2010842: 113*45a73a19SCédric Le Goater case 0x201082a: 114*45a73a19SCédric Le Goater case 0x2010828: 115*45a73a19SCédric Le Goater case 0x4010841: 116*45a73a19SCédric Le Goater case 0x4010842: 117*45a73a19SCédric Le Goater case 0x401082a: 118*45a73a19SCédric Le Goater case 0x4010828: 119967b7523SCédric Le Goater return 0; 120967b7523SCédric Le Goater default: 121967b7523SCédric Le Goater return -1; 122967b7523SCédric Le Goater } 123967b7523SCédric Le Goater } 124967b7523SCédric Le Goater 125967b7523SCédric Le Goater static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val) 126967b7523SCédric Le Goater { 127967b7523SCédric Le Goater /* We ignore writes to these */ 128967b7523SCédric Le Goater switch (pcba) { 129967b7523SCédric Le Goater case 0xf000f: /* chip id is RO */ 130967b7523SCédric Le Goater case 0x1010c00: /* PIBAM FIR */ 131967b7523SCédric Le Goater case 0x1010c01: /* PIBAM FIR */ 132967b7523SCédric Le Goater case 0x1010c02: /* PIBAM FIR */ 133967b7523SCédric Le Goater case 0x1010c03: /* PIBAM FIR MASK */ 134967b7523SCédric Le Goater case 0x1010c04: /* PIBAM FIR MASK */ 135967b7523SCédric Le Goater case 0x1010c05: /* PIBAM FIR MASK */ 136bc565116SCédric Le Goater /* P9 xscom reset */ 137bc565116SCédric Le Goater case 0x0090018: /* Receive status reg */ 138bc565116SCédric Le Goater case 0x0090012: /* log register */ 139bc565116SCédric Le Goater case 0x0090013: /* error register */ 140bc565116SCédric Le Goater 141bc565116SCédric Le Goater /* P8 xscom reset */ 142bc565116SCédric Le Goater case 0x2020007: /* ADU stuff, log register */ 143bc565116SCédric Le Goater case 0x2020009: /* ADU stuff, error register */ 144bc565116SCédric Le Goater case 0x202000f: /* ADU stuff, receive status register*/ 145bc565116SCédric Le Goater 146bc565116SCédric Le Goater case 0x2013028: /* CAPP stuff */ 147bc565116SCédric Le Goater case 0x201302a: /* CAPP stuff */ 148bc565116SCédric Le Goater case 0x2013801: /* CAPP stuff */ 149bc565116SCédric Le Goater case 0x2013802: /* CAPP stuff */ 150ce4b1b56SCédric Le Goater 151*45a73a19SCédric Le Goater /* P9 CAPP regs */ 152*45a73a19SCédric Le Goater case 0x2010841: 153*45a73a19SCédric Le Goater case 0x2010842: 154*45a73a19SCédric Le Goater case 0x201082a: 155*45a73a19SCédric Le Goater case 0x2010828: 156*45a73a19SCédric Le Goater case 0x4010841: 157*45a73a19SCédric Le Goater case 0x4010842: 158*45a73a19SCédric Le Goater case 0x401082a: 159*45a73a19SCédric Le Goater case 0x4010828: 160*45a73a19SCédric Le Goater 161ce4b1b56SCédric Le Goater /* P8 PRD registers */ 162ce4b1b56SCédric Le Goater case PRD_P8_IPOLL_REG_MASK: 163ce4b1b56SCédric Le Goater case PRD_P8_IPOLL_REG_STATUS: 164ce4b1b56SCédric Le Goater case PRD_P9_IPOLL_REG_MASK: 165ce4b1b56SCédric Le Goater case PRD_P9_IPOLL_REG_STATUS: 166967b7523SCédric Le Goater return true; 167967b7523SCédric Le Goater default: 168967b7523SCédric Le Goater return false; 169967b7523SCédric Le Goater } 170967b7523SCédric Le Goater } 171967b7523SCédric Le Goater 172967b7523SCédric Le Goater static uint64_t xscom_read(void *opaque, hwaddr addr, unsigned width) 173967b7523SCédric Le Goater { 174967b7523SCédric Le Goater PnvChip *chip = opaque; 175967b7523SCédric Le Goater uint32_t pcba = pnv_xscom_pcba(chip, addr); 176967b7523SCédric Le Goater uint64_t val = 0; 177967b7523SCédric Le Goater MemTxResult result; 178967b7523SCédric Le Goater 179967b7523SCédric Le Goater /* Handle some SCOMs here before dispatch */ 180967b7523SCédric Le Goater val = xscom_read_default(chip, pcba); 181967b7523SCédric Le Goater if (val != -1) { 182967b7523SCédric Le Goater goto complete; 183967b7523SCédric Le Goater } 184967b7523SCédric Le Goater 185f81e5512SCédric Le Goater val = address_space_ldq(&chip->xscom_as, (uint64_t) pcba << 3, 186f81e5512SCédric Le Goater MEMTXATTRS_UNSPECIFIED, &result); 187967b7523SCédric Le Goater if (result != MEMTX_OK) { 188967b7523SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "XSCOM read failed at @0x%" 189967b7523SCédric Le Goater HWADDR_PRIx " pcba=0x%08x\n", addr, pcba); 190967b7523SCédric Le Goater xscom_complete(current_cpu, HMER_XSCOM_FAIL | HMER_XSCOM_DONE); 191967b7523SCédric Le Goater return 0; 192967b7523SCédric Le Goater } 193967b7523SCédric Le Goater 194967b7523SCédric Le Goater complete: 195967b7523SCédric Le Goater xscom_complete(current_cpu, HMER_XSCOM_DONE); 196967b7523SCédric Le Goater return val; 197967b7523SCédric Le Goater } 198967b7523SCédric Le Goater 199967b7523SCédric Le Goater static void xscom_write(void *opaque, hwaddr addr, uint64_t val, 200967b7523SCédric Le Goater unsigned width) 201967b7523SCédric Le Goater { 202967b7523SCédric Le Goater PnvChip *chip = opaque; 203967b7523SCédric Le Goater uint32_t pcba = pnv_xscom_pcba(chip, addr); 204967b7523SCédric Le Goater MemTxResult result; 205967b7523SCédric Le Goater 206967b7523SCédric Le Goater /* Handle some SCOMs here before dispatch */ 207967b7523SCédric Le Goater if (xscom_write_default(chip, pcba, val)) { 208967b7523SCédric Le Goater goto complete; 209967b7523SCédric Le Goater } 210967b7523SCédric Le Goater 211f81e5512SCédric Le Goater address_space_stq(&chip->xscom_as, (uint64_t) pcba << 3, val, 212f81e5512SCédric Le Goater MEMTXATTRS_UNSPECIFIED, &result); 213967b7523SCédric Le Goater if (result != MEMTX_OK) { 214967b7523SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "XSCOM write failed at @0x%" 215967b7523SCédric Le Goater HWADDR_PRIx " pcba=0x%08x data=0x%" PRIx64 "\n", 216967b7523SCédric Le Goater addr, pcba, val); 217967b7523SCédric Le Goater xscom_complete(current_cpu, HMER_XSCOM_FAIL | HMER_XSCOM_DONE); 218967b7523SCédric Le Goater return; 219967b7523SCédric Le Goater } 220967b7523SCédric Le Goater 221967b7523SCédric Le Goater complete: 222967b7523SCédric Le Goater xscom_complete(current_cpu, HMER_XSCOM_DONE); 223967b7523SCédric Le Goater } 224967b7523SCédric Le Goater 225967b7523SCédric Le Goater const MemoryRegionOps pnv_xscom_ops = { 226967b7523SCédric Le Goater .read = xscom_read, 227967b7523SCédric Le Goater .write = xscom_write, 228967b7523SCédric Le Goater .valid.min_access_size = 8, 229967b7523SCédric Le Goater .valid.max_access_size = 8, 230967b7523SCédric Le Goater .impl.min_access_size = 8, 231967b7523SCédric Le Goater .impl.max_access_size = 8, 232967b7523SCédric Le Goater .endianness = DEVICE_BIG_ENDIAN, 233967b7523SCédric Le Goater }; 234967b7523SCédric Le Goater 235709044fdSCédric Le Goater void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp) 236967b7523SCédric Le Goater { 237967b7523SCédric Le Goater SysBusDevice *sbd = SYS_BUS_DEVICE(chip); 238967b7523SCédric Le Goater char *name; 239967b7523SCédric Le Goater 240967b7523SCédric Le Goater name = g_strdup_printf("xscom-%x", chip->chip_id); 241967b7523SCédric Le Goater memory_region_init_io(&chip->xscom_mmio, OBJECT(chip), &pnv_xscom_ops, 242709044fdSCédric Le Goater chip, name, size); 243967b7523SCédric Le Goater sysbus_init_mmio(sbd, &chip->xscom_mmio); 244967b7523SCédric Le Goater 245709044fdSCédric Le Goater memory_region_init(&chip->xscom, OBJECT(chip), name, size); 246967b7523SCédric Le Goater address_space_init(&chip->xscom_as, &chip->xscom, name); 247967b7523SCédric Le Goater g_free(name); 248967b7523SCédric Le Goater } 249967b7523SCédric Le Goater 250967b7523SCédric Le Goater static const TypeInfo pnv_xscom_interface_info = { 251967b7523SCédric Le Goater .name = TYPE_PNV_XSCOM_INTERFACE, 252967b7523SCédric Le Goater .parent = TYPE_INTERFACE, 253967b7523SCédric Le Goater .class_size = sizeof(PnvXScomInterfaceClass), 254967b7523SCédric Le Goater }; 255967b7523SCédric Le Goater 256967b7523SCédric Le Goater static void pnv_xscom_register_types(void) 257967b7523SCédric Le Goater { 258967b7523SCédric Le Goater type_register_static(&pnv_xscom_interface_info); 259967b7523SCédric Le Goater } 260967b7523SCédric Le Goater 261967b7523SCédric Le Goater type_init(pnv_xscom_register_types) 262967b7523SCédric Le Goater 263967b7523SCédric Le Goater typedef struct ForeachPopulateArgs { 264967b7523SCédric Le Goater void *fdt; 265967b7523SCédric Le Goater int xscom_offset; 266967b7523SCédric Le Goater } ForeachPopulateArgs; 267967b7523SCédric Le Goater 268b168a138SCédric Le Goater static int xscom_dt_child(Object *child, void *opaque) 269967b7523SCédric Le Goater { 270967b7523SCédric Le Goater if (object_dynamic_cast(child, TYPE_PNV_XSCOM_INTERFACE)) { 271967b7523SCédric Le Goater ForeachPopulateArgs *args = opaque; 272967b7523SCédric Le Goater PnvXScomInterface *xd = PNV_XSCOM_INTERFACE(child); 273967b7523SCédric Le Goater PnvXScomInterfaceClass *xc = PNV_XSCOM_INTERFACE_GET_CLASS(xd); 274967b7523SCédric Le Goater 275b168a138SCédric Le Goater if (xc->dt_xscom) { 276b168a138SCédric Le Goater _FDT((xc->dt_xscom(xd, args->fdt, args->xscom_offset))); 277967b7523SCédric Le Goater } 278967b7523SCédric Le Goater } 279967b7523SCédric Le Goater return 0; 280967b7523SCédric Le Goater } 281967b7523SCédric Le Goater 282967b7523SCédric Le Goater static const char compat_p8[] = "ibm,power8-xscom\0ibm,xscom"; 283967b7523SCédric Le Goater static const char compat_p9[] = "ibm,power9-xscom\0ibm,xscom"; 284967b7523SCédric Le Goater 285b168a138SCédric Le Goater int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset) 286967b7523SCédric Le Goater { 287709044fdSCédric Le Goater uint64_t reg[2]; 288967b7523SCédric Le Goater int xscom_offset; 289967b7523SCédric Le Goater ForeachPopulateArgs args; 290967b7523SCédric Le Goater char *name; 291967b7523SCédric Le Goater 292709044fdSCédric Le Goater if (pnv_chip_is_power9(chip)) { 293709044fdSCédric Le Goater reg[0] = cpu_to_be64(PNV9_XSCOM_BASE(chip)); 294709044fdSCédric Le Goater reg[1] = cpu_to_be64(PNV9_XSCOM_SIZE); 295709044fdSCédric Le Goater } else { 296709044fdSCédric Le Goater reg[0] = cpu_to_be64(PNV_XSCOM_BASE(chip)); 297709044fdSCédric Le Goater reg[1] = cpu_to_be64(PNV_XSCOM_SIZE); 298709044fdSCédric Le Goater } 299709044fdSCédric Le Goater 300967b7523SCédric Le Goater name = g_strdup_printf("xscom@%" PRIx64, be64_to_cpu(reg[0])); 301967b7523SCédric Le Goater xscom_offset = fdt_add_subnode(fdt, root_offset, name); 302967b7523SCédric Le Goater _FDT(xscom_offset); 303967b7523SCédric Le Goater g_free(name); 304967b7523SCédric Le Goater _FDT((fdt_setprop_cell(fdt, xscom_offset, "ibm,chip-id", chip->chip_id))); 305967b7523SCédric Le Goater _FDT((fdt_setprop_cell(fdt, xscom_offset, "#address-cells", 1))); 306967b7523SCédric Le Goater _FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1))); 307967b7523SCédric Le Goater _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg)))); 308967b7523SCédric Le Goater 309b3b066e9SCédric Le Goater if (pnv_chip_is_power9(chip)) { 310967b7523SCédric Le Goater _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p9, 311967b7523SCédric Le Goater sizeof(compat_p9)))); 312967b7523SCédric Le Goater } else { 313967b7523SCédric Le Goater _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p8, 314967b7523SCédric Le Goater sizeof(compat_p8)))); 315967b7523SCédric Le Goater } 316967b7523SCédric Le Goater 317967b7523SCédric Le Goater _FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0))); 318967b7523SCédric Le Goater 319967b7523SCédric Le Goater args.fdt = fdt; 320967b7523SCédric Le Goater args.xscom_offset = xscom_offset; 321967b7523SCédric Le Goater 322b168a138SCédric Le Goater object_child_foreach(OBJECT(chip), xscom_dt_child, &args); 323967b7523SCédric Le Goater return 0; 324967b7523SCédric Le Goater } 325967b7523SCédric Le Goater 326967b7523SCédric Le Goater void pnv_xscom_add_subregion(PnvChip *chip, hwaddr offset, MemoryRegion *mr) 327967b7523SCédric Le Goater { 328967b7523SCédric Le Goater memory_region_add_subregion(&chip->xscom, offset << 3, mr); 329967b7523SCédric Le Goater } 330967b7523SCédric Le Goater 331967b7523SCédric Le Goater void pnv_xscom_region_init(MemoryRegion *mr, 332967b7523SCédric Le Goater struct Object *owner, 333967b7523SCédric Le Goater const MemoryRegionOps *ops, 334967b7523SCédric Le Goater void *opaque, 335967b7523SCédric Le Goater const char *name, 336967b7523SCédric Le Goater uint64_t size) 337967b7523SCédric Le Goater { 338967b7523SCédric Le Goater memory_region_init_io(mr, owner, ops, opaque, name, size << 3); 339967b7523SCédric Le Goater } 340