1a3980bf5SBenjamin Herrenschmidt /* 2a3980bf5SBenjamin Herrenschmidt * QEMU PowerPC PowerNV LPC controller 3a3980bf5SBenjamin Herrenschmidt * 4a3980bf5SBenjamin Herrenschmidt * Copyright (c) 2016, IBM Corporation. 5a3980bf5SBenjamin Herrenschmidt * 6a3980bf5SBenjamin Herrenschmidt * This library is free software; you can redistribute it and/or 7a3980bf5SBenjamin Herrenschmidt * modify it under the terms of the GNU Lesser General Public 8a3980bf5SBenjamin Herrenschmidt * License as published by the Free Software Foundation; either 9f70c5966SChetan Pant * version 2.1 of the License, or (at your option) any later version. 10a3980bf5SBenjamin Herrenschmidt * 11a3980bf5SBenjamin Herrenschmidt * This library is distributed in the hope that it will be useful, 12a3980bf5SBenjamin Herrenschmidt * but WITHOUT ANY WARRANTY; without even the implied warranty of 13a3980bf5SBenjamin Herrenschmidt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14a3980bf5SBenjamin Herrenschmidt * Lesser General Public License for more details. 15a3980bf5SBenjamin Herrenschmidt * 16a3980bf5SBenjamin Herrenschmidt * You should have received a copy of the GNU Lesser General Public 17a3980bf5SBenjamin Herrenschmidt * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18a3980bf5SBenjamin Herrenschmidt */ 19a3980bf5SBenjamin Herrenschmidt 20a3980bf5SBenjamin Herrenschmidt #include "qemu/osdep.h" 21fcf5ef2aSThomas Huth #include "target/ppc/cpu.h" 22a3980bf5SBenjamin Herrenschmidt #include "qapi/error.h" 23a3980bf5SBenjamin Herrenschmidt #include "qemu/log.h" 240b8fa32fSMarkus Armbruster #include "qemu/module.h" 2564552b6bSMarkus Armbruster #include "hw/irq.h" 2604026890SCédric Le Goater #include "hw/isa/isa.h" 27b63f3893SGreg Kurz #include "hw/qdev-properties.h" 28a3980bf5SBenjamin Herrenschmidt #include "hw/ppc/pnv.h" 292c6fe2e2SMarkus Armbruster #include "hw/ppc/pnv_chip.h" 30ec575aa0SCédric Le Goater #include "hw/ppc/pnv_lpc.h" 31ec575aa0SCédric Le Goater #include "hw/ppc/pnv_xscom.h" 32a3980bf5SBenjamin Herrenschmidt #include "hw/ppc/fdt.h" 33a3980bf5SBenjamin Herrenschmidt 34a3980bf5SBenjamin Herrenschmidt #include <libfdt.h> 35a3980bf5SBenjamin Herrenschmidt 36a3980bf5SBenjamin Herrenschmidt enum { 37a3980bf5SBenjamin Herrenschmidt ECCB_CTL = 0, 38a3980bf5SBenjamin Herrenschmidt ECCB_RESET = 1, 39a3980bf5SBenjamin Herrenschmidt ECCB_STAT = 2, 40a3980bf5SBenjamin Herrenschmidt ECCB_DATA = 3, 41a3980bf5SBenjamin Herrenschmidt }; 42a3980bf5SBenjamin Herrenschmidt 43a3980bf5SBenjamin Herrenschmidt /* OPB Master LS registers */ 448207b906SCédric Le Goater #define OPB_MASTER_LS_ROUTE0 0x8 458207b906SCédric Le Goater #define OPB_MASTER_LS_ROUTE1 0xC 46a3980bf5SBenjamin Herrenschmidt #define OPB_MASTER_LS_IRQ_STAT 0x50 47a3980bf5SBenjamin Herrenschmidt #define OPB_MASTER_IRQ_LPC 0x00000800 48a3980bf5SBenjamin Herrenschmidt #define OPB_MASTER_LS_IRQ_MASK 0x54 49a3980bf5SBenjamin Herrenschmidt #define OPB_MASTER_LS_IRQ_POL 0x58 50a3980bf5SBenjamin Herrenschmidt #define OPB_MASTER_LS_IRQ_INPUT 0x5c 51a3980bf5SBenjamin Herrenschmidt 52a3980bf5SBenjamin Herrenschmidt /* LPC HC registers */ 53a3980bf5SBenjamin Herrenschmidt #define LPC_HC_FW_SEG_IDSEL 0x24 54a3980bf5SBenjamin Herrenschmidt #define LPC_HC_FW_RD_ACC_SIZE 0x28 55a3980bf5SBenjamin Herrenschmidt #define LPC_HC_FW_RD_1B 0x00000000 56a3980bf5SBenjamin Herrenschmidt #define LPC_HC_FW_RD_2B 0x01000000 57a3980bf5SBenjamin Herrenschmidt #define LPC_HC_FW_RD_4B 0x02000000 58a3980bf5SBenjamin Herrenschmidt #define LPC_HC_FW_RD_16B 0x04000000 59a3980bf5SBenjamin Herrenschmidt #define LPC_HC_FW_RD_128B 0x07000000 60a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQSER_CTRL 0x30 61a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQSER_EN 0x80000000 62a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQSER_QMODE 0x40000000 63a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQSER_START_MASK 0x03000000 64a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQSER_START_4CLK 0x00000000 65a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQSER_START_6CLK 0x01000000 66a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQSER_START_8CLK 0x02000000 67a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQMASK 0x34 /* same bit defs as LPC_HC_IRQSTAT */ 68a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQSTAT 0x38 69a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SERIRQ0 0x80000000 /* all bits down to ... */ 70a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SERIRQ16 0x00008000 /* IRQ16=IOCHK#, IRQ2=SMI# */ 71a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SERIRQ_ALL 0xffff8000 72a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_LRESET 0x00000400 73a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SYNC_ABNORM_ERR 0x00000080 74a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SYNC_NORESP_ERR 0x00000040 75a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SYNC_NORM_ERR 0x00000020 76a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SYNC_TIMEOUT_ERR 0x00000010 77a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SYNC_TARG_TAR_ERR 0x00000008 78a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SYNC_BM_TAR_ERR 0x00000004 79a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SYNC_BM0_REQ 0x00000002 80a3980bf5SBenjamin Herrenschmidt #define LPC_HC_IRQ_SYNC_BM1_REQ 0x00000001 81a3980bf5SBenjamin Herrenschmidt #define LPC_HC_ERROR_ADDRESS 0x40 82a3980bf5SBenjamin Herrenschmidt 83a3980bf5SBenjamin Herrenschmidt #define LPC_OPB_SIZE 0x100000000ull 84a3980bf5SBenjamin Herrenschmidt 85a3980bf5SBenjamin Herrenschmidt #define ISA_IO_SIZE 0x00010000 86a3980bf5SBenjamin Herrenschmidt #define ISA_MEM_SIZE 0x10000000 87d61c2857SCédric Le Goater #define ISA_FW_SIZE 0x10000000 88a3980bf5SBenjamin Herrenschmidt #define LPC_IO_OPB_ADDR 0xd0010000 89a3980bf5SBenjamin Herrenschmidt #define LPC_IO_OPB_SIZE 0x00010000 9095bd61c4SCédric Le Goater #define LPC_MEM_OPB_ADDR 0xe0000000 91a3980bf5SBenjamin Herrenschmidt #define LPC_MEM_OPB_SIZE 0x10000000 92a3980bf5SBenjamin Herrenschmidt #define LPC_FW_OPB_ADDR 0xf0000000 93a3980bf5SBenjamin Herrenschmidt #define LPC_FW_OPB_SIZE 0x10000000 94a3980bf5SBenjamin Herrenschmidt 95a3980bf5SBenjamin Herrenschmidt #define LPC_OPB_REGS_OPB_ADDR 0xc0010000 966f89f48eSCédric Le Goater #define LPC_OPB_REGS_OPB_SIZE 0x00000060 976f89f48eSCédric Le Goater #define LPC_OPB_REGS_OPBA_ADDR 0xc0011000 986f89f48eSCédric Le Goater #define LPC_OPB_REGS_OPBA_SIZE 0x00000008 99a3980bf5SBenjamin Herrenschmidt #define LPC_HC_REGS_OPB_ADDR 0xc0012000 1006f89f48eSCédric Le Goater #define LPC_HC_REGS_OPB_SIZE 0x00000100 101a3980bf5SBenjamin Herrenschmidt 102b168a138SCédric Le Goater static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset) 103a3980bf5SBenjamin Herrenschmidt { 104a3980bf5SBenjamin Herrenschmidt const char compat[] = "ibm,power8-lpc\0ibm,lpc"; 105a3980bf5SBenjamin Herrenschmidt char *name; 106a3980bf5SBenjamin Herrenschmidt int offset; 107a3980bf5SBenjamin Herrenschmidt uint32_t lpc_pcba = PNV_XSCOM_LPC_BASE; 108a3980bf5SBenjamin Herrenschmidt uint32_t reg[] = { 109a3980bf5SBenjamin Herrenschmidt cpu_to_be32(lpc_pcba), 110a3980bf5SBenjamin Herrenschmidt cpu_to_be32(PNV_XSCOM_LPC_SIZE) 111a3980bf5SBenjamin Herrenschmidt }; 112a3980bf5SBenjamin Herrenschmidt 113a3980bf5SBenjamin Herrenschmidt name = g_strdup_printf("isa@%x", lpc_pcba); 114a3980bf5SBenjamin Herrenschmidt offset = fdt_add_subnode(fdt, xscom_offset, name); 115a3980bf5SBenjamin Herrenschmidt _FDT(offset); 116a3980bf5SBenjamin Herrenschmidt g_free(name); 117a3980bf5SBenjamin Herrenschmidt 118a3980bf5SBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); 119a3980bf5SBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2))); 120a3980bf5SBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1))); 121a3980bf5SBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat)))); 122a3980bf5SBenjamin Herrenschmidt return 0; 123a3980bf5SBenjamin Herrenschmidt } 124a3980bf5SBenjamin Herrenschmidt 12515376c66SCédric Le Goater /* POWER9 only */ 1262661f6abSCédric Le Goater int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset, uint64_t lpcm_addr, 1272661f6abSCédric Le Goater uint64_t lpcm_size) 12815376c66SCédric Le Goater { 12915376c66SCédric Le Goater const char compat[] = "ibm,power9-lpcm-opb\0simple-bus"; 13015376c66SCédric Le Goater const char lpc_compat[] = "ibm,power9-lpc\0ibm,lpc"; 13115376c66SCédric Le Goater char *name; 13215376c66SCédric Le Goater int offset, lpcm_offset; 13315376c66SCédric Le Goater uint32_t opb_ranges[8] = { 0, 13415376c66SCédric Le Goater cpu_to_be32(lpcm_addr >> 32), 13515376c66SCédric Le Goater cpu_to_be32((uint32_t)lpcm_addr), 1362661f6abSCédric Le Goater cpu_to_be32(lpcm_size / 2), 1372661f6abSCédric Le Goater cpu_to_be32(lpcm_size / 2), 13815376c66SCédric Le Goater cpu_to_be32(lpcm_addr >> 32), 1392661f6abSCédric Le Goater cpu_to_be32(lpcm_size / 2), 1402661f6abSCédric Le Goater cpu_to_be32(lpcm_size / 2), 14115376c66SCédric Le Goater }; 14215376c66SCédric Le Goater uint32_t opb_reg[4] = { cpu_to_be32(lpcm_addr >> 32), 14315376c66SCédric Le Goater cpu_to_be32((uint32_t)lpcm_addr), 1442661f6abSCédric Le Goater cpu_to_be32(lpcm_size >> 32), 1452661f6abSCédric Le Goater cpu_to_be32((uint32_t)lpcm_size), 14615376c66SCédric Le Goater }; 14795bd61c4SCédric Le Goater uint32_t lpc_ranges[12] = { 0, 0, 14895bd61c4SCédric Le Goater cpu_to_be32(LPC_MEM_OPB_ADDR), 14995bd61c4SCédric Le Goater cpu_to_be32(LPC_MEM_OPB_SIZE), 15095bd61c4SCédric Le Goater cpu_to_be32(1), 0, 15195bd61c4SCédric Le Goater cpu_to_be32(LPC_IO_OPB_ADDR), 15295bd61c4SCédric Le Goater cpu_to_be32(LPC_IO_OPB_SIZE), 15395bd61c4SCédric Le Goater cpu_to_be32(3), 0, 15495bd61c4SCédric Le Goater cpu_to_be32(LPC_FW_OPB_ADDR), 15595bd61c4SCédric Le Goater cpu_to_be32(LPC_FW_OPB_SIZE), 15695bd61c4SCédric Le Goater }; 15715376c66SCédric Le Goater uint32_t reg[2]; 15815376c66SCédric Le Goater 15915376c66SCédric Le Goater /* 16015376c66SCédric Le Goater * OPB bus 16115376c66SCédric Le Goater */ 16215376c66SCédric Le Goater name = g_strdup_printf("lpcm-opb@%"PRIx64, lpcm_addr); 16315376c66SCédric Le Goater lpcm_offset = fdt_add_subnode(fdt, root_offset, name); 16415376c66SCédric Le Goater _FDT(lpcm_offset); 16515376c66SCédric Le Goater g_free(name); 16615376c66SCédric Le Goater 16715376c66SCédric Le Goater _FDT((fdt_setprop(fdt, lpcm_offset, "reg", opb_reg, sizeof(opb_reg)))); 16815376c66SCédric Le Goater _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#address-cells", 1))); 16915376c66SCédric Le Goater _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#size-cells", 1))); 17015376c66SCédric Le Goater _FDT((fdt_setprop(fdt, lpcm_offset, "compatible", compat, sizeof(compat)))); 17115376c66SCédric Le Goater _FDT((fdt_setprop_cell(fdt, lpcm_offset, "ibm,chip-id", chip->chip_id))); 17215376c66SCédric Le Goater _FDT((fdt_setprop(fdt, lpcm_offset, "ranges", opb_ranges, 17315376c66SCédric Le Goater sizeof(opb_ranges)))); 17415376c66SCédric Le Goater 17515376c66SCédric Le Goater /* 17615376c66SCédric Le Goater * OPB Master registers 17715376c66SCédric Le Goater */ 17815376c66SCédric Le Goater name = g_strdup_printf("opb-master@%x", LPC_OPB_REGS_OPB_ADDR); 17915376c66SCédric Le Goater offset = fdt_add_subnode(fdt, lpcm_offset, name); 18015376c66SCédric Le Goater _FDT(offset); 18115376c66SCédric Le Goater g_free(name); 18215376c66SCédric Le Goater 18315376c66SCédric Le Goater reg[0] = cpu_to_be32(LPC_OPB_REGS_OPB_ADDR); 18415376c66SCédric Le Goater reg[1] = cpu_to_be32(LPC_OPB_REGS_OPB_SIZE); 18515376c66SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); 18615376c66SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "compatible", 18715376c66SCédric Le Goater "ibm,power9-lpcm-opb-master"))); 18815376c66SCédric Le Goater 18915376c66SCédric Le Goater /* 19015376c66SCédric Le Goater * OPB arbitrer registers 19115376c66SCédric Le Goater */ 19215376c66SCédric Le Goater name = g_strdup_printf("opb-arbitrer@%x", LPC_OPB_REGS_OPBA_ADDR); 19315376c66SCédric Le Goater offset = fdt_add_subnode(fdt, lpcm_offset, name); 19415376c66SCédric Le Goater _FDT(offset); 19515376c66SCédric Le Goater g_free(name); 19615376c66SCédric Le Goater 19715376c66SCédric Le Goater reg[0] = cpu_to_be32(LPC_OPB_REGS_OPBA_ADDR); 19815376c66SCédric Le Goater reg[1] = cpu_to_be32(LPC_OPB_REGS_OPBA_SIZE); 19915376c66SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); 20015376c66SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "compatible", 20115376c66SCédric Le Goater "ibm,power9-lpcm-opb-arbiter"))); 20215376c66SCédric Le Goater 20315376c66SCédric Le Goater /* 20415376c66SCédric Le Goater * LPC Host Controller registers 20515376c66SCédric Le Goater */ 20615376c66SCédric Le Goater name = g_strdup_printf("lpc-controller@%x", LPC_HC_REGS_OPB_ADDR); 20715376c66SCédric Le Goater offset = fdt_add_subnode(fdt, lpcm_offset, name); 20815376c66SCédric Le Goater _FDT(offset); 20915376c66SCédric Le Goater g_free(name); 21015376c66SCédric Le Goater 21115376c66SCédric Le Goater reg[0] = cpu_to_be32(LPC_HC_REGS_OPB_ADDR); 21215376c66SCédric Le Goater reg[1] = cpu_to_be32(LPC_HC_REGS_OPB_SIZE); 21315376c66SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); 21415376c66SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "compatible", 21515376c66SCédric Le Goater "ibm,power9-lpc-controller"))); 21615376c66SCédric Le Goater 21715376c66SCédric Le Goater name = g_strdup_printf("lpc@0"); 21815376c66SCédric Le Goater offset = fdt_add_subnode(fdt, lpcm_offset, name); 21915376c66SCédric Le Goater _FDT(offset); 22015376c66SCédric Le Goater g_free(name); 22115376c66SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2))); 22215376c66SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1))); 22315376c66SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "compatible", lpc_compat, 22415376c66SCédric Le Goater sizeof(lpc_compat)))); 22595bd61c4SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ranges", lpc_ranges, 22695bd61c4SCédric Le Goater sizeof(lpc_ranges)))); 22715376c66SCédric Le Goater 22815376c66SCédric Le Goater return 0; 22915376c66SCédric Le Goater } 23015376c66SCédric Le Goater 231a3980bf5SBenjamin Herrenschmidt /* 232a3980bf5SBenjamin Herrenschmidt * These read/write handlers of the OPB address space should be common 233a3980bf5SBenjamin Herrenschmidt * with the P9 LPC Controller which uses direct MMIOs. 234a3980bf5SBenjamin Herrenschmidt * 235a3980bf5SBenjamin Herrenschmidt * TODO: rework to use address_space_stq() and address_space_ldq() 236a3980bf5SBenjamin Herrenschmidt * instead. 237a3980bf5SBenjamin Herrenschmidt */ 238a3980bf5SBenjamin Herrenschmidt static bool opb_read(PnvLpcController *lpc, uint32_t addr, uint8_t *data, 239a3980bf5SBenjamin Herrenschmidt int sz) 240a3980bf5SBenjamin Herrenschmidt { 241a3980bf5SBenjamin Herrenschmidt /* XXX Handle access size limits and FW read caching here */ 24219f70347SPeter Maydell return !address_space_read(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED, 24319f70347SPeter Maydell data, sz); 244a3980bf5SBenjamin Herrenschmidt } 245a3980bf5SBenjamin Herrenschmidt 246a3980bf5SBenjamin Herrenschmidt static bool opb_write(PnvLpcController *lpc, uint32_t addr, uint8_t *data, 247a3980bf5SBenjamin Herrenschmidt int sz) 248a3980bf5SBenjamin Herrenschmidt { 249a3980bf5SBenjamin Herrenschmidt /* XXX Handle access size limits here */ 25019f70347SPeter Maydell return !address_space_write(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED, 25119f70347SPeter Maydell data, sz); 252a3980bf5SBenjamin Herrenschmidt } 253a3980bf5SBenjamin Herrenschmidt 254a6a444a8SCédric Le Goater #define ECCB_CTL_READ PPC_BIT(15) 255a3980bf5SBenjamin Herrenschmidt #define ECCB_CTL_SZ_LSH (63 - 7) 256a6a444a8SCédric Le Goater #define ECCB_CTL_SZ_MASK PPC_BITMASK(4, 7) 257a6a444a8SCédric Le Goater #define ECCB_CTL_ADDR_MASK PPC_BITMASK(32, 63) 258a3980bf5SBenjamin Herrenschmidt 259a6a444a8SCédric Le Goater #define ECCB_STAT_OP_DONE PPC_BIT(52) 260a6a444a8SCédric Le Goater #define ECCB_STAT_OP_ERR PPC_BIT(52) 261a3980bf5SBenjamin Herrenschmidt #define ECCB_STAT_RD_DATA_LSH (63 - 37) 262a3980bf5SBenjamin Herrenschmidt #define ECCB_STAT_RD_DATA_MASK (0xffffffff << ECCB_STAT_RD_DATA_LSH) 263a3980bf5SBenjamin Herrenschmidt 264a3980bf5SBenjamin Herrenschmidt static void pnv_lpc_do_eccb(PnvLpcController *lpc, uint64_t cmd) 265a3980bf5SBenjamin Herrenschmidt { 266a3980bf5SBenjamin Herrenschmidt /* XXX Check for magic bits at the top, addr size etc... */ 267a3980bf5SBenjamin Herrenschmidt unsigned int sz = (cmd & ECCB_CTL_SZ_MASK) >> ECCB_CTL_SZ_LSH; 268a3980bf5SBenjamin Herrenschmidt uint32_t opb_addr = cmd & ECCB_CTL_ADDR_MASK; 269d07945e7SPrasad J Pandit uint8_t data[8]; 270a3980bf5SBenjamin Herrenschmidt bool success; 271a3980bf5SBenjamin Herrenschmidt 272d07945e7SPrasad J Pandit if (sz > sizeof(data)) { 273d07945e7SPrasad J Pandit qemu_log_mask(LOG_GUEST_ERROR, 274d07945e7SPrasad J Pandit "ECCB: invalid operation at @0x%08x size %d\n", opb_addr, sz); 275d07945e7SPrasad J Pandit return; 276d07945e7SPrasad J Pandit } 277d07945e7SPrasad J Pandit 278a3980bf5SBenjamin Herrenschmidt if (cmd & ECCB_CTL_READ) { 279a3980bf5SBenjamin Herrenschmidt success = opb_read(lpc, opb_addr, data, sz); 280a3980bf5SBenjamin Herrenschmidt if (success) { 281a3980bf5SBenjamin Herrenschmidt lpc->eccb_stat_reg = ECCB_STAT_OP_DONE | 282a3980bf5SBenjamin Herrenschmidt (((uint64_t)data[0]) << 24 | 283a3980bf5SBenjamin Herrenschmidt ((uint64_t)data[1]) << 16 | 284a3980bf5SBenjamin Herrenschmidt ((uint64_t)data[2]) << 8 | 285a3980bf5SBenjamin Herrenschmidt ((uint64_t)data[3])) << ECCB_STAT_RD_DATA_LSH; 286a3980bf5SBenjamin Herrenschmidt } else { 287a3980bf5SBenjamin Herrenschmidt lpc->eccb_stat_reg = ECCB_STAT_OP_DONE | 288a3980bf5SBenjamin Herrenschmidt (0xffffffffull << ECCB_STAT_RD_DATA_LSH); 289a3980bf5SBenjamin Herrenschmidt } 290a3980bf5SBenjamin Herrenschmidt } else { 291a3980bf5SBenjamin Herrenschmidt data[0] = lpc->eccb_data_reg >> 24; 292a3980bf5SBenjamin Herrenschmidt data[1] = lpc->eccb_data_reg >> 16; 293a3980bf5SBenjamin Herrenschmidt data[2] = lpc->eccb_data_reg >> 8; 294a3980bf5SBenjamin Herrenschmidt data[3] = lpc->eccb_data_reg; 295a3980bf5SBenjamin Herrenschmidt 296a3980bf5SBenjamin Herrenschmidt success = opb_write(lpc, opb_addr, data, sz); 297a3980bf5SBenjamin Herrenschmidt lpc->eccb_stat_reg = ECCB_STAT_OP_DONE; 298a3980bf5SBenjamin Herrenschmidt } 299a3980bf5SBenjamin Herrenschmidt /* XXX Which error bit (if any) to signal OPB error ? */ 300a3980bf5SBenjamin Herrenschmidt } 301a3980bf5SBenjamin Herrenschmidt 302a3980bf5SBenjamin Herrenschmidt static uint64_t pnv_lpc_xscom_read(void *opaque, hwaddr addr, unsigned size) 303a3980bf5SBenjamin Herrenschmidt { 304a3980bf5SBenjamin Herrenschmidt PnvLpcController *lpc = PNV_LPC(opaque); 305a3980bf5SBenjamin Herrenschmidt uint32_t offset = addr >> 3; 306a3980bf5SBenjamin Herrenschmidt uint64_t val = 0; 307a3980bf5SBenjamin Herrenschmidt 308a3980bf5SBenjamin Herrenschmidt switch (offset & 3) { 309a3980bf5SBenjamin Herrenschmidt case ECCB_CTL: 310a3980bf5SBenjamin Herrenschmidt case ECCB_RESET: 311a3980bf5SBenjamin Herrenschmidt val = 0; 312a3980bf5SBenjamin Herrenschmidt break; 313a3980bf5SBenjamin Herrenschmidt case ECCB_STAT: 314a3980bf5SBenjamin Herrenschmidt val = lpc->eccb_stat_reg; 315a3980bf5SBenjamin Herrenschmidt lpc->eccb_stat_reg = 0; 316a3980bf5SBenjamin Herrenschmidt break; 317a3980bf5SBenjamin Herrenschmidt case ECCB_DATA: 318a3980bf5SBenjamin Herrenschmidt val = ((uint64_t)lpc->eccb_data_reg) << 32; 319a3980bf5SBenjamin Herrenschmidt break; 320a3980bf5SBenjamin Herrenschmidt } 321a3980bf5SBenjamin Herrenschmidt return val; 322a3980bf5SBenjamin Herrenschmidt } 323a3980bf5SBenjamin Herrenschmidt 324a3980bf5SBenjamin Herrenschmidt static void pnv_lpc_xscom_write(void *opaque, hwaddr addr, 325a3980bf5SBenjamin Herrenschmidt uint64_t val, unsigned size) 326a3980bf5SBenjamin Herrenschmidt { 327a3980bf5SBenjamin Herrenschmidt PnvLpcController *lpc = PNV_LPC(opaque); 328a3980bf5SBenjamin Herrenschmidt uint32_t offset = addr >> 3; 329a3980bf5SBenjamin Herrenschmidt 330a3980bf5SBenjamin Herrenschmidt switch (offset & 3) { 331a3980bf5SBenjamin Herrenschmidt case ECCB_CTL: 332a3980bf5SBenjamin Herrenschmidt pnv_lpc_do_eccb(lpc, val); 333a3980bf5SBenjamin Herrenschmidt break; 334a3980bf5SBenjamin Herrenschmidt case ECCB_RESET: 335a3980bf5SBenjamin Herrenschmidt /* XXXX */ 336a3980bf5SBenjamin Herrenschmidt break; 337a3980bf5SBenjamin Herrenschmidt case ECCB_STAT: 338a3980bf5SBenjamin Herrenschmidt break; 339a3980bf5SBenjamin Herrenschmidt case ECCB_DATA: 340a3980bf5SBenjamin Herrenschmidt lpc->eccb_data_reg = val >> 32; 341a3980bf5SBenjamin Herrenschmidt break; 342a3980bf5SBenjamin Herrenschmidt } 343a3980bf5SBenjamin Herrenschmidt } 344a3980bf5SBenjamin Herrenschmidt 345a3980bf5SBenjamin Herrenschmidt static const MemoryRegionOps pnv_lpc_xscom_ops = { 346a3980bf5SBenjamin Herrenschmidt .read = pnv_lpc_xscom_read, 347a3980bf5SBenjamin Herrenschmidt .write = pnv_lpc_xscom_write, 348a3980bf5SBenjamin Herrenschmidt .valid.min_access_size = 8, 349a3980bf5SBenjamin Herrenschmidt .valid.max_access_size = 8, 350a3980bf5SBenjamin Herrenschmidt .impl.min_access_size = 8, 351a3980bf5SBenjamin Herrenschmidt .impl.max_access_size = 8, 352a3980bf5SBenjamin Herrenschmidt .endianness = DEVICE_BIG_ENDIAN, 353a3980bf5SBenjamin Herrenschmidt }; 354a3980bf5SBenjamin Herrenschmidt 35515376c66SCédric Le Goater static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size) 35615376c66SCédric Le Goater { 35715376c66SCédric Le Goater PnvLpcController *lpc = PNV_LPC(opaque); 35815376c66SCédric Le Goater uint64_t val = 0; 35915376c66SCédric Le Goater uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK; 36015376c66SCédric Le Goater MemTxResult result; 36115376c66SCédric Le Goater 36215376c66SCédric Le Goater switch (size) { 36315376c66SCédric Le Goater case 4: 36415376c66SCédric Le Goater val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED, 36515376c66SCédric Le Goater &result); 36615376c66SCédric Le Goater break; 36715376c66SCédric Le Goater case 1: 36815376c66SCédric Le Goater val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED, 36915376c66SCédric Le Goater &result); 37015376c66SCédric Le Goater break; 37115376c66SCédric Le Goater default: 37215376c66SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%" 37315376c66SCédric Le Goater HWADDR_PRIx " invalid size %d\n", addr, size); 37415376c66SCédric Le Goater return 0; 37515376c66SCédric Le Goater } 37615376c66SCédric Le Goater 37715376c66SCédric Le Goater if (result != MEMTX_OK) { 37815376c66SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%" 37915376c66SCédric Le Goater HWADDR_PRIx "\n", addr); 38015376c66SCédric Le Goater } 38115376c66SCédric Le Goater 38215376c66SCédric Le Goater return val; 38315376c66SCédric Le Goater } 38415376c66SCédric Le Goater 38515376c66SCédric Le Goater static void pnv_lpc_mmio_write(void *opaque, hwaddr addr, 38615376c66SCédric Le Goater uint64_t val, unsigned size) 38715376c66SCédric Le Goater { 38815376c66SCédric Le Goater PnvLpcController *lpc = PNV_LPC(opaque); 38915376c66SCédric Le Goater uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK; 39015376c66SCédric Le Goater MemTxResult result; 39115376c66SCédric Le Goater 39215376c66SCédric Le Goater switch (size) { 39315376c66SCédric Le Goater case 4: 39415376c66SCédric Le Goater address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED, 39515376c66SCédric Le Goater &result); 39615376c66SCédric Le Goater break; 39715376c66SCédric Le Goater case 1: 39815376c66SCédric Le Goater address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED, 39915376c66SCédric Le Goater &result); 40015376c66SCédric Le Goater break; 40115376c66SCédric Le Goater default: 40215376c66SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%" 40315376c66SCédric Le Goater HWADDR_PRIx " invalid size %d\n", addr, size); 40415376c66SCédric Le Goater return; 40515376c66SCédric Le Goater } 40615376c66SCédric Le Goater 40715376c66SCédric Le Goater if (result != MEMTX_OK) { 40815376c66SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%" 40915376c66SCédric Le Goater HWADDR_PRIx "\n", addr); 41015376c66SCédric Le Goater } 41115376c66SCédric Le Goater } 41215376c66SCédric Le Goater 41315376c66SCédric Le Goater static const MemoryRegionOps pnv_lpc_mmio_ops = { 41415376c66SCédric Le Goater .read = pnv_lpc_mmio_read, 41515376c66SCédric Le Goater .write = pnv_lpc_mmio_write, 41615376c66SCédric Le Goater .impl = { 41715376c66SCédric Le Goater .min_access_size = 1, 41815376c66SCédric Le Goater .max_access_size = 4, 41915376c66SCédric Le Goater }, 42015376c66SCédric Le Goater .endianness = DEVICE_BIG_ENDIAN, 42115376c66SCédric Le Goater }; 42215376c66SCédric Le Goater 4234d1df88bSBenjamin Herrenschmidt static void pnv_lpc_eval_irqs(PnvLpcController *lpc) 4244d1df88bSBenjamin Herrenschmidt { 4254d1df88bSBenjamin Herrenschmidt bool lpc_to_opb_irq = false; 4264d1df88bSBenjamin Herrenschmidt 4274d1df88bSBenjamin Herrenschmidt /* Update LPC controller to OPB line */ 4284d1df88bSBenjamin Herrenschmidt if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) { 4294d1df88bSBenjamin Herrenschmidt uint32_t irqs; 4304d1df88bSBenjamin Herrenschmidt 4314d1df88bSBenjamin Herrenschmidt irqs = lpc->lpc_hc_irqstat & lpc->lpc_hc_irqmask; 4324d1df88bSBenjamin Herrenschmidt lpc_to_opb_irq = (irqs != 0); 4334d1df88bSBenjamin Herrenschmidt } 4344d1df88bSBenjamin Herrenschmidt 4354d1df88bSBenjamin Herrenschmidt /* We don't honor the polarity register, it's pointless and unused 4364d1df88bSBenjamin Herrenschmidt * anyway 4374d1df88bSBenjamin Herrenschmidt */ 4384d1df88bSBenjamin Herrenschmidt if (lpc_to_opb_irq) { 4394d1df88bSBenjamin Herrenschmidt lpc->opb_irq_input |= OPB_MASTER_IRQ_LPC; 4404d1df88bSBenjamin Herrenschmidt } else { 4414d1df88bSBenjamin Herrenschmidt lpc->opb_irq_input &= ~OPB_MASTER_IRQ_LPC; 4424d1df88bSBenjamin Herrenschmidt } 4434d1df88bSBenjamin Herrenschmidt 4444d1df88bSBenjamin Herrenschmidt /* Update OPB internal latch */ 4454d1df88bSBenjamin Herrenschmidt lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask; 4464d1df88bSBenjamin Herrenschmidt 4474d1df88bSBenjamin Herrenschmidt /* Reflect the interrupt */ 448c05aa140SCédric Le Goater qemu_set_irq(lpc->psi_irq, lpc->opb_irq_stat != 0); 4494d1df88bSBenjamin Herrenschmidt } 4504d1df88bSBenjamin Herrenschmidt 451a3980bf5SBenjamin Herrenschmidt static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size) 452a3980bf5SBenjamin Herrenschmidt { 453a3980bf5SBenjamin Herrenschmidt PnvLpcController *lpc = opaque; 454a3980bf5SBenjamin Herrenschmidt uint64_t val = 0xfffffffffffffffful; 455a3980bf5SBenjamin Herrenschmidt 456a3980bf5SBenjamin Herrenschmidt switch (addr) { 457a3980bf5SBenjamin Herrenschmidt case LPC_HC_FW_SEG_IDSEL: 458a3980bf5SBenjamin Herrenschmidt val = lpc->lpc_hc_fw_seg_idsel; 459a3980bf5SBenjamin Herrenschmidt break; 460a3980bf5SBenjamin Herrenschmidt case LPC_HC_FW_RD_ACC_SIZE: 461a3980bf5SBenjamin Herrenschmidt val = lpc->lpc_hc_fw_rd_acc_size; 462a3980bf5SBenjamin Herrenschmidt break; 463a3980bf5SBenjamin Herrenschmidt case LPC_HC_IRQSER_CTRL: 464a3980bf5SBenjamin Herrenschmidt val = lpc->lpc_hc_irqser_ctrl; 465a3980bf5SBenjamin Herrenschmidt break; 466a3980bf5SBenjamin Herrenschmidt case LPC_HC_IRQMASK: 467a3980bf5SBenjamin Herrenschmidt val = lpc->lpc_hc_irqmask; 468a3980bf5SBenjamin Herrenschmidt break; 469a3980bf5SBenjamin Herrenschmidt case LPC_HC_IRQSTAT: 470a3980bf5SBenjamin Herrenschmidt val = lpc->lpc_hc_irqstat; 471a3980bf5SBenjamin Herrenschmidt break; 472a3980bf5SBenjamin Herrenschmidt case LPC_HC_ERROR_ADDRESS: 473a3980bf5SBenjamin Herrenschmidt val = lpc->lpc_hc_error_addr; 474a3980bf5SBenjamin Herrenschmidt break; 475a3980bf5SBenjamin Herrenschmidt default: 476cdbaf8cdSCédric Le Goater qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%" 477a3980bf5SBenjamin Herrenschmidt HWADDR_PRIx "\n", addr); 478a3980bf5SBenjamin Herrenschmidt } 479a3980bf5SBenjamin Herrenschmidt return val; 480a3980bf5SBenjamin Herrenschmidt } 481a3980bf5SBenjamin Herrenschmidt 482a3980bf5SBenjamin Herrenschmidt static void lpc_hc_write(void *opaque, hwaddr addr, uint64_t val, 483a3980bf5SBenjamin Herrenschmidt unsigned size) 484a3980bf5SBenjamin Herrenschmidt { 485a3980bf5SBenjamin Herrenschmidt PnvLpcController *lpc = opaque; 486a3980bf5SBenjamin Herrenschmidt 487a3980bf5SBenjamin Herrenschmidt /* XXX Filter out reserved bits */ 488a3980bf5SBenjamin Herrenschmidt 489a3980bf5SBenjamin Herrenschmidt switch (addr) { 490a3980bf5SBenjamin Herrenschmidt case LPC_HC_FW_SEG_IDSEL: 491a3980bf5SBenjamin Herrenschmidt /* XXX Actually figure out how that works as this impact 492a3980bf5SBenjamin Herrenschmidt * memory regions/aliases 493a3980bf5SBenjamin Herrenschmidt */ 494a3980bf5SBenjamin Herrenschmidt lpc->lpc_hc_fw_seg_idsel = val; 495a3980bf5SBenjamin Herrenschmidt break; 496a3980bf5SBenjamin Herrenschmidt case LPC_HC_FW_RD_ACC_SIZE: 497a3980bf5SBenjamin Herrenschmidt lpc->lpc_hc_fw_rd_acc_size = val; 498a3980bf5SBenjamin Herrenschmidt break; 499a3980bf5SBenjamin Herrenschmidt case LPC_HC_IRQSER_CTRL: 500a3980bf5SBenjamin Herrenschmidt lpc->lpc_hc_irqser_ctrl = val; 5014d1df88bSBenjamin Herrenschmidt pnv_lpc_eval_irqs(lpc); 502a3980bf5SBenjamin Herrenschmidt break; 503a3980bf5SBenjamin Herrenschmidt case LPC_HC_IRQMASK: 504a3980bf5SBenjamin Herrenschmidt lpc->lpc_hc_irqmask = val; 5054d1df88bSBenjamin Herrenschmidt pnv_lpc_eval_irqs(lpc); 506a3980bf5SBenjamin Herrenschmidt break; 507a3980bf5SBenjamin Herrenschmidt case LPC_HC_IRQSTAT: 508a3980bf5SBenjamin Herrenschmidt lpc->lpc_hc_irqstat &= ~val; 5094d1df88bSBenjamin Herrenschmidt pnv_lpc_eval_irqs(lpc); 510a3980bf5SBenjamin Herrenschmidt break; 511a3980bf5SBenjamin Herrenschmidt case LPC_HC_ERROR_ADDRESS: 512a3980bf5SBenjamin Herrenschmidt break; 513a3980bf5SBenjamin Herrenschmidt default: 514cdbaf8cdSCédric Le Goater qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%" 515a3980bf5SBenjamin Herrenschmidt HWADDR_PRIx "\n", addr); 516a3980bf5SBenjamin Herrenschmidt } 517a3980bf5SBenjamin Herrenschmidt } 518a3980bf5SBenjamin Herrenschmidt 519a3980bf5SBenjamin Herrenschmidt static const MemoryRegionOps lpc_hc_ops = { 520a3980bf5SBenjamin Herrenschmidt .read = lpc_hc_read, 521a3980bf5SBenjamin Herrenschmidt .write = lpc_hc_write, 522a3980bf5SBenjamin Herrenschmidt .endianness = DEVICE_BIG_ENDIAN, 523a3980bf5SBenjamin Herrenschmidt .valid = { 524a3980bf5SBenjamin Herrenschmidt .min_access_size = 4, 525a3980bf5SBenjamin Herrenschmidt .max_access_size = 4, 526a3980bf5SBenjamin Herrenschmidt }, 527a3980bf5SBenjamin Herrenschmidt .impl = { 528a3980bf5SBenjamin Herrenschmidt .min_access_size = 4, 529a3980bf5SBenjamin Herrenschmidt .max_access_size = 4, 530a3980bf5SBenjamin Herrenschmidt }, 531a3980bf5SBenjamin Herrenschmidt }; 532a3980bf5SBenjamin Herrenschmidt 533a3980bf5SBenjamin Herrenschmidt static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size) 534a3980bf5SBenjamin Herrenschmidt { 535a3980bf5SBenjamin Herrenschmidt PnvLpcController *lpc = opaque; 536a3980bf5SBenjamin Herrenschmidt uint64_t val = 0xfffffffffffffffful; 537a3980bf5SBenjamin Herrenschmidt 538a3980bf5SBenjamin Herrenschmidt switch (addr) { 5398207b906SCédric Le Goater case OPB_MASTER_LS_ROUTE0: /* TODO */ 5408207b906SCédric Le Goater val = lpc->opb_irq_route0; 5418207b906SCédric Le Goater break; 5428207b906SCédric Le Goater case OPB_MASTER_LS_ROUTE1: /* TODO */ 5438207b906SCédric Le Goater val = lpc->opb_irq_route1; 5448207b906SCédric Le Goater break; 545a3980bf5SBenjamin Herrenschmidt case OPB_MASTER_LS_IRQ_STAT: 546a3980bf5SBenjamin Herrenschmidt val = lpc->opb_irq_stat; 547a3980bf5SBenjamin Herrenschmidt break; 548a3980bf5SBenjamin Herrenschmidt case OPB_MASTER_LS_IRQ_MASK: 549a3980bf5SBenjamin Herrenschmidt val = lpc->opb_irq_mask; 550a3980bf5SBenjamin Herrenschmidt break; 551a3980bf5SBenjamin Herrenschmidt case OPB_MASTER_LS_IRQ_POL: 552a3980bf5SBenjamin Herrenschmidt val = lpc->opb_irq_pol; 553a3980bf5SBenjamin Herrenschmidt break; 554a3980bf5SBenjamin Herrenschmidt case OPB_MASTER_LS_IRQ_INPUT: 555a3980bf5SBenjamin Herrenschmidt val = lpc->opb_irq_input; 556a3980bf5SBenjamin Herrenschmidt break; 557a3980bf5SBenjamin Herrenschmidt default: 558cdbaf8cdSCédric Le Goater qemu_log_mask(LOG_UNIMP, "OPBM: read on unimplemented register: 0x%" 559a3980bf5SBenjamin Herrenschmidt HWADDR_PRIx "\n", addr); 560a3980bf5SBenjamin Herrenschmidt } 561a3980bf5SBenjamin Herrenschmidt 562a3980bf5SBenjamin Herrenschmidt return val; 563a3980bf5SBenjamin Herrenschmidt } 564a3980bf5SBenjamin Herrenschmidt 565a3980bf5SBenjamin Herrenschmidt static void opb_master_write(void *opaque, hwaddr addr, 566a3980bf5SBenjamin Herrenschmidt uint64_t val, unsigned size) 567a3980bf5SBenjamin Herrenschmidt { 568a3980bf5SBenjamin Herrenschmidt PnvLpcController *lpc = opaque; 569a3980bf5SBenjamin Herrenschmidt 570a3980bf5SBenjamin Herrenschmidt switch (addr) { 5718207b906SCédric Le Goater case OPB_MASTER_LS_ROUTE0: /* TODO */ 5728207b906SCédric Le Goater lpc->opb_irq_route0 = val; 5738207b906SCédric Le Goater break; 5748207b906SCédric Le Goater case OPB_MASTER_LS_ROUTE1: /* TODO */ 5758207b906SCédric Le Goater lpc->opb_irq_route1 = val; 5768207b906SCédric Le Goater break; 577a3980bf5SBenjamin Herrenschmidt case OPB_MASTER_LS_IRQ_STAT: 578a3980bf5SBenjamin Herrenschmidt lpc->opb_irq_stat &= ~val; 5794d1df88bSBenjamin Herrenschmidt pnv_lpc_eval_irqs(lpc); 580a3980bf5SBenjamin Herrenschmidt break; 581a3980bf5SBenjamin Herrenschmidt case OPB_MASTER_LS_IRQ_MASK: 582a3980bf5SBenjamin Herrenschmidt lpc->opb_irq_mask = val; 5834d1df88bSBenjamin Herrenschmidt pnv_lpc_eval_irqs(lpc); 584a3980bf5SBenjamin Herrenschmidt break; 585a3980bf5SBenjamin Herrenschmidt case OPB_MASTER_LS_IRQ_POL: 586a3980bf5SBenjamin Herrenschmidt lpc->opb_irq_pol = val; 5874d1df88bSBenjamin Herrenschmidt pnv_lpc_eval_irqs(lpc); 588a3980bf5SBenjamin Herrenschmidt break; 589a3980bf5SBenjamin Herrenschmidt case OPB_MASTER_LS_IRQ_INPUT: 590a3980bf5SBenjamin Herrenschmidt /* Read only */ 591a3980bf5SBenjamin Herrenschmidt break; 592a3980bf5SBenjamin Herrenschmidt default: 593cdbaf8cdSCédric Le Goater qemu_log_mask(LOG_UNIMP, "OPBM: write on unimplemented register: 0x%" 594cdbaf8cdSCédric Le Goater HWADDR_PRIx " val=0x%08"PRIx64"\n", addr, val); 595a3980bf5SBenjamin Herrenschmidt } 596a3980bf5SBenjamin Herrenschmidt } 597a3980bf5SBenjamin Herrenschmidt 598a3980bf5SBenjamin Herrenschmidt static const MemoryRegionOps opb_master_ops = { 599a3980bf5SBenjamin Herrenschmidt .read = opb_master_read, 600a3980bf5SBenjamin Herrenschmidt .write = opb_master_write, 601a3980bf5SBenjamin Herrenschmidt .endianness = DEVICE_BIG_ENDIAN, 602a3980bf5SBenjamin Herrenschmidt .valid = { 603a3980bf5SBenjamin Herrenschmidt .min_access_size = 4, 604a3980bf5SBenjamin Herrenschmidt .max_access_size = 4, 605a3980bf5SBenjamin Herrenschmidt }, 606a3980bf5SBenjamin Herrenschmidt .impl = { 607a3980bf5SBenjamin Herrenschmidt .min_access_size = 4, 608a3980bf5SBenjamin Herrenschmidt .max_access_size = 4, 609a3980bf5SBenjamin Herrenschmidt }, 610a3980bf5SBenjamin Herrenschmidt }; 611a3980bf5SBenjamin Herrenschmidt 61282514be2SCédric Le Goater static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp) 61382514be2SCédric Le Goater { 61482514be2SCédric Le Goater PnvLpcController *lpc = PNV_LPC(dev); 61582514be2SCédric Le Goater PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev); 61682514be2SCédric Le Goater Error *local_err = NULL; 61782514be2SCédric Le Goater 61882514be2SCédric Le Goater plc->parent_realize(dev, &local_err); 61982514be2SCédric Le Goater if (local_err) { 62082514be2SCédric Le Goater error_propagate(errp, local_err); 62182514be2SCédric Le Goater return; 62282514be2SCédric Le Goater } 62382514be2SCédric Le Goater 62482514be2SCédric Le Goater /* P8 uses a XSCOM region for LPC registers */ 62582514be2SCédric Le Goater pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(lpc), 62682514be2SCédric Le Goater &pnv_lpc_xscom_ops, lpc, "xscom-lpc", 62782514be2SCédric Le Goater PNV_XSCOM_LPC_SIZE); 62882514be2SCédric Le Goater } 62982514be2SCédric Le Goater 63082514be2SCédric Le Goater static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data) 63182514be2SCédric Le Goater { 63282514be2SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 63382514be2SCédric Le Goater PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); 63482514be2SCédric Le Goater PnvLpcClass *plc = PNV_LPC_CLASS(klass); 63582514be2SCédric Le Goater 63682514be2SCédric Le Goater dc->desc = "PowerNV LPC Controller POWER8"; 63782514be2SCédric Le Goater 63882514be2SCédric Le Goater xdc->dt_xscom = pnv_lpc_dt_xscom; 63982514be2SCédric Le Goater 64082514be2SCédric Le Goater device_class_set_parent_realize(dc, pnv_lpc_power8_realize, 64182514be2SCédric Le Goater &plc->parent_realize); 64282514be2SCédric Le Goater } 64382514be2SCédric Le Goater 64482514be2SCédric Le Goater static const TypeInfo pnv_lpc_power8_info = { 64582514be2SCédric Le Goater .name = TYPE_PNV8_LPC, 64682514be2SCédric Le Goater .parent = TYPE_PNV_LPC, 64782514be2SCédric Le Goater .class_init = pnv_lpc_power8_class_init, 64882514be2SCédric Le Goater .interfaces = (InterfaceInfo[]) { 64982514be2SCédric Le Goater { TYPE_PNV_XSCOM_INTERFACE }, 65082514be2SCédric Le Goater { } 65182514be2SCédric Le Goater } 65282514be2SCédric Le Goater }; 65382514be2SCédric Le Goater 65415376c66SCédric Le Goater static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp) 65515376c66SCédric Le Goater { 65615376c66SCédric Le Goater PnvLpcController *lpc = PNV_LPC(dev); 65715376c66SCédric Le Goater PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev); 65815376c66SCédric Le Goater Error *local_err = NULL; 65915376c66SCédric Le Goater 66015376c66SCédric Le Goater plc->parent_realize(dev, &local_err); 66115376c66SCédric Le Goater if (local_err) { 66215376c66SCédric Le Goater error_propagate(errp, local_err); 66315376c66SCédric Le Goater return; 66415376c66SCédric Le Goater } 66515376c66SCédric Le Goater 66615376c66SCédric Le Goater /* P9 uses a MMIO region */ 66715376c66SCédric Le Goater memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops, 66815376c66SCédric Le Goater lpc, "lpcm", PNV9_LPCM_SIZE); 66915376c66SCédric Le Goater } 67015376c66SCédric Le Goater 67115376c66SCédric Le Goater static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data) 67215376c66SCédric Le Goater { 67315376c66SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 67415376c66SCédric Le Goater PnvLpcClass *plc = PNV_LPC_CLASS(klass); 67515376c66SCédric Le Goater 67615376c66SCédric Le Goater dc->desc = "PowerNV LPC Controller POWER9"; 67715376c66SCédric Le Goater 67815376c66SCédric Le Goater device_class_set_parent_realize(dc, pnv_lpc_power9_realize, 67915376c66SCédric Le Goater &plc->parent_realize); 68015376c66SCédric Le Goater } 68115376c66SCédric Le Goater 68215376c66SCédric Le Goater static const TypeInfo pnv_lpc_power9_info = { 68315376c66SCédric Le Goater .name = TYPE_PNV9_LPC, 68415376c66SCédric Le Goater .parent = TYPE_PNV_LPC, 68515376c66SCédric Le Goater .class_init = pnv_lpc_power9_class_init, 68615376c66SCédric Le Goater }; 68715376c66SCédric Le Goater 6882661f6abSCédric Le Goater static void pnv_lpc_power10_class_init(ObjectClass *klass, void *data) 6892661f6abSCédric Le Goater { 6902661f6abSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 6912661f6abSCédric Le Goater 6922661f6abSCédric Le Goater dc->desc = "PowerNV LPC Controller POWER10"; 6932661f6abSCédric Le Goater } 6942661f6abSCédric Le Goater 6952661f6abSCédric Le Goater static const TypeInfo pnv_lpc_power10_info = { 6962661f6abSCédric Le Goater .name = TYPE_PNV10_LPC, 6972661f6abSCédric Le Goater .parent = TYPE_PNV9_LPC, 6982661f6abSCédric Le Goater .class_init = pnv_lpc_power10_class_init, 6992661f6abSCédric Le Goater }; 7002661f6abSCédric Le Goater 701a3980bf5SBenjamin Herrenschmidt static void pnv_lpc_realize(DeviceState *dev, Error **errp) 702a3980bf5SBenjamin Herrenschmidt { 703a3980bf5SBenjamin Herrenschmidt PnvLpcController *lpc = PNV_LPC(dev); 70482514be2SCédric Le Goater 705a3980bf5SBenjamin Herrenschmidt /* Reg inits */ 706a3980bf5SBenjamin Herrenschmidt lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B; 707a3980bf5SBenjamin Herrenschmidt 708a3980bf5SBenjamin Herrenschmidt /* Create address space and backing MR for the OPB bus */ 709a3980bf5SBenjamin Herrenschmidt memory_region_init(&lpc->opb_mr, OBJECT(dev), "lpc-opb", 0x100000000ull); 710a3980bf5SBenjamin Herrenschmidt address_space_init(&lpc->opb_as, &lpc->opb_mr, "lpc-opb"); 711a3980bf5SBenjamin Herrenschmidt 712a3980bf5SBenjamin Herrenschmidt /* Create ISA IO and Mem space regions which are the root of 713a3980bf5SBenjamin Herrenschmidt * the ISA bus (ie, ISA address spaces). We don't create a 714a3980bf5SBenjamin Herrenschmidt * separate one for FW which we alias to memory. 715a3980bf5SBenjamin Herrenschmidt */ 716a3980bf5SBenjamin Herrenschmidt memory_region_init(&lpc->isa_io, OBJECT(dev), "isa-io", ISA_IO_SIZE); 717a3980bf5SBenjamin Herrenschmidt memory_region_init(&lpc->isa_mem, OBJECT(dev), "isa-mem", ISA_MEM_SIZE); 718d61c2857SCédric Le Goater memory_region_init(&lpc->isa_fw, OBJECT(dev), "isa-fw", ISA_FW_SIZE); 719a3980bf5SBenjamin Herrenschmidt 720a3980bf5SBenjamin Herrenschmidt /* Create windows from the OPB space to the ISA space */ 721a3980bf5SBenjamin Herrenschmidt memory_region_init_alias(&lpc->opb_isa_io, OBJECT(dev), "lpc-isa-io", 722a3980bf5SBenjamin Herrenschmidt &lpc->isa_io, 0, LPC_IO_OPB_SIZE); 723a3980bf5SBenjamin Herrenschmidt memory_region_add_subregion(&lpc->opb_mr, LPC_IO_OPB_ADDR, 724a3980bf5SBenjamin Herrenschmidt &lpc->opb_isa_io); 725a3980bf5SBenjamin Herrenschmidt memory_region_init_alias(&lpc->opb_isa_mem, OBJECT(dev), "lpc-isa-mem", 726a3980bf5SBenjamin Herrenschmidt &lpc->isa_mem, 0, LPC_MEM_OPB_SIZE); 727a3980bf5SBenjamin Herrenschmidt memory_region_add_subregion(&lpc->opb_mr, LPC_MEM_OPB_ADDR, 728a3980bf5SBenjamin Herrenschmidt &lpc->opb_isa_mem); 729a3980bf5SBenjamin Herrenschmidt memory_region_init_alias(&lpc->opb_isa_fw, OBJECT(dev), "lpc-isa-fw", 730d61c2857SCédric Le Goater &lpc->isa_fw, 0, LPC_FW_OPB_SIZE); 731a3980bf5SBenjamin Herrenschmidt memory_region_add_subregion(&lpc->opb_mr, LPC_FW_OPB_ADDR, 732a3980bf5SBenjamin Herrenschmidt &lpc->opb_isa_fw); 733a3980bf5SBenjamin Herrenschmidt 734a3980bf5SBenjamin Herrenschmidt /* Create MMIO regions for LPC HC and OPB registers */ 735a3980bf5SBenjamin Herrenschmidt memory_region_init_io(&lpc->opb_master_regs, OBJECT(dev), &opb_master_ops, 736a3980bf5SBenjamin Herrenschmidt lpc, "lpc-opb-master", LPC_OPB_REGS_OPB_SIZE); 737*76f9ebffSAlexander Bulekov lpc->opb_master_regs.disable_reentrancy_guard = true; 738a3980bf5SBenjamin Herrenschmidt memory_region_add_subregion(&lpc->opb_mr, LPC_OPB_REGS_OPB_ADDR, 739a3980bf5SBenjamin Herrenschmidt &lpc->opb_master_regs); 740a3980bf5SBenjamin Herrenschmidt memory_region_init_io(&lpc->lpc_hc_regs, OBJECT(dev), &lpc_hc_ops, lpc, 741a3980bf5SBenjamin Herrenschmidt "lpc-hc", LPC_HC_REGS_OPB_SIZE); 742*76f9ebffSAlexander Bulekov /* xscom writes to lpc-hc. As such mark lpc-hc re-entrancy safe */ 743*76f9ebffSAlexander Bulekov lpc->lpc_hc_regs.disable_reentrancy_guard = true; 744a3980bf5SBenjamin Herrenschmidt memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR, 745a3980bf5SBenjamin Herrenschmidt &lpc->lpc_hc_regs); 746a3980bf5SBenjamin Herrenschmidt 747c05aa140SCédric Le Goater qdev_init_gpio_out(DEVICE(dev), &lpc->psi_irq, 1); 748c05aa140SCédric Le Goater } 749b63f3893SGreg Kurz 750a3980bf5SBenjamin Herrenschmidt static void pnv_lpc_class_init(ObjectClass *klass, void *data) 751a3980bf5SBenjamin Herrenschmidt { 752a3980bf5SBenjamin Herrenschmidt DeviceClass *dc = DEVICE_CLASS(klass); 753a3980bf5SBenjamin Herrenschmidt 754a3980bf5SBenjamin Herrenschmidt dc->realize = pnv_lpc_realize; 75582514be2SCédric Le Goater dc->desc = "PowerNV LPC Controller"; 75623a782ebSCédric Le Goater dc->user_creatable = false; 757a3980bf5SBenjamin Herrenschmidt } 758a3980bf5SBenjamin Herrenschmidt 759a3980bf5SBenjamin Herrenschmidt static const TypeInfo pnv_lpc_info = { 760a3980bf5SBenjamin Herrenschmidt .name = TYPE_PNV_LPC, 761a3980bf5SBenjamin Herrenschmidt .parent = TYPE_DEVICE, 762021e878fSCédric Le Goater .instance_size = sizeof(PnvLpcController), 763a3980bf5SBenjamin Herrenschmidt .class_init = pnv_lpc_class_init, 76482514be2SCédric Le Goater .class_size = sizeof(PnvLpcClass), 76582514be2SCédric Le Goater .abstract = true, 766a3980bf5SBenjamin Herrenschmidt }; 767a3980bf5SBenjamin Herrenschmidt 768a3980bf5SBenjamin Herrenschmidt static void pnv_lpc_register_types(void) 769a3980bf5SBenjamin Herrenschmidt { 770a3980bf5SBenjamin Herrenschmidt type_register_static(&pnv_lpc_info); 77182514be2SCédric Le Goater type_register_static(&pnv_lpc_power8_info); 77215376c66SCédric Le Goater type_register_static(&pnv_lpc_power9_info); 7732661f6abSCédric Le Goater type_register_static(&pnv_lpc_power10_info); 774a3980bf5SBenjamin Herrenschmidt } 775a3980bf5SBenjamin Herrenschmidt 776a3980bf5SBenjamin Herrenschmidt type_init(pnv_lpc_register_types) 7774d1df88bSBenjamin Herrenschmidt 7784d1df88bSBenjamin Herrenschmidt /* If we don't use the built-in LPC interrupt deserializer, we need 7794d1df88bSBenjamin Herrenschmidt * to provide a set of qirqs for the ISA bus or things will go bad. 7804d1df88bSBenjamin Herrenschmidt * 7814d1df88bSBenjamin Herrenschmidt * Most machines using pre-Naples chips (without said deserializer) 7824d1df88bSBenjamin Herrenschmidt * have a CPLD that will collect the SerIRQ and shoot them as a 7834d1df88bSBenjamin Herrenschmidt * single level interrupt to the P8 chip. So let's setup a hook 7844d1df88bSBenjamin Herrenschmidt * for doing just that. 7854d1df88bSBenjamin Herrenschmidt */ 7864d1df88bSBenjamin Herrenschmidt static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level) 7874d1df88bSBenjamin Herrenschmidt { 788b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); 7894d1df88bSBenjamin Herrenschmidt uint32_t old_state = pnv->cpld_irqstate; 7904d1df88bSBenjamin Herrenschmidt PnvLpcController *lpc = PNV_LPC(opaque); 7914d1df88bSBenjamin Herrenschmidt 7924d1df88bSBenjamin Herrenschmidt if (level) { 7934d1df88bSBenjamin Herrenschmidt pnv->cpld_irqstate |= 1u << n; 7944d1df88bSBenjamin Herrenschmidt } else { 7954d1df88bSBenjamin Herrenschmidt pnv->cpld_irqstate &= ~(1u << n); 7964d1df88bSBenjamin Herrenschmidt } 7974d1df88bSBenjamin Herrenschmidt 7984d1df88bSBenjamin Herrenschmidt if (pnv->cpld_irqstate != old_state) { 799c05aa140SCédric Le Goater qemu_set_irq(lpc->psi_irq, pnv->cpld_irqstate != 0); 8004d1df88bSBenjamin Herrenschmidt } 8014d1df88bSBenjamin Herrenschmidt } 8024d1df88bSBenjamin Herrenschmidt 8034d1df88bSBenjamin Herrenschmidt static void pnv_lpc_isa_irq_handler(void *opaque, int n, int level) 8044d1df88bSBenjamin Herrenschmidt { 8054d1df88bSBenjamin Herrenschmidt PnvLpcController *lpc = PNV_LPC(opaque); 8064d1df88bSBenjamin Herrenschmidt 8074d1df88bSBenjamin Herrenschmidt /* The Naples HW latches the 1 levels, clearing is done by SW */ 8084d1df88bSBenjamin Herrenschmidt if (level) { 8094d1df88bSBenjamin Herrenschmidt lpc->lpc_hc_irqstat |= LPC_HC_IRQ_SERIRQ0 >> n; 8104d1df88bSBenjamin Herrenschmidt pnv_lpc_eval_irqs(lpc); 8114d1df88bSBenjamin Herrenschmidt } 8124d1df88bSBenjamin Herrenschmidt } 8134d1df88bSBenjamin Herrenschmidt 81404026890SCédric Le Goater ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp) 8154d1df88bSBenjamin Herrenschmidt { 81604026890SCédric Le Goater Error *local_err = NULL; 81704026890SCédric Le Goater ISABus *isa_bus; 81804026890SCédric Le Goater qemu_irq *irqs; 81904026890SCédric Le Goater qemu_irq_handler handler; 82004026890SCédric Le Goater 82104026890SCédric Le Goater /* let isa_bus_new() create its own bridge on SysBus otherwise 822f42274cfSPhilippe Mathieu-Daudé * devices specified on the command line won't find the bus and 82304026890SCédric Le Goater * will fail to create. 82404026890SCédric Le Goater */ 82504026890SCédric Le Goater isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io, &local_err); 82604026890SCédric Le Goater if (local_err) { 82704026890SCédric Le Goater error_propagate(errp, local_err); 82804026890SCédric Le Goater return NULL; 82904026890SCédric Le Goater } 83004026890SCédric Le Goater 8314d1df88bSBenjamin Herrenschmidt /* Not all variants have a working serial irq decoder. If not, 8324d1df88bSBenjamin Herrenschmidt * handling of LPC interrupts becomes a platform issue (some 8334d1df88bSBenjamin Herrenschmidt * platforms have a CPLD to do it). 8344d1df88bSBenjamin Herrenschmidt */ 83504026890SCédric Le Goater if (use_cpld) { 83604026890SCédric Le Goater handler = pnv_lpc_isa_irq_handler_cpld; 8374d1df88bSBenjamin Herrenschmidt } else { 83804026890SCédric Le Goater handler = pnv_lpc_isa_irq_handler; 8394d1df88bSBenjamin Herrenschmidt } 84004026890SCédric Le Goater 84104026890SCédric Le Goater irqs = qemu_allocate_irqs(handler, lpc, ISA_NUM_IRQS); 84204026890SCédric Le Goater 8437067887eSPhilippe Mathieu-Daudé isa_bus_register_input_irqs(isa_bus, irqs); 844ca661faeSCédric Le Goater 84504026890SCédric Le Goater return isa_bus; 8464d1df88bSBenjamin Herrenschmidt } 847