]>
Commit | Line | Data |
---|---|---|
9f617635 EI |
1 | /* |
2 | * QEMU model of the Xilinx XRAM Controller. | |
3 | * | |
4 | * Copyright (c) 2021 Xilinx Inc. | |
5 | * SPDX-License-Identifier: GPL-2.0-or-later | |
6 | * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> | |
7 | */ | |
8 | ||
9 | #include "qemu/osdep.h" | |
10 | #include "qemu/units.h" | |
11 | #include "qapi/error.h" | |
12 | #include "migration/vmstate.h" | |
13 | #include "hw/sysbus.h" | |
14 | #include "hw/register.h" | |
15 | #include "hw/qdev-properties.h" | |
16 | #include "hw/irq.h" | |
17 | #include "hw/misc/xlnx-versal-xramc.h" | |
18 | ||
19 | #ifndef XLNX_XRAM_CTRL_ERR_DEBUG | |
20 | #define XLNX_XRAM_CTRL_ERR_DEBUG 0 | |
21 | #endif | |
22 | ||
23 | static void xram_update_irq(XlnxXramCtrl *s) | |
24 | { | |
25 | bool pending = s->regs[R_XRAM_ISR] & ~s->regs[R_XRAM_IMR]; | |
26 | qemu_set_irq(s->irq, pending); | |
27 | } | |
28 | ||
29 | static void xram_isr_postw(RegisterInfo *reg, uint64_t val64) | |
30 | { | |
31 | XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); | |
32 | xram_update_irq(s); | |
33 | } | |
34 | ||
35 | static uint64_t xram_ien_prew(RegisterInfo *reg, uint64_t val64) | |
36 | { | |
37 | XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); | |
38 | uint32_t val = val64; | |
39 | ||
40 | s->regs[R_XRAM_IMR] &= ~val; | |
41 | xram_update_irq(s); | |
42 | return 0; | |
43 | } | |
44 | ||
45 | static uint64_t xram_ids_prew(RegisterInfo *reg, uint64_t val64) | |
46 | { | |
47 | XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); | |
48 | uint32_t val = val64; | |
49 | ||
50 | s->regs[R_XRAM_IMR] |= val; | |
51 | xram_update_irq(s); | |
52 | return 0; | |
53 | } | |
54 | ||
55 | static const RegisterAccessInfo xram_ctrl_regs_info[] = { | |
56 | { .name = "XRAM_ERR_CTRL", .addr = A_XRAM_ERR_CTRL, | |
57 | .reset = 0xf, | |
58 | .rsvd = 0xfffffff0, | |
59 | },{ .name = "XRAM_ISR", .addr = A_XRAM_ISR, | |
60 | .rsvd = 0xfffff800, | |
61 | .w1c = 0x7ff, | |
62 | .post_write = xram_isr_postw, | |
63 | },{ .name = "XRAM_IMR", .addr = A_XRAM_IMR, | |
64 | .reset = 0x7ff, | |
65 | .rsvd = 0xfffff800, | |
66 | .ro = 0x7ff, | |
67 | },{ .name = "XRAM_IEN", .addr = A_XRAM_IEN, | |
68 | .rsvd = 0xfffff800, | |
69 | .pre_write = xram_ien_prew, | |
70 | },{ .name = "XRAM_IDS", .addr = A_XRAM_IDS, | |
71 | .rsvd = 0xfffff800, | |
72 | .pre_write = xram_ids_prew, | |
73 | },{ .name = "XRAM_ECC_CNTL", .addr = A_XRAM_ECC_CNTL, | |
74 | .rsvd = 0xfffffff8, | |
75 | },{ .name = "XRAM_CLR_EXE", .addr = A_XRAM_CLR_EXE, | |
76 | .rsvd = 0xffffff00, | |
77 | },{ .name = "XRAM_CE_FFA", .addr = A_XRAM_CE_FFA, | |
78 | .rsvd = 0xfff00000, | |
79 | .ro = 0xfffff, | |
80 | },{ .name = "XRAM_CE_FFD0", .addr = A_XRAM_CE_FFD0, | |
81 | .ro = 0xffffffff, | |
82 | },{ .name = "XRAM_CE_FFD1", .addr = A_XRAM_CE_FFD1, | |
83 | .ro = 0xffffffff, | |
84 | },{ .name = "XRAM_CE_FFD2", .addr = A_XRAM_CE_FFD2, | |
85 | .ro = 0xffffffff, | |
86 | },{ .name = "XRAM_CE_FFD3", .addr = A_XRAM_CE_FFD3, | |
87 | .ro = 0xffffffff, | |
88 | },{ .name = "XRAM_CE_FFE", .addr = A_XRAM_CE_FFE, | |
89 | .rsvd = 0xffff0000, | |
90 | .ro = 0xffff, | |
91 | },{ .name = "XRAM_UE_FFA", .addr = A_XRAM_UE_FFA, | |
92 | .rsvd = 0xfff00000, | |
93 | .ro = 0xfffff, | |
94 | },{ .name = "XRAM_UE_FFD0", .addr = A_XRAM_UE_FFD0, | |
95 | .ro = 0xffffffff, | |
96 | },{ .name = "XRAM_UE_FFD1", .addr = A_XRAM_UE_FFD1, | |
97 | .ro = 0xffffffff, | |
98 | },{ .name = "XRAM_UE_FFD2", .addr = A_XRAM_UE_FFD2, | |
99 | .ro = 0xffffffff, | |
100 | },{ .name = "XRAM_UE_FFD3", .addr = A_XRAM_UE_FFD3, | |
101 | .ro = 0xffffffff, | |
102 | },{ .name = "XRAM_UE_FFE", .addr = A_XRAM_UE_FFE, | |
103 | .rsvd = 0xffff0000, | |
104 | .ro = 0xffff, | |
105 | },{ .name = "XRAM_FI_D0", .addr = A_XRAM_FI_D0, | |
106 | },{ .name = "XRAM_FI_D1", .addr = A_XRAM_FI_D1, | |
107 | },{ .name = "XRAM_FI_D2", .addr = A_XRAM_FI_D2, | |
108 | },{ .name = "XRAM_FI_D3", .addr = A_XRAM_FI_D3, | |
109 | },{ .name = "XRAM_FI_SY", .addr = A_XRAM_FI_SY, | |
110 | .rsvd = 0xffff0000, | |
111 | },{ .name = "XRAM_RMW_UE_FFA", .addr = A_XRAM_RMW_UE_FFA, | |
112 | .rsvd = 0xfff00000, | |
113 | .ro = 0xfffff, | |
114 | },{ .name = "XRAM_FI_CNTR", .addr = A_XRAM_FI_CNTR, | |
115 | .rsvd = 0xff000000, | |
116 | },{ .name = "XRAM_IMP", .addr = A_XRAM_IMP, | |
117 | .reset = 0x4, | |
118 | .rsvd = 0xfffffff0, | |
119 | .ro = 0xf, | |
120 | },{ .name = "XRAM_PRDY_DBG", .addr = A_XRAM_PRDY_DBG, | |
121 | .reset = 0xffff, | |
122 | .rsvd = 0xffff0000, | |
123 | .ro = 0xffff, | |
124 | },{ .name = "XRAM_SAFETY_CHK", .addr = A_XRAM_SAFETY_CHK, | |
125 | } | |
126 | }; | |
127 | ||
128 | static void xram_ctrl_reset_enter(Object *obj, ResetType type) | |
129 | { | |
130 | XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); | |
131 | unsigned int i; | |
132 | ||
133 | for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { | |
134 | register_reset(&s->regs_info[i]); | |
135 | } | |
136 | ||
137 | ARRAY_FIELD_DP32(s->regs, XRAM_IMP, SIZE, s->cfg.encoded_size); | |
138 | } | |
139 | ||
140 | static void xram_ctrl_reset_hold(Object *obj) | |
141 | { | |
142 | XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); | |
143 | ||
144 | xram_update_irq(s); | |
145 | } | |
146 | ||
147 | static const MemoryRegionOps xram_ctrl_ops = { | |
148 | .read = register_read_memory, | |
149 | .write = register_write_memory, | |
150 | .endianness = DEVICE_LITTLE_ENDIAN, | |
151 | .valid = { | |
152 | .min_access_size = 4, | |
153 | .max_access_size = 4, | |
154 | }, | |
155 | }; | |
156 | ||
157 | static void xram_ctrl_realize(DeviceState *dev, Error **errp) | |
158 | { | |
159 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | |
160 | XlnxXramCtrl *s = XLNX_XRAM_CTRL(dev); | |
161 | ||
162 | switch (s->cfg.size) { | |
163 | case 64 * KiB: | |
164 | s->cfg.encoded_size = 0; | |
165 | break; | |
166 | case 128 * KiB: | |
167 | s->cfg.encoded_size = 1; | |
168 | break; | |
169 | case 256 * KiB: | |
170 | s->cfg.encoded_size = 2; | |
171 | break; | |
172 | case 512 * KiB: | |
173 | s->cfg.encoded_size = 3; | |
174 | break; | |
175 | case 1 * MiB: | |
176 | s->cfg.encoded_size = 4; | |
177 | break; | |
178 | default: | |
179 | error_setg(errp, "Unsupported XRAM size %" PRId64, s->cfg.size); | |
180 | return; | |
181 | } | |
182 | ||
183 | memory_region_init_ram(&s->ram, OBJECT(s), | |
184 | object_get_canonical_path_component(OBJECT(s)), | |
185 | s->cfg.size, &error_fatal); | |
186 | sysbus_init_mmio(sbd, &s->ram); | |
187 | } | |
188 | ||
189 | static void xram_ctrl_init(Object *obj) | |
190 | { | |
191 | XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); | |
192 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | |
193 | ||
194 | s->reg_array = | |
195 | register_init_block32(DEVICE(obj), xram_ctrl_regs_info, | |
196 | ARRAY_SIZE(xram_ctrl_regs_info), | |
197 | s->regs_info, s->regs, | |
198 | &xram_ctrl_ops, | |
199 | XLNX_XRAM_CTRL_ERR_DEBUG, | |
200 | XRAM_CTRL_R_MAX * 4); | |
201 | sysbus_init_mmio(sbd, &s->reg_array->mem); | |
202 | sysbus_init_irq(sbd, &s->irq); | |
203 | } | |
204 | ||
205 | static void xram_ctrl_finalize(Object *obj) | |
206 | { | |
207 | XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); | |
208 | register_finalize_block(s->reg_array); | |
209 | } | |
210 | ||
211 | static const VMStateDescription vmstate_xram_ctrl = { | |
212 | .name = TYPE_XLNX_XRAM_CTRL, | |
213 | .version_id = 1, | |
214 | .minimum_version_id = 1, | |
215 | .fields = (VMStateField[]) { | |
216 | VMSTATE_UINT32_ARRAY(regs, XlnxXramCtrl, XRAM_CTRL_R_MAX), | |
217 | VMSTATE_END_OF_LIST(), | |
218 | } | |
219 | }; | |
220 | ||
221 | static Property xram_ctrl_properties[] = { | |
222 | DEFINE_PROP_UINT64("size", XlnxXramCtrl, cfg.size, 1 * MiB), | |
223 | DEFINE_PROP_END_OF_LIST(), | |
224 | }; | |
225 | ||
226 | static void xram_ctrl_class_init(ObjectClass *klass, void *data) | |
227 | { | |
228 | ResettableClass *rc = RESETTABLE_CLASS(klass); | |
229 | DeviceClass *dc = DEVICE_CLASS(klass); | |
230 | ||
231 | dc->realize = xram_ctrl_realize; | |
232 | dc->vmsd = &vmstate_xram_ctrl; | |
233 | device_class_set_props(dc, xram_ctrl_properties); | |
234 | ||
235 | rc->phases.enter = xram_ctrl_reset_enter; | |
236 | rc->phases.hold = xram_ctrl_reset_hold; | |
237 | } | |
238 | ||
239 | static const TypeInfo xram_ctrl_info = { | |
240 | .name = TYPE_XLNX_XRAM_CTRL, | |
241 | .parent = TYPE_SYS_BUS_DEVICE, | |
242 | .instance_size = sizeof(XlnxXramCtrl), | |
243 | .class_init = xram_ctrl_class_init, | |
244 | .instance_init = xram_ctrl_init, | |
245 | .instance_finalize = xram_ctrl_finalize, | |
246 | }; | |
247 | ||
248 | static void xram_ctrl_register_types(void) | |
249 | { | |
250 | type_register_static(&xram_ctrl_info); | |
251 | } | |
252 | ||
253 | type_init(xram_ctrl_register_types) |