On Thu, Sep 15, 2016 at 02:45:59PM +0200, Cédric Le Goater wrote: > From: Benjamin Herrenschmidt <b...@kernel.crashing.org> > > This version of the LPC controller model doesn't yet implement > support for the SerIRQ deserializer present in the Naples version > of the chip though some preliminary work is there. > > Signed-off-by: Benjamin Herrenschmidt <b...@kernel.crashing.org> > [clg: - updated for qemu-2.7 > - ported on latest PowerNV patchset (v3) > - changed the XSCOM interface to fit new model > - qomified the model > - moved the ISA hunks in another patch > - removed printf logging > - added a couple of UNIMP logging ] > Signed-off-by: Cédric Le Goater <c...@kaod.org> > --- > hw/ppc/Makefile.objs | 2 +- > hw/ppc/pnv.c | 15 ++ > hw/ppc/pnv_lpc.c | 455 > +++++++++++++++++++++++++++++++++++++++++++++ > include/hw/ppc/pnv.h | 3 + > include/hw/ppc/pnv_lpc.h | 63 +++++++ > include/hw/ppc/pnv_xscom.h | 3 + > 6 files changed, 540 insertions(+), 1 deletion(-) > create mode 100644 hw/ppc/pnv_lpc.c > create mode 100644 include/hw/ppc/pnv_lpc.h > > diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs > index 08c213c40684..ebc72af0a7c6 100644 > --- a/hw/ppc/Makefile.objs > +++ b/hw/ppc/Makefile.objs > @@ -6,7 +6,7 @@ obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o > spapr_rtas.o > obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o > obj-$(CONFIG_PSERIES) += spapr_cpu_core.o > # IBM PowerNV > -obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o > +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o > ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) > obj-y += spapr_pci_vfio.o > endif > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c > index 6a3d1fbf8403..1aa7b8ee8903 100644 > --- a/hw/ppc/pnv.c > +++ b/hw/ppc/pnv.c > @@ -569,6 +569,14 @@ static void pnv_chip_init(Object *obj) > object_property_add_child(obj, "xscom", OBJECT(&chip->xscom), NULL); > object_property_add_const_link(OBJECT(&chip->xscom), "chip", > OBJECT(chip), &error_abort); > + > + /* > + * Add the lpc controller as an XScom child as we need to populate > + * the device tree for the isa bus. > + */ > + object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC); > + object_property_add_child(OBJECT(&chip->xscom), "lpc", > + OBJECT(&chip->lpc), NULL); > } > > static void pnv_chip_realize(DeviceState *dev, Error **errp) > @@ -626,6 +634,13 @@ static void pnv_chip_realize(DeviceState *dev, Error > **errp) > } > g_free(typename); > > + /* Create LPC controller */ > + object_property_set_bool(OBJECT(&chip->lpc), true, "realized", > + &error_fatal); > + memory_region_add_subregion(&chip->xscom.xscom_mr, > + pcc->xscom_addr(PNV_XSCOM_LPC_BASE), > + &chip->lpc.xscom_regs);
Again, I think the memory region construction should be in the actual LPC device's realize(). > + > if (pcc->realize) { > pcc->realize(chip, errp); > } > diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c > new file mode 100644 > index 000000000000..de4bab0ca085 > --- /dev/null > +++ b/hw/ppc/pnv_lpc.c > @@ -0,0 +1,455 @@ > +/* > + * QEMU PowerPC PowerNV LPC controller > + * > + * Copyright (c) 2016, IBM Corporation. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > <http://www.gnu.org/licenses/>. > + */ > + > +#include "qemu/osdep.h" > +#include "sysemu/sysemu.h" > +#include "target-ppc/cpu.h" > +#include "qapi/error.h" > +#include "qemu/log.h" > + > +#include "hw/ppc/pnv_lpc.h" > +#include "hw/ppc/pnv.h" > +#include "hw/ppc/fdt.h" > + > +#include <libfdt.h> > + > +enum { > + ECCB_CTL = 0, > + ECCB_RESET = 1, > + ECCB_STAT = 2, > + ECCB_DATA = 3, > +}; > + > +/* OPB Master LS registers */ > +#define OPB_MASTER_LS_IRQ_STAT 0x50 > +#define OPB_MASTER_IRQ_LPC 0x00000800 > +#define OPB_MASTER_LS_IRQ_MASK 0x54 > +#define OPB_MASTER_LS_IRQ_POL 0x58 > +#define OPB_MASTER_LS_IRQ_INPUT 0x5c > + > +/* LPC HC registers */ > +#define LPC_HC_FW_SEG_IDSEL 0x24 > +#define LPC_HC_FW_RD_ACC_SIZE 0x28 > +#define LPC_HC_FW_RD_1B 0x00000000 > +#define LPC_HC_FW_RD_2B 0x01000000 > +#define LPC_HC_FW_RD_4B 0x02000000 > +#define LPC_HC_FW_RD_16B 0x04000000 > +#define LPC_HC_FW_RD_128B 0x07000000 > +#define LPC_HC_IRQSER_CTRL 0x30 > +#define LPC_HC_IRQSER_EN 0x80000000 > +#define LPC_HC_IRQSER_QMODE 0x40000000 > +#define LPC_HC_IRQSER_START_MASK 0x03000000 > +#define LPC_HC_IRQSER_START_4CLK 0x00000000 > +#define LPC_HC_IRQSER_START_6CLK 0x01000000 > +#define LPC_HC_IRQSER_START_8CLK 0x02000000 > +#define LPC_HC_IRQMASK 0x34 /* same bit defs as LPC_HC_IRQSTAT */ > +#define LPC_HC_IRQSTAT 0x38 > +#define LPC_HC_IRQ_SERIRQ0 0x80000000 /* all bits down to ... */ > +#define LPC_HC_IRQ_SERIRQ16 0x00008000 /* IRQ16=IOCHK#, > IRQ2=SMI# */ > +#define LPC_HC_IRQ_SERIRQ_ALL 0xffff8000 > +#define LPC_HC_IRQ_LRESET 0x00000400 > +#define LPC_HC_IRQ_SYNC_ABNORM_ERR 0x00000080 > +#define LPC_HC_IRQ_SYNC_NORESP_ERR 0x00000040 > +#define LPC_HC_IRQ_SYNC_NORM_ERR 0x00000020 > +#define LPC_HC_IRQ_SYNC_TIMEOUT_ERR 0x00000010 > +#define LPC_HC_IRQ_SYNC_TARG_TAR_ERR 0x00000008 > +#define LPC_HC_IRQ_SYNC_BM_TAR_ERR 0x00000004 > +#define LPC_HC_IRQ_SYNC_BM0_REQ 0x00000002 > +#define LPC_HC_IRQ_SYNC_BM1_REQ 0x00000001 > +#define LPC_HC_ERROR_ADDRESS 0x40 > + > +#define ISA_IO_SIZE 0x00010000 > +#define ISA_MEM_SIZE 0x10000000 > +#define LPC_IO_OPB_ADDR 0xd0010000 > +#define LPC_IO_OPB_SIZE 0x00010000 > +#define LPC_MEM_OPB_ADDR 0xe0010000 > +#define LPC_MEM_OPB_SIZE 0x10000000 > +#define LPC_FW_OPB_ADDR 0xf0000000 > +#define LPC_FW_OPB_SIZE 0x10000000 > + > +#define LPC_OPB_REGS_OPB_ADDR 0xc0010000 > +#define LPC_OPB_REGS_OPB_SIZE 0x00002000 > +#define LPC_HC_REGS_OPB_ADDR 0xc0012000 > +#define LPC_HC_REGS_OPB_SIZE 0x00001000 > + > + > +static int pnv_lpc_devnode(PnvXScomInterface *dev, void *fdt, int > xscom_offset) > +{ > + const char compat[] = "ibm,power8-lpc"; > + char *name; > + int offset; > + uint32_t lpc_pcba = PNV_XSCOM_LPC_BASE; > + uint32_t reg[] = { > + cpu_to_be32(lpc_pcba), > + cpu_to_be32(PNV_XSCOM_LPC_SIZE) > + }; > + > + name = g_strdup_printf("isa@%x", lpc_pcba); > + offset = fdt_add_subnode(fdt, xscom_offset, name); > + _FDT(offset); > + g_free(name); > + > + _FDT((fdt_appendprop(fdt, offset, "reg", reg, sizeof(reg)))); Any particular reason for the appendprop instead of setprop? > + _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2))); > + _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1))); > + _FDT((fdt_setprop(fdt, offset, "primary", NULL, 0))); > + _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat)))); > + return 0; > +} > + > +static bool opb_read(PnvLpcController *lpc, uint32_t addr, uint8_t *data, > + int sz) > +{ > + bool success; > + > + /* XXX Handle access size limits and FW read caching here */ Are the access size limits built into the address_space mechanism not sufficient? > + success = !address_space_rw(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED, > + data, sz, false); > + > + return success; > +} > + > +static bool opb_write(PnvLpcController *lpc, uint32_t addr, uint8_t *data, > + int sz) > +{ > + bool success; > + > + /* XXX Handle access size limits here */ > + success = !address_space_rw(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED, > + data, sz, true); > + > + return success; > +} > + > +#define ECCB_CTL_READ (1ull << (63 - 15)) > +#define ECCB_CTL_SZ_LSH (63 - 7) > +#define ECCB_CTL_SZ_MASK (0xfull << ECCB_CTL_SZ_LSH) > +#define ECCB_CTL_ADDR_MASK 0xffffffffu; > + > +#define ECCB_STAT_OP_DONE (1ull << (63 - 52)) > +#define ECCB_STAT_OP_ERR (1ull << (63 - 52)) > +#define ECCB_STAT_RD_DATA_LSH (63 - 37) > +#define ECCB_STAT_RD_DATA_MASK (0xffffffff << ECCB_STAT_RD_DATA_LSH) > + > +static void pnv_lpc_do_eccb(PnvLpcController *lpc, uint64_t cmd) > +{ > + /* XXX Check for magic bits at the top, addr size etc... */ > + unsigned int sz = (cmd & ECCB_CTL_SZ_MASK) >> ECCB_CTL_SZ_LSH; > + uint32_t opb_addr = cmd & ECCB_CTL_ADDR_MASK; > + uint8_t data[4]; > + bool success; > + > + if (cmd & ECCB_CTL_READ) { > + success = opb_read(lpc, opb_addr, data, sz); > + if (success) { > + lpc->eccb_stat_reg = ECCB_STAT_OP_DONE | > + (((uint64_t)data[0]) << 24 | > + ((uint64_t)data[1]) << 16 | > + ((uint64_t)data[2]) << 8 | > + ((uint64_t)data[3])) << ECCB_STAT_RD_DATA_LSH; > + } else { > + lpc->eccb_stat_reg = ECCB_STAT_OP_DONE | > + (0xffffffffull << ECCB_STAT_RD_DATA_LSH); > + } > + } else { > + data[0] = lpc->eccb_data_reg >> 24; > + data[1] = lpc->eccb_data_reg >> 16; > + data[2] = lpc->eccb_data_reg >> 8; > + data[3] = lpc->eccb_data_reg; > + > + success = opb_write(lpc, opb_addr, data, sz); > + lpc->eccb_stat_reg = ECCB_STAT_OP_DONE; > + } > + /* XXX Which error bit (if any) to signal OPB error ? */ > +} > + > +static uint64_t pnv_lpc_xscom_read(void *opaque, hwaddr addr, unsigned size) > +{ > + PnvLpcController *lpc = PNV_LPC(opaque); > + uint32_t offset = pnv_xscom_pcba(opaque, addr); > + uint64_t val = 0; > + > + switch (offset & 3) { > + case ECCB_CTL: > + case ECCB_RESET: > + val = 0; > + break; > + case ECCB_STAT: > + val = lpc->eccb_stat_reg; > + lpc->eccb_stat_reg = 0; > + break; > + case ECCB_DATA: > + val = ((uint64_t)lpc->eccb_data_reg) << 32; > + break; > + } > + return val; > +} > + > +static void pnv_lpc_xscom_write(void *opaque, hwaddr addr, > + uint64_t val, unsigned size) > +{ > + PnvLpcController *lpc = PNV_LPC(opaque); > + uint32_t offset = pnv_xscom_pcba(opaque, addr); > + > + switch (offset & 3) { > + case ECCB_CTL: > + pnv_lpc_do_eccb(lpc, val); > + break; > + case ECCB_RESET: > + /* XXXX */ > + break; > + case ECCB_STAT: > + break; > + case ECCB_DATA: > + lpc->eccb_data_reg = val >> 32; > + break; > + } > +} > + > +static const MemoryRegionOps pnv_lpc_xscom_ops = { > + .read = pnv_lpc_xscom_read, > + .write = pnv_lpc_xscom_write, > + .valid.min_access_size = 8, > + .valid.max_access_size = 8, > + .impl.min_access_size = 8, > + .impl.max_access_size = 8, > + .endianness = DEVICE_BIG_ENDIAN, > +}; > + > +static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size) > +{ > + PnvLpcController *lpc = opaque; > + uint64_t val = 0xfffffffffffffffful; > + > + switch (addr) { > + case LPC_HC_FW_SEG_IDSEL: > + val = lpc->lpc_hc_fw_seg_idsel; > + break; > + case LPC_HC_FW_RD_ACC_SIZE: > + val = lpc->lpc_hc_fw_rd_acc_size; > + break; > + case LPC_HC_IRQSER_CTRL: > + val = lpc->lpc_hc_irqser_ctrl; > + break; > + case LPC_HC_IRQMASK: > + val = lpc->lpc_hc_irqmask; > + break; > + case LPC_HC_IRQSTAT: > + val = lpc->lpc_hc_irqstat; > + break; > + case LPC_HC_ERROR_ADDRESS: > + val = lpc->lpc_hc_error_addr; > + break; > + default: > + qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%" > + HWADDR_PRIx "\n", addr); > + } > + return val; > +} > + > +static void lpc_hc_write(void *opaque, hwaddr addr, uint64_t val, > + unsigned size) > +{ > + PnvLpcController *lpc = opaque; > + > + /* XXX Filter out reserved bits */ > + > + switch (addr) { > + case LPC_HC_FW_SEG_IDSEL: > + /* XXX Actually figure out how that works as this impact > + * memory regions/aliases > + */ > + lpc->lpc_hc_fw_seg_idsel = val; > + break; > + case LPC_HC_FW_RD_ACC_SIZE: > + lpc->lpc_hc_fw_rd_acc_size = val; > + break; > + case LPC_HC_IRQSER_CTRL: > + lpc->lpc_hc_irqser_ctrl = val; > + break; > + case LPC_HC_IRQMASK: > + lpc->lpc_hc_irqmask = val; > + break; > + case LPC_HC_IRQSTAT: > + lpc->lpc_hc_irqstat &= ~val; > + break; > + case LPC_HC_ERROR_ADDRESS: > + break; > + default: > + qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%" > + HWADDR_PRIx "\n", addr); > + } > +} > + > +static const MemoryRegionOps lpc_hc_ops = { > + .read = lpc_hc_read, > + .write = lpc_hc_write, > + .endianness = DEVICE_BIG_ENDIAN, > + .valid = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > + .impl = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > +}; > + > +static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size) > +{ > + PnvLpcController *lpc = opaque; > + uint64_t val = 0xfffffffffffffffful; > + > + switch (addr) { > + case OPB_MASTER_LS_IRQ_STAT: > + val = lpc->opb_irq_stat; > + break; > + case OPB_MASTER_LS_IRQ_MASK: > + val = lpc->opb_irq_mask; > + break; > + case OPB_MASTER_LS_IRQ_POL: > + val = lpc->opb_irq_pol; > + break; > + case OPB_MASTER_LS_IRQ_INPUT: > + val = lpc->opb_irq_input; > + break; > + default: > + qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%" > + HWADDR_PRIx "\n", addr); > + } > + > + return val; > +} > + > +static void opb_master_write(void *opaque, hwaddr addr, > + uint64_t val, unsigned size) > +{ > + PnvLpcController *lpc = opaque; > + > + switch (addr) { > + case OPB_MASTER_LS_IRQ_STAT: > + lpc->opb_irq_stat &= ~val; > + break; > + case OPB_MASTER_LS_IRQ_MASK: > + /* XXX Filter out reserved bits */ > + lpc->opb_irq_mask = val; > + break; > + case OPB_MASTER_LS_IRQ_POL: > + /* XXX Filter out reserved bits */ > + lpc->opb_irq_pol = val; > + break; > + case OPB_MASTER_LS_IRQ_INPUT: > + /* Read only */ > + break; > + default: > + qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%" > + HWADDR_PRIx "\n", addr); > + } > +} > + > +static const MemoryRegionOps opb_master_ops = { > + .read = opb_master_read, > + .write = opb_master_write, > + .endianness = DEVICE_BIG_ENDIAN, > + .valid = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > + .impl = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > +}; > + > +static void pnv_lpc_realize(DeviceState *dev, Error **errp) > +{ > + PnvLpcController *lpc = PNV_LPC(dev); > + > + /* Reg inits */ > + lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B; > + > + /* Create address space and backing MR for the OPB bus */ > + memory_region_init(&lpc->opb_mr, OBJECT(dev), "lpc-opb", 0x100000000ull); > + address_space_init(&lpc->opb_as, &lpc->opb_mr, "lpc-opb"); > + > + /* Create ISA IO and Mem space regions which are the root of > + * the ISA bus (ie, ISA address spaces). We don't create a > + * separate one for FW which we alias to memory. > + */ > + memory_region_init(&lpc->isa_io, OBJECT(dev), "isa-io", ISA_IO_SIZE); > + memory_region_init(&lpc->isa_mem, OBJECT(dev), "isa-mem", ISA_MEM_SIZE); > + > + /* Create windows from the OPB space to the ISA space */ > + memory_region_init_alias(&lpc->opb_isa_io, OBJECT(dev), "lpc-isa-io", > + &lpc->isa_io, 0, LPC_IO_OPB_SIZE); > + memory_region_add_subregion(&lpc->opb_mr, LPC_IO_OPB_ADDR, > + &lpc->opb_isa_io); > + memory_region_init_alias(&lpc->opb_isa_mem, OBJECT(dev), "lpc-isa-mem", > + &lpc->isa_mem, 0, LPC_MEM_OPB_SIZE); > + memory_region_add_subregion(&lpc->opb_mr, LPC_MEM_OPB_ADDR, > + &lpc->opb_isa_mem); > + memory_region_init_alias(&lpc->opb_isa_fw, OBJECT(dev), "lpc-isa-fw", > + &lpc->isa_mem, 0, LPC_FW_OPB_SIZE); > + memory_region_add_subregion(&lpc->opb_mr, LPC_FW_OPB_ADDR, > + &lpc->opb_isa_fw); > + > + /* Create MMIO regions for LPC HC and OPB registers */ > + memory_region_init_io(&lpc->opb_master_regs, OBJECT(dev), > &opb_master_ops, > + lpc, "lpc-opb-master", LPC_OPB_REGS_OPB_SIZE); > + memory_region_add_subregion(&lpc->opb_mr, LPC_OPB_REGS_OPB_ADDR, > + &lpc->opb_master_regs); > + memory_region_init_io(&lpc->lpc_hc_regs, OBJECT(dev), &lpc_hc_ops, lpc, > + "lpc-hc", LPC_HC_REGS_OPB_SIZE); > + memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR, > + &lpc->lpc_hc_regs); > + > + /* XScom region for LPC registers */ > + memory_region_init_io(&lpc->xscom_regs, OBJECT(dev), > + &pnv_lpc_xscom_ops, lpc, "xscom-lpc", > + pnv_xscom_addr(PNV_XSCOM_INTERFACE(dev), > + PNV_XSCOM_LPC_SIZE)); > +} > + > +static void pnv_lpc_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); > + > + xdc->devnode = pnv_lpc_devnode; > + > + dc->realize = pnv_lpc_realize; > +} > + > +static const TypeInfo pnv_lpc_info = { > + .name = TYPE_PNV_LPC, > + .parent = TYPE_DEVICE, > + .instance_size = sizeof(PnvLpcController), > + .class_init = pnv_lpc_class_init, > + .interfaces = (InterfaceInfo[]) { > + { TYPE_PNV_XSCOM_INTERFACE }, > + { } > + } > +}; > + > +static void pnv_lpc_register_types(void) > +{ > + type_register_static(&pnv_lpc_info); > +} > + > +type_init(pnv_lpc_register_types) > diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h > index 0371710b1882..a30579a5817f 100644 > --- a/include/hw/ppc/pnv.h > +++ b/include/hw/ppc/pnv.h > @@ -22,6 +22,7 @@ > #include "hw/boards.h" > #include "hw/sysbus.h" > #include "hw/ppc/pnv_xscom.h" > +#include "hw/ppc/pnv_lpc.h" > > #define TYPE_PNV_CHIP "powernv-chip" > #define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP) > @@ -48,6 +49,8 @@ typedef struct PnvChip { > uint32_t nr_cores; > uint64_t cores_mask; > void *cores; > + > + PnvLpcController lpc; > } PnvChip; > > typedef struct PnvChipClass { > diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h > new file mode 100644 > index 000000000000..3741e573b200 > --- /dev/null > +++ b/include/hw/ppc/pnv_lpc.h > @@ -0,0 +1,63 @@ > +/* > + * QEMU PowerPC PowerNV LPC controller > + * > + * Copyright (c) 2016, IBM Corporation. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > <http://www.gnu.org/licenses/>. > + */ > +#ifndef _PPC_PNV_LPC_H > +#define _PPC_PNV_LPC_H > + > +#define TYPE_PNV_LPC "pnv-lpc" > +#define PNV_LPC(obj) \ > + OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC) > + > +typedef struct PnvLpcController { > + DeviceState parent; > + > + uint64_t eccb_stat_reg; > + uint32_t eccb_data_reg; > + > + /* OPB bus */ > + MemoryRegion opb_mr; > + AddressSpace opb_as; > + /* ISA IO and Memory space */ > + MemoryRegion isa_io; > + MemoryRegion isa_mem; > + /* Windows from OPB to ISA (aliases) */ > + MemoryRegion opb_isa_io; > + MemoryRegion opb_isa_mem; > + MemoryRegion opb_isa_fw; > + /* Registers */ > + MemoryRegion lpc_hc_regs; > + MemoryRegion opb_master_regs; > + > + /* OPB Master LS registers */ > + uint32_t opb_irq_stat; > + uint32_t opb_irq_mask; > + uint32_t opb_irq_pol; > + uint32_t opb_irq_input; > + > + /* LPC HC registers */ > + uint32_t lpc_hc_fw_seg_idsel; > + uint32_t lpc_hc_fw_rd_acc_size; > + uint32_t lpc_hc_irqser_ctrl; > + uint32_t lpc_hc_irqmask; > + uint32_t lpc_hc_irqstat; > + uint32_t lpc_hc_error_addr; > + > + MemoryRegion xscom_regs; > +} PnvLpcController; > + > +#endif /* _PPC_PNV_LPC_H */ > diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h > index 31e5e8847b90..46b6ce7767c7 100644 > --- a/include/hw/ppc/pnv_xscom.h > +++ b/include/hw/ppc/pnv_xscom.h > @@ -82,6 +82,9 @@ typedef struct PnvXScom { > #define PNV_XSCOM_EX_CORE_BASE(i) (PNV_XSCOM_EX_BASE | (((uint64_t)i) << 24)) > #define PNV_XSCOM_EX_CORE_SIZE 0x100000 > > +#define PNV_XSCOM_LPC_BASE 0xb0020 > +#define PNV_XSCOM_LPC_SIZE 0x4 > + > extern int pnv_xscom_populate_fdt(PnvXScom *xscom, void *fdt, int offset); > > /* -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
signature.asc
Description: PGP signature