All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: "Cédric Le Goater" <clg@kaod.org>
Cc: qemu-ppc@nongnu.org,
	Benjamin Herrenschmidt <benh@kernel.crashing.org>,
	qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v3 09/10] ppc/pnv: add a LPC controller
Date: Wed, 21 Sep 2016 16:23:47 +1000	[thread overview]
Message-ID: <20160921062347.GE20488@umbus> (raw)
In-Reply-To: <1473943560-14846-10-git-send-email-clg@kaod.org>

[-- Attachment #1: Type: text/plain, Size: 23577 bytes --]

On Thu, Sep 15, 2016 at 02:45:59PM +0200, Cédric Le Goater wrote:
> From: Benjamin Herrenschmidt <benh@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 <benh@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 <clg@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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

  parent reply	other threads:[~2016-09-21  6:31 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-15 12:45 [Qemu-devel] [PATCH v3 00/10] ppc/pnv: loading skiboot and booting the kernel Cédric Le Goater
2016-09-15 12:45 ` [Qemu-devel] [PATCH v3 01/10] ppc/pnv: add skeleton PowerNV platform Cédric Le Goater
2016-09-20  7:53   ` David Gibson
2016-09-21  7:32     ` Cédric Le Goater
2016-09-15 12:45 ` [Qemu-devel] [PATCH v3 02/10] ppc/pnv: add a PnvChip object Cédric Le Goater
2016-09-20 13:50   ` David Gibson
2016-09-21  7:44     ` Cédric Le Goater
2016-09-15 12:45 ` [Qemu-devel] [PATCH v3 03/10] ppc/pnv: add a core mask to PnvChip Cédric Le Goater
2016-09-20 13:57   ` David Gibson
2016-09-21  7:57     ` Cédric Le Goater
2016-09-15 12:45 ` [Qemu-devel] [PATCH v3 04/10] ppc/pnv: add a PIR handler " Cédric Le Goater
2016-09-21  1:29   ` David Gibson
2016-09-21  1:52     ` Benjamin Herrenschmidt
2016-09-21  7:05     ` Cédric Le Goater
2016-09-15 12:45 ` [Qemu-devel] [PATCH v3 05/10] ppc/pnv: add a PnvCore object Cédric Le Goater
2016-09-21  1:51   ` David Gibson
2016-09-21  2:05     ` Benjamin Herrenschmidt
2016-09-21  2:15       ` David Gibson
2016-09-21  7:15       ` Cédric Le Goater
2016-09-21  7:09     ` Cédric Le Goater
2016-09-21 14:24     ` Cédric Le Goater
2016-09-15 12:45 ` [Qemu-devel] [PATCH v3 06/10] monitor: fix crash for platforms without a CPU 0 Cédric Le Goater
2016-09-21  5:30   ` David Gibson
2016-09-21  8:06     ` Cédric Le Goater
2016-09-15 12:45 ` [Qemu-devel] [PATCH v3 07/10] ppc/pnv: add XSCOM infrastructure Cédric Le Goater
2016-09-15 22:11   ` Benjamin Herrenschmidt
2016-09-21  5:56     ` David Gibson
2016-09-21  7:44       ` Benjamin Herrenschmidt
2016-09-21  6:08   ` David Gibson
2016-09-22  8:25     ` Cédric Le Goater
2016-09-23  2:46       ` David Gibson
2016-09-26 16:11         ` Cédric Le Goater
2016-09-27  2:35           ` David Gibson
2016-09-27  5:54             ` Cédric Le Goater
2016-09-27  6:10               ` Benjamin Herrenschmidt
2016-09-27  7:16                 ` Cédric Le Goater
2016-09-28  1:40               ` David Gibson
2016-09-27  9:10     ` Cédric Le Goater
2016-09-27  9:30       ` Cédric Le Goater
2016-09-27 10:18         ` Benjamin Herrenschmidt
2016-09-27 10:17       ` Benjamin Herrenschmidt
2016-09-15 12:45 ` [Qemu-devel] [PATCH v3 08/10] ppc/pnv: add a XScomDevice to PnvCore Cédric Le Goater
2016-09-21  6:12   ` David Gibson
2016-09-22  8:33     ` Cédric Le Goater
2016-09-23  2:50       ` David Gibson
2016-09-15 12:45 ` [Qemu-devel] [PATCH v3 09/10] ppc/pnv: add a LPC controller Cédric Le Goater
2016-09-15 22:13   ` Benjamin Herrenschmidt
2016-09-16 17:35     ` Cédric Le Goater
2016-09-21  6:23   ` David Gibson [this message]
2016-09-15 12:46 ` [Qemu-devel] [PATCH v3 10/10] ppc/pnv: add a ISA bus Cédric Le Goater
2016-09-21  6:30   ` David Gibson
2016-09-22  8:44     ` Cédric Le Goater
2016-09-23  2:54       ` David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160921062347.GE20488@umbus \
    --to=david@gibson.dropbear.id.au \
    --cc=benh@kernel.crashing.org \
    --cc=clg@kaod.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.