1152f0bf0SEdgar E. Iglesias /* 2152f0bf0SEdgar E. Iglesias * QEMU model of the CRF - Clock Reset FPD. 3152f0bf0SEdgar E. Iglesias * 4152f0bf0SEdgar E. Iglesias * Copyright (c) 2022 Xilinx Inc. 5152f0bf0SEdgar E. Iglesias * SPDX-License-Identifier: GPL-2.0-or-later 6152f0bf0SEdgar E. Iglesias * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> 7152f0bf0SEdgar E. Iglesias */ 8152f0bf0SEdgar E. Iglesias 9152f0bf0SEdgar E. Iglesias #include "qemu/osdep.h" 10152f0bf0SEdgar E. Iglesias #include "hw/sysbus.h" 11152f0bf0SEdgar E. Iglesias #include "hw/register.h" 12152f0bf0SEdgar E. Iglesias #include "qemu/bitops.h" 13152f0bf0SEdgar E. Iglesias #include "qemu/log.h" 14152f0bf0SEdgar E. Iglesias #include "migration/vmstate.h" 15152f0bf0SEdgar E. Iglesias #include "hw/irq.h" 16152f0bf0SEdgar E. Iglesias #include "hw/misc/xlnx-zynqmp-crf.h" 17152f0bf0SEdgar E. Iglesias #include "target/arm/arm-powerctl.h" 18152f0bf0SEdgar E. Iglesias 19152f0bf0SEdgar E. Iglesias #ifndef XLNX_ZYNQMP_CRF_ERR_DEBUG 20152f0bf0SEdgar E. Iglesias #define XLNX_ZYNQMP_CRF_ERR_DEBUG 0 21152f0bf0SEdgar E. Iglesias #endif 22152f0bf0SEdgar E. Iglesias 23152f0bf0SEdgar E. Iglesias #define CRF_MAX_CPU 4 24152f0bf0SEdgar E. Iglesias 25152f0bf0SEdgar E. Iglesias static void ir_update_irq(XlnxZynqMPCRF *s) 26152f0bf0SEdgar E. Iglesias { 27152f0bf0SEdgar E. Iglesias bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK]; 28152f0bf0SEdgar E. Iglesias qemu_set_irq(s->irq_ir, pending); 29152f0bf0SEdgar E. Iglesias } 30152f0bf0SEdgar E. Iglesias 31152f0bf0SEdgar E. Iglesias static void ir_status_postw(RegisterInfo *reg, uint64_t val64) 32152f0bf0SEdgar E. Iglesias { 33152f0bf0SEdgar E. Iglesias XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque); 34152f0bf0SEdgar E. Iglesias ir_update_irq(s); 35152f0bf0SEdgar E. Iglesias } 36152f0bf0SEdgar E. Iglesias 37152f0bf0SEdgar E. Iglesias static uint64_t ir_enable_prew(RegisterInfo *reg, uint64_t val64) 38152f0bf0SEdgar E. Iglesias { 39152f0bf0SEdgar E. Iglesias XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque); 40152f0bf0SEdgar E. Iglesias uint32_t val = val64; 41152f0bf0SEdgar E. Iglesias 42152f0bf0SEdgar E. Iglesias s->regs[R_IR_MASK] &= ~val; 43152f0bf0SEdgar E. Iglesias ir_update_irq(s); 44152f0bf0SEdgar E. Iglesias return 0; 45152f0bf0SEdgar E. Iglesias } 46152f0bf0SEdgar E. Iglesias 47152f0bf0SEdgar E. Iglesias static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64) 48152f0bf0SEdgar E. Iglesias { 49152f0bf0SEdgar E. Iglesias XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque); 50152f0bf0SEdgar E. Iglesias uint32_t val = val64; 51152f0bf0SEdgar E. Iglesias 52152f0bf0SEdgar E. Iglesias s->regs[R_IR_MASK] |= val; 53152f0bf0SEdgar E. Iglesias ir_update_irq(s); 54152f0bf0SEdgar E. Iglesias return 0; 55152f0bf0SEdgar E. Iglesias } 56152f0bf0SEdgar E. Iglesias 57152f0bf0SEdgar E. Iglesias static uint64_t rst_fpd_apu_prew(RegisterInfo *reg, uint64_t val64) 58152f0bf0SEdgar E. Iglesias { 59152f0bf0SEdgar E. Iglesias XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque); 60152f0bf0SEdgar E. Iglesias uint32_t val = val64; 61152f0bf0SEdgar E. Iglesias uint32_t val_old = s->regs[R_RST_FPD_APU]; 62152f0bf0SEdgar E. Iglesias unsigned int i; 63152f0bf0SEdgar E. Iglesias 64152f0bf0SEdgar E. Iglesias for (i = 0; i < CRF_MAX_CPU; i++) { 65152f0bf0SEdgar E. Iglesias uint32_t mask = (1 << (R_RST_FPD_APU_ACPU0_RESET_SHIFT + i)); 66152f0bf0SEdgar E. Iglesias 67152f0bf0SEdgar E. Iglesias if ((val ^ val_old) & mask) { 68152f0bf0SEdgar E. Iglesias if (val & mask) { 69152f0bf0SEdgar E. Iglesias arm_set_cpu_off(i); 70152f0bf0SEdgar E. Iglesias } else { 71152f0bf0SEdgar E. Iglesias arm_set_cpu_on_and_reset(i); 72152f0bf0SEdgar E. Iglesias } 73152f0bf0SEdgar E. Iglesias } 74152f0bf0SEdgar E. Iglesias } 75152f0bf0SEdgar E. Iglesias return val64; 76152f0bf0SEdgar E. Iglesias } 77152f0bf0SEdgar E. Iglesias 78152f0bf0SEdgar E. Iglesias static const RegisterAccessInfo crf_regs_info[] = { 79152f0bf0SEdgar E. Iglesias { .name = "ERR_CTRL", .addr = A_ERR_CTRL, 80152f0bf0SEdgar E. Iglesias },{ .name = "IR_STATUS", .addr = A_IR_STATUS, 81152f0bf0SEdgar E. Iglesias .w1c = 0x1, 82152f0bf0SEdgar E. Iglesias .post_write = ir_status_postw, 83152f0bf0SEdgar E. Iglesias },{ .name = "IR_MASK", .addr = A_IR_MASK, 84152f0bf0SEdgar E. Iglesias .reset = 0x1, 85152f0bf0SEdgar E. Iglesias .ro = 0x1, 86152f0bf0SEdgar E. Iglesias },{ .name = "IR_ENABLE", .addr = A_IR_ENABLE, 87152f0bf0SEdgar E. Iglesias .pre_write = ir_enable_prew, 88152f0bf0SEdgar E. Iglesias },{ .name = "IR_DISABLE", .addr = A_IR_DISABLE, 89152f0bf0SEdgar E. Iglesias .pre_write = ir_disable_prew, 90152f0bf0SEdgar E. Iglesias },{ .name = "CRF_WPROT", .addr = A_CRF_WPROT, 91152f0bf0SEdgar E. Iglesias },{ .name = "APLL_CTRL", .addr = A_APLL_CTRL, 92152f0bf0SEdgar E. Iglesias .reset = 0x12c09, 93152f0bf0SEdgar E. Iglesias .rsvd = 0xf88c80f6, 94152f0bf0SEdgar E. Iglesias },{ .name = "APLL_CFG", .addr = A_APLL_CFG, 95152f0bf0SEdgar E. Iglesias .rsvd = 0x1801210, 96152f0bf0SEdgar E. Iglesias },{ .name = "APLL_FRAC_CFG", .addr = A_APLL_FRAC_CFG, 97152f0bf0SEdgar E. Iglesias .rsvd = 0x7e330000, 98152f0bf0SEdgar E. Iglesias },{ .name = "DPLL_CTRL", .addr = A_DPLL_CTRL, 99152f0bf0SEdgar E. Iglesias .reset = 0x2c09, 100152f0bf0SEdgar E. Iglesias .rsvd = 0xf88c80f6, 101152f0bf0SEdgar E. Iglesias },{ .name = "DPLL_CFG", .addr = A_DPLL_CFG, 102152f0bf0SEdgar E. Iglesias .rsvd = 0x1801210, 103152f0bf0SEdgar E. Iglesias },{ .name = "DPLL_FRAC_CFG", .addr = A_DPLL_FRAC_CFG, 104152f0bf0SEdgar E. Iglesias .rsvd = 0x7e330000, 105152f0bf0SEdgar E. Iglesias },{ .name = "VPLL_CTRL", .addr = A_VPLL_CTRL, 106152f0bf0SEdgar E. Iglesias .reset = 0x12809, 107152f0bf0SEdgar E. Iglesias .rsvd = 0xf88c80f6, 108152f0bf0SEdgar E. Iglesias },{ .name = "VPLL_CFG", .addr = A_VPLL_CFG, 109152f0bf0SEdgar E. Iglesias .rsvd = 0x1801210, 110152f0bf0SEdgar E. Iglesias },{ .name = "VPLL_FRAC_CFG", .addr = A_VPLL_FRAC_CFG, 111152f0bf0SEdgar E. Iglesias .rsvd = 0x7e330000, 112152f0bf0SEdgar E. Iglesias },{ .name = "PLL_STATUS", .addr = A_PLL_STATUS, 113152f0bf0SEdgar E. Iglesias .reset = 0x3f, 114152f0bf0SEdgar E. Iglesias .rsvd = 0xc0, 115152f0bf0SEdgar E. Iglesias .ro = 0x3f, 116152f0bf0SEdgar E. Iglesias },{ .name = "APLL_TO_LPD_CTRL", .addr = A_APLL_TO_LPD_CTRL, 117152f0bf0SEdgar E. Iglesias .reset = 0x400, 118152f0bf0SEdgar E. Iglesias .rsvd = 0xc0ff, 119152f0bf0SEdgar E. Iglesias },{ .name = "DPLL_TO_LPD_CTRL", .addr = A_DPLL_TO_LPD_CTRL, 120152f0bf0SEdgar E. Iglesias .reset = 0x400, 121152f0bf0SEdgar E. Iglesias .rsvd = 0xc0ff, 122152f0bf0SEdgar E. Iglesias },{ .name = "VPLL_TO_LPD_CTRL", .addr = A_VPLL_TO_LPD_CTRL, 123152f0bf0SEdgar E. Iglesias .reset = 0x400, 124152f0bf0SEdgar E. Iglesias .rsvd = 0xc0ff, 125152f0bf0SEdgar E. Iglesias },{ .name = "ACPU_CTRL", .addr = A_ACPU_CTRL, 126152f0bf0SEdgar E. Iglesias .reset = 0x3000400, 127152f0bf0SEdgar E. Iglesias .rsvd = 0xfcffc0f8, 128152f0bf0SEdgar E. Iglesias },{ .name = "DBG_TRACE_CTRL", .addr = A_DBG_TRACE_CTRL, 129152f0bf0SEdgar E. Iglesias .reset = 0x2500, 130152f0bf0SEdgar E. Iglesias .rsvd = 0xfeffc0f8, 131152f0bf0SEdgar E. Iglesias },{ .name = "DBG_FPD_CTRL", .addr = A_DBG_FPD_CTRL, 132152f0bf0SEdgar E. Iglesias .reset = 0x1002500, 133152f0bf0SEdgar E. Iglesias .rsvd = 0xfeffc0f8, 134152f0bf0SEdgar E. Iglesias },{ .name = "DP_VIDEO_REF_CTRL", .addr = A_DP_VIDEO_REF_CTRL, 135152f0bf0SEdgar E. Iglesias .reset = 0x1002300, 136152f0bf0SEdgar E. Iglesias .rsvd = 0xfec0c0f8, 137152f0bf0SEdgar E. Iglesias },{ .name = "DP_AUDIO_REF_CTRL", .addr = A_DP_AUDIO_REF_CTRL, 138152f0bf0SEdgar E. Iglesias .reset = 0x1032300, 139152f0bf0SEdgar E. Iglesias .rsvd = 0xfec0c0f8, 140152f0bf0SEdgar E. Iglesias },{ .name = "DP_STC_REF_CTRL", .addr = A_DP_STC_REF_CTRL, 141152f0bf0SEdgar E. Iglesias .reset = 0x1203200, 142152f0bf0SEdgar E. Iglesias .rsvd = 0xfec0c0f8, 143152f0bf0SEdgar E. Iglesias },{ .name = "DDR_CTRL", .addr = A_DDR_CTRL, 144152f0bf0SEdgar E. Iglesias .reset = 0x1000500, 145152f0bf0SEdgar E. Iglesias .rsvd = 0xfeffc0f8, 146152f0bf0SEdgar E. Iglesias },{ .name = "GPU_REF_CTRL", .addr = A_GPU_REF_CTRL, 147152f0bf0SEdgar E. Iglesias .reset = 0x1500, 148152f0bf0SEdgar E. Iglesias .rsvd = 0xf8ffc0f8, 149152f0bf0SEdgar E. Iglesias },{ .name = "SATA_REF_CTRL", .addr = A_SATA_REF_CTRL, 150152f0bf0SEdgar E. Iglesias .reset = 0x1001600, 151152f0bf0SEdgar E. Iglesias .rsvd = 0xfeffc0f8, 152152f0bf0SEdgar E. Iglesias },{ .name = "PCIE_REF_CTRL", .addr = A_PCIE_REF_CTRL, 153152f0bf0SEdgar E. Iglesias .reset = 0x1500, 154152f0bf0SEdgar E. Iglesias .rsvd = 0xfeffc0f8, 155152f0bf0SEdgar E. Iglesias },{ .name = "GDMA_REF_CTRL", .addr = A_GDMA_REF_CTRL, 156152f0bf0SEdgar E. Iglesias .reset = 0x1000500, 157152f0bf0SEdgar E. Iglesias .rsvd = 0xfeffc0f8, 158152f0bf0SEdgar E. Iglesias },{ .name = "DPDMA_REF_CTRL", .addr = A_DPDMA_REF_CTRL, 159152f0bf0SEdgar E. Iglesias .reset = 0x1000500, 160152f0bf0SEdgar E. Iglesias .rsvd = 0xfeffc0f8, 161152f0bf0SEdgar E. Iglesias },{ .name = "TOPSW_MAIN_CTRL", .addr = A_TOPSW_MAIN_CTRL, 162152f0bf0SEdgar E. Iglesias .reset = 0x1000400, 163152f0bf0SEdgar E. Iglesias .rsvd = 0xfeffc0f8, 164152f0bf0SEdgar E. Iglesias },{ .name = "TOPSW_LSBUS_CTRL", .addr = A_TOPSW_LSBUS_CTRL, 165152f0bf0SEdgar E. Iglesias .reset = 0x1000800, 166152f0bf0SEdgar E. Iglesias .rsvd = 0xfeffc0f8, 167152f0bf0SEdgar E. Iglesias },{ .name = "DBG_TSTMP_CTRL", .addr = A_DBG_TSTMP_CTRL, 168152f0bf0SEdgar E. Iglesias .reset = 0xa00, 169152f0bf0SEdgar E. Iglesias .rsvd = 0xffffc0f8, 170152f0bf0SEdgar E. Iglesias }, 171152f0bf0SEdgar E. Iglesias { .name = "RST_FPD_TOP", .addr = A_RST_FPD_TOP, 172152f0bf0SEdgar E. Iglesias .reset = 0xf9ffe, 173152f0bf0SEdgar E. Iglesias .rsvd = 0xf06001, 174152f0bf0SEdgar E. Iglesias },{ .name = "RST_FPD_APU", .addr = A_RST_FPD_APU, 175152f0bf0SEdgar E. Iglesias .reset = 0x3d0f, 176152f0bf0SEdgar E. Iglesias .rsvd = 0xc2f0, 177152f0bf0SEdgar E. Iglesias .pre_write = rst_fpd_apu_prew, 178152f0bf0SEdgar E. Iglesias },{ .name = "RST_DDR_SS", .addr = A_RST_DDR_SS, 179152f0bf0SEdgar E. Iglesias .reset = 0xf, 180152f0bf0SEdgar E. Iglesias .rsvd = 0xf3, 181152f0bf0SEdgar E. Iglesias } 182152f0bf0SEdgar E. Iglesias }; 183152f0bf0SEdgar E. Iglesias 184152f0bf0SEdgar E. Iglesias static void crf_reset_enter(Object *obj, ResetType type) 185152f0bf0SEdgar E. Iglesias { 186152f0bf0SEdgar E. Iglesias XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj); 187152f0bf0SEdgar E. Iglesias unsigned int i; 188152f0bf0SEdgar E. Iglesias 189152f0bf0SEdgar E. Iglesias for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { 190152f0bf0SEdgar E. Iglesias register_reset(&s->regs_info[i]); 191152f0bf0SEdgar E. Iglesias } 192152f0bf0SEdgar E. Iglesias } 193152f0bf0SEdgar E. Iglesias 194152f0bf0SEdgar E. Iglesias static void crf_reset_hold(Object *obj) 195152f0bf0SEdgar E. Iglesias { 196152f0bf0SEdgar E. Iglesias XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj); 197152f0bf0SEdgar E. Iglesias ir_update_irq(s); 198152f0bf0SEdgar E. Iglesias } 199152f0bf0SEdgar E. Iglesias 200152f0bf0SEdgar E. Iglesias static const MemoryRegionOps crf_ops = { 201152f0bf0SEdgar E. Iglesias .read = register_read_memory, 202152f0bf0SEdgar E. Iglesias .write = register_write_memory, 203152f0bf0SEdgar E. Iglesias .endianness = DEVICE_LITTLE_ENDIAN, 204152f0bf0SEdgar E. Iglesias .valid = { 205152f0bf0SEdgar E. Iglesias .min_access_size = 4, 206152f0bf0SEdgar E. Iglesias .max_access_size = 4, 207152f0bf0SEdgar E. Iglesias }, 208152f0bf0SEdgar E. Iglesias }; 209152f0bf0SEdgar E. Iglesias 210152f0bf0SEdgar E. Iglesias static void crf_init(Object *obj) 211152f0bf0SEdgar E. Iglesias { 212152f0bf0SEdgar E. Iglesias XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj); 213152f0bf0SEdgar E. Iglesias SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 214152f0bf0SEdgar E. Iglesias 215152f0bf0SEdgar E. Iglesias s->reg_array = 216152f0bf0SEdgar E. Iglesias register_init_block32(DEVICE(obj), crf_regs_info, 217152f0bf0SEdgar E. Iglesias ARRAY_SIZE(crf_regs_info), 218152f0bf0SEdgar E. Iglesias s->regs_info, s->regs, 219152f0bf0SEdgar E. Iglesias &crf_ops, 220152f0bf0SEdgar E. Iglesias XLNX_ZYNQMP_CRF_ERR_DEBUG, 221152f0bf0SEdgar E. Iglesias CRF_R_MAX * 4); 222152f0bf0SEdgar E. Iglesias sysbus_init_mmio(sbd, &s->reg_array->mem); 223152f0bf0SEdgar E. Iglesias sysbus_init_irq(sbd, &s->irq_ir); 224152f0bf0SEdgar E. Iglesias } 225152f0bf0SEdgar E. Iglesias 226152f0bf0SEdgar E. Iglesias static void crf_finalize(Object *obj) 227152f0bf0SEdgar E. Iglesias { 228152f0bf0SEdgar E. Iglesias XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj); 229152f0bf0SEdgar E. Iglesias register_finalize_block(s->reg_array); 230152f0bf0SEdgar E. Iglesias } 231152f0bf0SEdgar E. Iglesias 232152f0bf0SEdgar E. Iglesias static const VMStateDescription vmstate_crf = { 233152f0bf0SEdgar E. Iglesias .name = TYPE_XLNX_ZYNQMP_CRF, 234152f0bf0SEdgar E. Iglesias .version_id = 1, 235152f0bf0SEdgar E. Iglesias .minimum_version_id = 1, 236*e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 237152f0bf0SEdgar E. Iglesias VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPCRF, CRF_R_MAX), 238152f0bf0SEdgar E. Iglesias VMSTATE_END_OF_LIST(), 239152f0bf0SEdgar E. Iglesias } 240152f0bf0SEdgar E. Iglesias }; 241152f0bf0SEdgar E. Iglesias 242152f0bf0SEdgar E. Iglesias static void crf_class_init(ObjectClass *klass, void *data) 243152f0bf0SEdgar E. Iglesias { 244152f0bf0SEdgar E. Iglesias ResettableClass *rc = RESETTABLE_CLASS(klass); 245152f0bf0SEdgar E. Iglesias DeviceClass *dc = DEVICE_CLASS(klass); 246152f0bf0SEdgar E. Iglesias 247152f0bf0SEdgar E. Iglesias dc->vmsd = &vmstate_crf; 248152f0bf0SEdgar E. Iglesias rc->phases.enter = crf_reset_enter; 249152f0bf0SEdgar E. Iglesias rc->phases.hold = crf_reset_hold; 250152f0bf0SEdgar E. Iglesias } 251152f0bf0SEdgar E. Iglesias 252152f0bf0SEdgar E. Iglesias static const TypeInfo crf_info = { 253152f0bf0SEdgar E. Iglesias .name = TYPE_XLNX_ZYNQMP_CRF, 254152f0bf0SEdgar E. Iglesias .parent = TYPE_SYS_BUS_DEVICE, 255152f0bf0SEdgar E. Iglesias .instance_size = sizeof(XlnxZynqMPCRF), 256152f0bf0SEdgar E. Iglesias .class_init = crf_class_init, 257152f0bf0SEdgar E. Iglesias .instance_init = crf_init, 258152f0bf0SEdgar E. Iglesias .instance_finalize = crf_finalize, 259152f0bf0SEdgar E. Iglesias }; 260152f0bf0SEdgar E. Iglesias 261152f0bf0SEdgar E. Iglesias static void crf_register_types(void) 262152f0bf0SEdgar E. Iglesias { 263152f0bf0SEdgar E. Iglesias type_register_static(&crf_info); 264152f0bf0SEdgar E. Iglesias } 265152f0bf0SEdgar E. Iglesias 266152f0bf0SEdgar E. Iglesias type_init(crf_register_types) 267