2 * QEMU model of the CRF - Clock Reset FPD.
4 * Copyright (c) 2022 Xilinx Inc.
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
9 #include "qemu/osdep.h"
10 #include "hw/sysbus.h"
11 #include "hw/register.h"
12 #include "qemu/bitops.h"
14 #include "migration/vmstate.h"
16 #include "hw/misc/xlnx-zynqmp-crf.h"
17 #include "target/arm/arm-powerctl.h"
19 #ifndef XLNX_ZYNQMP_CRF_ERR_DEBUG
20 #define XLNX_ZYNQMP_CRF_ERR_DEBUG 0
25 static void ir_update_irq(XlnxZynqMPCRF *s)
27 bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK];
28 qemu_set_irq(s->irq_ir, pending);
31 static void ir_status_postw(RegisterInfo *reg, uint64_t val64)
33 XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque);
37 static uint64_t ir_enable_prew(RegisterInfo *reg, uint64_t val64)
39 XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque);
42 s->regs[R_IR_MASK] &= ~val;
47 static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64)
49 XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque);
52 s->regs[R_IR_MASK] |= val;
57 static uint64_t rst_fpd_apu_prew(RegisterInfo *reg, uint64_t val64)
59 XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque);
61 uint32_t val_old = s->regs[R_RST_FPD_APU];
64 for (i = 0; i < CRF_MAX_CPU; i++) {
65 uint32_t mask = (1 << (R_RST_FPD_APU_ACPU0_RESET_SHIFT + i));
67 if ((val ^ val_old) & mask) {
71 arm_set_cpu_on_and_reset(i);
78 static const RegisterAccessInfo crf_regs_info[] = {
79 { .name = "ERR_CTRL", .addr = A_ERR_CTRL,
80 },{ .name = "IR_STATUS", .addr = A_IR_STATUS,
82 .post_write = ir_status_postw,
83 },{ .name = "IR_MASK", .addr = A_IR_MASK,
86 },{ .name = "IR_ENABLE", .addr = A_IR_ENABLE,
87 .pre_write = ir_enable_prew,
88 },{ .name = "IR_DISABLE", .addr = A_IR_DISABLE,
89 .pre_write = ir_disable_prew,
90 },{ .name = "CRF_WPROT", .addr = A_CRF_WPROT,
91 },{ .name = "APLL_CTRL", .addr = A_APLL_CTRL,
94 },{ .name = "APLL_CFG", .addr = A_APLL_CFG,
96 },{ .name = "APLL_FRAC_CFG", .addr = A_APLL_FRAC_CFG,
98 },{ .name = "DPLL_CTRL", .addr = A_DPLL_CTRL,
101 },{ .name = "DPLL_CFG", .addr = A_DPLL_CFG,
103 },{ .name = "DPLL_FRAC_CFG", .addr = A_DPLL_FRAC_CFG,
105 },{ .name = "VPLL_CTRL", .addr = A_VPLL_CTRL,
108 },{ .name = "VPLL_CFG", .addr = A_VPLL_CFG,
110 },{ .name = "VPLL_FRAC_CFG", .addr = A_VPLL_FRAC_CFG,
112 },{ .name = "PLL_STATUS", .addr = A_PLL_STATUS,
116 },{ .name = "APLL_TO_LPD_CTRL", .addr = A_APLL_TO_LPD_CTRL,
119 },{ .name = "DPLL_TO_LPD_CTRL", .addr = A_DPLL_TO_LPD_CTRL,
122 },{ .name = "VPLL_TO_LPD_CTRL", .addr = A_VPLL_TO_LPD_CTRL,
125 },{ .name = "ACPU_CTRL", .addr = A_ACPU_CTRL,
128 },{ .name = "DBG_TRACE_CTRL", .addr = A_DBG_TRACE_CTRL,
131 },{ .name = "DBG_FPD_CTRL", .addr = A_DBG_FPD_CTRL,
134 },{ .name = "DP_VIDEO_REF_CTRL", .addr = A_DP_VIDEO_REF_CTRL,
137 },{ .name = "DP_AUDIO_REF_CTRL", .addr = A_DP_AUDIO_REF_CTRL,
140 },{ .name = "DP_STC_REF_CTRL", .addr = A_DP_STC_REF_CTRL,
143 },{ .name = "DDR_CTRL", .addr = A_DDR_CTRL,
146 },{ .name = "GPU_REF_CTRL", .addr = A_GPU_REF_CTRL,
149 },{ .name = "SATA_REF_CTRL", .addr = A_SATA_REF_CTRL,
152 },{ .name = "PCIE_REF_CTRL", .addr = A_PCIE_REF_CTRL,
155 },{ .name = "GDMA_REF_CTRL", .addr = A_GDMA_REF_CTRL,
158 },{ .name = "DPDMA_REF_CTRL", .addr = A_DPDMA_REF_CTRL,
161 },{ .name = "TOPSW_MAIN_CTRL", .addr = A_TOPSW_MAIN_CTRL,
164 },{ .name = "TOPSW_LSBUS_CTRL", .addr = A_TOPSW_LSBUS_CTRL,
167 },{ .name = "DBG_TSTMP_CTRL", .addr = A_DBG_TSTMP_CTRL,
171 { .name = "RST_FPD_TOP", .addr = A_RST_FPD_TOP,
174 },{ .name = "RST_FPD_APU", .addr = A_RST_FPD_APU,
177 .pre_write = rst_fpd_apu_prew,
178 },{ .name = "RST_DDR_SS", .addr = A_RST_DDR_SS,
184 static void crf_reset_enter(Object *obj, ResetType type)
186 XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
189 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
190 register_reset(&s->regs_info[i]);
194 static void crf_reset_hold(Object *obj)
196 XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
200 static const MemoryRegionOps crf_ops = {
201 .read = register_read_memory,
202 .write = register_write_memory,
203 .endianness = DEVICE_LITTLE_ENDIAN,
205 .min_access_size = 4,
206 .max_access_size = 4,
210 static void crf_init(Object *obj)
212 XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
213 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
216 register_init_block32(DEVICE(obj), crf_regs_info,
217 ARRAY_SIZE(crf_regs_info),
218 s->regs_info, s->regs,
220 XLNX_ZYNQMP_CRF_ERR_DEBUG,
222 sysbus_init_mmio(sbd, &s->reg_array->mem);
223 sysbus_init_irq(sbd, &s->irq_ir);
226 static void crf_finalize(Object *obj)
228 XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
229 register_finalize_block(s->reg_array);
232 static const VMStateDescription vmstate_crf = {
233 .name = TYPE_XLNX_ZYNQMP_CRF,
235 .minimum_version_id = 1,
236 .fields = (VMStateField[]) {
237 VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPCRF, CRF_R_MAX),
238 VMSTATE_END_OF_LIST(),
242 static void crf_class_init(ObjectClass *klass, void *data)
244 ResettableClass *rc = RESETTABLE_CLASS(klass);
245 DeviceClass *dc = DEVICE_CLASS(klass);
247 dc->vmsd = &vmstate_crf;
248 rc->phases.enter = crf_reset_enter;
249 rc->phases.hold = crf_reset_hold;
252 static const TypeInfo crf_info = {
253 .name = TYPE_XLNX_ZYNQMP_CRF,
254 .parent = TYPE_SYS_BUS_DEVICE,
255 .instance_size = sizeof(XlnxZynqMPCRF),
256 .class_init = crf_class_init,
257 .instance_init = crf_init,
258 .instance_finalize = crf_finalize,
261 static void crf_register_types(void)
263 type_register_static(&crf_info);
266 type_init(crf_register_types)