xref: /openbmc/qemu/hw/misc/xlnx-zynqmp-crf.c (revision 83baec642a13a69398a2643a1f905606c13cd363)
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 
ir_update_irq(XlnxZynqMPCRF * s)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 
ir_status_postw(RegisterInfo * reg,uint64_t val64)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 
ir_enable_prew(RegisterInfo * reg,uint64_t val64)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 
ir_disable_prew(RegisterInfo * reg,uint64_t val64)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 
rst_fpd_apu_prew(RegisterInfo * reg,uint64_t val64)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 
crf_reset_enter(Object * obj,ResetType type)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 
crf_reset_hold(Object * obj,ResetType type)194*ad80e367SPeter Maydell static void crf_reset_hold(Object *obj, ResetType type)
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 
crf_init(Object * obj)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 
crf_finalize(Object * obj)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,
236e4ea952fSRichard 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 
crf_class_init(ObjectClass * klass,void * data)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 
crf_register_types(void)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