qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xlnx-versal-crl.c (13450B)


      1 /*
      2  * QEMU model of the Clock-Reset-LPD (CRL).
      3  *
      4  * Copyright (c) 2022 Advanced Micro Devices, Inc.
      5  * SPDX-License-Identifier: GPL-2.0-or-later
      6  *
      7  * Written by Edgar E. Iglesias <edgar.iglesias@amd.com>
      8  */
      9 
     10 #include "qemu/osdep.h"
     11 #include "qapi/error.h"
     12 #include "qemu/log.h"
     13 #include "qemu/bitops.h"
     14 #include "migration/vmstate.h"
     15 #include "hw/qdev-properties.h"
     16 #include "hw/sysbus.h"
     17 #include "hw/irq.h"
     18 #include "hw/register.h"
     19 #include "hw/resettable.h"
     20 
     21 #include "target/arm/arm-powerctl.h"
     22 #include "hw/misc/xlnx-versal-crl.h"
     23 
     24 #ifndef XLNX_VERSAL_CRL_ERR_DEBUG
     25 #define XLNX_VERSAL_CRL_ERR_DEBUG 0
     26 #endif
     27 
     28 static void crl_update_irq(XlnxVersalCRL *s)
     29 {
     30     bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK];
     31     qemu_set_irq(s->irq, pending);
     32 }
     33 
     34 static void crl_status_postw(RegisterInfo *reg, uint64_t val64)
     35 {
     36     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
     37     crl_update_irq(s);
     38 }
     39 
     40 static uint64_t crl_enable_prew(RegisterInfo *reg, uint64_t val64)
     41 {
     42     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
     43     uint32_t val = val64;
     44 
     45     s->regs[R_IR_MASK] &= ~val;
     46     crl_update_irq(s);
     47     return 0;
     48 }
     49 
     50 static uint64_t crl_disable_prew(RegisterInfo *reg, uint64_t val64)
     51 {
     52     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
     53     uint32_t val = val64;
     54 
     55     s->regs[R_IR_MASK] |= val;
     56     crl_update_irq(s);
     57     return 0;
     58 }
     59 
     60 static void crl_reset_dev(XlnxVersalCRL *s, DeviceState *dev,
     61                           bool rst_old, bool rst_new)
     62 {
     63     device_cold_reset(dev);
     64 }
     65 
     66 static void crl_reset_cpu(XlnxVersalCRL *s, ARMCPU *armcpu,
     67                           bool rst_old, bool rst_new)
     68 {
     69     if (rst_new) {
     70         arm_set_cpu_off(armcpu->mp_affinity);
     71     } else {
     72         arm_set_cpu_on_and_reset(armcpu->mp_affinity);
     73     }
     74 }
     75 
     76 #define REGFIELD_RESET(type, s, reg, f, new_val, dev) {     \
     77     bool old_f = ARRAY_FIELD_EX32((s)->regs, reg, f);       \
     78     bool new_f = FIELD_EX32(new_val, reg, f);               \
     79                                                             \
     80     /* Detect edges.  */                                    \
     81     if (dev && old_f != new_f) {                            \
     82         crl_reset_ ## type(s, dev, old_f, new_f);           \
     83     }                                                       \
     84 }
     85 
     86 static uint64_t crl_rst_r5_prew(RegisterInfo *reg, uint64_t val64)
     87 {
     88     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
     89 
     90     REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU0, val64, s->cfg.cpu_r5[0]);
     91     REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU1, val64, s->cfg.cpu_r5[1]);
     92     return val64;
     93 }
     94 
     95 static uint64_t crl_rst_adma_prew(RegisterInfo *reg, uint64_t val64)
     96 {
     97     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
     98     int i;
     99 
    100     /* A single register fans out to all ADMA reset inputs.  */
    101     for (i = 0; i < ARRAY_SIZE(s->cfg.adma); i++) {
    102         REGFIELD_RESET(dev, s, RST_ADMA, RESET, val64, s->cfg.adma[i]);
    103     }
    104     return val64;
    105 }
    106 
    107 static uint64_t crl_rst_uart0_prew(RegisterInfo *reg, uint64_t val64)
    108 {
    109     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
    110 
    111     REGFIELD_RESET(dev, s, RST_UART0, RESET, val64, s->cfg.uart[0]);
    112     return val64;
    113 }
    114 
    115 static uint64_t crl_rst_uart1_prew(RegisterInfo *reg, uint64_t val64)
    116 {
    117     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
    118 
    119     REGFIELD_RESET(dev, s, RST_UART1, RESET, val64, s->cfg.uart[1]);
    120     return val64;
    121 }
    122 
    123 static uint64_t crl_rst_gem0_prew(RegisterInfo *reg, uint64_t val64)
    124 {
    125     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
    126 
    127     REGFIELD_RESET(dev, s, RST_GEM0, RESET, val64, s->cfg.gem[0]);
    128     return val64;
    129 }
    130 
    131 static uint64_t crl_rst_gem1_prew(RegisterInfo *reg, uint64_t val64)
    132 {
    133     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
    134 
    135     REGFIELD_RESET(dev, s, RST_GEM1, RESET, val64, s->cfg.gem[1]);
    136     return val64;
    137 }
    138 
    139 static uint64_t crl_rst_usb_prew(RegisterInfo *reg, uint64_t val64)
    140 {
    141     XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
    142 
    143     REGFIELD_RESET(dev, s, RST_USB0, RESET, val64, s->cfg.usb);
    144     return val64;
    145 }
    146 
    147 static const RegisterAccessInfo crl_regs_info[] = {
    148     {   .name = "ERR_CTRL",  .addr = A_ERR_CTRL,
    149     },{ .name = "IR_STATUS",  .addr = A_IR_STATUS,
    150         .w1c = 0x1,
    151         .post_write = crl_status_postw,
    152     },{ .name = "IR_MASK",  .addr = A_IR_MASK,
    153         .reset = 0x1,
    154         .ro = 0x1,
    155     },{ .name = "IR_ENABLE",  .addr = A_IR_ENABLE,
    156         .pre_write = crl_enable_prew,
    157     },{ .name = "IR_DISABLE",  .addr = A_IR_DISABLE,
    158         .pre_write = crl_disable_prew,
    159     },{ .name = "WPROT",  .addr = A_WPROT,
    160     },{ .name = "PLL_CLK_OTHER_DMN",  .addr = A_PLL_CLK_OTHER_DMN,
    161         .reset = 0x1,
    162         .rsvd = 0xe,
    163     },{ .name = "RPLL_CTRL",  .addr = A_RPLL_CTRL,
    164         .reset = 0x24809,
    165         .rsvd = 0xf88c00f6,
    166     },{ .name = "RPLL_CFG",  .addr = A_RPLL_CFG,
    167         .reset = 0x2000000,
    168         .rsvd = 0x1801210,
    169     },{ .name = "RPLL_FRAC_CFG",  .addr = A_RPLL_FRAC_CFG,
    170         .rsvd = 0x7e330000,
    171     },{ .name = "PLL_STATUS",  .addr = A_PLL_STATUS,
    172         .reset = R_PLL_STATUS_RPLL_STABLE_MASK |
    173                  R_PLL_STATUS_RPLL_LOCK_MASK,
    174         .rsvd = 0xfa,
    175         .ro = 0x5,
    176     },{ .name = "RPLL_TO_XPD_CTRL",  .addr = A_RPLL_TO_XPD_CTRL,
    177         .reset = 0x2000100,
    178         .rsvd = 0xfdfc00ff,
    179     },{ .name = "LPD_TOP_SWITCH_CTRL",  .addr = A_LPD_TOP_SWITCH_CTRL,
    180         .reset = 0x6000300,
    181         .rsvd = 0xf9fc00f8,
    182     },{ .name = "LPD_LSBUS_CTRL",  .addr = A_LPD_LSBUS_CTRL,
    183         .reset = 0x2000800,
    184         .rsvd = 0xfdfc00f8,
    185     },{ .name = "CPU_R5_CTRL",  .addr = A_CPU_R5_CTRL,
    186         .reset = 0xe000300,
    187         .rsvd = 0xe1fc00f8,
    188     },{ .name = "IOU_SWITCH_CTRL",  .addr = A_IOU_SWITCH_CTRL,
    189         .reset = 0x2000500,
    190         .rsvd = 0xfdfc00f8,
    191     },{ .name = "GEM0_REF_CTRL",  .addr = A_GEM0_REF_CTRL,
    192         .reset = 0xe000a00,
    193         .rsvd = 0xf1fc00f8,
    194     },{ .name = "GEM1_REF_CTRL",  .addr = A_GEM1_REF_CTRL,
    195         .reset = 0xe000a00,
    196         .rsvd = 0xf1fc00f8,
    197     },{ .name = "GEM_TSU_REF_CTRL",  .addr = A_GEM_TSU_REF_CTRL,
    198         .reset = 0x300,
    199         .rsvd = 0xfdfc00f8,
    200     },{ .name = "USB0_BUS_REF_CTRL",  .addr = A_USB0_BUS_REF_CTRL,
    201         .reset = 0x2001900,
    202         .rsvd = 0xfdfc00f8,
    203     },{ .name = "UART0_REF_CTRL",  .addr = A_UART0_REF_CTRL,
    204         .reset = 0xc00,
    205         .rsvd = 0xfdfc00f8,
    206     },{ .name = "UART1_REF_CTRL",  .addr = A_UART1_REF_CTRL,
    207         .reset = 0xc00,
    208         .rsvd = 0xfdfc00f8,
    209     },{ .name = "SPI0_REF_CTRL",  .addr = A_SPI0_REF_CTRL,
    210         .reset = 0x600,
    211         .rsvd = 0xfdfc00f8,
    212     },{ .name = "SPI1_REF_CTRL",  .addr = A_SPI1_REF_CTRL,
    213         .reset = 0x600,
    214         .rsvd = 0xfdfc00f8,
    215     },{ .name = "CAN0_REF_CTRL",  .addr = A_CAN0_REF_CTRL,
    216         .reset = 0xc00,
    217         .rsvd = 0xfdfc00f8,
    218     },{ .name = "CAN1_REF_CTRL",  .addr = A_CAN1_REF_CTRL,
    219         .reset = 0xc00,
    220         .rsvd = 0xfdfc00f8,
    221     },{ .name = "I2C0_REF_CTRL",  .addr = A_I2C0_REF_CTRL,
    222         .reset = 0xc00,
    223         .rsvd = 0xfdfc00f8,
    224     },{ .name = "I2C1_REF_CTRL",  .addr = A_I2C1_REF_CTRL,
    225         .reset = 0xc00,
    226         .rsvd = 0xfdfc00f8,
    227     },{ .name = "DBG_LPD_CTRL",  .addr = A_DBG_LPD_CTRL,
    228         .reset = 0x300,
    229         .rsvd = 0xfdfc00f8,
    230     },{ .name = "TIMESTAMP_REF_CTRL",  .addr = A_TIMESTAMP_REF_CTRL,
    231         .reset = 0x2000c00,
    232         .rsvd = 0xfdfc00f8,
    233     },{ .name = "CRL_SAFETY_CHK",  .addr = A_CRL_SAFETY_CHK,
    234     },{ .name = "PSM_REF_CTRL",  .addr = A_PSM_REF_CTRL,
    235         .reset = 0xf04,
    236         .rsvd = 0xfffc00f8,
    237     },{ .name = "DBG_TSTMP_CTRL",  .addr = A_DBG_TSTMP_CTRL,
    238         .reset = 0x300,
    239         .rsvd = 0xfdfc00f8,
    240     },{ .name = "CPM_TOPSW_REF_CTRL",  .addr = A_CPM_TOPSW_REF_CTRL,
    241         .reset = 0x300,
    242         .rsvd = 0xfdfc00f8,
    243     },{ .name = "USB3_DUAL_REF_CTRL",  .addr = A_USB3_DUAL_REF_CTRL,
    244         .reset = 0x3c00,
    245         .rsvd = 0xfdfc00f8,
    246     },{ .name = "RST_CPU_R5",  .addr = A_RST_CPU_R5,
    247         .reset = 0x17,
    248         .rsvd = 0x8,
    249         .pre_write = crl_rst_r5_prew,
    250     },{ .name = "RST_ADMA",  .addr = A_RST_ADMA,
    251         .reset = 0x1,
    252         .pre_write = crl_rst_adma_prew,
    253     },{ .name = "RST_GEM0",  .addr = A_RST_GEM0,
    254         .reset = 0x1,
    255         .pre_write = crl_rst_gem0_prew,
    256     },{ .name = "RST_GEM1",  .addr = A_RST_GEM1,
    257         .reset = 0x1,
    258         .pre_write = crl_rst_gem1_prew,
    259     },{ .name = "RST_SPARE",  .addr = A_RST_SPARE,
    260         .reset = 0x1,
    261     },{ .name = "RST_USB0",  .addr = A_RST_USB0,
    262         .reset = 0x1,
    263         .pre_write = crl_rst_usb_prew,
    264     },{ .name = "RST_UART0",  .addr = A_RST_UART0,
    265         .reset = 0x1,
    266         .pre_write = crl_rst_uart0_prew,
    267     },{ .name = "RST_UART1",  .addr = A_RST_UART1,
    268         .reset = 0x1,
    269         .pre_write = crl_rst_uart1_prew,
    270     },{ .name = "RST_SPI0",  .addr = A_RST_SPI0,
    271         .reset = 0x1,
    272     },{ .name = "RST_SPI1",  .addr = A_RST_SPI1,
    273         .reset = 0x1,
    274     },{ .name = "RST_CAN0",  .addr = A_RST_CAN0,
    275         .reset = 0x1,
    276     },{ .name = "RST_CAN1",  .addr = A_RST_CAN1,
    277         .reset = 0x1,
    278     },{ .name = "RST_I2C0",  .addr = A_RST_I2C0,
    279         .reset = 0x1,
    280     },{ .name = "RST_I2C1",  .addr = A_RST_I2C1,
    281         .reset = 0x1,
    282     },{ .name = "RST_DBG_LPD",  .addr = A_RST_DBG_LPD,
    283         .reset = 0x33,
    284         .rsvd = 0xcc,
    285     },{ .name = "RST_GPIO",  .addr = A_RST_GPIO,
    286         .reset = 0x1,
    287     },{ .name = "RST_TTC",  .addr = A_RST_TTC,
    288         .reset = 0xf,
    289     },{ .name = "RST_TIMESTAMP",  .addr = A_RST_TIMESTAMP,
    290         .reset = 0x1,
    291     },{ .name = "RST_SWDT",  .addr = A_RST_SWDT,
    292         .reset = 0x1,
    293     },{ .name = "RST_OCM",  .addr = A_RST_OCM,
    294     },{ .name = "RST_IPI",  .addr = A_RST_IPI,
    295     },{ .name = "RST_FPD",  .addr = A_RST_FPD,
    296         .reset = 0x3,
    297     },{ .name = "PSM_RST_MODE",  .addr = A_PSM_RST_MODE,
    298         .reset = 0x1,
    299         .rsvd = 0xf8,
    300     }
    301 };
    302 
    303 static void crl_reset_enter(Object *obj, ResetType type)
    304 {
    305     XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
    306     unsigned int i;
    307 
    308     for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
    309         register_reset(&s->regs_info[i]);
    310     }
    311 }
    312 
    313 static void crl_reset_hold(Object *obj)
    314 {
    315     XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
    316 
    317     crl_update_irq(s);
    318 }
    319 
    320 static const MemoryRegionOps crl_ops = {
    321     .read = register_read_memory,
    322     .write = register_write_memory,
    323     .endianness = DEVICE_LITTLE_ENDIAN,
    324     .valid = {
    325         .min_access_size = 4,
    326         .max_access_size = 4,
    327     },
    328 };
    329 
    330 static void crl_init(Object *obj)
    331 {
    332     XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
    333     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    334     int i;
    335 
    336     s->reg_array =
    337         register_init_block32(DEVICE(obj), crl_regs_info,
    338                               ARRAY_SIZE(crl_regs_info),
    339                               s->regs_info, s->regs,
    340                               &crl_ops,
    341                               XLNX_VERSAL_CRL_ERR_DEBUG,
    342                               CRL_R_MAX * 4);
    343     sysbus_init_mmio(sbd, &s->reg_array->mem);
    344     sysbus_init_irq(sbd, &s->irq);
    345 
    346     for (i = 0; i < ARRAY_SIZE(s->cfg.cpu_r5); ++i) {
    347         object_property_add_link(obj, "cpu_r5[*]", TYPE_ARM_CPU,
    348                                  (Object **)&s->cfg.cpu_r5[i],
    349                                  qdev_prop_allow_set_link_before_realize,
    350                                  OBJ_PROP_LINK_STRONG);
    351     }
    352 
    353     for (i = 0; i < ARRAY_SIZE(s->cfg.adma); ++i) {
    354         object_property_add_link(obj, "adma[*]", TYPE_DEVICE,
    355                                  (Object **)&s->cfg.adma[i],
    356                                  qdev_prop_allow_set_link_before_realize,
    357                                  OBJ_PROP_LINK_STRONG);
    358     }
    359 
    360     for (i = 0; i < ARRAY_SIZE(s->cfg.uart); ++i) {
    361         object_property_add_link(obj, "uart[*]", TYPE_DEVICE,
    362                                  (Object **)&s->cfg.uart[i],
    363                                  qdev_prop_allow_set_link_before_realize,
    364                                  OBJ_PROP_LINK_STRONG);
    365     }
    366 
    367     for (i = 0; i < ARRAY_SIZE(s->cfg.gem); ++i) {
    368         object_property_add_link(obj, "gem[*]", TYPE_DEVICE,
    369                                  (Object **)&s->cfg.gem[i],
    370                                  qdev_prop_allow_set_link_before_realize,
    371                                  OBJ_PROP_LINK_STRONG);
    372     }
    373 
    374     object_property_add_link(obj, "usb", TYPE_DEVICE,
    375                              (Object **)&s->cfg.gem[i],
    376                              qdev_prop_allow_set_link_before_realize,
    377                              OBJ_PROP_LINK_STRONG);
    378 }
    379 
    380 static void crl_finalize(Object *obj)
    381 {
    382     XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
    383     register_finalize_block(s->reg_array);
    384 }
    385 
    386 static const VMStateDescription vmstate_crl = {
    387     .name = TYPE_XLNX_VERSAL_CRL,
    388     .version_id = 1,
    389     .minimum_version_id = 1,
    390     .fields = (VMStateField[]) {
    391         VMSTATE_UINT32_ARRAY(regs, XlnxVersalCRL, CRL_R_MAX),
    392         VMSTATE_END_OF_LIST(),
    393     }
    394 };
    395 
    396 static void crl_class_init(ObjectClass *klass, void *data)
    397 {
    398     ResettableClass *rc = RESETTABLE_CLASS(klass);
    399     DeviceClass *dc = DEVICE_CLASS(klass);
    400 
    401     dc->vmsd = &vmstate_crl;
    402 
    403     rc->phases.enter = crl_reset_enter;
    404     rc->phases.hold = crl_reset_hold;
    405 }
    406 
    407 static const TypeInfo crl_info = {
    408     .name          = TYPE_XLNX_VERSAL_CRL,
    409     .parent        = TYPE_SYS_BUS_DEVICE,
    410     .instance_size = sizeof(XlnxVersalCRL),
    411     .class_init    = crl_class_init,
    412     .instance_init = crl_init,
    413     .instance_finalize = crl_finalize,
    414 };
    415 
    416 static void crl_register_types(void)
    417 {
    418     type_register_static(&crl_info);
    419 }
    420 
    421 type_init(crl_register_types)