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/hw.h"
  30#include "hw/sysbus.h"
  31#include "migration/vmstate.h"
  32#include "hw/qdev-properties.h"
  33#include "hw/register.h"
  34#include "qemu/bitops.h"
  35#include "qemu/log.h"
  36#include "hw/irq.h"
  37
  38#ifndef XILINX_OCM_ERR_DEBUG
  39#define XILINX_OCM_ERR_DEBUG 0
  40#endif
  41
  42#define TYPE_XILINX_OCM "xlnx.zynqmp-ocmc"
  43
  44#define XILINX_OCM(obj) \
  45     OBJECT_CHECK(OCMC, (obj), TYPE_XILINX_OCM)
  46
  47REG32(OCM_ERR_CTRL, 0x0)
  48    FIELD(OCM_ERR_CTRL, UE_RES, 3, 1)
  49    FIELD(OCM_ERR_CTRL, PWR_ERR_RES, 2, 1)
  50    FIELD(OCM_ERR_CTRL, PZ_ERR_RES, 1, 1)
  51    FIELD(OCM_ERR_CTRL, APB_ERR_RES, 0, 1)
  52REG32(OCM_ISR, 0x4)
  53    FIELD(OCM_ISR, UE_RMW, 10, 1)
  54    FIELD(OCM_ISR, FIX_BURST_WR, 9, 1)
  55    FIELD(OCM_ISR, FIX_BURST_RD, 8, 1)
  56    FIELD(OCM_ISR, ECC_UE, 7, 1)
  57    FIELD(OCM_ISR, ECC_CE, 6, 1)
  58    FIELD(OCM_ISR, LOCK_ERR_WR, 5, 1)
  59    FIELD(OCM_ISR, LOCK_ERR_RD, 4, 1)
  60    FIELD(OCM_ISR, INV_OCM_WR, 3, 1)
  61    FIELD(OCM_ISR, INV_OCM_RD, 2, 1)
  62    FIELD(OCM_ISR, PWR_DWN, 1, 1)
  63    FIELD(OCM_ISR, INV_APB, 0, 1)
  64REG32(OCM_IMR, 0x8)
  65    FIELD(OCM_IMR, UE_RMW, 10, 1)
  66    FIELD(OCM_IMR, FIX_BURST_WR, 9, 1)
  67    FIELD(OCM_IMR, FIX_BURST_RD, 8, 1)
  68    FIELD(OCM_IMR, ECC_UE, 7, 1)
  69    FIELD(OCM_IMR, ECC_CE, 6, 1)
  70    FIELD(OCM_IMR, LOCK_ERR_WR, 5, 1)
  71    FIELD(OCM_IMR, LOCK_ERR_RD, 4, 1)
  72    FIELD(OCM_IMR, INV_OCM_WR, 3, 1)
  73    FIELD(OCM_IMR, INV_OCM_RD, 2, 1)
  74    FIELD(OCM_IMR, PWR_DWN, 1, 1)
  75    FIELD(OCM_IMR, INV_APB, 0, 1)
  76REG32(OCM_IEN, 0xc)
  77    FIELD(OCM_IEN, UE_RMW, 10, 1)
  78    FIELD(OCM_IEN, FIX_BURST_WR, 9, 1)
  79    FIELD(OCM_IEN, FIX_BURST_RD, 8, 1)
  80    FIELD(OCM_IEN, ECC_UE, 7, 1)
  81    FIELD(OCM_IEN, ECC_CE, 6, 1)
  82    FIELD(OCM_IEN, LOCK_ERR_WR, 5, 1)
  83    FIELD(OCM_IEN, LOCK_ERR_RD, 4, 1)
  84    FIELD(OCM_IEN, INV_OCM_WR, 3, 1)
  85    FIELD(OCM_IEN, INV_OCM_RD, 2, 1)
  86    FIELD(OCM_IEN, PWR_DWN, 1, 1)
  87    FIELD(OCM_IEN, INV_APB, 0, 1)
  88REG32(OCM_IDS, 0x10)
  89    FIELD(OCM_IDS, UE_RMW, 10, 1)
  90    FIELD(OCM_IDS, FIX_BURST_WR, 9, 1)
  91    FIELD(OCM_IDS, FIX_BURST_RD, 8, 1)
  92    FIELD(OCM_IDS, ECC_UE, 7, 1)
  93    FIELD(OCM_IDS, ECC_CE, 6, 1)
  94    FIELD(OCM_IDS, LOCK_ERR_WR, 5, 1)
  95    FIELD(OCM_IDS, LOCK_ERR_RD, 4, 1)
  96    FIELD(OCM_IDS, INV_OCM_WR, 3, 1)
  97    FIELD(OCM_IDS, INV_OCM_RD, 2, 1)
  98    FIELD(OCM_IDS, PWR_DWN, 1, 1)
  99    FIELD(OCM_IDS, INV_APB, 0, 1)
 100REG32(OCM_ECC_CNTL, 0x14)
 101    FIELD(OCM_ECC_CNTL, FI_MODE, 2, 1)
 102    FIELD(OCM_ECC_CNTL, DET_ONLY, 1, 1)
 103    FIELD(OCM_ECC_CNTL, ECC_ON_OFF, 0, 1)
 104REG32(OCM_CLR_EXE, 0x18)
 105    FIELD(OCM_CLR_EXE, MON_7, 7, 1)
 106    FIELD(OCM_CLR_EXE, MON_6, 6, 1)
 107    FIELD(OCM_CLR_EXE, MON_5, 5, 1)
 108    FIELD(OCM_CLR_EXE, MON_4, 4, 1)
 109    FIELD(OCM_CLR_EXE, MON_3, 3, 1)
 110    FIELD(OCM_CLR_EXE, MON_2, 2, 1)
 111    FIELD(OCM_CLR_EXE, MON_1, 1, 1)
 112    FIELD(OCM_CLR_EXE, MON_0, 0, 1)
 113REG32(OCM_CE_FFA, 0x1c)
 114    FIELD(OCM_CE_FFA, ADDR, 0, 18)
 115REG32(OCM_CE_FFD0, 0x20)
 116REG32(OCM_CE_FFD1, 0x24)
 117REG32(OCM_CE_FFD2, 0x28)
 118REG32(OCM_CE_FFD3, 0x2c)
 119REG32(OCM_CE_FFE, 0x30)
 120    FIELD(OCM_CE_FFE, SYNDROME, 0, 16)
 121REG32(OCM_UE_FFA, 0x34)
 122    FIELD(OCM_UE_FFA, ADDR, 0, 18)
 123REG32(OCM_UE_FFD0, 0x38)
 124REG32(OCM_UE_FFD1, 0x3c)
 125REG32(OCM_UE_FFD2, 0x40)
 126REG32(OCM_UE_FFD3, 0x44)
 127REG32(OCM_UE_FFE, 0x48)
 128    FIELD(OCM_UE_FFE, SYNDROME, 0, 16)
 129REG32(OCM_FI_D0, 0x4c)
 130REG32(OCM_FI_D1, 0x50)
 131REG32(OCM_FI_D2, 0x54)
 132REG32(OCM_FI_D3, 0x58)
 133REG32(OCM_FI_SY, 0x5c)
 134    FIELD(OCM_FI_SY, DATA, 0, 16)
 135REG32(OCM_EMA, 0x60)
 136    FIELD(OCM_EMA, BANK3, 9, 3)
 137    FIELD(OCM_EMA, BANK2, 6, 3)
 138    FIELD(OCM_EMA, BANK1, 3, 3)
 139    FIELD(OCM_EMA, BANK0, 0, 3)
 140REG32(OCM_EMAW, 0x64)
 141    FIELD(OCM_EMAW, BANK3, 6, 2)
 142    FIELD(OCM_EMAW, BANK2, 4, 2)
 143    FIELD(OCM_EMAW, BANK1, 2, 2)
 144    FIELD(OCM_EMAW, BANK0, 0, 2)
 145REG32(OCM_EMAS, 0x68)
 146    FIELD(OCM_EMAS, BANK3, 3, 1)
 147    FIELD(OCM_EMAS, BANK2, 2, 1)
 148    FIELD(OCM_EMAS, BANK1, 1, 1)
 149    FIELD(OCM_EMAS, BANK0, 0, 1)
 150REG32(OCM_CE_CNT, 0x6c)
 151    FIELD(OCM_CE_CNT, COUNT, 0, 16)
 152REG32(OCM_RMW_UE_FFA, 0x70)
 153    FIELD(OCM_RMW_UE_FFA, ADDR, 0, 18)
 154REG32(OCM_FI_CNTR, 0x74)
 155    FIELD(OCM_FI_CNTR, COUNT, 0, 24)
 156REG32(OCM_DBG_SYN_TOMEM, 0x78)
 157REG32(OCM_DBG_SYN_FROMEM, 0x7c)
 158REG32(OCM_IMP, 0x80)
 159    FIELD(OCM_IMP, SIZE, 0, 4)
 160REG32(OCM_ECO, 0xffc)
 161
 162#define R_MAX (R_OCM_ECO + 1)
 163
 164typedef struct OCMC {
 165    SysBusDevice parent_obj;
 166    MemoryRegion iomem;
 167    qemu_irq irq;
 168
 169    struct {
 170        uint64_t memsize;
 171    } cfg;
 172
 173    uint32_t regs[R_MAX];
 174    RegisterInfo regs_info[R_MAX];
 175} OCMC;
 176
 177static const MemoryRegionOps ocm_ops = {
 178    .read = register_read_memory,
 179    .write = register_write_memory,
 180    .endianness = DEVICE_LITTLE_ENDIAN,
 181    .valid = {
 182        .min_access_size = 4,
 183        .max_access_size = 4,
 184    },
 185};
 186
 187static void ocm_update_irq(OCMC *s)
 188{
 189    bool pending = s->regs[R_OCM_ISR] & s->regs[R_OCM_IMR];
 190    qemu_set_irq(s->irq, pending);
 191}
 192
 193static void ocm_isr_postw(RegisterInfo *reg, uint64_t val64)
 194{
 195    OCMC *s = XILINX_OCM(reg->opaque);
 196    ocm_update_irq(s);
 197}
 198
 199static uint64_t ocm_ien_prew(RegisterInfo *reg, uint64_t val64)
 200{
 201    OCMC *s = XILINX_OCM(reg->opaque);
 202    uint32_t val = val64;
 203
 204    s->regs[R_OCM_IMR] |= val;
 205    ocm_update_irq(s);
 206    return 0;
 207}
 208
 209static uint64_t ocm_ids_prew(RegisterInfo *reg, uint64_t val64)
 210{
 211    OCMC *s = XILINX_OCM(reg->opaque);
 212    uint32_t val = val64;
 213
 214    s->regs[R_OCM_IMR] &= ~val;
 215    ocm_update_irq(s);
 216    return 0;
 217}
 218
 219static const RegisterAccessInfo ocm_regs_info[] = {
 220    {   .name = "OCM_ERR_CTRL",  .addr = A_OCM_ERR_CTRL,
 221        .rsvd = 0xfffffff0,
 222    },{ .name = "OCM_ISR",  .addr = A_OCM_ISR,
 223        .rsvd = 0xfffff800,
 224        .w1c = 0x7ff,
 225        .ro = ~0x7ffull,
 226        .post_write = ocm_isr_postw,
 227    },{ .name = "OCM_IMR",  .addr = A_OCM_IMR,
 228        .reset = 0x7ff,
 229        .rsvd = 0xfffff800,
 230        .ro = 0x7ff,
 231    },{ .name = "OCM_IEN",  .addr = A_OCM_IEN,
 232        .rsvd = 0xfffff800,
 233        .pre_write = ocm_ien_prew,
 234    },{ .name = "OCM_IDS",  .addr = A_OCM_IDS,
 235        .rsvd = 0xfffff800,
 236        .pre_write = ocm_ids_prew,
 237    },{ .name = "OCM_ECC_CNTL",  .addr = A_OCM_ECC_CNTL,
 238        .rsvd = 0xfffffff8,
 239    },{ .name = "OCM_CLR_EXE",  .addr = A_OCM_CLR_EXE,
 240        .rsvd = 0xffffff00,
 241    },{ .name = "OCM_CE_FFA",  .addr = A_OCM_CE_FFA,
 242        .rsvd = 0xfffc0000,
 243        .ro = 0x3ffff,
 244    },{ .name = "OCM_CE_FFD0",  .addr = A_OCM_CE_FFD0,
 245        .ro = 0xffffffff,
 246    },{ .name = "OCM_CE_FFD1",  .addr = A_OCM_CE_FFD1,
 247        .ro = 0xffffffff,
 248    },{ .name = "OCM_CE_FFD2",  .addr = A_OCM_CE_FFD2,
 249        .ro = 0xffffffff,
 250    },{ .name = "OCM_CE_FFD3",  .addr = A_OCM_CE_FFD3,
 251        .ro = 0xffffffff,
 252    },{ .name = "OCM_CE_FFE",  .addr = A_OCM_CE_FFE,
 253        .rsvd = 0xffff0000,
 254        .ro = 0xffff,
 255    },{ .name = "OCM_UE_FFA",  .addr = A_OCM_UE_FFA,
 256        .rsvd = 0xfffc0000,
 257        .ro = 0x3ffff,
 258    },{ .name = "OCM_UE_FFD0",  .addr = A_OCM_UE_FFD0,
 259        .ro = 0xffffffff,
 260    },{ .name = "OCM_UE_FFD1",  .addr = A_OCM_UE_FFD1,
 261        .ro = 0xffffffff,
 262    },{ .name = "OCM_UE_FFD2",  .addr = A_OCM_UE_FFD2,
 263        .ro = 0xffffffff,
 264    },{ .name = "OCM_UE_FFD3",  .addr = A_OCM_UE_FFD3,
 265        .ro = 0xffffffff,
 266    },{ .name = "OCM_UE_FFE",  .addr = A_OCM_UE_FFE,
 267        .rsvd = 0xffff0000,
 268        .ro = 0xffff,
 269    },{ .name = "OCM_FI_D0",  .addr = A_OCM_FI_D0,
 270    },{ .name = "OCM_FI_D1",  .addr = A_OCM_FI_D1,
 271    },{ .name = "OCM_FI_D2",  .addr = A_OCM_FI_D2,
 272    },{ .name = "OCM_FI_D3",  .addr = A_OCM_FI_D3,
 273    },{ .name = "OCM_FI_SY",  .addr = A_OCM_FI_SY,
 274        .rsvd = 0xffff0000,
 275    },{ .name = "OCM_EMA",  .addr = A_OCM_EMA,
 276        .reset = 0x249,
 277        .rsvd = 0xfffff000,
 278    },{ .name = "OCM_EMAW",  .addr = A_OCM_EMAW,
 279        .rsvd = 0xffffff00,
 280    },{ .name = "OCM_EMAS",  .addr = A_OCM_EMAS,
 281        .rsvd = 0xfffffff0,
 282    },{ .name = "OCM_CE_CNT",  .addr = A_OCM_CE_CNT,
 283        .w1c = 0xffff,
 284    },{ .name = "OCM_RMW_UE_FFA",  .addr = A_OCM_RMW_UE_FFA,
 285        .rsvd = 0xfffc0000,
 286        .ro = 0x3ffff,
 287    },{ .name = "OCM_FI_CNTR",  .addr = A_OCM_FI_CNTR,
 288        .rsvd = 0xff000000,
 289    },{ .name = "OCM_DBG_SYN_TOMEM",  .addr = A_OCM_DBG_SYN_TOMEM,
 290        .ro = 0xffffffff,
 291    },{ .name = "OCM_DBG_SYN_FROMEM",  .addr = A_OCM_DBG_SYN_FROMEM,
 292        .ro = 0xffffffff,
 293    },{ .name = "OCM_IMP",  .addr = A_OCM_IMP,
 294        .reset = 0x2,
 295        .ro = 0xf,
 296    },{ .name = "OCM_ECO",  .addr = A_OCM_ECO,
 297    }
 298};
 299
 300static uint32_t ocmc_imp_encode_memsize(OCMC *s, uint64_t memsize)
 301{
 302    const char *prefix = object_get_canonical_path(OBJECT(s));
 303    uint32_t r;
 304
 305    switch (memsize) {
 306    case 64 * 1024:
 307        r = 0;
 308        break;
 309    case 128 * 1024:
 310        r = 1;
 311        break;
 312    case 256 * 1024:
 313        r = 2;
 314        break;
 315    /* 512KB is still to be defined.  */
 316    case 512 * 1024:
 317        qemu_log("%s: WARN: Using an undefined OCM memory size.\n", prefix);
 318        r = 3;
 319        break;
 320    default:
 321        hw_error("%s: Invalid OCM memory size %" PRIu64 " bytes\n",
 322                 prefix, memsize);
 323        break;
 324    }
 325    return r;
 326}
 327
 328static void ocm_reset(DeviceState *dev)
 329{
 330    OCMC *s = XILINX_OCM(dev);
 331    unsigned int i;
 332
 333    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
 334        register_reset(&s->regs_info[i]);
 335    }
 336
 337    s->regs[R_OCM_IMP] = ocmc_imp_encode_memsize(s, s->cfg.memsize);
 338    ocm_update_irq(s);
 339}
 340
 341static void ocm_init(Object *obj)
 342{
 343    OCMC *s = XILINX_OCM(obj);
 344    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 345    RegisterInfoArray *reg_array;
 346
 347    memory_region_init(&s->iomem, obj, TYPE_XILINX_OCM, R_MAX * 4);
 348    reg_array =
 349        register_init_block32(DEVICE(obj), ocm_regs_info,
 350                              ARRAY_SIZE(ocm_regs_info),
 351                              s->regs_info, s->regs,
 352                              &ocm_ops,
 353                              XILINX_OCM_ERR_DEBUG,
 354                              R_MAX * 4);
 355    memory_region_add_subregion(&s->iomem,
 356                                0x0,
 357                                &reg_array->mem);
 358
 359    sysbus_init_mmio(sbd, &s->iomem);
 360    sysbus_init_irq(sbd, &s->irq);
 361}
 362
 363static Property ocmc_properties[] = {
 364    DEFINE_PROP_UINT64("memsize", OCMC, cfg.memsize, 0),
 365    DEFINE_PROP_END_OF_LIST(),
 366};
 367
 368static const VMStateDescription vmstate_ocm = {
 369    .name = TYPE_XILINX_OCM,
 370    .version_id = 1,
 371    .minimum_version_id = 1,
 372    .minimum_version_id_old = 1,
 373    .fields = (VMStateField[]) {
 374        VMSTATE_UINT32_ARRAY(regs, OCMC, R_MAX),
 375        VMSTATE_END_OF_LIST(),
 376    }
 377};
 378
 379static void ocm_class_init(ObjectClass *klass, void *data)
 380{
 381    DeviceClass *dc = DEVICE_CLASS(klass);
 382
 383    dc->reset = ocm_reset;
 384    dc->vmsd = &vmstate_ocm;
 385    device_class_set_props(dc, ocmc_properties);
 386}
 387
 388static const TypeInfo ocm_info = {
 389    .name          = TYPE_XILINX_OCM,
 390    .parent        = TYPE_SYS_BUS_DEVICE,
 391    .instance_size = sizeof(OCMC),
 392    .class_init    = ocm_class_init,
 393    .instance_init = ocm_init,
 394};
 395
 396static void ocm_register_types(void)
 397{
 398    type_register_static(&ocm_info);
 399}
 400
 401type_init(ocm_register_types)
 402