qemu/hw/ppc/pnv_lpc.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC PowerNV LPC controller
   3 *
   4 * Copyright (c) 2016, IBM Corporation.
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "sysemu/sysemu.h"
  22#include "target-ppc/cpu.h"
  23#include "qapi/error.h"
  24#include "qemu/log.h"
  25
  26#include "hw/ppc/pnv.h"
  27#include "hw/ppc/pnv_lpc.h"
  28#include "hw/ppc/pnv_xscom.h"
  29#include "hw/ppc/fdt.h"
  30
  31#include <libfdt.h>
  32
  33enum {
  34    ECCB_CTL    = 0,
  35    ECCB_RESET  = 1,
  36    ECCB_STAT   = 2,
  37    ECCB_DATA   = 3,
  38};
  39
  40/* OPB Master LS registers */
  41#define OPB_MASTER_LS_IRQ_STAT  0x50
  42#define   OPB_MASTER_IRQ_LPC            0x00000800
  43#define OPB_MASTER_LS_IRQ_MASK  0x54
  44#define OPB_MASTER_LS_IRQ_POL   0x58
  45#define OPB_MASTER_LS_IRQ_INPUT 0x5c
  46
  47/* LPC HC registers */
  48#define LPC_HC_FW_SEG_IDSEL     0x24
  49#define LPC_HC_FW_RD_ACC_SIZE   0x28
  50#define   LPC_HC_FW_RD_1B               0x00000000
  51#define   LPC_HC_FW_RD_2B               0x01000000
  52#define   LPC_HC_FW_RD_4B               0x02000000
  53#define   LPC_HC_FW_RD_16B              0x04000000
  54#define   LPC_HC_FW_RD_128B             0x07000000
  55#define LPC_HC_IRQSER_CTRL      0x30
  56#define   LPC_HC_IRQSER_EN              0x80000000
  57#define   LPC_HC_IRQSER_QMODE           0x40000000
  58#define   LPC_HC_IRQSER_START_MASK      0x03000000
  59#define   LPC_HC_IRQSER_START_4CLK      0x00000000
  60#define   LPC_HC_IRQSER_START_6CLK      0x01000000
  61#define   LPC_HC_IRQSER_START_8CLK      0x02000000
  62#define LPC_HC_IRQMASK          0x34    /* same bit defs as LPC_HC_IRQSTAT */
  63#define LPC_HC_IRQSTAT          0x38
  64#define   LPC_HC_IRQ_SERIRQ0            0x80000000 /* all bits down to ... */
  65#define   LPC_HC_IRQ_SERIRQ16           0x00008000 /* IRQ16=IOCHK#, IRQ2=SMI# */
  66#define   LPC_HC_IRQ_SERIRQ_ALL         0xffff8000
  67#define   LPC_HC_IRQ_LRESET             0x00000400
  68#define   LPC_HC_IRQ_SYNC_ABNORM_ERR    0x00000080
  69#define   LPC_HC_IRQ_SYNC_NORESP_ERR    0x00000040
  70#define   LPC_HC_IRQ_SYNC_NORM_ERR      0x00000020
  71#define   LPC_HC_IRQ_SYNC_TIMEOUT_ERR   0x00000010
  72#define   LPC_HC_IRQ_SYNC_TARG_TAR_ERR  0x00000008
  73#define   LPC_HC_IRQ_SYNC_BM_TAR_ERR    0x00000004
  74#define   LPC_HC_IRQ_SYNC_BM0_REQ       0x00000002
  75#define   LPC_HC_IRQ_SYNC_BM1_REQ       0x00000001
  76#define LPC_HC_ERROR_ADDRESS    0x40
  77
  78#define LPC_OPB_SIZE            0x100000000ull
  79
  80#define ISA_IO_SIZE             0x00010000
  81#define ISA_MEM_SIZE            0x10000000
  82#define LPC_IO_OPB_ADDR         0xd0010000
  83#define LPC_IO_OPB_SIZE         0x00010000
  84#define LPC_MEM_OPB_ADDR        0xe0010000
  85#define LPC_MEM_OPB_SIZE        0x10000000
  86#define LPC_FW_OPB_ADDR         0xf0000000
  87#define LPC_FW_OPB_SIZE         0x10000000
  88
  89#define LPC_OPB_REGS_OPB_ADDR   0xc0010000
  90#define LPC_OPB_REGS_OPB_SIZE   0x00002000
  91#define LPC_HC_REGS_OPB_ADDR    0xc0012000
  92#define LPC_HC_REGS_OPB_SIZE    0x00001000
  93
  94
  95/*
  96 * TODO: the "primary" cell should only be added on chip 0. This is
  97 * how skiboot chooses the default LPC controller on multichip
  98 * systems.
  99 *
 100 * It would be easly done if we can change the populate() interface to
 101 * replace the PnvXScomInterface parameter by a PnvChip one
 102 */
 103static int pnv_lpc_populate(PnvXScomInterface *dev, void *fdt, int xscom_offset)
 104{
 105    const char compat[] = "ibm,power8-lpc\0ibm,lpc";
 106    char *name;
 107    int offset;
 108    uint32_t lpc_pcba = PNV_XSCOM_LPC_BASE;
 109    uint32_t reg[] = {
 110        cpu_to_be32(lpc_pcba),
 111        cpu_to_be32(PNV_XSCOM_LPC_SIZE)
 112    };
 113
 114    name = g_strdup_printf("isa@%x", lpc_pcba);
 115    offset = fdt_add_subnode(fdt, xscom_offset, name);
 116    _FDT(offset);
 117    g_free(name);
 118
 119    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
 120    _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
 121    _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
 122    _FDT((fdt_setprop(fdt, offset, "primary", NULL, 0)));
 123    _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
 124    return 0;
 125}
 126
 127/*
 128 * These read/write handlers of the OPB address space should be common
 129 * with the P9 LPC Controller which uses direct MMIOs.
 130 *
 131 * TODO: rework to use address_space_stq() and address_space_ldq()
 132 * instead.
 133 */
 134static bool opb_read(PnvLpcController *lpc, uint32_t addr, uint8_t *data,
 135                     int sz)
 136{
 137    bool success;
 138
 139    /* XXX Handle access size limits and FW read caching here */
 140    success = !address_space_rw(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED,
 141                                data, sz, false);
 142
 143    return success;
 144}
 145
 146static bool opb_write(PnvLpcController *lpc, uint32_t addr, uint8_t *data,
 147                      int sz)
 148{
 149    bool success;
 150
 151    /* XXX Handle access size limits here */
 152    success = !address_space_rw(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED,
 153                                data, sz, true);
 154
 155    return success;
 156}
 157
 158#define ECCB_CTL_READ           (1ull << (63 - 15))
 159#define ECCB_CTL_SZ_LSH         (63 - 7)
 160#define ECCB_CTL_SZ_MASK        (0xfull << ECCB_CTL_SZ_LSH)
 161#define ECCB_CTL_ADDR_MASK      0xffffffffu;
 162
 163#define ECCB_STAT_OP_DONE       (1ull << (63 - 52))
 164#define ECCB_STAT_OP_ERR        (1ull << (63 - 52))
 165#define ECCB_STAT_RD_DATA_LSH   (63 - 37)
 166#define ECCB_STAT_RD_DATA_MASK  (0xffffffff << ECCB_STAT_RD_DATA_LSH)
 167
 168static void pnv_lpc_do_eccb(PnvLpcController *lpc, uint64_t cmd)
 169{
 170    /* XXX Check for magic bits at the top, addr size etc... */
 171    unsigned int sz = (cmd & ECCB_CTL_SZ_MASK) >> ECCB_CTL_SZ_LSH;
 172    uint32_t opb_addr = cmd & ECCB_CTL_ADDR_MASK;
 173    uint8_t data[4];
 174    bool success;
 175
 176    if (cmd & ECCB_CTL_READ) {
 177        success = opb_read(lpc, opb_addr, data, sz);
 178        if (success) {
 179            lpc->eccb_stat_reg = ECCB_STAT_OP_DONE |
 180                    (((uint64_t)data[0]) << 24 |
 181                     ((uint64_t)data[1]) << 16 |
 182                     ((uint64_t)data[2]) <<  8 |
 183                     ((uint64_t)data[3])) << ECCB_STAT_RD_DATA_LSH;
 184        } else {
 185            lpc->eccb_stat_reg = ECCB_STAT_OP_DONE |
 186                    (0xffffffffull << ECCB_STAT_RD_DATA_LSH);
 187        }
 188    } else {
 189        data[0] = lpc->eccb_data_reg >> 24;
 190        data[1] = lpc->eccb_data_reg >> 16;
 191        data[2] = lpc->eccb_data_reg >>  8;
 192        data[3] = lpc->eccb_data_reg;
 193
 194        success = opb_write(lpc, opb_addr, data, sz);
 195        lpc->eccb_stat_reg = ECCB_STAT_OP_DONE;
 196    }
 197    /* XXX Which error bit (if any) to signal OPB error ? */
 198}
 199
 200static uint64_t pnv_lpc_xscom_read(void *opaque, hwaddr addr, unsigned size)
 201{
 202    PnvLpcController *lpc = PNV_LPC(opaque);
 203    uint32_t offset = addr >> 3;
 204    uint64_t val = 0;
 205
 206    switch (offset & 3) {
 207    case ECCB_CTL:
 208    case ECCB_RESET:
 209        val = 0;
 210        break;
 211    case ECCB_STAT:
 212        val = lpc->eccb_stat_reg;
 213        lpc->eccb_stat_reg = 0;
 214        break;
 215    case ECCB_DATA:
 216        val = ((uint64_t)lpc->eccb_data_reg) << 32;
 217        break;
 218    }
 219    return val;
 220}
 221
 222static void pnv_lpc_xscom_write(void *opaque, hwaddr addr,
 223                                uint64_t val, unsigned size)
 224{
 225    PnvLpcController *lpc = PNV_LPC(opaque);
 226    uint32_t offset = addr >> 3;
 227
 228    switch (offset & 3) {
 229    case ECCB_CTL:
 230        pnv_lpc_do_eccb(lpc, val);
 231        break;
 232    case ECCB_RESET:
 233        /*  XXXX  */
 234        break;
 235    case ECCB_STAT:
 236        break;
 237    case ECCB_DATA:
 238        lpc->eccb_data_reg = val >> 32;
 239        break;
 240    }
 241}
 242
 243static const MemoryRegionOps pnv_lpc_xscom_ops = {
 244    .read = pnv_lpc_xscom_read,
 245    .write = pnv_lpc_xscom_write,
 246    .valid.min_access_size = 8,
 247    .valid.max_access_size = 8,
 248    .impl.min_access_size = 8,
 249    .impl.max_access_size = 8,
 250    .endianness = DEVICE_BIG_ENDIAN,
 251};
 252
 253static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
 254{
 255    PnvLpcController *lpc = opaque;
 256    uint64_t val = 0xfffffffffffffffful;
 257
 258    switch (addr) {
 259    case LPC_HC_FW_SEG_IDSEL:
 260        val =  lpc->lpc_hc_fw_seg_idsel;
 261        break;
 262    case LPC_HC_FW_RD_ACC_SIZE:
 263        val =  lpc->lpc_hc_fw_rd_acc_size;
 264        break;
 265    case LPC_HC_IRQSER_CTRL:
 266        val =  lpc->lpc_hc_irqser_ctrl;
 267        break;
 268    case LPC_HC_IRQMASK:
 269        val =  lpc->lpc_hc_irqmask;
 270        break;
 271    case LPC_HC_IRQSTAT:
 272        val =  lpc->lpc_hc_irqstat;
 273        break;
 274    case LPC_HC_ERROR_ADDRESS:
 275        val =  lpc->lpc_hc_error_addr;
 276        break;
 277    default:
 278        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%"
 279                      HWADDR_PRIx "\n", addr);
 280    }
 281    return val;
 282}
 283
 284static void lpc_hc_write(void *opaque, hwaddr addr, uint64_t val,
 285                         unsigned size)
 286{
 287    PnvLpcController *lpc = opaque;
 288
 289    /* XXX Filter out reserved bits */
 290
 291    switch (addr) {
 292    case LPC_HC_FW_SEG_IDSEL:
 293        /* XXX Actually figure out how that works as this impact
 294         * memory regions/aliases
 295         */
 296        lpc->lpc_hc_fw_seg_idsel = val;
 297        break;
 298    case LPC_HC_FW_RD_ACC_SIZE:
 299        lpc->lpc_hc_fw_rd_acc_size = val;
 300        break;
 301    case LPC_HC_IRQSER_CTRL:
 302        lpc->lpc_hc_irqser_ctrl = val;
 303        break;
 304    case LPC_HC_IRQMASK:
 305        lpc->lpc_hc_irqmask = val;
 306        break;
 307    case LPC_HC_IRQSTAT:
 308        lpc->lpc_hc_irqstat &= ~val;
 309        break;
 310    case LPC_HC_ERROR_ADDRESS:
 311        break;
 312    default:
 313        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%"
 314                      HWADDR_PRIx "\n", addr);
 315    }
 316}
 317
 318static const MemoryRegionOps lpc_hc_ops = {
 319    .read = lpc_hc_read,
 320    .write = lpc_hc_write,
 321    .endianness = DEVICE_BIG_ENDIAN,
 322    .valid = {
 323        .min_access_size = 4,
 324        .max_access_size = 4,
 325    },
 326    .impl = {
 327        .min_access_size = 4,
 328        .max_access_size = 4,
 329    },
 330};
 331
 332static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size)
 333{
 334    PnvLpcController *lpc = opaque;
 335    uint64_t val = 0xfffffffffffffffful;
 336
 337    switch (addr) {
 338    case OPB_MASTER_LS_IRQ_STAT:
 339        val = lpc->opb_irq_stat;
 340        break;
 341    case OPB_MASTER_LS_IRQ_MASK:
 342        val = lpc->opb_irq_mask;
 343        break;
 344    case OPB_MASTER_LS_IRQ_POL:
 345        val = lpc->opb_irq_pol;
 346        break;
 347    case OPB_MASTER_LS_IRQ_INPUT:
 348        val = lpc->opb_irq_input;
 349        break;
 350    default:
 351        qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%"
 352                      HWADDR_PRIx "\n", addr);
 353    }
 354
 355    return val;
 356}
 357
 358static void opb_master_write(void *opaque, hwaddr addr,
 359                             uint64_t val, unsigned size)
 360{
 361    PnvLpcController *lpc = opaque;
 362
 363    switch (addr) {
 364    case OPB_MASTER_LS_IRQ_STAT:
 365        lpc->opb_irq_stat &= ~val;
 366        break;
 367    case OPB_MASTER_LS_IRQ_MASK:
 368        /* XXX Filter out reserved bits */
 369        lpc->opb_irq_mask = val;
 370        break;
 371    case OPB_MASTER_LS_IRQ_POL:
 372        /* XXX Filter out reserved bits */
 373        lpc->opb_irq_pol = val;
 374        break;
 375    case OPB_MASTER_LS_IRQ_INPUT:
 376        /* Read only */
 377        break;
 378    default:
 379        qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%"
 380                      HWADDR_PRIx "\n", addr);
 381    }
 382}
 383
 384static const MemoryRegionOps opb_master_ops = {
 385    .read = opb_master_read,
 386    .write = opb_master_write,
 387    .endianness = DEVICE_BIG_ENDIAN,
 388    .valid = {
 389        .min_access_size = 4,
 390        .max_access_size = 4,
 391    },
 392    .impl = {
 393        .min_access_size = 4,
 394        .max_access_size = 4,
 395    },
 396};
 397
 398static void pnv_lpc_realize(DeviceState *dev, Error **errp)
 399{
 400    PnvLpcController *lpc = PNV_LPC(dev);
 401
 402    /* Reg inits */
 403    lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B;
 404
 405    /* Create address space and backing MR for the OPB bus */
 406    memory_region_init(&lpc->opb_mr, OBJECT(dev), "lpc-opb", 0x100000000ull);
 407    address_space_init(&lpc->opb_as, &lpc->opb_mr, "lpc-opb");
 408
 409    /* Create ISA IO and Mem space regions which are the root of
 410     * the ISA bus (ie, ISA address spaces). We don't create a
 411     * separate one for FW which we alias to memory.
 412     */
 413    memory_region_init(&lpc->isa_io, OBJECT(dev), "isa-io", ISA_IO_SIZE);
 414    memory_region_init(&lpc->isa_mem, OBJECT(dev), "isa-mem", ISA_MEM_SIZE);
 415
 416    /* Create windows from the OPB space to the ISA space */
 417    memory_region_init_alias(&lpc->opb_isa_io, OBJECT(dev), "lpc-isa-io",
 418                             &lpc->isa_io, 0, LPC_IO_OPB_SIZE);
 419    memory_region_add_subregion(&lpc->opb_mr, LPC_IO_OPB_ADDR,
 420                                &lpc->opb_isa_io);
 421    memory_region_init_alias(&lpc->opb_isa_mem, OBJECT(dev), "lpc-isa-mem",
 422                             &lpc->isa_mem, 0, LPC_MEM_OPB_SIZE);
 423    memory_region_add_subregion(&lpc->opb_mr, LPC_MEM_OPB_ADDR,
 424                                &lpc->opb_isa_mem);
 425    memory_region_init_alias(&lpc->opb_isa_fw, OBJECT(dev), "lpc-isa-fw",
 426                             &lpc->isa_mem, 0, LPC_FW_OPB_SIZE);
 427    memory_region_add_subregion(&lpc->opb_mr, LPC_FW_OPB_ADDR,
 428                                &lpc->opb_isa_fw);
 429
 430    /* Create MMIO regions for LPC HC and OPB registers */
 431    memory_region_init_io(&lpc->opb_master_regs, OBJECT(dev), &opb_master_ops,
 432                          lpc, "lpc-opb-master", LPC_OPB_REGS_OPB_SIZE);
 433    memory_region_add_subregion(&lpc->opb_mr, LPC_OPB_REGS_OPB_ADDR,
 434                                &lpc->opb_master_regs);
 435    memory_region_init_io(&lpc->lpc_hc_regs, OBJECT(dev), &lpc_hc_ops, lpc,
 436                          "lpc-hc", LPC_HC_REGS_OPB_SIZE);
 437    memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR,
 438                                &lpc->lpc_hc_regs);
 439
 440    /* XScom region for LPC registers */
 441    pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(dev),
 442                          &pnv_lpc_xscom_ops, lpc, "xscom-lpc",
 443                          PNV_XSCOM_LPC_SIZE);
 444}
 445
 446static void pnv_lpc_class_init(ObjectClass *klass, void *data)
 447{
 448    DeviceClass *dc = DEVICE_CLASS(klass);
 449    PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
 450
 451    xdc->populate = pnv_lpc_populate;
 452
 453    dc->realize = pnv_lpc_realize;
 454}
 455
 456static const TypeInfo pnv_lpc_info = {
 457    .name          = TYPE_PNV_LPC,
 458    .parent        = TYPE_DEVICE,
 459    .instance_size = sizeof(PnvLpcController),
 460    .class_init    = pnv_lpc_class_init,
 461    .interfaces = (InterfaceInfo[]) {
 462        { TYPE_PNV_XSCOM_INTERFACE },
 463        { }
 464    }
 465};
 466
 467static void pnv_lpc_register_types(void)
 468{
 469    type_register_static(&pnv_lpc_info);
 470}
 471
 472type_init(pnv_lpc_register_types)
 473