qemu/hw/misc/xlnx-versal-psm-local.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the PSM_LOCAL_REG Power Management Unit Local Register File
   3 *
   4 * Copyright (c) 2018 Xilinx Inc.
   5 *
   6 * Partly autogenerated by xregqemu.py 2018-08-20.
   7 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   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.h"
  31#include "qemu/bitops.h"
  32#include "qemu/log.h"
  33#include "migration/vmstate.h"
  34#include "hw/qdev-properties.h"
  35
  36#include "hw/fdt_generic_util.h"
  37
  38#ifndef XILINX_PSM_LOCAL_REG_ERR_DEBUG
  39#define XILINX_PSM_LOCAL_REG_ERR_DEBUG 0
  40#endif
  41
  42#define TYPE_XILINX_PSM_LOCAL_REG "xlnx.psm-local-reg"
  43
  44#define XILINX_PSM_LOCAL_REG(obj) \
  45     OBJECT_CHECK(PSM_LOCAL_REG, (obj), TYPE_XILINX_PSM_LOCAL_REG)
  46
  47REG32(ACPU0_PWR_CNTRL, 0x0)
  48    FIELD(ACPU0_PWR_CNTRL, ISOLATION, 4, 1)
  49    FIELD(ACPU0_PWR_CNTRL, PWR_GATES, 0, 4)
  50REG32(ACPU0_PWR_STATUS, 0x4)
  51    FIELD(ACPU0_PWR_STATUS, PWR_GATES, 0, 4)
  52REG32(ACPU1_PWR_CNTRL, 0x10)
  53    FIELD(ACPU1_PWR_CNTRL, ISOLATION, 4, 1)
  54    FIELD(ACPU1_PWR_CNTRL, PWR_GATES, 0, 4)
  55REG32(ACPU1_PWR_STATUS, 0x14)
  56    FIELD(ACPU1_PWR_STATUS, PWR_GATES, 0, 4)
  57REG32(RPU_PWR_CNTRL, 0x80)
  58    FIELD(RPU_PWR_CNTRL, ISOLATION, 4, 1)
  59    FIELD(RPU_PWR_CNTRL, PWR_GATES, 0, 4)
  60REG32(RPU_PWR_STATUS, 0x84)
  61    FIELD(RPU_PWR_STATUS, PWR_GATES, 0, 4)
  62REG32(L2_PWR_CNTRL, 0xb0)
  63    FIELD(L2_PWR_CNTRL, BANK0, 0, 1)
  64REG32(L2_CE_CNTRL, 0xb8)
  65    FIELD(L2_CE_CNTRL, BANK0, 0, 1)
  66REG32(L2_PWR_STATUS, 0xbc)
  67    FIELD(L2_PWR_STATUS, BANK0, 0, 1)
  68REG32(OCM_PWR_CNTRL, 0xc0)
  69    FIELD(OCM_PWR_CNTRL, BANK3, 24, 1)
  70    FIELD(OCM_PWR_CNTRL, BANK2, 16, 1)
  71    FIELD(OCM_PWR_CNTRL, BANK1, 8, 1)
  72    FIELD(OCM_PWR_CNTRL, BANK0, 0, 1)
  73REG32(OCM_CE_CNTRL, 0xc8)
  74    FIELD(OCM_CE_CNTRL, BANK3, 3, 1)
  75    FIELD(OCM_CE_CNTRL, BANK2, 2, 1)
  76    FIELD(OCM_CE_CNTRL, BANK1, 1, 1)
  77    FIELD(OCM_CE_CNTRL, BANK0, 0, 1)
  78REG32(OCM_PWR_STATUS, 0xcc)
  79    FIELD(OCM_PWR_STATUS, BANK3, 24, 1)
  80    FIELD(OCM_PWR_STATUS, BANK2, 16, 1)
  81    FIELD(OCM_PWR_STATUS, BANK1, 8, 1)
  82    FIELD(OCM_PWR_STATUS, BANK0, 0, 1)
  83REG32(TCM_PWR_CNTRL, 0xd0)
  84    FIELD(TCM_PWR_CNTRL, TCMB1, 24, 1)
  85    FIELD(TCM_PWR_CNTRL, TCMA1, 16, 1)
  86    FIELD(TCM_PWR_CNTRL, TCMB0, 8, 1)
  87    FIELD(TCM_PWR_CNTRL, TCMA0, 0, 1)
  88REG32(TCM_CE_CNTRL, 0xd8)
  89    FIELD(TCM_CE_CNTRL, TCMB1, 3, 1)
  90    FIELD(TCM_CE_CNTRL, TCMA1, 2, 1)
  91    FIELD(TCM_CE_CNTRL, TCMB0, 1, 1)
  92    FIELD(TCM_CE_CNTRL, TCMA0, 0, 1)
  93REG32(TCM_PWR_STATUS, 0xdc)
  94    FIELD(TCM_PWR_STATUS, TCMB1, 24, 1)
  95    FIELD(TCM_PWR_STATUS, TCMA1, 16, 1)
  96    FIELD(TCM_PWR_STATUS, TCMB0, 8, 1)
  97    FIELD(TCM_PWR_STATUS, TCMA0, 0, 1)
  98REG32(GEM_PWR_CNTRL, 0xe0)
  99    FIELD(GEM_PWR_CNTRL, GEM1, 8, 1)
 100    FIELD(GEM_PWR_CNTRL, GEM0, 0, 1)
 101REG32(GEM_CE_CNTRL, 0xe4)
 102    FIELD(GEM_CE_CNTRL, GEM1, 1, 1)
 103    FIELD(GEM_CE_CNTRL, GEM0, 0, 1)
 104REG32(GEM_PWR_STATUS, 0xe8)
 105    FIELD(GEM_PWR_STATUS, GEM1, 8, 1)
 106    FIELD(GEM_PWR_STATUS, GEM0, 0, 1)
 107REG32(DOMAIN_ISO_CNTRL, 0xf0)
 108    FIELD(DOMAIN_ISO_CNTRL, LPD_OCM2_DFX, 3, 1)
 109    FIELD(DOMAIN_ISO_CNTRL, LPD_OCM2, 2, 1)
 110    FIELD(DOMAIN_ISO_CNTRL, LPD_FPD_DFX, 1, 1)
 111    FIELD(DOMAIN_ISO_CNTRL, LPD_FPD, 0, 1)
 112REG32(LOC_PWR_STATE, 0x100)
 113    FIELD(LOC_PWR_STATE, FP, 22, 1)
 114    FIELD(LOC_PWR_STATE, GEM0, 21, 1)
 115    FIELD(LOC_PWR_STATE, GEM1, 20, 1)
 116    FIELD(LOC_PWR_STATE, OCM_BANK3, 19, 1)
 117    FIELD(LOC_PWR_STATE, OCM_BANK2, 18, 1)
 118    FIELD(LOC_PWR_STATE, OCM_BANK1, 17, 1)
 119    FIELD(LOC_PWR_STATE, OCM_BANK0, 16, 1)
 120    FIELD(LOC_PWR_STATE, TCM1B, 15, 1)
 121    FIELD(LOC_PWR_STATE, TCM1A, 14, 1)
 122    FIELD(LOC_PWR_STATE, TCM0B, 13, 1)
 123    FIELD(LOC_PWR_STATE, TCM0A, 12, 1)
 124    FIELD(LOC_PWR_STATE, R5_1, 11, 1)
 125    FIELD(LOC_PWR_STATE, R5_0, 10, 1)
 126    FIELD(LOC_PWR_STATE, L2_BANK0, 7, 1)
 127    FIELD(LOC_PWR_STATE, ACPU1, 1, 1)
 128    FIELD(LOC_PWR_STATE, ACPU0, 0, 1)
 129REG32(LOC_AUX_PWR_STATE, 0x104)
 130    FIELD(LOC_AUX_PWR_STATE, ACPU1_EMUL, 29, 1)
 131    FIELD(LOC_AUX_PWR_STATE, ACPU0_EMUL, 28, 1)
 132    FIELD(LOC_AUX_PWR_STATE, RPU_EMUL, 27, 1)
 133    FIELD(LOC_AUX_PWR_STATE, OCM_BANK3, 19, 1)
 134    FIELD(LOC_AUX_PWR_STATE, OCM_BANK2, 18, 1)
 135    FIELD(LOC_AUX_PWR_STATE, OCM_BANK1, 17, 1)
 136    FIELD(LOC_AUX_PWR_STATE, OCM_BANK0, 16, 1)
 137    FIELD(LOC_AUX_PWR_STATE, TCM1B, 15, 1)
 138    FIELD(LOC_AUX_PWR_STATE, TCM1A, 14, 1)
 139    FIELD(LOC_AUX_PWR_STATE, TCM0B, 13, 1)
 140    FIELD(LOC_AUX_PWR_STATE, TCM0A, 12, 1)
 141    FIELD(LOC_AUX_PWR_STATE, L2, 7, 1)
 142REG32(LOCAL_GEN_STORAGE0, 0x300)
 143REG32(LOCAL_GEN_STORAGE1, 0x304)
 144REG32(LOCAL_GEN_STORAGE2, 0x308)
 145REG32(LOCAL_GEN_STORAGE3, 0x30c)
 146REG32(PERS_LOC_GEN_STORAGE0, 0x310)
 147REG32(PERS_LOC_GEN_STORAGE1, 0x314)
 148REG32(PERS_LOC_GEN_STORAGE2, 0x318)
 149REG32(PERS_LOC_GEN_STORAGE3, 0x31c)
 150REG32(ADDR_ERROR_STATUS, 0x320)
 151    FIELD(ADDR_ERROR_STATUS, STATUS, 0, 1)
 152REG32(ADDR_ERROR_INT_MASK, 0x324)
 153    FIELD(ADDR_ERROR_INT_MASK, MASK, 0, 1)
 154REG32(ADDR_ERROR_INT_EN, 0x328)
 155    FIELD(ADDR_ERROR_INT_EN, EN, 0, 1)
 156REG32(ADDR_ERROR_INT_DIS, 0x32c)
 157    FIELD(ADDR_ERROR_INT_DIS, DIS, 0, 1)
 158REG32(APU_WFI_STATUS, 0x418)
 159    FIELD(APU_WFI_STATUS, L2_WFI, 16, 1)
 160    FIELD(APU_WFI_STATUS, ACPU1_WFI, 1, 1)
 161    FIELD(APU_WFI_STATUS, ACPU0_WFI, 0, 1)
 162REG32(SCAN_CLEAR_CPU0, 0x500)
 163    FIELD(SCAN_CLEAR_CPU0, PASS, 2, 1)
 164    FIELD(SCAN_CLEAR_CPU0, DONE, 1, 1)
 165    FIELD(SCAN_CLEAR_CPU0, TRIGGER, 0, 1)
 166REG32(SCAN_CLEAR_CPU1, 0x504)
 167    FIELD(SCAN_CLEAR_CPU1, PASS, 2, 1)
 168    FIELD(SCAN_CLEAR_CPU1, DONE, 1, 1)
 169    FIELD(SCAN_CLEAR_CPU1, TRIGGER, 0, 1)
 170REG32(SCAN_CLEAR_APU, 0x508)
 171    FIELD(SCAN_CLEAR_APU, PASS, 2, 1)
 172    FIELD(SCAN_CLEAR_APU, DONE, 1, 1)
 173    FIELD(SCAN_CLEAR_APU, TRIGGER, 0, 1)
 174REG32(SCAN_CLEAR_FPD, 0x50c)
 175    FIELD(SCAN_CLEAR_FPD, PASS, 2, 1)
 176    FIELD(SCAN_CLEAR_FPD, DONE, 1, 1)
 177    FIELD(SCAN_CLEAR_FPD, TRIGGER, 0, 1)
 178REG32(MBISR_CNTRL, 0x510)
 179    FIELD(MBISR_CNTRL, FPD_GROUP, 5, 1)
 180    FIELD(MBISR_CNTRL, ENABLE, 0, 1)
 181REG32(MBISR_STATUS, 0x514)
 182    FIELD(MBISR_STATUS, PASS, 4, 1)
 183    FIELD(MBISR_STATUS, DONE, 0, 1)
 184REG32(MBIST_RST, 0x518)
 185    FIELD(MBIST_RST, FPD, 1, 1)
 186    FIELD(MBIST_RST, LPD, 0, 1)
 187REG32(MBIST_PG_EN, 0x51c)
 188    FIELD(MBIST_PG_EN, FPD, 1, 1)
 189    FIELD(MBIST_PG_EN, LPD, 0, 1)
 190REG32(MBIST_SETUP, 0x520)
 191    FIELD(MBIST_SETUP, FPD, 1, 1)
 192    FIELD(MBIST_SETUP, LPD, 0, 1)
 193REG32(MBIST_DONE, 0x524)
 194    FIELD(MBIST_DONE, FPD, 1, 1)
 195    FIELD(MBIST_DONE, LPD, 0, 1)
 196REG32(MBIST_GOOD, 0x528)
 197    FIELD(MBIST_GOOD, FPD, 1, 1)
 198    FIELD(MBIST_GOOD, LPD, 0, 1)
 199REG32(PSM_GLOBAL_APB, 0x600)
 200    FIELD(PSM_GLOBAL_APB, RST_N, 4, 1)
 201    FIELD(PSM_GLOBAL_APB, POWER_IDLEREQ, 3, 1)
 202    FIELD(PSM_GLOBAL_APB, POWER_IDLEACK, 2, 1)
 203    FIELD(PSM_GLOBAL_APB, POWER_IDLE, 1, 1)
 204    FIELD(PSM_GLOBAL_APB, MAINEXTEN, 0, 1)
 205
 206#define PSM_LOCAL_REG_R_MAX (R_PSM_GLOBAL_APB + 1)
 207
 208typedef struct PSM_LOCAL_REG {
 209    SysBusDevice parent_obj;
 210    MemoryRegion iomem;
 211    qemu_irq irq_addr_error_int;
 212
 213    qemu_irq pwr_acpu0[4];
 214    qemu_irq pwr_acpu1[4];
 215    qemu_irq pwr_rpu[4];
 216    qemu_irq pwr_l2;
 217    qemu_irq pwr_ocm[4];
 218    qemu_irq pwr_tcm_a[2];
 219    qemu_irq pwr_tcm_b[2];
 220    qemu_irq pwr_gem[2];
 221
 222    qemu_irq loc_pwr_state[32];
 223    qemu_irq loc_aux_pwr_state[32];
 224    qemu_irq apu_sleep[4];
 225    qemu_irq apu_pwrdw_status[4];
 226
 227    bool has_por;
 228    uint8_t apu_pwrdw_req;
 229
 230    uint32_t regs[PSM_LOCAL_REG_R_MAX];
 231    RegisterInfo regs_info[PSM_LOCAL_REG_R_MAX];
 232} PSM_LOCAL_REG;
 233
 234#define PROPAGATE_FIELD1(s, sreg, sf, dreg, df, irq) {           \
 235    unsigned int val = ARRAY_FIELD_EX32((s)->regs, sreg, sf);    \
 236    ARRAY_FIELD_DP32((s)->regs, dreg, df, val);                  \
 237    qemu_set_irq(irq, val);                                      \
 238}
 239
 240#define PROPAGATE_FIELD(s, sreg, sf, dreg, df, irq) {            \
 241    unsigned int val = ARRAY_FIELD_EX32((s)->regs, sreg, sf);    \
 242    unsigned int i;                                              \
 243                                                                 \
 244    ARRAY_FIELD_DP32((s)->regs, dreg, df, val);                  \
 245    assert(ARRAY_SIZE(irq) == R_ ## sreg ## _ ## sf ## _LENGTH); \
 246    for (i = 0; i < R_ ## sreg ## _ ## sf ## _LENGTH; i++) {     \
 247        qemu_set_irq(irq[i], (val >> i) & 1);                    \
 248    }                                                            \
 249}
 250
 251#define PROPAGATE_REG32(s, reg, irq) {                           \
 252    unsigned int val = (s)->regs[R_ ## reg];                     \
 253    unsigned int i;                                              \
 254                                                                 \
 255    assert(ARRAY_SIZE(irq) == sizeof((s)->regs[0]) * 8);         \
 256    for (i = 0; i < sizeof((s)->regs[0]) * 8; i++) {             \
 257        qemu_set_irq(irq[i], (val >> i) & 1);                    \
 258    }                                                            \
 259}
 260
 261static void update_pwr_status(PSM_LOCAL_REG *s)
 262{
 263    PROPAGATE_FIELD(s, ACPU0_PWR_CNTRL, PWR_GATES,
 264                       ACPU0_PWR_STATUS, PWR_GATES, s->pwr_acpu0);
 265    PROPAGATE_FIELD(s, ACPU1_PWR_CNTRL, PWR_GATES,
 266                       ACPU1_PWR_STATUS, PWR_GATES, s->pwr_acpu1);
 267    PROPAGATE_FIELD(s, RPU_PWR_CNTRL, PWR_GATES, RPU_PWR_STATUS, PWR_GATES,
 268                    s->pwr_rpu);
 269
 270    PROPAGATE_FIELD1(s, L2_PWR_CNTRL, BANK0, L2_PWR_STATUS, BANK0,
 271                     s->pwr_l2);
 272
 273    PROPAGATE_FIELD1(s, OCM_PWR_CNTRL, BANK0, OCM_PWR_STATUS, BANK0,
 274                     s->pwr_ocm[0]);
 275    PROPAGATE_FIELD1(s, OCM_PWR_CNTRL, BANK1, OCM_PWR_STATUS, BANK1,
 276                     s->pwr_ocm[1]);
 277    PROPAGATE_FIELD1(s, OCM_PWR_CNTRL, BANK2, OCM_PWR_STATUS, BANK2,
 278                     s->pwr_ocm[2]);
 279    PROPAGATE_FIELD1(s, OCM_PWR_CNTRL, BANK3, OCM_PWR_STATUS, BANK3,
 280                     s->pwr_ocm[3]);
 281
 282    PROPAGATE_FIELD1(s, TCM_PWR_CNTRL, TCMA0, TCM_PWR_STATUS, TCMA0,
 283                     s->pwr_tcm_a[0]);
 284    PROPAGATE_FIELD1(s, TCM_PWR_CNTRL, TCMB0, TCM_PWR_STATUS, TCMB0,
 285                     s->pwr_tcm_b[0]);
 286    PROPAGATE_FIELD1(s, TCM_PWR_CNTRL, TCMA1, TCM_PWR_STATUS, TCMA1,
 287                     s->pwr_tcm_a[1]);
 288    PROPAGATE_FIELD1(s, TCM_PWR_CNTRL, TCMB1, TCM_PWR_STATUS, TCMB1,
 289                     s->pwr_tcm_b[1]);
 290    PROPAGATE_FIELD1(s, GEM_PWR_CNTRL, GEM0, GEM_PWR_STATUS, GEM0,
 291                     s->pwr_gem[0]);
 292    PROPAGATE_FIELD1(s, GEM_PWR_CNTRL, GEM1, GEM_PWR_STATUS, GEM1,
 293                     s->pwr_gem[1]);
 294}
 295
 296static void update_loc_pwr_state(PSM_LOCAL_REG *s)
 297{
 298    int i;
 299    PROPAGATE_REG32(s, LOC_PWR_STATE, s->loc_pwr_state);
 300    PROPAGATE_REG32(s, LOC_AUX_PWR_STATE, s->loc_aux_pwr_state);
 301
 302    /*
 303     * Send apu powerdown signals to intc-redirect
 304     */
 305    for (i = 0; i < 4; i++) {
 306        qemu_set_irq(s->apu_pwrdw_status[i],
 307              !(s->regs[R_LOC_PWR_STATE] & (1 << i)));
 308    }
 309}
 310
 311static void addr_error_int_update_irq(PSM_LOCAL_REG *s)
 312{
 313    bool pending;
 314
 315    pending = s->regs[R_ADDR_ERROR_STATUS] & ~s->regs[R_ADDR_ERROR_INT_MASK];
 316    qemu_set_irq(s->irq_addr_error_int, pending);
 317}
 318
 319static void addr_error_status_postw(RegisterInfo *reg, uint64_t val64)
 320{
 321    PSM_LOCAL_REG *s = XILINX_PSM_LOCAL_REG(reg->opaque);
 322    addr_error_int_update_irq(s);
 323}
 324
 325static uint64_t addr_error_int_en_prew(RegisterInfo *reg, uint64_t val64)
 326{
 327    PSM_LOCAL_REG *s = XILINX_PSM_LOCAL_REG(reg->opaque);
 328    uint32_t val = val64;
 329
 330    s->regs[R_ADDR_ERROR_INT_MASK] &= ~val;
 331    addr_error_int_update_irq(s);
 332    return 0;
 333}
 334
 335static uint64_t addr_error_int_dis_prew(RegisterInfo *reg, uint64_t val64)
 336{
 337    PSM_LOCAL_REG *s = XILINX_PSM_LOCAL_REG(reg->opaque);
 338    uint32_t val = val64;
 339
 340    s->regs[R_ADDR_ERROR_INT_MASK] |= val;
 341    addr_error_int_update_irq(s);
 342    return 0;
 343}
 344
 345static void pwr_cntrl_postw(RegisterInfo *reg, uint64_t val64)
 346{
 347    PSM_LOCAL_REG *s = XILINX_PSM_LOCAL_REG(reg->opaque);
 348    update_pwr_status(s);
 349}
 350
 351static void loc_pwr_state_postw(RegisterInfo *reg, uint64_t val64)
 352{
 353    PSM_LOCAL_REG *s = XILINX_PSM_LOCAL_REG(reg->opaque);
 354    update_loc_pwr_state(s);
 355}
 356
 357static const RegisterAccessInfo psm_local_reg_regs_info[] = {
 358    {   .name = "ACPU0_PWR_CNTRL",  .addr = A_ACPU0_PWR_CNTRL,
 359        .reset = 0xf,
 360        .rsvd = 0xffffffe0,
 361        .ro = 0xffffffe0,
 362        .post_write = pwr_cntrl_postw,
 363    },{ .name = "ACPU0_PWR_STATUS",  .addr = A_ACPU0_PWR_STATUS,
 364        .reset = 0xf,
 365        .rsvd = 0xfffffff0,
 366        .ro = 0xffffffff,
 367    },{ .name = "ACPU1_PWR_CNTRL",  .addr = A_ACPU1_PWR_CNTRL,
 368        .reset = 0xf,
 369        .rsvd = 0xffffffe0,
 370        .ro = 0xffffffe0,
 371        .post_write = pwr_cntrl_postw,
 372    },{ .name = "ACPU1_PWR_STATUS",  .addr = A_ACPU1_PWR_STATUS,
 373        .reset = 0xf,
 374        .rsvd = 0xfffffff0,
 375        .ro = 0xffffffff,
 376        .post_write = pwr_cntrl_postw,
 377    },{ .name = "RPU_PWR_CNTRL",  .addr = A_RPU_PWR_CNTRL,
 378        .reset = 0xf,
 379        .rsvd = 0xffffffe0,
 380        .ro = 0xffffffe0,
 381        .post_write = pwr_cntrl_postw,
 382    },{ .name = "RPU_PWR_STATUS",  .addr = A_RPU_PWR_STATUS,
 383        .reset = 0xf,
 384        .rsvd = 0xfffffff0,
 385        .ro = 0xffffffff,
 386    },{ .name = "L2_PWR_CNTRL",  .addr = A_L2_PWR_CNTRL,
 387        .reset = 0x1,
 388        .rsvd = 0xfffffffe,
 389        .ro = 0xfffffffe,
 390        .post_write = pwr_cntrl_postw,
 391    },{ .name = "L2_CE_CNTRL",  .addr = A_L2_CE_CNTRL,
 392        .reset = 0x1,
 393        .rsvd = 0xfffffffe,
 394        .ro = 0xfffffffe,
 395    },{ .name = "L2_PWR_STATUS",  .addr = A_L2_PWR_STATUS,
 396        .reset = 0x1,
 397        .rsvd = 0xfffffffe,
 398        .ro = 0xffffffff,
 399    },{ .name = "OCM_PWR_CNTRL",  .addr = A_OCM_PWR_CNTRL,
 400        .reset = 0x1010101,
 401        .rsvd = 0xfefefefe,
 402        .ro = 0xfefefefe,
 403        .post_write = pwr_cntrl_postw,
 404    },{ .name = "OCM_CE_CNTRL",  .addr = A_OCM_CE_CNTRL,
 405        .reset = 0xf,
 406        .rsvd = 0xfffffff0,
 407        .ro = 0xfffffff0,
 408    },{ .name = "OCM_PWR_STATUS",  .addr = A_OCM_PWR_STATUS,
 409        .reset = 0x1010101,
 410        .rsvd = 0xfefefefe,
 411        .ro = 0xffffffff,
 412    },{ .name = "TCM_PWR_CNTRL",  .addr = A_TCM_PWR_CNTRL,
 413        .reset = 0x1010101,
 414        .rsvd = 0xfefefefe,
 415        .ro = 0xfefefefe,
 416        .post_write = pwr_cntrl_postw,
 417    },{ .name = "TCM_CE_CNTRL",  .addr = A_TCM_CE_CNTRL,
 418        .reset = 0xf,
 419        .rsvd = 0xfffffff0,
 420        .ro = 0xfffffff0,
 421    },{ .name = "TCM_PWR_STATUS",  .addr = A_TCM_PWR_STATUS,
 422        .reset = 0x1010101,
 423        .rsvd = 0xfefefefe,
 424        .ro = 0xffffffff,
 425    },{ .name = "GEM_PWR_CNTRL",  .addr = A_GEM_PWR_CNTRL,
 426        .reset = 0x101,
 427        .rsvd = 0xfffffefe,
 428        .ro = 0xfffffefe,
 429        .post_write = pwr_cntrl_postw,
 430    },{ .name = "GEM_CE_CNTRL",  .addr = A_GEM_CE_CNTRL,
 431        .reset = 0x3,
 432        .rsvd = 0xfffffffc,
 433        .ro = 0xfffffffc,
 434    },{ .name = "GEM_PWR_STATUS",  .addr = A_GEM_PWR_STATUS,
 435        .reset = 0x101,
 436        .rsvd = 0xfffffefe,
 437        .ro = 0xffffffff,
 438    },{ .name = "DOMAIN_ISO_CNTRL",  .addr = A_DOMAIN_ISO_CNTRL,
 439        .reset = 0x1f,
 440        .rsvd = 0xfffffff0,
 441        .ro = 0xfffffff0,
 442    },{ .name = "LOC_PWR_STATE",  .addr = A_LOC_PWR_STATE,
 443        .reset = 0xfffd87,
 444        .rsvd = 0xff80037c,
 445        .post_write = loc_pwr_state_postw,
 446    },{ .name = "LOC_AUX_PWR_STATE",  .addr = A_LOC_AUX_PWR_STATE,
 447        .reset = 0xff080,
 448        .rsvd = 0xc7f00f7f,
 449        .ro = 0xc7f00f7f,
 450        .post_write = loc_pwr_state_postw,
 451    },{ .name = "LOCAL_GEN_STORAGE0",  .addr = A_LOCAL_GEN_STORAGE0,
 452    },{ .name = "LOCAL_GEN_STORAGE1",  .addr = A_LOCAL_GEN_STORAGE1,
 453    },{ .name = "LOCAL_GEN_STORAGE2",  .addr = A_LOCAL_GEN_STORAGE2,
 454    },{ .name = "LOCAL_GEN_STORAGE3",  .addr = A_LOCAL_GEN_STORAGE3,
 455    },{ .name = "PERS_LOC_GEN_STORAGE0",  .addr = A_PERS_LOC_GEN_STORAGE0,
 456    },{ .name = "PERS_LOC_GEN_STORAGE1",  .addr = A_PERS_LOC_GEN_STORAGE1,
 457    },{ .name = "PERS_LOC_GEN_STORAGE2",  .addr = A_PERS_LOC_GEN_STORAGE2,
 458    },{ .name = "PERS_LOC_GEN_STORAGE3",  .addr = A_PERS_LOC_GEN_STORAGE3,
 459    },{ .name = "ADDR_ERROR_STATUS",  .addr = A_ADDR_ERROR_STATUS,
 460        .w1c = 0x1,
 461        .post_write = addr_error_status_postw,
 462    },{ .name = "ADDR_ERROR_INT_MASK",  .addr = A_ADDR_ERROR_INT_MASK,
 463        .reset = 0x1,
 464        .ro = 0x1,
 465    },{ .name = "ADDR_ERROR_INT_EN",  .addr = A_ADDR_ERROR_INT_EN,
 466        .pre_write = addr_error_int_en_prew,
 467    },{ .name = "ADDR_ERROR_INT_DIS",  .addr = A_ADDR_ERROR_INT_DIS,
 468        .pre_write = addr_error_int_dis_prew,
 469    },{ .name = "APU_WFI_STATUS",  .addr = A_APU_WFI_STATUS,
 470        .reset = 0x10003,
 471        .rsvd = 0xfffefffc,
 472        .ro = 0xffffffff,
 473    },{ .name = "SCAN_CLEAR_CPU0",  .addr = A_SCAN_CLEAR_CPU0,
 474        .rsvd = 0xfffffff8,
 475        .ro = 0xfffffffe,
 476        .reset = R_SCAN_CLEAR_CPU0_PASS_MASK | R_SCAN_CLEAR_CPU0_DONE_MASK,
 477    },{ .name = "SCAN_CLEAR_CPU1",  .addr = A_SCAN_CLEAR_CPU1,
 478        .rsvd = 0xfffffff8,
 479        .ro = 0xfffffffe,
 480        .reset = R_SCAN_CLEAR_CPU1_PASS_MASK | R_SCAN_CLEAR_CPU1_DONE_MASK,
 481    },{ .name = "SCAN_CLEAR_APU",  .addr = A_SCAN_CLEAR_APU,
 482        .rsvd = 0xfffffff8,
 483        .ro = 0xfffffffe,
 484        .reset = R_SCAN_CLEAR_APU_PASS_MASK | R_SCAN_CLEAR_APU_DONE_MASK,
 485    },{ .name = "SCAN_CLEAR_FPD",  .addr = A_SCAN_CLEAR_FPD,
 486        .rsvd = 0xfffffff8,
 487        .ro = 0xfffffffe,
 488        .reset = R_SCAN_CLEAR_FPD_PASS_MASK | R_SCAN_CLEAR_FPD_DONE_MASK,
 489    },{ .name = "MBISR_CNTRL",  .addr = A_MBISR_CNTRL,
 490        .rsvd = 0xffffffde,
 491        .ro = 0xffffffde,
 492    },{ .name = "MBISR_STATUS",  .addr = A_MBISR_STATUS,
 493        .rsvd = 0xffffffee,
 494        .ro = 0xffffffff,
 495        .reset = R_MBISR_STATUS_PASS_MASK | R_MBISR_STATUS_DONE_MASK,
 496    },{ .name = "MBIST_RST",  .addr = A_MBIST_RST,
 497    },{ .name = "MBIST_PG_EN",  .addr = A_MBIST_PG_EN,
 498    },{ .name = "MBIST_SETUP",  .addr = A_MBIST_SETUP,
 499    },{ .name = "MBIST_DONE",  .addr = A_MBIST_DONE,
 500        .ro = 0x3,
 501    },{ .name = "MBIST_GOOD",  .addr = A_MBIST_GOOD,
 502        .ro = 0x3,
 503    },{ .name = "PSM_GLOBAL_APB",  .addr = A_PSM_GLOBAL_APB,
 504        .reset = 0x16,
 505        .rsvd = 0xffffffe0,
 506        .ro = 0x6,
 507    }
 508};
 509
 510static void psm_local_reg_reset(DeviceState *dev)
 511{
 512    PSM_LOCAL_REG *s = XILINX_PSM_LOCAL_REG(dev);
 513    unsigned int i;
 514
 515    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
 516        /*
 517         * Most registers in this blocks are preserved across warm resets.
 518         */
 519        switch (i) {
 520        case R_LOCAL_GEN_STORAGE0...R_LOCAL_GEN_STORAGE3:
 521        case R_ADDR_ERROR_STATUS...R_ADDR_ERROR_INT_DIS:
 522            if (!s->has_por) {
 523                register_reset(&s->regs_info[i]);
 524            }
 525            break;
 526        default:
 527            register_reset(&s->regs_info[i]);
 528            break;
 529        }
 530    }
 531
 532    addr_error_int_update_irq(s);
 533    update_pwr_status(s);
 534    update_loc_pwr_state(s);
 535
 536    s->has_por = true;
 537}
 538
 539static const MemoryRegionOps psm_local_reg_ops = {
 540    .read = register_read_memory,
 541    .write = register_write_memory,
 542    .endianness = DEVICE_LITTLE_ENDIAN,
 543    .valid = {
 544        .min_access_size = 4,
 545        .max_access_size = 4,
 546    },
 547};
 548
 549static void update_apu_sleep(PSM_LOCAL_REG *s)
 550{
 551    int i;
 552
 553    for (i = 0; i < 4; i++) {
 554        if ((s->apu_pwrdw_req &
 555            s->regs[R_APU_WFI_STATUS]) &
 556            (1 << i)) {
 557            qemu_irq_pulse(s->apu_sleep[i]);
 558        }
 559    }
 560}
 561
 562static void apu_wfi_h(void *opaque, int n, int level)
 563{
 564    PSM_LOCAL_REG *s = XILINX_PSM_LOCAL_REG(opaque);
 565
 566    switch (n) {
 567    case 0:
 568        ARRAY_FIELD_DP32(s->regs, APU_WFI_STATUS, ACPU0_WFI, !!level);
 569        break;
 570    case 1:
 571        ARRAY_FIELD_DP32(s->regs, APU_WFI_STATUS, ACPU1_WFI, !!level);
 572        break;
 573    case 4:
 574        ARRAY_FIELD_DP32(s->regs, APU_WFI_STATUS, L2_WFI, !!level);
 575        break;
 576    default:
 577        g_assert_not_reached();
 578    }
 579
 580    update_apu_sleep(s);
 581}
 582
 583static void apu_pwrdw_h(void *opaque, int n, int level)
 584{
 585    PSM_LOCAL_REG *s = XILINX_PSM_LOCAL_REG(opaque);
 586
 587    s->apu_pwrdw_req &= ~(1 << n);
 588    s->apu_pwrdw_req |= (level << n);
 589
 590    update_apu_sleep(s);
 591}
 592
 593static void psm_local_reg_init(Object *obj)
 594{
 595    PSM_LOCAL_REG *s = XILINX_PSM_LOCAL_REG(obj);
 596    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 597    RegisterInfoArray *reg_array;
 598
 599    memory_region_init(&s->iomem, obj, TYPE_XILINX_PSM_LOCAL_REG,
 600                       PSM_LOCAL_REG_R_MAX * 4);
 601    reg_array =
 602        register_init_block32(DEVICE(obj), psm_local_reg_regs_info,
 603                              ARRAY_SIZE(psm_local_reg_regs_info),
 604                              s->regs_info, s->regs,
 605                              &psm_local_reg_ops,
 606                              XILINX_PSM_LOCAL_REG_ERR_DEBUG,
 607                              PSM_LOCAL_REG_R_MAX * 4);
 608    memory_region_add_subregion(&s->iomem,
 609                                0x0,
 610                                &reg_array->mem);
 611    sysbus_init_mmio(sbd, &s->iomem);
 612    sysbus_init_irq(sbd, &s->irq_addr_error_int);
 613
 614    qdev_init_gpio_out_named(DEVICE(obj), s->pwr_acpu0, "pwr-acpu0", 4);
 615    qdev_init_gpio_out_named(DEVICE(obj), s->pwr_acpu1, "pwr-acpu1", 4);
 616    qdev_init_gpio_out_named(DEVICE(obj), s->pwr_rpu, "pwr-rpu", 4);
 617
 618    qdev_init_gpio_out_named(DEVICE(obj), &s->pwr_l2, "pwr-l2", 1);
 619    qdev_init_gpio_out_named(DEVICE(obj), s->pwr_ocm, "pwr-ocm", 4);
 620
 621    qdev_init_gpio_out_named(DEVICE(obj), &s->pwr_tcm_a[0], "pwr-tcm-a0", 1);
 622    qdev_init_gpio_out_named(DEVICE(obj), &s->pwr_tcm_b[0], "pwr-tcm-b0", 1);
 623    qdev_init_gpio_out_named(DEVICE(obj), &s->pwr_tcm_a[1], "pwr-tcm-a1", 1);
 624    qdev_init_gpio_out_named(DEVICE(obj), &s->pwr_tcm_b[1], "pwr-tcm-b1", 1);
 625
 626    qdev_init_gpio_out_named(DEVICE(obj), s->pwr_gem, "pwr-gem", 2);
 627
 628    qdev_init_gpio_out_named(DEVICE(obj), s->loc_pwr_state,
 629                             "loc-pwr-state", 32);
 630    qdev_init_gpio_out_named(DEVICE(obj), s->loc_aux_pwr_state,
 631                             "loc-aux-pwr-state", 32);
 632
 633    qdev_init_gpio_in_named(DEVICE(obj), apu_wfi_h, "apu-wfi", 5);
 634    qdev_init_gpio_in_named(DEVICE(obj), apu_pwrdw_h, "apu-pwrdw", 4);
 635    qdev_init_gpio_out_named(DEVICE(obj), s->apu_sleep, "apu-sleep", 4);
 636    qdev_init_gpio_out_named(DEVICE(obj), s->apu_pwrdw_status,
 637                             "apu-pwrdw-status", 4);
 638}
 639
 640static const VMStateDescription vmstate_psm_local_reg = {
 641    .name = TYPE_XILINX_PSM_LOCAL_REG,
 642    .version_id = 1,
 643    .minimum_version_id = 1,
 644    .fields = (VMStateField[]) {
 645        VMSTATE_UINT32_ARRAY(regs, PSM_LOCAL_REG, PSM_LOCAL_REG_R_MAX),
 646        VMSTATE_END_OF_LIST(),
 647    }
 648};
 649
 650static const FDTGenericGPIOSet psm_local_reg_gpios[] = {
 651    {
 652      .names = &fdt_generic_gpio_name_set_gpio,
 653      .gpios = (FDTGenericGPIOConnection[]) {
 654        { .name = "pwr-acpu0", .fdt_index = 0, .range = 4 },
 655        { .name = "pwr-acpu1", .fdt_index = 4, .range = 4 },
 656        { .name = "pwr-rpu", .fdt_index = 8, .range = 4 },
 657        { .name = "pwr-l2", .fdt_index = 12, .range = 1 },
 658        { .name = "pwr-ocm", .fdt_index = 13, .range = 4 },
 659        { .name = "pwr-tcm-a0", .fdt_index = 17, .range = 1 },
 660        { .name = "pwr-tcm-b0", .fdt_index = 18, .range = 1 },
 661        { .name = "pwr-tcm-a1", .fdt_index = 19, .range = 1 },
 662        { .name = "pwr-tcm-b1", .fdt_index = 20, .range = 1 },
 663        /* These control the GEM RAMs.  */
 664        { .name = "pwr-gem", .fdt_index = 21, .range = 2 },
 665        { .name = "apu-wfi", .fdt_index = 24, .range = 5 },
 666        { .name = "loc-pwr-state", .fdt_index = 32, .range = 32 },
 667        { .name = "loc-aux-pwr-state", .fdt_index = 64, .range = 32 },
 668        { .name = "apu-sleep", .fdt_index = 96, .range = 4 },
 669        { .name = "apu-pwrdw-status", .fdt_index = 100, .range = 4 },
 670        { },
 671      },
 672    },
 673    { },
 674};
 675
 676static const FDTGenericGPIOSet psm_local_reg_client_gpios[] = {
 677    {
 678      .names = &fdt_generic_gpio_name_set_gpio,
 679      .gpios = (FDTGenericGPIOConnection[]) {
 680        { .name = "apu-pwrdw", .fdt_index = 0, .range = 4 },
 681        { },
 682      },
 683    },
 684    { },
 685};
 686
 687static void psm_local_reg_class_init(ObjectClass *klass, void *data)
 688{
 689    DeviceClass *dc = DEVICE_CLASS(klass);
 690    FDTGenericGPIOClass *fggc = FDT_GENERIC_GPIO_CLASS(klass);
 691
 692    dc->reset = psm_local_reg_reset;
 693    dc->vmsd = &vmstate_psm_local_reg;
 694    fggc->controller_gpios = psm_local_reg_gpios;
 695    fggc->client_gpios = psm_local_reg_client_gpios;
 696}
 697
 698static const TypeInfo psm_local_reg_info = {
 699    .name          = TYPE_XILINX_PSM_LOCAL_REG,
 700    .parent        = TYPE_SYS_BUS_DEVICE,
 701    .instance_size = sizeof(PSM_LOCAL_REG),
 702    .class_init    = psm_local_reg_class_init,
 703    .instance_init = psm_local_reg_init,
 704    .interfaces    = (InterfaceInfo[]) {
 705        { TYPE_FDT_GENERIC_GPIO },
 706        { }
 707    },
 708};
 709
 710static void psm_local_reg_register_types(void)
 711{
 712    type_register_static(&psm_local_reg_info);
 713}
 714
 715type_init(psm_local_reg_register_types)
 716