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
)