qemu/hw/misc/xilinx_zynqmp_ocmc.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the OCM General purpose memory for all system masters
   3 *
   4 * Copyright (c) 2013 Xilinx Inc.
   5 *
   6 * Written by Edgar E. Iglesias <edgari@xilinx.com>
   7 * Partly autogenerated by xregqemu.py 2013-10-15.
   8 *
   9 * Permission is hereby granted, free of charge, to any person obtaining a copy
  10 * of this software and associated documentation files (the "Software"), to deal
  11 * in the Software without restriction, including without limitation the rights
  12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13 * copies of the Software, and to permit persons to whom the Software is
  14 * furnished to do so, subject to the following conditions:
  15 *
  16 * The above copyright notice and this permission notice shall be included in
  17 * all copies or substantial portions of the Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25 * THE SOFTWARE.
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "hw/sysbus.h"
  30#include "hw/register-dep.h"
  31#include "qemu/bitops.h"
  32#include "qemu/log.h"
  33
  34#ifndef XILINX_OCM_ERR_DEBUG
  35#define XILINX_OCM_ERR_DEBUG 0
  36#endif
  37
  38#define TYPE_XILINX_OCM "xlnx.zynqmp-ocmc"
  39
  40#define XILINX_OCM(obj) \
  41     OBJECT_CHECK(OCMC, (obj), TYPE_XILINX_OCM)
  42
  43DEP_REG32(OCM_ERR_CTRL, 0x0)
  44    DEP_FIELD(OCM_ERR_CTRL, UE_RES, 1, 3)
  45    DEP_FIELD(OCM_ERR_CTRL, PWR_ERR_RES, 1, 2)
  46    DEP_FIELD(OCM_ERR_CTRL, PZ_ERR_RES, 1, 1)
  47    DEP_FIELD(OCM_ERR_CTRL, APB_ERR_RES, 1, 0)
  48DEP_REG32(OCM_ISR, 0x4)
  49    DEP_FIELD(OCM_ISR, UE_RMW, 1, 10)
  50    DEP_FIELD(OCM_ISR, FIX_BURST_WR, 1, 9)
  51    DEP_FIELD(OCM_ISR, FIX_BURST_RD, 1, 8)
  52    DEP_FIELD(OCM_ISR, ECC_UE, 1, 7)
  53    DEP_FIELD(OCM_ISR, ECC_CE, 1, 6)
  54    DEP_FIELD(OCM_ISR, LOCK_ERR_WR, 1, 5)
  55    DEP_FIELD(OCM_ISR, LOCK_ERR_RD, 1, 4)
  56    DEP_FIELD(OCM_ISR, INV_OCM_WR, 1, 3)
  57    DEP_FIELD(OCM_ISR, INV_OCM_RD, 1, 2)
  58    DEP_FIELD(OCM_ISR, PWR_DWN, 1, 1)
  59    DEP_FIELD(OCM_ISR, INV_APB, 1, 0)
  60DEP_REG32(OCM_IMR, 0x8)
  61    DEP_FIELD(OCM_IMR, UE_RMW, 1, 10)
  62    DEP_FIELD(OCM_IMR, FIX_BURST_WR, 1, 9)
  63    DEP_FIELD(OCM_IMR, FIX_BURST_RD, 1, 8)
  64    DEP_FIELD(OCM_IMR, ECC_UE, 1, 7)
  65    DEP_FIELD(OCM_IMR, ECC_CE, 1, 6)
  66    DEP_FIELD(OCM_IMR, LOCK_ERR_WR, 1, 5)
  67    DEP_FIELD(OCM_IMR, LOCK_ERR_RD, 1, 4)
  68    DEP_FIELD(OCM_IMR, INV_OCM_WR, 1, 3)
  69    DEP_FIELD(OCM_IMR, INV_OCM_RD, 1, 2)
  70    DEP_FIELD(OCM_IMR, PWR_DWN, 1, 1)
  71    DEP_FIELD(OCM_IMR, INV_APB, 1, 0)
  72DEP_REG32(OCM_IEN, 0xc)
  73    DEP_FIELD(OCM_IEN, UE_RMW, 1, 10)
  74    DEP_FIELD(OCM_IEN, FIX_BURST_WR, 1, 9)
  75    DEP_FIELD(OCM_IEN, FIX_BURST_RD, 1, 8)
  76    DEP_FIELD(OCM_IEN, ECC_UE, 1, 7)
  77    DEP_FIELD(OCM_IEN, ECC_CE, 1, 6)
  78    DEP_FIELD(OCM_IEN, LOCK_ERR_WR, 1, 5)
  79    DEP_FIELD(OCM_IEN, LOCK_ERR_RD, 1, 4)
  80    DEP_FIELD(OCM_IEN, INV_OCM_WR, 1, 3)
  81    DEP_FIELD(OCM_IEN, INV_OCM_RD, 1, 2)
  82    DEP_FIELD(OCM_IEN, PWR_DWN, 1, 1)
  83    DEP_FIELD(OCM_IEN, INV_APB, 1, 0)
  84DEP_REG32(OCM_IDS, 0x10)
  85    DEP_FIELD(OCM_IDS, UE_RMW, 1, 10)
  86    DEP_FIELD(OCM_IDS, FIX_BURST_WR, 1, 9)
  87    DEP_FIELD(OCM_IDS, FIX_BURST_RD, 1, 8)
  88    DEP_FIELD(OCM_IDS, ECC_UE, 1, 7)
  89    DEP_FIELD(OCM_IDS, ECC_CE, 1, 6)
  90    DEP_FIELD(OCM_IDS, LOCK_ERR_WR, 1, 5)
  91    DEP_FIELD(OCM_IDS, LOCK_ERR_RD, 1, 4)
  92    DEP_FIELD(OCM_IDS, INV_OCM_WR, 1, 3)
  93    DEP_FIELD(OCM_IDS, INV_OCM_RD, 1, 2)
  94    DEP_FIELD(OCM_IDS, PWR_DWN, 1, 1)
  95    DEP_FIELD(OCM_IDS, INV_APB, 1, 0)
  96DEP_REG32(OCM_ECC_CNTL, 0x14)
  97    DEP_FIELD(OCM_ECC_CNTL, FI_MODE, 1, 2)
  98    DEP_FIELD(OCM_ECC_CNTL, DET_ONLY, 1, 1)
  99    DEP_FIELD(OCM_ECC_CNTL, ECC_ON_OFF, 1, 0)
 100DEP_REG32(OCM_CLR_EXE, 0x18)
 101    DEP_FIELD(OCM_CLR_EXE, MON_7, 1, 7)
 102    DEP_FIELD(OCM_CLR_EXE, MON_6, 1, 6)
 103    DEP_FIELD(OCM_CLR_EXE, MON_5, 1, 5)
 104    DEP_FIELD(OCM_CLR_EXE, MON_4, 1, 4)
 105    DEP_FIELD(OCM_CLR_EXE, MON_3, 1, 3)
 106    DEP_FIELD(OCM_CLR_EXE, MON_2, 1, 2)
 107    DEP_FIELD(OCM_CLR_EXE, MON_1, 1, 1)
 108    DEP_FIELD(OCM_CLR_EXE, MON_0, 1, 0)
 109DEP_REG32(OCM_CE_FFA, 0x1c)
 110    DEP_FIELD(OCM_CE_FFA, ADDR, 18, 0)
 111DEP_REG32(OCM_CE_FFD0, 0x20)
 112DEP_REG32(OCM_CE_FFD1, 0x24)
 113DEP_REG32(OCM_CE_FFD2, 0x28)
 114DEP_REG32(OCM_CE_FFD3, 0x2c)
 115DEP_REG32(OCM_CE_FFE, 0x30)
 116    DEP_FIELD(OCM_CE_FFE, SYNDROME, 16, 0)
 117DEP_REG32(OCM_UE_FFA, 0x34)
 118    DEP_FIELD(OCM_UE_FFA, ADDR, 18, 0)
 119DEP_REG32(OCM_UE_FFD0, 0x38)
 120DEP_REG32(OCM_UE_FFD1, 0x3c)
 121DEP_REG32(OCM_UE_FFD2, 0x40)
 122DEP_REG32(OCM_UE_FFD3, 0x44)
 123DEP_REG32(OCM_UE_FFE, 0x48)
 124    DEP_FIELD(OCM_UE_FFE, SYNDROME, 16, 0)
 125DEP_REG32(OCM_FI_D0, 0x4c)
 126DEP_REG32(OCM_FI_D1, 0x50)
 127DEP_REG32(OCM_FI_D2, 0x54)
 128DEP_REG32(OCM_FI_D3, 0x58)
 129DEP_REG32(OCM_FI_SY, 0x5c)
 130    DEP_FIELD(OCM_FI_SY, DATA, 16, 0)
 131DEP_REG32(OCM_EMA, 0x60)
 132    DEP_FIELD(OCM_EMA, BANK3, 3, 9)
 133    DEP_FIELD(OCM_EMA, BANK2, 3, 6)
 134    DEP_FIELD(OCM_EMA, BANK1, 3, 3)
 135    DEP_FIELD(OCM_EMA, BANK0, 3, 0)
 136DEP_REG32(OCM_EMAW, 0x64)
 137    DEP_FIELD(OCM_EMAW, BANK3, 2, 6)
 138    DEP_FIELD(OCM_EMAW, BANK2, 2, 4)
 139    DEP_FIELD(OCM_EMAW, BANK1, 2, 2)
 140    DEP_FIELD(OCM_EMAW, BANK0, 2, 0)
 141DEP_REG32(OCM_EMAS, 0x68)
 142    DEP_FIELD(OCM_EMAS, BANK3, 1, 3)
 143    DEP_FIELD(OCM_EMAS, BANK2, 1, 2)
 144    DEP_FIELD(OCM_EMAS, BANK1, 1, 1)
 145    DEP_FIELD(OCM_EMAS, BANK0, 1, 0)
 146DEP_REG32(OCM_CE_CNT, 0x6c)
 147    DEP_FIELD(OCM_CE_CNT, COUNT, 16, 0)
 148DEP_REG32(OCM_RMW_UE_FFA, 0x70)
 149    DEP_FIELD(OCM_RMW_UE_FFA, ADDR, 18, 0)
 150DEP_REG32(OCM_FI_CNTR, 0x74)
 151    DEP_FIELD(OCM_FI_CNTR, COUNT, 24, 0)
 152DEP_REG32(OCM_DBG_SYN_TOMEM, 0x78)
 153DEP_REG32(OCM_DBG_SYN_FROMEM, 0x7c)
 154DEP_REG32(OCM_IMP, 0x80)
 155    DEP_FIELD(OCM_IMP, SIZE, 4, 0)
 156DEP_REG32(OCM_ECO, 0xffc)
 157
 158#define R_MAX (R_OCM_ECO + 1)
 159
 160typedef struct OCMC {
 161    SysBusDevice parent_obj;
 162    MemoryRegion iomem;
 163    qemu_irq irq;
 164
 165    struct {
 166        uint64_t memsize;
 167    } cfg;
 168
 169    uint32_t regs[R_MAX];
 170    DepRegisterInfo regs_info[R_MAX];
 171} OCMC;
 172
 173static const MemoryRegionOps ocm_ops = {
 174    .read = dep_register_read_memory_le,
 175    .write = dep_register_write_memory_le,
 176    .endianness = DEVICE_LITTLE_ENDIAN,
 177    .valid = {
 178        .min_access_size = 4,
 179        .max_access_size = 4,
 180    },
 181};
 182
 183static void ocm_update_irq(OCMC *s)
 184{
 185    bool pending = s->regs[R_OCM_ISR] & s->regs[R_OCM_IMR];
 186    qemu_set_irq(s->irq, pending);
 187}
 188
 189static void ocm_isr_postw(DepRegisterInfo *reg, uint64_t val64)
 190{
 191    OCMC *s = XILINX_OCM(reg->opaque);
 192    ocm_update_irq(s);
 193}
 194
 195static uint64_t ocm_ien_prew(DepRegisterInfo *reg, uint64_t val64)
 196{
 197    OCMC *s = XILINX_OCM(reg->opaque);
 198    uint32_t val = val64;
 199
 200    s->regs[R_OCM_IMR] |= val;
 201    ocm_update_irq(s);
 202    return 0;
 203}
 204
 205static uint64_t ocm_ids_prew(DepRegisterInfo *reg, uint64_t val64)
 206{
 207    OCMC *s = XILINX_OCM(reg->opaque);
 208    uint32_t val = val64;
 209
 210    s->regs[R_OCM_IMR] &= ~val;
 211    ocm_update_irq(s);
 212    return 0;
 213}
 214
 215static DepRegisterAccessInfo ocm_regs_info[] = {
 216    {   .name = "OCM_ERR_CTRL",  .decode.addr = A_OCM_ERR_CTRL,
 217        .rsvd = 0xfffffff0,
 218    },{ .name = "OCM_ISR",  .decode.addr = A_OCM_ISR,
 219        .rsvd = 0xfffff800,
 220        .w1c = 0x7ff,
 221        .ro = ~0x7ffull,
 222        .post_write = ocm_isr_postw,
 223    },{ .name = "OCM_IMR",  .decode.addr = A_OCM_IMR,
 224        .reset = 0x7ff,
 225        .rsvd = 0xfffff800,
 226        .ro = 0x7ff,
 227    },{ .name = "OCM_IEN",  .decode.addr = A_OCM_IEN,
 228        .rsvd = 0xfffff800,
 229        .pre_write = ocm_ien_prew,
 230    },{ .name = "OCM_IDS",  .decode.addr = A_OCM_IDS,
 231        .rsvd = 0xfffff800,
 232        .pre_write = ocm_ids_prew,
 233    },{ .name = "OCM_ECC_CNTL",  .decode.addr = A_OCM_ECC_CNTL,
 234        .rsvd = 0xfffffff8,
 235    },{ .name = "OCM_CLR_EXE",  .decode.addr = A_OCM_CLR_EXE,
 236        .rsvd = 0xffffff00,
 237    },{ .name = "OCM_CE_FFA",  .decode.addr = A_OCM_CE_FFA,
 238        .rsvd = 0xfffc0000,
 239        .ro = 0x3ffff,
 240    },{ .name = "OCM_CE_FFD0",  .decode.addr = A_OCM_CE_FFD0,
 241        .ro = 0xffffffff,
 242    },{ .name = "OCM_CE_FFD1",  .decode.addr = A_OCM_CE_FFD1,
 243        .ro = 0xffffffff,
 244    },{ .name = "OCM_CE_FFD2",  .decode.addr = A_OCM_CE_FFD2,
 245        .ro = 0xffffffff,
 246    },{ .name = "OCM_CE_FFD3",  .decode.addr = A_OCM_CE_FFD3,
 247        .ro = 0xffffffff,
 248    },{ .name = "OCM_CE_FFE",  .decode.addr = A_OCM_CE_FFE,
 249        .rsvd = 0xffff0000,
 250        .ro = 0xffff,
 251    },{ .name = "OCM_UE_FFA",  .decode.addr = A_OCM_UE_FFA,
 252        .rsvd = 0xfffc0000,
 253        .ro = 0x3ffff,
 254    },{ .name = "OCM_UE_FFD0",  .decode.addr = A_OCM_UE_FFD0,
 255        .ro = 0xffffffff,
 256    },{ .name = "OCM_UE_FFD1",  .decode.addr = A_OCM_UE_FFD1,
 257        .ro = 0xffffffff,
 258    },{ .name = "OCM_UE_FFD2",  .decode.addr = A_OCM_UE_FFD2,
 259        .ro = 0xffffffff,
 260    },{ .name = "OCM_UE_FFD3",  .decode.addr = A_OCM_UE_FFD3,
 261        .ro = 0xffffffff,
 262    },{ .name = "OCM_UE_FFE",  .decode.addr = A_OCM_UE_FFE,
 263        .rsvd = 0xffff0000,
 264        .ro = 0xffff,
 265    },{ .name = "OCM_FI_D0",  .decode.addr = A_OCM_FI_D0,
 266    },{ .name = "OCM_FI_D1",  .decode.addr = A_OCM_FI_D1,
 267    },{ .name = "OCM_FI_D2",  .decode.addr = A_OCM_FI_D2,
 268    },{ .name = "OCM_FI_D3",  .decode.addr = A_OCM_FI_D3,
 269    },{ .name = "OCM_FI_SY",  .decode.addr = A_OCM_FI_SY,
 270        .rsvd = 0xffff0000,
 271    },{ .name = "OCM_EMA",  .decode.addr = A_OCM_EMA,
 272        .reset = 0x249,
 273        .rsvd = 0xfffff000,
 274    },{ .name = "OCM_EMAW",  .decode.addr = A_OCM_EMAW,
 275        .rsvd = 0xffffff00,
 276    },{ .name = "OCM_EMAS",  .decode.addr = A_OCM_EMAS,
 277        .rsvd = 0xfffffff0,
 278    },{ .name = "OCM_CE_CNT",  .decode.addr = A_OCM_CE_CNT,
 279        .w1c = 0xffff,
 280    },{ .name = "OCM_RMW_UE_FFA",  .decode.addr = A_OCM_RMW_UE_FFA,
 281        .rsvd = 0xfffc0000,
 282        .ro = 0x3ffff,
 283    },{ .name = "OCM_FI_CNTR",  .decode.addr = A_OCM_FI_CNTR,
 284        .rsvd = 0xff000000,
 285    },{ .name = "OCM_DBG_SYN_TOMEM",  .decode.addr = A_OCM_DBG_SYN_TOMEM,
 286        .ro = 0xffffffff,
 287    },{ .name = "OCM_DBG_SYN_FROMEM",  .decode.addr = A_OCM_DBG_SYN_FROMEM,
 288        .ro = 0xffffffff,
 289    },{ .name = "OCM_IMP",  .decode.addr = A_OCM_IMP,
 290        .reset = 0x2,
 291        .ro = 0xf,
 292    },{ .name = "OCM_ECO",  .decode.addr = A_OCM_ECO,
 293    }
 294};
 295
 296static uint32_t ocmc_imp_encode_memsize(OCMC *s, uint64_t memsize)
 297{
 298    const char *prefix = object_get_canonical_path(OBJECT(s));
 299    uint32_t r;
 300
 301    switch (memsize) {
 302    case 64 * 1024:
 303        r = 0;
 304        break;
 305    case 128 * 1024:
 306        r = 1;
 307        break;
 308    case 256 * 1024:
 309        r = 2;
 310        break;
 311    /* 512KB is still to be defined.  */
 312    case 512 * 1024:
 313        qemu_log("%s: WARN: Using an undefined OCM memory size.\n", prefix);
 314        r = 3;
 315        break;
 316    default:
 317        hw_error("%s: Invalid OCM memory size %" PRIu64 " bytes\n",
 318                 prefix, memsize);
 319        break;
 320    }
 321    return r;
 322}
 323
 324static void ocm_reset(DeviceState *dev)
 325{
 326    OCMC *s = XILINX_OCM(dev);
 327    unsigned int i;
 328
 329    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
 330        dep_register_reset(&s->regs_info[i]);
 331    }
 332
 333    s->regs[R_OCM_IMP] = ocmc_imp_encode_memsize(s, s->cfg.memsize);
 334    ocm_update_irq(s);
 335}
 336
 337static void ocm_realize(DeviceState *dev, Error **errp)
 338{
 339    OCMC *s = XILINX_OCM(dev);
 340    const char *prefix = object_get_canonical_path(OBJECT(dev));
 341    unsigned int i;
 342
 343    for (i = 0; i < ARRAY_SIZE(ocm_regs_info); ++i) {
 344        DepRegisterInfo *r = &s->regs_info[i];
 345
 346        *r = (DepRegisterInfo) {
 347            .data = (uint8_t *)&s->regs[
 348                    ocm_regs_info[i].decode.addr/4],
 349            .data_size = sizeof(uint32_t),
 350            .access = &ocm_regs_info[i],
 351            .debug = XILINX_OCM_ERR_DEBUG,
 352            .prefix = prefix,
 353            .opaque = s,
 354        };
 355        memory_region_init_io(&r->mem, OBJECT(dev), &ocm_ops, r,
 356                              r->access->name, 4);
 357        memory_region_add_subregion(&s->iomem, r->access->decode.addr, &r->mem);
 358    }
 359}
 360
 361static void ocm_init(Object *obj)
 362{
 363    OCMC *s = XILINX_OCM(obj);
 364    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 365
 366    memory_region_init(&s->iomem, obj, TYPE_XILINX_OCM, R_MAX * 4);
 367    sysbus_init_mmio(sbd, &s->iomem);
 368    sysbus_init_irq(sbd, &s->irq);
 369}
 370
 371static Property ocmc_properties[] = {
 372    DEFINE_PROP_UINT64("memsize", OCMC, cfg.memsize, 0),
 373    DEFINE_PROP_END_OF_LIST(),
 374};
 375
 376static const VMStateDescription vmstate_ocm = {
 377    .name = TYPE_XILINX_OCM,
 378    .version_id = 1,
 379    .minimum_version_id = 1,
 380    .minimum_version_id_old = 1,
 381    .fields = (VMStateField[]) {
 382        VMSTATE_UINT32_ARRAY(regs, OCMC, R_MAX),
 383        VMSTATE_END_OF_LIST(),
 384    }
 385};
 386
 387static void ocm_class_init(ObjectClass *klass, void *data)
 388{
 389    DeviceClass *dc = DEVICE_CLASS(klass);
 390
 391    dc->reset = ocm_reset;
 392    dc->realize = ocm_realize;
 393    dc->vmsd = &vmstate_ocm;
 394    dc->props = ocmc_properties;
 395}
 396
 397static const TypeInfo ocm_info = {
 398    .name          = TYPE_XILINX_OCM,
 399    .parent        = TYPE_SYS_BUS_DEVICE,
 400    .instance_size = sizeof(OCMC),
 401    .class_init    = ocm_class_init,
 402    .instance_init = ocm_init,
 403};
 404
 405static void ocm_register_types(void)
 406{
 407    type_register_static(&ocm_info);
 408}
 409
 410type_init(ocm_register_types)
 411