1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#include "qemu/osdep.h"
29#include "hw/hw.h"
30#include "hw/sysbus.h"
31#include "migration/vmstate.h"
32#include "hw/qdev-properties.h"
33#include "hw/register.h"
34#include "qemu/bitops.h"
35#include "qemu/log.h"
36#include "hw/irq.h"
37
38#ifndef XILINX_OCM_ERR_DEBUG
39#define XILINX_OCM_ERR_DEBUG 0
40#endif
41
42#define TYPE_XILINX_OCM "xlnx.zynqmp-ocmc"
43
44#define XILINX_OCM(obj) \
45 OBJECT_CHECK(OCMC, (obj), TYPE_XILINX_OCM)
46
47REG32(OCM_ERR_CTRL, 0x0)
48 FIELD(OCM_ERR_CTRL, UE_RES, 3, 1)
49 FIELD(OCM_ERR_CTRL, PWR_ERR_RES, 2, 1)
50 FIELD(OCM_ERR_CTRL, PZ_ERR_RES, 1, 1)
51 FIELD(OCM_ERR_CTRL, APB_ERR_RES, 0, 1)
52REG32(OCM_ISR, 0x4)
53 FIELD(OCM_ISR, UE_RMW, 10, 1)
54 FIELD(OCM_ISR, FIX_BURST_WR, 9, 1)
55 FIELD(OCM_ISR, FIX_BURST_RD, 8, 1)
56 FIELD(OCM_ISR, ECC_UE, 7, 1)
57 FIELD(OCM_ISR, ECC_CE, 6, 1)
58 FIELD(OCM_ISR, LOCK_ERR_WR, 5, 1)
59 FIELD(OCM_ISR, LOCK_ERR_RD, 4, 1)
60 FIELD(OCM_ISR, INV_OCM_WR, 3, 1)
61 FIELD(OCM_ISR, INV_OCM_RD, 2, 1)
62 FIELD(OCM_ISR, PWR_DWN, 1, 1)
63 FIELD(OCM_ISR, INV_APB, 0, 1)
64REG32(OCM_IMR, 0x8)
65 FIELD(OCM_IMR, UE_RMW, 10, 1)
66 FIELD(OCM_IMR, FIX_BURST_WR, 9, 1)
67 FIELD(OCM_IMR, FIX_BURST_RD, 8, 1)
68 FIELD(OCM_IMR, ECC_UE, 7, 1)
69 FIELD(OCM_IMR, ECC_CE, 6, 1)
70 FIELD(OCM_IMR, LOCK_ERR_WR, 5, 1)
71 FIELD(OCM_IMR, LOCK_ERR_RD, 4, 1)
72 FIELD(OCM_IMR, INV_OCM_WR, 3, 1)
73 FIELD(OCM_IMR, INV_OCM_RD, 2, 1)
74 FIELD(OCM_IMR, PWR_DWN, 1, 1)
75 FIELD(OCM_IMR, INV_APB, 0, 1)
76REG32(OCM_IEN, 0xc)
77 FIELD(OCM_IEN, UE_RMW, 10, 1)
78 FIELD(OCM_IEN, FIX_BURST_WR, 9, 1)
79 FIELD(OCM_IEN, FIX_BURST_RD, 8, 1)
80 FIELD(OCM_IEN, ECC_UE, 7, 1)
81 FIELD(OCM_IEN, ECC_CE, 6, 1)
82 FIELD(OCM_IEN, LOCK_ERR_WR, 5, 1)
83 FIELD(OCM_IEN, LOCK_ERR_RD, 4, 1)
84 FIELD(OCM_IEN, INV_OCM_WR, 3, 1)
85 FIELD(OCM_IEN, INV_OCM_RD, 2, 1)
86 FIELD(OCM_IEN, PWR_DWN, 1, 1)
87 FIELD(OCM_IEN, INV_APB, 0, 1)
88REG32(OCM_IDS, 0x10)
89 FIELD(OCM_IDS, UE_RMW, 10, 1)
90 FIELD(OCM_IDS, FIX_BURST_WR, 9, 1)
91 FIELD(OCM_IDS, FIX_BURST_RD, 8, 1)
92 FIELD(OCM_IDS, ECC_UE, 7, 1)
93 FIELD(OCM_IDS, ECC_CE, 6, 1)
94 FIELD(OCM_IDS, LOCK_ERR_WR, 5, 1)
95 FIELD(OCM_IDS, LOCK_ERR_RD, 4, 1)
96 FIELD(OCM_IDS, INV_OCM_WR, 3, 1)
97 FIELD(OCM_IDS, INV_OCM_RD, 2, 1)
98 FIELD(OCM_IDS, PWR_DWN, 1, 1)
99 FIELD(OCM_IDS, INV_APB, 0, 1)
100REG32(OCM_ECC_CNTL, 0x14)
101 FIELD(OCM_ECC_CNTL, FI_MODE, 2, 1)
102 FIELD(OCM_ECC_CNTL, DET_ONLY, 1, 1)
103 FIELD(OCM_ECC_CNTL, ECC_ON_OFF, 0, 1)
104REG32(OCM_CLR_EXE, 0x18)
105 FIELD(OCM_CLR_EXE, MON_7, 7, 1)
106 FIELD(OCM_CLR_EXE, MON_6, 6, 1)
107 FIELD(OCM_CLR_EXE, MON_5, 5, 1)
108 FIELD(OCM_CLR_EXE, MON_4, 4, 1)
109 FIELD(OCM_CLR_EXE, MON_3, 3, 1)
110 FIELD(OCM_CLR_EXE, MON_2, 2, 1)
111 FIELD(OCM_CLR_EXE, MON_1, 1, 1)
112 FIELD(OCM_CLR_EXE, MON_0, 0, 1)
113REG32(OCM_CE_FFA, 0x1c)
114 FIELD(OCM_CE_FFA, ADDR, 0, 18)
115REG32(OCM_CE_FFD0, 0x20)
116REG32(OCM_CE_FFD1, 0x24)
117REG32(OCM_CE_FFD2, 0x28)
118REG32(OCM_CE_FFD3, 0x2c)
119REG32(OCM_CE_FFE, 0x30)
120 FIELD(OCM_CE_FFE, SYNDROME, 0, 16)
121REG32(OCM_UE_FFA, 0x34)
122 FIELD(OCM_UE_FFA, ADDR, 0, 18)
123REG32(OCM_UE_FFD0, 0x38)
124REG32(OCM_UE_FFD1, 0x3c)
125REG32(OCM_UE_FFD2, 0x40)
126REG32(OCM_UE_FFD3, 0x44)
127REG32(OCM_UE_FFE, 0x48)
128 FIELD(OCM_UE_FFE, SYNDROME, 0, 16)
129REG32(OCM_FI_D0, 0x4c)
130REG32(OCM_FI_D1, 0x50)
131REG32(OCM_FI_D2, 0x54)
132REG32(OCM_FI_D3, 0x58)
133REG32(OCM_FI_SY, 0x5c)
134 FIELD(OCM_FI_SY, DATA, 0, 16)
135REG32(OCM_EMA, 0x60)
136 FIELD(OCM_EMA, BANK3, 9, 3)
137 FIELD(OCM_EMA, BANK2, 6, 3)
138 FIELD(OCM_EMA, BANK1, 3, 3)
139 FIELD(OCM_EMA, BANK0, 0, 3)
140REG32(OCM_EMAW, 0x64)
141 FIELD(OCM_EMAW, BANK3, 6, 2)
142 FIELD(OCM_EMAW, BANK2, 4, 2)
143 FIELD(OCM_EMAW, BANK1, 2, 2)
144 FIELD(OCM_EMAW, BANK0, 0, 2)
145REG32(OCM_EMAS, 0x68)
146 FIELD(OCM_EMAS, BANK3, 3, 1)
147 FIELD(OCM_EMAS, BANK2, 2, 1)
148 FIELD(OCM_EMAS, BANK1, 1, 1)
149 FIELD(OCM_EMAS, BANK0, 0, 1)
150REG32(OCM_CE_CNT, 0x6c)
151 FIELD(OCM_CE_CNT, COUNT, 0, 16)
152REG32(OCM_RMW_UE_FFA, 0x70)
153 FIELD(OCM_RMW_UE_FFA, ADDR, 0, 18)
154REG32(OCM_FI_CNTR, 0x74)
155 FIELD(OCM_FI_CNTR, COUNT, 0, 24)
156REG32(OCM_DBG_SYN_TOMEM, 0x78)
157REG32(OCM_DBG_SYN_FROMEM, 0x7c)
158REG32(OCM_IMP, 0x80)
159 FIELD(OCM_IMP, SIZE, 0, 4)
160REG32(OCM_ECO, 0xffc)
161
162#define R_MAX (R_OCM_ECO + 1)
163
164typedef struct OCMC {
165 SysBusDevice parent_obj;
166 MemoryRegion iomem;
167 qemu_irq irq;
168
169 struct {
170 uint64_t memsize;
171 } cfg;
172
173 uint32_t regs[R_MAX];
174 RegisterInfo regs_info[R_MAX];
175} OCMC;
176
177static const MemoryRegionOps ocm_ops = {
178 .read = register_read_memory,
179 .write = register_write_memory,
180 .endianness = DEVICE_LITTLE_ENDIAN,
181 .valid = {
182 .min_access_size = 4,
183 .max_access_size = 4,
184 },
185};
186
187static void ocm_update_irq(OCMC *s)
188{
189 bool pending = s->regs[R_OCM_ISR] & s->regs[R_OCM_IMR];
190 qemu_set_irq(s->irq, pending);
191}
192
193static void ocm_isr_postw(RegisterInfo *reg, uint64_t val64)
194{
195 OCMC *s = XILINX_OCM(reg->opaque);
196 ocm_update_irq(s);
197}
198
199static uint64_t ocm_ien_prew(RegisterInfo *reg, uint64_t val64)
200{
201 OCMC *s = XILINX_OCM(reg->opaque);
202 uint32_t val = val64;
203
204 s->regs[R_OCM_IMR] |= val;
205 ocm_update_irq(s);
206 return 0;
207}
208
209static uint64_t ocm_ids_prew(RegisterInfo *reg, uint64_t val64)
210{
211 OCMC *s = XILINX_OCM(reg->opaque);
212 uint32_t val = val64;
213
214 s->regs[R_OCM_IMR] &= ~val;
215 ocm_update_irq(s);
216 return 0;
217}
218
219static const RegisterAccessInfo ocm_regs_info[] = {
220 { .name = "OCM_ERR_CTRL", .addr = A_OCM_ERR_CTRL,
221 .rsvd = 0xfffffff0,
222 },{ .name = "OCM_ISR", .addr = A_OCM_ISR,
223 .rsvd = 0xfffff800,
224 .w1c = 0x7ff,
225 .ro = ~0x7ffull,
226 .post_write = ocm_isr_postw,
227 },{ .name = "OCM_IMR", .addr = A_OCM_IMR,
228 .reset = 0x7ff,
229 .rsvd = 0xfffff800,
230 .ro = 0x7ff,
231 },{ .name = "OCM_IEN", .addr = A_OCM_IEN,
232 .rsvd = 0xfffff800,
233 .pre_write = ocm_ien_prew,
234 },{ .name = "OCM_IDS", .addr = A_OCM_IDS,
235 .rsvd = 0xfffff800,
236 .pre_write = ocm_ids_prew,
237 },{ .name = "OCM_ECC_CNTL", .addr = A_OCM_ECC_CNTL,
238 .rsvd = 0xfffffff8,
239 },{ .name = "OCM_CLR_EXE", .addr = A_OCM_CLR_EXE,
240 .rsvd = 0xffffff00,
241 },{ .name = "OCM_CE_FFA", .addr = A_OCM_CE_FFA,
242 .rsvd = 0xfffc0000,
243 .ro = 0x3ffff,
244 },{ .name = "OCM_CE_FFD0", .addr = A_OCM_CE_FFD0,
245 .ro = 0xffffffff,
246 },{ .name = "OCM_CE_FFD1", .addr = A_OCM_CE_FFD1,
247 .ro = 0xffffffff,
248 },{ .name = "OCM_CE_FFD2", .addr = A_OCM_CE_FFD2,
249 .ro = 0xffffffff,
250 },{ .name = "OCM_CE_FFD3", .addr = A_OCM_CE_FFD3,
251 .ro = 0xffffffff,
252 },{ .name = "OCM_CE_FFE", .addr = A_OCM_CE_FFE,
253 .rsvd = 0xffff0000,
254 .ro = 0xffff,
255 },{ .name = "OCM_UE_FFA", .addr = A_OCM_UE_FFA,
256 .rsvd = 0xfffc0000,
257 .ro = 0x3ffff,
258 },{ .name = "OCM_UE_FFD0", .addr = A_OCM_UE_FFD0,
259 .ro = 0xffffffff,
260 },{ .name = "OCM_UE_FFD1", .addr = A_OCM_UE_FFD1,
261 .ro = 0xffffffff,
262 },{ .name = "OCM_UE_FFD2", .addr = A_OCM_UE_FFD2,
263 .ro = 0xffffffff,
264 },{ .name = "OCM_UE_FFD3", .addr = A_OCM_UE_FFD3,
265 .ro = 0xffffffff,
266 },{ .name = "OCM_UE_FFE", .addr = A_OCM_UE_FFE,
267 .rsvd = 0xffff0000,
268 .ro = 0xffff,
269 },{ .name = "OCM_FI_D0", .addr = A_OCM_FI_D0,
270 },{ .name = "OCM_FI_D1", .addr = A_OCM_FI_D1,
271 },{ .name = "OCM_FI_D2", .addr = A_OCM_FI_D2,
272 },{ .name = "OCM_FI_D3", .addr = A_OCM_FI_D3,
273 },{ .name = "OCM_FI_SY", .addr = A_OCM_FI_SY,
274 .rsvd = 0xffff0000,
275 },{ .name = "OCM_EMA", .addr = A_OCM_EMA,
276 .reset = 0x249,
277 .rsvd = 0xfffff000,
278 },{ .name = "OCM_EMAW", .addr = A_OCM_EMAW,
279 .rsvd = 0xffffff00,
280 },{ .name = "OCM_EMAS", .addr = A_OCM_EMAS,
281 .rsvd = 0xfffffff0,
282 },{ .name = "OCM_CE_CNT", .addr = A_OCM_CE_CNT,
283 .w1c = 0xffff,
284 },{ .name = "OCM_RMW_UE_FFA", .addr = A_OCM_RMW_UE_FFA,
285 .rsvd = 0xfffc0000,
286 .ro = 0x3ffff,
287 },{ .name = "OCM_FI_CNTR", .addr = A_OCM_FI_CNTR,
288 .rsvd = 0xff000000,
289 },{ .name = "OCM_DBG_SYN_TOMEM", .addr = A_OCM_DBG_SYN_TOMEM,
290 .ro = 0xffffffff,
291 },{ .name = "OCM_DBG_SYN_FROMEM", .addr = A_OCM_DBG_SYN_FROMEM,
292 .ro = 0xffffffff,
293 },{ .name = "OCM_IMP", .addr = A_OCM_IMP,
294 .reset = 0x2,
295 .ro = 0xf,
296 },{ .name = "OCM_ECO", .addr = A_OCM_ECO,
297 }
298};
299
300static uint32_t ocmc_imp_encode_memsize(OCMC *s, uint64_t memsize)
301{
302 const char *prefix = object_get_canonical_path(OBJECT(s));
303 uint32_t r;
304
305 switch (memsize) {
306 case 64 * 1024:
307 r = 0;
308 break;
309 case 128 * 1024:
310 r = 1;
311 break;
312 case 256 * 1024:
313 r = 2;
314 break;
315
316 case 512 * 1024:
317 qemu_log("%s: WARN: Using an undefined OCM memory size.\n", prefix);
318 r = 3;
319 break;
320 default:
321 hw_error("%s: Invalid OCM memory size %" PRIu64 " bytes\n",
322 prefix, memsize);
323 break;
324 }
325 return r;
326}
327
328static void ocm_reset(DeviceState *dev)
329{
330 OCMC *s = XILINX_OCM(dev);
331 unsigned int i;
332
333 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
334 register_reset(&s->regs_info[i]);
335 }
336
337 s->regs[R_OCM_IMP] = ocmc_imp_encode_memsize(s, s->cfg.memsize);
338 ocm_update_irq(s);
339}
340
341static void ocm_init(Object *obj)
342{
343 OCMC *s = XILINX_OCM(obj);
344 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
345 RegisterInfoArray *reg_array;
346
347 memory_region_init(&s->iomem, obj, TYPE_XILINX_OCM, R_MAX * 4);
348 reg_array =
349 register_init_block32(DEVICE(obj), ocm_regs_info,
350 ARRAY_SIZE(ocm_regs_info),
351 s->regs_info, s->regs,
352 &ocm_ops,
353 XILINX_OCM_ERR_DEBUG,
354 R_MAX * 4);
355 memory_region_add_subregion(&s->iomem,
356 0x0,
357 ®_array->mem);
358
359 sysbus_init_mmio(sbd, &s->iomem);
360 sysbus_init_irq(sbd, &s->irq);
361}
362
363static Property ocmc_properties[] = {
364 DEFINE_PROP_UINT64("memsize", OCMC, cfg.memsize, 0),
365 DEFINE_PROP_END_OF_LIST(),
366};
367
368static const VMStateDescription vmstate_ocm = {
369 .name = TYPE_XILINX_OCM,
370 .version_id = 1,
371 .minimum_version_id = 1,
372 .minimum_version_id_old = 1,
373 .fields = (VMStateField[]) {
374 VMSTATE_UINT32_ARRAY(regs, OCMC, R_MAX),
375 VMSTATE_END_OF_LIST(),
376 }
377};
378
379static void ocm_class_init(ObjectClass *klass, void *data)
380{
381 DeviceClass *dc = DEVICE_CLASS(klass);
382
383 dc->reset = ocm_reset;
384 dc->vmsd = &vmstate_ocm;
385 device_class_set_props(dc, ocmc_properties);
386}
387
388static const TypeInfo ocm_info = {
389 .name = TYPE_XILINX_OCM,
390 .parent = TYPE_SYS_BUS_DEVICE,
391 .instance_size = sizeof(OCMC),
392 .class_init = ocm_class_init,
393 .instance_init = ocm_init,
394};
395
396static void ocm_register_types(void)
397{
398 type_register_static(&ocm_info);
399}
400
401type_init(ocm_register_types)
402