1 | /* |
2 | * QEMU PowerPC 440 embedded processors emulation |
3 | * |
4 | * Copyright (c) 2012 François Revol |
5 | * Copyright (c) 2016-2019 BALATON Zoltan |
6 | * |
7 | * This work is licensed under the GNU GPL license version 2 or later. |
8 | * |
9 | */ |
10 | |
11 | #include "qemu/osdep.h" |
12 | #include "qemu/units.h" |
13 | #include "qemu/error-report.h" |
14 | #include "qapi/error.h" |
15 | #include "qemu/log.h" |
16 | #include "qemu/main-loop.h" |
17 | #include "qemu/module.h" |
18 | #include "cpu.h" |
19 | #include "hw/irq.h" |
20 | #include "exec/address-spaces.h" |
21 | #include "exec/memory.h" |
22 | #include "hw/ppc/ppc.h" |
23 | #include "hw/qdev-properties.h" |
24 | #include "hw/pci/pci.h" |
25 | #include "sysemu/block-backend.h" |
26 | #include "sysemu/reset.h" |
27 | #include "ppc440.h" |
28 | |
29 | /*****************************************************************************/ |
30 | /* L2 Cache as SRAM */ |
31 | /* FIXME:fix names */ |
32 | enum { |
33 | DCR_L2CACHE_BASE = 0x30, |
34 | DCR_L2CACHE_CFG = DCR_L2CACHE_BASE, |
35 | DCR_L2CACHE_CMD, |
36 | DCR_L2CACHE_ADDR, |
37 | DCR_L2CACHE_DATA, |
38 | DCR_L2CACHE_STAT, |
39 | DCR_L2CACHE_CVER, |
40 | DCR_L2CACHE_SNP0, |
41 | DCR_L2CACHE_SNP1, |
42 | DCR_L2CACHE_END = DCR_L2CACHE_SNP1, |
43 | }; |
44 | |
45 | /* base is 460ex-specific, cf. U-Boot, ppc4xx-isram.h */ |
46 | enum { |
47 | DCR_ISRAM0_BASE = 0x20, |
48 | DCR_ISRAM0_SB0CR = DCR_ISRAM0_BASE, |
49 | DCR_ISRAM0_SB1CR, |
50 | DCR_ISRAM0_SB2CR, |
51 | DCR_ISRAM0_SB3CR, |
52 | DCR_ISRAM0_BEAR, |
53 | DCR_ISRAM0_BESR0, |
54 | DCR_ISRAM0_BESR1, |
55 | DCR_ISRAM0_PMEG, |
56 | DCR_ISRAM0_CID, |
57 | DCR_ISRAM0_REVID, |
58 | DCR_ISRAM0_DPC, |
59 | DCR_ISRAM0_END = DCR_ISRAM0_DPC |
60 | }; |
61 | |
62 | enum { |
63 | DCR_ISRAM1_BASE = 0xb0, |
64 | DCR_ISRAM1_SB0CR = DCR_ISRAM1_BASE, |
65 | /* single bank */ |
66 | DCR_ISRAM1_BEAR = DCR_ISRAM1_BASE + 0x04, |
67 | DCR_ISRAM1_BESR0, |
68 | DCR_ISRAM1_BESR1, |
69 | DCR_ISRAM1_PMEG, |
70 | DCR_ISRAM1_CID, |
71 | DCR_ISRAM1_REVID, |
72 | DCR_ISRAM1_DPC, |
73 | DCR_ISRAM1_END = DCR_ISRAM1_DPC |
74 | }; |
75 | |
76 | typedef struct ppc4xx_l2sram_t { |
77 | MemoryRegion bank[4]; |
78 | uint32_t l2cache[8]; |
79 | uint32_t isram0[11]; |
80 | } ppc4xx_l2sram_t; |
81 | |
82 | #ifdef MAP_L2SRAM |
83 | static void l2sram_update_mappings(ppc4xx_l2sram_t *l2sram, |
84 | uint32_t isarc, uint32_t isacntl, |
85 | uint32_t dsarc, uint32_t dsacntl) |
86 | { |
87 | if (l2sram->isarc != isarc || |
88 | (l2sram->isacntl & 0x80000000) != (isacntl & 0x80000000)) { |
89 | if (l2sram->isacntl & 0x80000000) { |
90 | /* Unmap previously assigned memory region */ |
91 | memory_region_del_subregion(get_system_memory(), |
92 | &l2sram->isarc_ram); |
93 | } |
94 | if (isacntl & 0x80000000) { |
95 | /* Map new instruction memory region */ |
96 | memory_region_add_subregion(get_system_memory(), isarc, |
97 | &l2sram->isarc_ram); |
98 | } |
99 | } |
100 | if (l2sram->dsarc != dsarc || |
101 | (l2sram->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) { |
102 | if (l2sram->dsacntl & 0x80000000) { |
103 | /* Beware not to unmap the region we just mapped */ |
104 | if (!(isacntl & 0x80000000) || l2sram->dsarc != isarc) { |
105 | /* Unmap previously assigned memory region */ |
106 | memory_region_del_subregion(get_system_memory(), |
107 | &l2sram->dsarc_ram); |
108 | } |
109 | } |
110 | if (dsacntl & 0x80000000) { |
111 | /* Beware not to remap the region we just mapped */ |
112 | if (!(isacntl & 0x80000000) || dsarc != isarc) { |
113 | /* Map new data memory region */ |
114 | memory_region_add_subregion(get_system_memory(), dsarc, |
115 | &l2sram->dsarc_ram); |
116 | } |
117 | } |
118 | } |
119 | } |
120 | #endif |
121 | |
122 | static uint32_t dcr_read_l2sram(void *opaque, int dcrn) |
123 | { |
124 | ppc4xx_l2sram_t *l2sram = opaque; |
125 | uint32_t ret = 0; |
126 | |
127 | switch (dcrn) { |
128 | case DCR_L2CACHE_CFG: |
129 | case DCR_L2CACHE_CMD: |
130 | case DCR_L2CACHE_ADDR: |
131 | case DCR_L2CACHE_DATA: |
132 | case DCR_L2CACHE_STAT: |
133 | case DCR_L2CACHE_CVER: |
134 | case DCR_L2CACHE_SNP0: |
135 | case DCR_L2CACHE_SNP1: |
136 | ret = l2sram->l2cache[dcrn - DCR_L2CACHE_BASE]; |
137 | break; |
138 | |
139 | case DCR_ISRAM0_SB0CR: |
140 | case DCR_ISRAM0_SB1CR: |
141 | case DCR_ISRAM0_SB2CR: |
142 | case DCR_ISRAM0_SB3CR: |
143 | case DCR_ISRAM0_BEAR: |
144 | case DCR_ISRAM0_BESR0: |
145 | case DCR_ISRAM0_BESR1: |
146 | case DCR_ISRAM0_PMEG: |
147 | case DCR_ISRAM0_CID: |
148 | case DCR_ISRAM0_REVID: |
149 | case DCR_ISRAM0_DPC: |
150 | ret = l2sram->isram0[dcrn - DCR_ISRAM0_BASE]; |
151 | break; |
152 | |
153 | default: |
154 | break; |
155 | } |
156 | |
157 | return ret; |
158 | } |
159 | |
160 | static void dcr_write_l2sram(void *opaque, int dcrn, uint32_t val) |
161 | { |
162 | /*ppc4xx_l2sram_t *l2sram = opaque;*/ |
163 | /* FIXME: Actually handle L2 cache mapping */ |
164 | |
165 | switch (dcrn) { |
166 | case DCR_L2CACHE_CFG: |
167 | case DCR_L2CACHE_CMD: |
168 | case DCR_L2CACHE_ADDR: |
169 | case DCR_L2CACHE_DATA: |
170 | case DCR_L2CACHE_STAT: |
171 | case DCR_L2CACHE_CVER: |
172 | case DCR_L2CACHE_SNP0: |
173 | case DCR_L2CACHE_SNP1: |
174 | /*l2sram->l2cache[dcrn - DCR_L2CACHE_BASE] = val;*/ |
175 | break; |
176 | |
177 | case DCR_ISRAM0_SB0CR: |
178 | case DCR_ISRAM0_SB1CR: |
179 | case DCR_ISRAM0_SB2CR: |
180 | case DCR_ISRAM0_SB3CR: |
181 | case DCR_ISRAM0_BEAR: |
182 | case DCR_ISRAM0_BESR0: |
183 | case DCR_ISRAM0_BESR1: |
184 | case DCR_ISRAM0_PMEG: |
185 | case DCR_ISRAM0_CID: |
186 | case DCR_ISRAM0_REVID: |
187 | case DCR_ISRAM0_DPC: |
188 | /*l2sram->isram0[dcrn - DCR_L2CACHE_BASE] = val;*/ |
189 | break; |
190 | |
191 | case DCR_ISRAM1_SB0CR: |
192 | case DCR_ISRAM1_BEAR: |
193 | case DCR_ISRAM1_BESR0: |
194 | case DCR_ISRAM1_BESR1: |
195 | case DCR_ISRAM1_PMEG: |
196 | case DCR_ISRAM1_CID: |
197 | case DCR_ISRAM1_REVID: |
198 | case DCR_ISRAM1_DPC: |
199 | /*l2sram->isram1[dcrn - DCR_L2CACHE_BASE] = val;*/ |
200 | break; |
201 | } |
202 | /*l2sram_update_mappings(l2sram, isarc, isacntl, dsarc, dsacntl);*/ |
203 | } |
204 | |
205 | static void l2sram_reset(void *opaque) |
206 | { |
207 | ppc4xx_l2sram_t *l2sram = opaque; |
208 | |
209 | memset(l2sram->l2cache, 0, sizeof(l2sram->l2cache)); |
210 | l2sram->l2cache[DCR_L2CACHE_STAT - DCR_L2CACHE_BASE] = 0x80000000; |
211 | memset(l2sram->isram0, 0, sizeof(l2sram->isram0)); |
212 | /*l2sram_update_mappings(l2sram, isarc, isacntl, dsarc, dsacntl);*/ |
213 | } |
214 | |
215 | void ppc4xx_l2sram_init(CPUPPCState *env) |
216 | { |
217 | ppc4xx_l2sram_t *l2sram; |
218 | |
219 | l2sram = g_malloc0(sizeof(*l2sram)); |
220 | /* XXX: Size is 4*64kB for 460ex, cf. U-Boot, ppc4xx-isram.h */ |
221 | memory_region_init_ram(&l2sram->bank[0], NULL, "ppc4xx.l2sram_bank0" , |
222 | 64 * KiB, &error_abort); |
223 | memory_region_init_ram(&l2sram->bank[1], NULL, "ppc4xx.l2sram_bank1" , |
224 | 64 * KiB, &error_abort); |
225 | memory_region_init_ram(&l2sram->bank[2], NULL, "ppc4xx.l2sram_bank2" , |
226 | 64 * KiB, &error_abort); |
227 | memory_region_init_ram(&l2sram->bank[3], NULL, "ppc4xx.l2sram_bank3" , |
228 | 64 * KiB, &error_abort); |
229 | qemu_register_reset(&l2sram_reset, l2sram); |
230 | ppc_dcr_register(env, DCR_L2CACHE_CFG, |
231 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
232 | ppc_dcr_register(env, DCR_L2CACHE_CMD, |
233 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
234 | ppc_dcr_register(env, DCR_L2CACHE_ADDR, |
235 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
236 | ppc_dcr_register(env, DCR_L2CACHE_DATA, |
237 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
238 | ppc_dcr_register(env, DCR_L2CACHE_STAT, |
239 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
240 | ppc_dcr_register(env, DCR_L2CACHE_CVER, |
241 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
242 | ppc_dcr_register(env, DCR_L2CACHE_SNP0, |
243 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
244 | ppc_dcr_register(env, DCR_L2CACHE_SNP1, |
245 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
246 | |
247 | ppc_dcr_register(env, DCR_ISRAM0_SB0CR, |
248 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
249 | ppc_dcr_register(env, DCR_ISRAM0_SB1CR, |
250 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
251 | ppc_dcr_register(env, DCR_ISRAM0_SB2CR, |
252 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
253 | ppc_dcr_register(env, DCR_ISRAM0_SB3CR, |
254 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
255 | ppc_dcr_register(env, DCR_ISRAM0_PMEG, |
256 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
257 | ppc_dcr_register(env, DCR_ISRAM0_DPC, |
258 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
259 | |
260 | ppc_dcr_register(env, DCR_ISRAM1_SB0CR, |
261 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
262 | ppc_dcr_register(env, DCR_ISRAM1_PMEG, |
263 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
264 | ppc_dcr_register(env, DCR_ISRAM1_DPC, |
265 | l2sram, &dcr_read_l2sram, &dcr_write_l2sram); |
266 | } |
267 | |
268 | /*****************************************************************************/ |
269 | /* Clocking Power on Reset */ |
270 | enum { |
271 | CPR0_CFGADDR = 0xC, |
272 | CPR0_CFGDATA = 0xD, |
273 | |
274 | CPR0_PLLD = 0x060, |
275 | CPR0_PLBED = 0x080, |
276 | CPR0_OPBD = 0x0C0, |
277 | CPR0_PERD = 0x0E0, |
278 | CPR0_AHBD = 0x100, |
279 | }; |
280 | |
281 | typedef struct ppc4xx_cpr_t { |
282 | uint32_t addr; |
283 | } ppc4xx_cpr_t; |
284 | |
285 | static uint32_t dcr_read_cpr(void *opaque, int dcrn) |
286 | { |
287 | ppc4xx_cpr_t *cpr = opaque; |
288 | uint32_t ret = 0; |
289 | |
290 | switch (dcrn) { |
291 | case CPR0_CFGADDR: |
292 | ret = cpr->addr; |
293 | break; |
294 | case CPR0_CFGDATA: |
295 | switch (cpr->addr) { |
296 | case CPR0_PLLD: |
297 | ret = (0xb5 << 24) | (1 << 16) | (9 << 8); |
298 | break; |
299 | case CPR0_PLBED: |
300 | ret = (5 << 24); |
301 | break; |
302 | case CPR0_OPBD: |
303 | ret = (2 << 24); |
304 | break; |
305 | case CPR0_PERD: |
306 | case CPR0_AHBD: |
307 | ret = (1 << 24); |
308 | break; |
309 | default: |
310 | break; |
311 | } |
312 | break; |
313 | default: |
314 | break; |
315 | } |
316 | |
317 | return ret; |
318 | } |
319 | |
320 | static void dcr_write_cpr(void *opaque, int dcrn, uint32_t val) |
321 | { |
322 | ppc4xx_cpr_t *cpr = opaque; |
323 | |
324 | switch (dcrn) { |
325 | case CPR0_CFGADDR: |
326 | cpr->addr = val; |
327 | break; |
328 | case CPR0_CFGDATA: |
329 | break; |
330 | default: |
331 | break; |
332 | } |
333 | } |
334 | |
335 | static void ppc4xx_cpr_reset(void *opaque) |
336 | { |
337 | ppc4xx_cpr_t *cpr = opaque; |
338 | |
339 | cpr->addr = 0; |
340 | } |
341 | |
342 | void ppc4xx_cpr_init(CPUPPCState *env) |
343 | { |
344 | ppc4xx_cpr_t *cpr; |
345 | |
346 | cpr = g_malloc0(sizeof(*cpr)); |
347 | ppc_dcr_register(env, CPR0_CFGADDR, cpr, &dcr_read_cpr, &dcr_write_cpr); |
348 | ppc_dcr_register(env, CPR0_CFGDATA, cpr, &dcr_read_cpr, &dcr_write_cpr); |
349 | qemu_register_reset(ppc4xx_cpr_reset, cpr); |
350 | } |
351 | |
352 | /*****************************************************************************/ |
353 | /* System DCRs */ |
354 | typedef struct ppc4xx_sdr_t ppc4xx_sdr_t; |
355 | struct ppc4xx_sdr_t { |
356 | uint32_t addr; |
357 | }; |
358 | |
359 | enum { |
360 | SDR0_CFGADDR = 0x00e, |
361 | SDR0_CFGDATA, |
362 | SDR0_STRP0 = 0x020, |
363 | SDR0_STRP1, |
364 | SDR0_102 = 0x66, |
365 | SDR0_103, |
366 | SDR0_128 = 0x80, |
367 | SDR0_ECID3 = 0x083, |
368 | SDR0_DDR0 = 0x0e1, |
369 | SDR0_USB0 = 0x320, |
370 | }; |
371 | |
372 | enum { |
373 | PESDR0_LOOP = 0x303, |
374 | PESDR0_RCSSET, |
375 | PESDR0_RCSSTS, |
376 | PESDR0_RSTSTA = 0x310, |
377 | PESDR1_LOOP = 0x343, |
378 | PESDR1_RCSSET, |
379 | PESDR1_RCSSTS, |
380 | PESDR1_RSTSTA = 0x365, |
381 | }; |
382 | |
383 | #define SDR0_DDR0_DDRM_ENCODE(n) ((((unsigned long)(n)) & 0x03) << 29) |
384 | #define SDR0_DDR0_DDRM_DDR1 0x20000000 |
385 | #define SDR0_DDR0_DDRM_DDR2 0x40000000 |
386 | |
387 | static uint32_t dcr_read_sdr(void *opaque, int dcrn) |
388 | { |
389 | ppc4xx_sdr_t *sdr = opaque; |
390 | uint32_t ret = 0; |
391 | |
392 | switch (dcrn) { |
393 | case SDR0_CFGADDR: |
394 | ret = sdr->addr; |
395 | break; |
396 | case SDR0_CFGDATA: |
397 | switch (sdr->addr) { |
398 | case SDR0_STRP0: |
399 | ret = (0xb5 << 8) | (1 << 4) | 9; |
400 | break; |
401 | case SDR0_STRP1: |
402 | ret = (5 << 29) | (2 << 26) | (1 << 24); |
403 | break; |
404 | case SDR0_ECID3: |
405 | ret = 1 << 20; /* No Security/Kasumi support */ |
406 | break; |
407 | case SDR0_DDR0: |
408 | ret = SDR0_DDR0_DDRM_ENCODE(1) | SDR0_DDR0_DDRM_DDR1; |
409 | break; |
410 | case PESDR0_RCSSET: |
411 | case PESDR1_RCSSET: |
412 | ret = (1 << 24) | (1 << 16); |
413 | break; |
414 | case PESDR0_RCSSTS: |
415 | case PESDR1_RCSSTS: |
416 | ret = (1 << 16) | (1 << 12); |
417 | break; |
418 | case PESDR0_RSTSTA: |
419 | case PESDR1_RSTSTA: |
420 | ret = 1; |
421 | break; |
422 | case PESDR0_LOOP: |
423 | case PESDR1_LOOP: |
424 | ret = 1 << 12; |
425 | break; |
426 | default: |
427 | break; |
428 | } |
429 | break; |
430 | default: |
431 | break; |
432 | } |
433 | |
434 | return ret; |
435 | } |
436 | |
437 | static void dcr_write_sdr(void *opaque, int dcrn, uint32_t val) |
438 | { |
439 | ppc4xx_sdr_t *sdr = opaque; |
440 | |
441 | switch (dcrn) { |
442 | case SDR0_CFGADDR: |
443 | sdr->addr = val; |
444 | break; |
445 | case SDR0_CFGDATA: |
446 | switch (sdr->addr) { |
447 | case 0x00: /* B0CR */ |
448 | break; |
449 | default: |
450 | break; |
451 | } |
452 | break; |
453 | default: |
454 | break; |
455 | } |
456 | } |
457 | |
458 | static void sdr_reset(void *opaque) |
459 | { |
460 | ppc4xx_sdr_t *sdr = opaque; |
461 | |
462 | sdr->addr = 0; |
463 | } |
464 | |
465 | void ppc4xx_sdr_init(CPUPPCState *env) |
466 | { |
467 | ppc4xx_sdr_t *sdr; |
468 | |
469 | sdr = g_malloc0(sizeof(*sdr)); |
470 | qemu_register_reset(&sdr_reset, sdr); |
471 | ppc_dcr_register(env, SDR0_CFGADDR, |
472 | sdr, &dcr_read_sdr, &dcr_write_sdr); |
473 | ppc_dcr_register(env, SDR0_CFGDATA, |
474 | sdr, &dcr_read_sdr, &dcr_write_sdr); |
475 | ppc_dcr_register(env, SDR0_102, |
476 | sdr, &dcr_read_sdr, &dcr_write_sdr); |
477 | ppc_dcr_register(env, SDR0_103, |
478 | sdr, &dcr_read_sdr, &dcr_write_sdr); |
479 | ppc_dcr_register(env, SDR0_128, |
480 | sdr, &dcr_read_sdr, &dcr_write_sdr); |
481 | ppc_dcr_register(env, SDR0_USB0, |
482 | sdr, &dcr_read_sdr, &dcr_write_sdr); |
483 | } |
484 | |
485 | /*****************************************************************************/ |
486 | /* SDRAM controller */ |
487 | typedef struct ppc440_sdram_t { |
488 | uint32_t addr; |
489 | int nbanks; |
490 | MemoryRegion containers[4]; /* used for clipping */ |
491 | MemoryRegion *ram_memories; |
492 | hwaddr ram_bases[4]; |
493 | hwaddr ram_sizes[4]; |
494 | uint32_t bcr[4]; |
495 | } ppc440_sdram_t; |
496 | |
497 | enum { |
498 | SDRAM0_CFGADDR = 0x10, |
499 | SDRAM0_CFGDATA, |
500 | SDRAM_R0BAS = 0x40, |
501 | SDRAM_R1BAS, |
502 | SDRAM_R2BAS, |
503 | SDRAM_R3BAS, |
504 | SDRAM_CONF1HB = 0x45, |
505 | SDRAM_PLBADDULL = 0x4a, |
506 | SDRAM_CONF1LL = 0x4b, |
507 | SDRAM_CONFPATHB = 0x4f, |
508 | SDRAM_PLBADDUHB = 0x50, |
509 | }; |
510 | |
511 | static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size) |
512 | { |
513 | uint32_t bcr; |
514 | |
515 | switch (ram_size) { |
516 | case (8 * MiB): |
517 | bcr = 0xffc0; |
518 | break; |
519 | case (16 * MiB): |
520 | bcr = 0xff80; |
521 | break; |
522 | case (32 * MiB): |
523 | bcr = 0xff00; |
524 | break; |
525 | case (64 * MiB): |
526 | bcr = 0xfe00; |
527 | break; |
528 | case (128 * MiB): |
529 | bcr = 0xfc00; |
530 | break; |
531 | case (256 * MiB): |
532 | bcr = 0xf800; |
533 | break; |
534 | case (512 * MiB): |
535 | bcr = 0xf000; |
536 | break; |
537 | case (1 * GiB): |
538 | bcr = 0xe000; |
539 | break; |
540 | case (2 * GiB): |
541 | bcr = 0xc000; |
542 | break; |
543 | case (4 * GiB): |
544 | bcr = 0x8000; |
545 | break; |
546 | default: |
547 | error_report("invalid RAM size " TARGET_FMT_plx, ram_size); |
548 | return 0; |
549 | } |
550 | bcr |= ram_base >> 2 & 0xffe00000; |
551 | bcr |= 1; |
552 | |
553 | return bcr; |
554 | } |
555 | |
556 | static inline hwaddr sdram_base(uint32_t bcr) |
557 | { |
558 | return (bcr & 0xffe00000) << 2; |
559 | } |
560 | |
561 | static uint64_t sdram_size(uint32_t bcr) |
562 | { |
563 | uint64_t size; |
564 | int sh; |
565 | |
566 | sh = 1024 - ((bcr >> 6) & 0x3ff); |
567 | size = 8 * MiB * sh; |
568 | |
569 | return size; |
570 | } |
571 | |
572 | static void sdram_set_bcr(ppc440_sdram_t *sdram, int i, |
573 | uint32_t bcr, int enabled) |
574 | { |
575 | if (sdram->bcr[i] & 1) { |
576 | /* First unmap RAM if enabled */ |
577 | memory_region_del_subregion(get_system_memory(), |
578 | &sdram->containers[i]); |
579 | memory_region_del_subregion(&sdram->containers[i], |
580 | &sdram->ram_memories[i]); |
581 | object_unparent(OBJECT(&sdram->containers[i])); |
582 | } |
583 | sdram->bcr[i] = bcr & 0xffe0ffc1; |
584 | if (enabled && (bcr & 1)) { |
585 | memory_region_init(&sdram->containers[i], NULL, "sdram-containers" , |
586 | sdram_size(bcr)); |
587 | memory_region_add_subregion(&sdram->containers[i], 0, |
588 | &sdram->ram_memories[i]); |
589 | memory_region_add_subregion(get_system_memory(), |
590 | sdram_base(bcr), |
591 | &sdram->containers[i]); |
592 | } |
593 | } |
594 | |
595 | static void sdram_map_bcr(ppc440_sdram_t *sdram) |
596 | { |
597 | int i; |
598 | |
599 | for (i = 0; i < sdram->nbanks; i++) { |
600 | if (sdram->ram_sizes[i] != 0) { |
601 | sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], |
602 | sdram->ram_sizes[i]), 1); |
603 | } else { |
604 | sdram_set_bcr(sdram, i, 0, 0); |
605 | } |
606 | } |
607 | } |
608 | |
609 | static uint32_t dcr_read_sdram(void *opaque, int dcrn) |
610 | { |
611 | ppc440_sdram_t *sdram = opaque; |
612 | uint32_t ret = 0; |
613 | |
614 | switch (dcrn) { |
615 | case SDRAM_R0BAS: |
616 | case SDRAM_R1BAS: |
617 | case SDRAM_R2BAS: |
618 | case SDRAM_R3BAS: |
619 | if (sdram->ram_sizes[dcrn - SDRAM_R0BAS]) { |
620 | ret = sdram_bcr(sdram->ram_bases[dcrn - SDRAM_R0BAS], |
621 | sdram->ram_sizes[dcrn - SDRAM_R0BAS]); |
622 | } |
623 | break; |
624 | case SDRAM_CONF1HB: |
625 | case SDRAM_CONF1LL: |
626 | case SDRAM_CONFPATHB: |
627 | case SDRAM_PLBADDULL: |
628 | case SDRAM_PLBADDUHB: |
629 | break; |
630 | case SDRAM0_CFGADDR: |
631 | ret = sdram->addr; |
632 | break; |
633 | case SDRAM0_CFGDATA: |
634 | switch (sdram->addr) { |
635 | case 0x14: /* SDRAM_MCSTAT (405EX) */ |
636 | case 0x1F: |
637 | ret = 0x80000000; |
638 | break; |
639 | case 0x21: /* SDRAM_MCOPT2 */ |
640 | ret = 0x08000000; |
641 | break; |
642 | case 0x40: /* SDRAM_MB0CF */ |
643 | ret = 0x00008001; |
644 | break; |
645 | case 0x7A: /* SDRAM_DLCR */ |
646 | ret = 0x02000000; |
647 | break; |
648 | case 0xE1: /* SDR0_DDR0 */ |
649 | ret = SDR0_DDR0_DDRM_ENCODE(1) | SDR0_DDR0_DDRM_DDR1; |
650 | break; |
651 | default: |
652 | break; |
653 | } |
654 | break; |
655 | default: |
656 | break; |
657 | } |
658 | |
659 | return ret; |
660 | } |
661 | |
662 | static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) |
663 | { |
664 | ppc440_sdram_t *sdram = opaque; |
665 | |
666 | switch (dcrn) { |
667 | case SDRAM_R0BAS: |
668 | case SDRAM_R1BAS: |
669 | case SDRAM_R2BAS: |
670 | case SDRAM_R3BAS: |
671 | case SDRAM_CONF1HB: |
672 | case SDRAM_CONF1LL: |
673 | case SDRAM_CONFPATHB: |
674 | case SDRAM_PLBADDULL: |
675 | case SDRAM_PLBADDUHB: |
676 | break; |
677 | case SDRAM0_CFGADDR: |
678 | sdram->addr = val; |
679 | break; |
680 | case SDRAM0_CFGDATA: |
681 | switch (sdram->addr) { |
682 | case 0x00: /* B0CR */ |
683 | break; |
684 | default: |
685 | break; |
686 | } |
687 | break; |
688 | default: |
689 | break; |
690 | } |
691 | } |
692 | |
693 | static void sdram_reset(void *opaque) |
694 | { |
695 | ppc440_sdram_t *sdram = opaque; |
696 | |
697 | sdram->addr = 0; |
698 | } |
699 | |
700 | void ppc440_sdram_init(CPUPPCState *env, int nbanks, |
701 | MemoryRegion *ram_memories, |
702 | hwaddr *ram_bases, hwaddr *ram_sizes, |
703 | int do_init) |
704 | { |
705 | ppc440_sdram_t *sdram; |
706 | |
707 | sdram = g_malloc0(sizeof(*sdram)); |
708 | sdram->nbanks = nbanks; |
709 | sdram->ram_memories = ram_memories; |
710 | memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(hwaddr)); |
711 | memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(hwaddr)); |
712 | qemu_register_reset(&sdram_reset, sdram); |
713 | ppc_dcr_register(env, SDRAM0_CFGADDR, |
714 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
715 | ppc_dcr_register(env, SDRAM0_CFGDATA, |
716 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
717 | if (do_init) { |
718 | sdram_map_bcr(sdram); |
719 | } |
720 | |
721 | ppc_dcr_register(env, SDRAM_R0BAS, |
722 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
723 | ppc_dcr_register(env, SDRAM_R1BAS, |
724 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
725 | ppc_dcr_register(env, SDRAM_R2BAS, |
726 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
727 | ppc_dcr_register(env, SDRAM_R3BAS, |
728 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
729 | ppc_dcr_register(env, SDRAM_CONF1HB, |
730 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
731 | ppc_dcr_register(env, SDRAM_PLBADDULL, |
732 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
733 | ppc_dcr_register(env, SDRAM_CONF1LL, |
734 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
735 | ppc_dcr_register(env, SDRAM_CONFPATHB, |
736 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
737 | ppc_dcr_register(env, SDRAM_PLBADDUHB, |
738 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
739 | } |
740 | |
741 | /*****************************************************************************/ |
742 | /* PLB to AHB bridge */ |
743 | enum { |
744 | AHB_TOP = 0xA4, |
745 | AHB_BOT = 0xA5, |
746 | }; |
747 | |
748 | typedef struct ppc4xx_ahb_t { |
749 | uint32_t top; |
750 | uint32_t bot; |
751 | } ppc4xx_ahb_t; |
752 | |
753 | static uint32_t dcr_read_ahb(void *opaque, int dcrn) |
754 | { |
755 | ppc4xx_ahb_t *ahb = opaque; |
756 | uint32_t ret = 0; |
757 | |
758 | switch (dcrn) { |
759 | case AHB_TOP: |
760 | ret = ahb->top; |
761 | break; |
762 | case AHB_BOT: |
763 | ret = ahb->bot; |
764 | break; |
765 | default: |
766 | break; |
767 | } |
768 | |
769 | return ret; |
770 | } |
771 | |
772 | static void dcr_write_ahb(void *opaque, int dcrn, uint32_t val) |
773 | { |
774 | ppc4xx_ahb_t *ahb = opaque; |
775 | |
776 | switch (dcrn) { |
777 | case AHB_TOP: |
778 | ahb->top = val; |
779 | break; |
780 | case AHB_BOT: |
781 | ahb->bot = val; |
782 | break; |
783 | } |
784 | } |
785 | |
786 | static void ppc4xx_ahb_reset(void *opaque) |
787 | { |
788 | ppc4xx_ahb_t *ahb = opaque; |
789 | |
790 | /* No error */ |
791 | ahb->top = 0; |
792 | ahb->bot = 0; |
793 | } |
794 | |
795 | void ppc4xx_ahb_init(CPUPPCState *env) |
796 | { |
797 | ppc4xx_ahb_t *ahb; |
798 | |
799 | ahb = g_malloc0(sizeof(*ahb)); |
800 | ppc_dcr_register(env, AHB_TOP, ahb, &dcr_read_ahb, &dcr_write_ahb); |
801 | ppc_dcr_register(env, AHB_BOT, ahb, &dcr_read_ahb, &dcr_write_ahb); |
802 | qemu_register_reset(ppc4xx_ahb_reset, ahb); |
803 | } |
804 | |
805 | /*****************************************************************************/ |
806 | /* DMA controller */ |
807 | |
808 | #define DMA0_CR_CE (1 << 31) |
809 | #define DMA0_CR_PW (1 << 26 | 1 << 25) |
810 | #define DMA0_CR_DAI (1 << 24) |
811 | #define DMA0_CR_SAI (1 << 23) |
812 | #define DMA0_CR_DEC (1 << 2) |
813 | |
814 | enum { |
815 | DMA0_CR = 0x00, |
816 | DMA0_CT, |
817 | DMA0_SAH, |
818 | DMA0_SAL, |
819 | DMA0_DAH, |
820 | DMA0_DAL, |
821 | DMA0_SGH, |
822 | DMA0_SGL, |
823 | |
824 | DMA0_SR = 0x20, |
825 | DMA0_SGC = 0x23, |
826 | DMA0_SLP = 0x25, |
827 | DMA0_POL = 0x26, |
828 | }; |
829 | |
830 | typedef struct { |
831 | uint32_t cr; |
832 | uint32_t ct; |
833 | uint64_t sa; |
834 | uint64_t da; |
835 | uint64_t sg; |
836 | } PPC4xxDmaChnl; |
837 | |
838 | typedef struct { |
839 | int base; |
840 | PPC4xxDmaChnl ch[4]; |
841 | uint32_t sr; |
842 | } PPC4xxDmaState; |
843 | |
844 | static uint32_t dcr_read_dma(void *opaque, int dcrn) |
845 | { |
846 | PPC4xxDmaState *dma = opaque; |
847 | uint32_t val = 0; |
848 | int addr = dcrn - dma->base; |
849 | int chnl = addr / 8; |
850 | |
851 | switch (addr) { |
852 | case 0x00 ... 0x1f: |
853 | switch (addr % 8) { |
854 | case DMA0_CR: |
855 | val = dma->ch[chnl].cr; |
856 | break; |
857 | case DMA0_CT: |
858 | val = dma->ch[chnl].ct; |
859 | break; |
860 | case DMA0_SAH: |
861 | val = dma->ch[chnl].sa >> 32; |
862 | break; |
863 | case DMA0_SAL: |
864 | val = dma->ch[chnl].sa; |
865 | break; |
866 | case DMA0_DAH: |
867 | val = dma->ch[chnl].da >> 32; |
868 | break; |
869 | case DMA0_DAL: |
870 | val = dma->ch[chnl].da; |
871 | break; |
872 | case DMA0_SGH: |
873 | val = dma->ch[chnl].sg >> 32; |
874 | break; |
875 | case DMA0_SGL: |
876 | val = dma->ch[chnl].sg; |
877 | break; |
878 | } |
879 | break; |
880 | case DMA0_SR: |
881 | val = dma->sr; |
882 | break; |
883 | default: |
884 | qemu_log_mask(LOG_UNIMP, "%s: unimplemented register %x (%d, %x)\n" , |
885 | __func__, dcrn, chnl, addr); |
886 | } |
887 | |
888 | return val; |
889 | } |
890 | |
891 | static void dcr_write_dma(void *opaque, int dcrn, uint32_t val) |
892 | { |
893 | PPC4xxDmaState *dma = opaque; |
894 | int addr = dcrn - dma->base; |
895 | int chnl = addr / 8; |
896 | |
897 | switch (addr) { |
898 | case 0x00 ... 0x1f: |
899 | switch (addr % 8) { |
900 | case DMA0_CR: |
901 | dma->ch[chnl].cr = val; |
902 | if (val & DMA0_CR_CE) { |
903 | int count = dma->ch[chnl].ct & 0xffff; |
904 | |
905 | if (count) { |
906 | int width, i, sidx, didx; |
907 | uint8_t *rptr, *wptr; |
908 | hwaddr rlen, wlen; |
909 | |
910 | sidx = didx = 0; |
911 | width = 1 << ((val & DMA0_CR_PW) >> 25); |
912 | rptr = cpu_physical_memory_map(dma->ch[chnl].sa, &rlen, 0); |
913 | wptr = cpu_physical_memory_map(dma->ch[chnl].da, &wlen, 1); |
914 | if (rptr && wptr) { |
915 | if (!(val & DMA0_CR_DEC) && |
916 | val & DMA0_CR_SAI && val & DMA0_CR_DAI) { |
917 | /* optimise common case */ |
918 | memmove(wptr, rptr, count * width); |
919 | sidx = didx = count * width; |
920 | } else { |
921 | /* do it the slow way */ |
922 | for (sidx = didx = i = 0; i < count; i++) { |
923 | uint64_t v = ldn_le_p(rptr + sidx, width); |
924 | stn_le_p(wptr + didx, width, v); |
925 | if (val & DMA0_CR_SAI) { |
926 | sidx += width; |
927 | } |
928 | if (val & DMA0_CR_DAI) { |
929 | didx += width; |
930 | } |
931 | } |
932 | } |
933 | } |
934 | if (wptr) { |
935 | cpu_physical_memory_unmap(wptr, wlen, 1, didx); |
936 | } |
937 | if (rptr) { |
938 | cpu_physical_memory_unmap(rptr, rlen, 0, sidx); |
939 | } |
940 | } |
941 | } |
942 | break; |
943 | case DMA0_CT: |
944 | dma->ch[chnl].ct = val; |
945 | break; |
946 | case DMA0_SAH: |
947 | dma->ch[chnl].sa &= 0xffffffffULL; |
948 | dma->ch[chnl].sa |= (uint64_t)val << 32; |
949 | break; |
950 | case DMA0_SAL: |
951 | dma->ch[chnl].sa &= 0xffffffff00000000ULL; |
952 | dma->ch[chnl].sa |= val; |
953 | break; |
954 | case DMA0_DAH: |
955 | dma->ch[chnl].da &= 0xffffffffULL; |
956 | dma->ch[chnl].da |= (uint64_t)val << 32; |
957 | break; |
958 | case DMA0_DAL: |
959 | dma->ch[chnl].da &= 0xffffffff00000000ULL; |
960 | dma->ch[chnl].da |= val; |
961 | break; |
962 | case DMA0_SGH: |
963 | dma->ch[chnl].sg &= 0xffffffffULL; |
964 | dma->ch[chnl].sg |= (uint64_t)val << 32; |
965 | break; |
966 | case DMA0_SGL: |
967 | dma->ch[chnl].sg &= 0xffffffff00000000ULL; |
968 | dma->ch[chnl].sg |= val; |
969 | break; |
970 | } |
971 | break; |
972 | case DMA0_SR: |
973 | dma->sr &= ~val; |
974 | break; |
975 | default: |
976 | qemu_log_mask(LOG_UNIMP, "%s: unimplemented register %x (%d, %x)\n" , |
977 | __func__, dcrn, chnl, addr); |
978 | } |
979 | } |
980 | |
981 | static void ppc4xx_dma_reset(void *opaque) |
982 | { |
983 | PPC4xxDmaState *dma = opaque; |
984 | int dma_base = dma->base; |
985 | |
986 | memset(dma, 0, sizeof(*dma)); |
987 | dma->base = dma_base; |
988 | } |
989 | |
990 | void ppc4xx_dma_init(CPUPPCState *env, int dcr_base) |
991 | { |
992 | PPC4xxDmaState *dma; |
993 | int i; |
994 | |
995 | dma = g_malloc0(sizeof(*dma)); |
996 | dma->base = dcr_base; |
997 | qemu_register_reset(&ppc4xx_dma_reset, dma); |
998 | for (i = 0; i < 4; i++) { |
999 | ppc_dcr_register(env, dcr_base + i * 8 + DMA0_CR, |
1000 | dma, &dcr_read_dma, &dcr_write_dma); |
1001 | ppc_dcr_register(env, dcr_base + i * 8 + DMA0_CT, |
1002 | dma, &dcr_read_dma, &dcr_write_dma); |
1003 | ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SAH, |
1004 | dma, &dcr_read_dma, &dcr_write_dma); |
1005 | ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SAL, |
1006 | dma, &dcr_read_dma, &dcr_write_dma); |
1007 | ppc_dcr_register(env, dcr_base + i * 8 + DMA0_DAH, |
1008 | dma, &dcr_read_dma, &dcr_write_dma); |
1009 | ppc_dcr_register(env, dcr_base + i * 8 + DMA0_DAL, |
1010 | dma, &dcr_read_dma, &dcr_write_dma); |
1011 | ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SGH, |
1012 | dma, &dcr_read_dma, &dcr_write_dma); |
1013 | ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SGL, |
1014 | dma, &dcr_read_dma, &dcr_write_dma); |
1015 | } |
1016 | ppc_dcr_register(env, dcr_base + DMA0_SR, |
1017 | dma, &dcr_read_dma, &dcr_write_dma); |
1018 | ppc_dcr_register(env, dcr_base + DMA0_SGC, |
1019 | dma, &dcr_read_dma, &dcr_write_dma); |
1020 | ppc_dcr_register(env, dcr_base + DMA0_SLP, |
1021 | dma, &dcr_read_dma, &dcr_write_dma); |
1022 | ppc_dcr_register(env, dcr_base + DMA0_POL, |
1023 | dma, &dcr_read_dma, &dcr_write_dma); |
1024 | } |
1025 | |
1026 | /*****************************************************************************/ |
1027 | /* PCI Express controller */ |
1028 | /* FIXME: This is not complete and does not work, only implemented partially |
1029 | * to allow firmware and guests to find an empty bus. Cards should use PCI. |
1030 | */ |
1031 | #include "hw/pci/pcie_host.h" |
1032 | |
1033 | #define TYPE_PPC460EX_PCIE_HOST "ppc460ex-pcie-host" |
1034 | #define PPC460EX_PCIE_HOST(obj) \ |
1035 | OBJECT_CHECK(PPC460EXPCIEState, (obj), TYPE_PPC460EX_PCIE_HOST) |
1036 | |
1037 | typedef struct PPC460EXPCIEState { |
1038 | PCIExpressHost host; |
1039 | |
1040 | MemoryRegion iomem; |
1041 | qemu_irq irq[4]; |
1042 | int32_t dcrn_base; |
1043 | |
1044 | uint64_t cfg_base; |
1045 | uint32_t cfg_mask; |
1046 | uint64_t msg_base; |
1047 | uint32_t msg_mask; |
1048 | uint64_t omr1_base; |
1049 | uint64_t omr1_mask; |
1050 | uint64_t omr2_base; |
1051 | uint64_t omr2_mask; |
1052 | uint64_t omr3_base; |
1053 | uint64_t omr3_mask; |
1054 | uint64_t reg_base; |
1055 | uint32_t reg_mask; |
1056 | uint32_t special; |
1057 | uint32_t cfg; |
1058 | } PPC460EXPCIEState; |
1059 | |
1060 | #define DCRN_PCIE0_BASE 0x100 |
1061 | #define DCRN_PCIE1_BASE 0x120 |
1062 | |
1063 | enum { |
1064 | PEGPL_CFGBAH = 0x0, |
1065 | PEGPL_CFGBAL, |
1066 | PEGPL_CFGMSK, |
1067 | PEGPL_MSGBAH, |
1068 | PEGPL_MSGBAL, |
1069 | PEGPL_MSGMSK, |
1070 | PEGPL_OMR1BAH, |
1071 | PEGPL_OMR1BAL, |
1072 | PEGPL_OMR1MSKH, |
1073 | PEGPL_OMR1MSKL, |
1074 | PEGPL_OMR2BAH, |
1075 | PEGPL_OMR2BAL, |
1076 | PEGPL_OMR2MSKH, |
1077 | PEGPL_OMR2MSKL, |
1078 | PEGPL_OMR3BAH, |
1079 | PEGPL_OMR3BAL, |
1080 | PEGPL_OMR3MSKH, |
1081 | PEGPL_OMR3MSKL, |
1082 | PEGPL_REGBAH, |
1083 | PEGPL_REGBAL, |
1084 | PEGPL_REGMSK, |
1085 | PEGPL_SPECIAL, |
1086 | PEGPL_CFG, |
1087 | }; |
1088 | |
1089 | static uint32_t dcr_read_pcie(void *opaque, int dcrn) |
1090 | { |
1091 | PPC460EXPCIEState *state = opaque; |
1092 | uint32_t ret = 0; |
1093 | |
1094 | switch (dcrn - state->dcrn_base) { |
1095 | case PEGPL_CFGBAH: |
1096 | ret = state->cfg_base >> 32; |
1097 | break; |
1098 | case PEGPL_CFGBAL: |
1099 | ret = state->cfg_base; |
1100 | break; |
1101 | case PEGPL_CFGMSK: |
1102 | ret = state->cfg_mask; |
1103 | break; |
1104 | case PEGPL_MSGBAH: |
1105 | ret = state->msg_base >> 32; |
1106 | break; |
1107 | case PEGPL_MSGBAL: |
1108 | ret = state->msg_base; |
1109 | break; |
1110 | case PEGPL_MSGMSK: |
1111 | ret = state->msg_mask; |
1112 | break; |
1113 | case PEGPL_OMR1BAH: |
1114 | ret = state->omr1_base >> 32; |
1115 | break; |
1116 | case PEGPL_OMR1BAL: |
1117 | ret = state->omr1_base; |
1118 | break; |
1119 | case PEGPL_OMR1MSKH: |
1120 | ret = state->omr1_mask >> 32; |
1121 | break; |
1122 | case PEGPL_OMR1MSKL: |
1123 | ret = state->omr1_mask; |
1124 | break; |
1125 | case PEGPL_OMR2BAH: |
1126 | ret = state->omr2_base >> 32; |
1127 | break; |
1128 | case PEGPL_OMR2BAL: |
1129 | ret = state->omr2_base; |
1130 | break; |
1131 | case PEGPL_OMR2MSKH: |
1132 | ret = state->omr2_mask >> 32; |
1133 | break; |
1134 | case PEGPL_OMR2MSKL: |
1135 | ret = state->omr3_mask; |
1136 | break; |
1137 | case PEGPL_OMR3BAH: |
1138 | ret = state->omr3_base >> 32; |
1139 | break; |
1140 | case PEGPL_OMR3BAL: |
1141 | ret = state->omr3_base; |
1142 | break; |
1143 | case PEGPL_OMR3MSKH: |
1144 | ret = state->omr3_mask >> 32; |
1145 | break; |
1146 | case PEGPL_OMR3MSKL: |
1147 | ret = state->omr3_mask; |
1148 | break; |
1149 | case PEGPL_REGBAH: |
1150 | ret = state->reg_base >> 32; |
1151 | break; |
1152 | case PEGPL_REGBAL: |
1153 | ret = state->reg_base; |
1154 | break; |
1155 | case PEGPL_REGMSK: |
1156 | ret = state->reg_mask; |
1157 | break; |
1158 | case PEGPL_SPECIAL: |
1159 | ret = state->special; |
1160 | break; |
1161 | case PEGPL_CFG: |
1162 | ret = state->cfg; |
1163 | break; |
1164 | } |
1165 | |
1166 | return ret; |
1167 | } |
1168 | |
1169 | static void dcr_write_pcie(void *opaque, int dcrn, uint32_t val) |
1170 | { |
1171 | PPC460EXPCIEState *s = opaque; |
1172 | uint64_t size; |
1173 | |
1174 | switch (dcrn - s->dcrn_base) { |
1175 | case PEGPL_CFGBAH: |
1176 | s->cfg_base = ((uint64_t)val << 32) | (s->cfg_base & 0xffffffff); |
1177 | break; |
1178 | case PEGPL_CFGBAL: |
1179 | s->cfg_base = (s->cfg_base & 0xffffffff00000000ULL) | val; |
1180 | break; |
1181 | case PEGPL_CFGMSK: |
1182 | s->cfg_mask = val; |
1183 | size = ~(val & 0xfffffffe) + 1; |
1184 | qemu_mutex_lock_iothread(); |
1185 | pcie_host_mmcfg_update(PCIE_HOST_BRIDGE(s), val & 1, s->cfg_base, size); |
1186 | qemu_mutex_unlock_iothread(); |
1187 | break; |
1188 | case PEGPL_MSGBAH: |
1189 | s->msg_base = ((uint64_t)val << 32) | (s->msg_base & 0xffffffff); |
1190 | break; |
1191 | case PEGPL_MSGBAL: |
1192 | s->msg_base = (s->msg_base & 0xffffffff00000000ULL) | val; |
1193 | break; |
1194 | case PEGPL_MSGMSK: |
1195 | s->msg_mask = val; |
1196 | break; |
1197 | case PEGPL_OMR1BAH: |
1198 | s->omr1_base = ((uint64_t)val << 32) | (s->omr1_base & 0xffffffff); |
1199 | break; |
1200 | case PEGPL_OMR1BAL: |
1201 | s->omr1_base = (s->omr1_base & 0xffffffff00000000ULL) | val; |
1202 | break; |
1203 | case PEGPL_OMR1MSKH: |
1204 | s->omr1_mask = ((uint64_t)val << 32) | (s->omr1_mask & 0xffffffff); |
1205 | break; |
1206 | case PEGPL_OMR1MSKL: |
1207 | s->omr1_mask = (s->omr1_mask & 0xffffffff00000000ULL) | val; |
1208 | break; |
1209 | case PEGPL_OMR2BAH: |
1210 | s->omr2_base = ((uint64_t)val << 32) | (s->omr2_base & 0xffffffff); |
1211 | break; |
1212 | case PEGPL_OMR2BAL: |
1213 | s->omr2_base = (s->omr2_base & 0xffffffff00000000ULL) | val; |
1214 | break; |
1215 | case PEGPL_OMR2MSKH: |
1216 | s->omr2_mask = ((uint64_t)val << 32) | (s->omr2_mask & 0xffffffff); |
1217 | break; |
1218 | case PEGPL_OMR2MSKL: |
1219 | s->omr2_mask = (s->omr2_mask & 0xffffffff00000000ULL) | val; |
1220 | break; |
1221 | case PEGPL_OMR3BAH: |
1222 | s->omr3_base = ((uint64_t)val << 32) | (s->omr3_base & 0xffffffff); |
1223 | break; |
1224 | case PEGPL_OMR3BAL: |
1225 | s->omr3_base = (s->omr3_base & 0xffffffff00000000ULL) | val; |
1226 | break; |
1227 | case PEGPL_OMR3MSKH: |
1228 | s->omr3_mask = ((uint64_t)val << 32) | (s->omr3_mask & 0xffffffff); |
1229 | break; |
1230 | case PEGPL_OMR3MSKL: |
1231 | s->omr3_mask = (s->omr3_mask & 0xffffffff00000000ULL) | val; |
1232 | break; |
1233 | case PEGPL_REGBAH: |
1234 | s->reg_base = ((uint64_t)val << 32) | (s->reg_base & 0xffffffff); |
1235 | break; |
1236 | case PEGPL_REGBAL: |
1237 | s->reg_base = (s->reg_base & 0xffffffff00000000ULL) | val; |
1238 | break; |
1239 | case PEGPL_REGMSK: |
1240 | s->reg_mask = val; |
1241 | /* FIXME: how is size encoded? */ |
1242 | size = (val == 0x7001 ? 4096 : ~(val & 0xfffffffe) + 1); |
1243 | break; |
1244 | case PEGPL_SPECIAL: |
1245 | s->special = val; |
1246 | break; |
1247 | case PEGPL_CFG: |
1248 | s->cfg = val; |
1249 | break; |
1250 | } |
1251 | } |
1252 | |
1253 | static void ppc460ex_set_irq(void *opaque, int irq_num, int level) |
1254 | { |
1255 | PPC460EXPCIEState *s = opaque; |
1256 | qemu_set_irq(s->irq[irq_num], level); |
1257 | } |
1258 | |
1259 | static void ppc460ex_pcie_realize(DeviceState *dev, Error **errp) |
1260 | { |
1261 | PPC460EXPCIEState *s = PPC460EX_PCIE_HOST(dev); |
1262 | PCIHostState *pci = PCI_HOST_BRIDGE(dev); |
1263 | int i, id; |
1264 | char buf[16]; |
1265 | |
1266 | switch (s->dcrn_base) { |
1267 | case DCRN_PCIE0_BASE: |
1268 | id = 0; |
1269 | break; |
1270 | case DCRN_PCIE1_BASE: |
1271 | id = 1; |
1272 | break; |
1273 | default: |
1274 | error_setg(errp, "invalid PCIe DCRN base" ); |
1275 | return; |
1276 | } |
1277 | snprintf(buf, sizeof(buf), "pcie%d-io" , id); |
1278 | memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX); |
1279 | for (i = 0; i < 4; i++) { |
1280 | sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); |
1281 | } |
1282 | snprintf(buf, sizeof(buf), "pcie.%d" , id); |
1283 | pci->bus = pci_register_root_bus(DEVICE(s), buf, ppc460ex_set_irq, |
1284 | pci_swizzle_map_irq_fn, s, &s->iomem, |
1285 | get_system_io(), 0, 4, TYPE_PCIE_BUS); |
1286 | } |
1287 | |
1288 | static Property ppc460ex_pcie_props[] = { |
1289 | DEFINE_PROP_INT32("dcrn-base" , PPC460EXPCIEState, dcrn_base, -1), |
1290 | DEFINE_PROP_END_OF_LIST(), |
1291 | }; |
1292 | |
1293 | static void ppc460ex_pcie_class_init(ObjectClass *klass, void *data) |
1294 | { |
1295 | DeviceClass *dc = DEVICE_CLASS(klass); |
1296 | |
1297 | set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); |
1298 | dc->realize = ppc460ex_pcie_realize; |
1299 | dc->props = ppc460ex_pcie_props; |
1300 | dc->hotpluggable = false; |
1301 | } |
1302 | |
1303 | static const TypeInfo ppc460ex_pcie_host_info = { |
1304 | .name = TYPE_PPC460EX_PCIE_HOST, |
1305 | .parent = TYPE_PCIE_HOST_BRIDGE, |
1306 | .instance_size = sizeof(PPC460EXPCIEState), |
1307 | .class_init = ppc460ex_pcie_class_init, |
1308 | }; |
1309 | |
1310 | static void ppc460ex_pcie_register(void) |
1311 | { |
1312 | type_register_static(&ppc460ex_pcie_host_info); |
1313 | } |
1314 | |
1315 | type_init(ppc460ex_pcie_register) |
1316 | |
1317 | static void ppc460ex_pcie_register_dcrs(PPC460EXPCIEState *s, CPUPPCState *env) |
1318 | { |
1319 | ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGBAH, s, |
1320 | &dcr_read_pcie, &dcr_write_pcie); |
1321 | ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGBAL, s, |
1322 | &dcr_read_pcie, &dcr_write_pcie); |
1323 | ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGMSK, s, |
1324 | &dcr_read_pcie, &dcr_write_pcie); |
1325 | ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGBAH, s, |
1326 | &dcr_read_pcie, &dcr_write_pcie); |
1327 | ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGBAL, s, |
1328 | &dcr_read_pcie, &dcr_write_pcie); |
1329 | ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGMSK, s, |
1330 | &dcr_read_pcie, &dcr_write_pcie); |
1331 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1BAH, s, |
1332 | &dcr_read_pcie, &dcr_write_pcie); |
1333 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1BAL, s, |
1334 | &dcr_read_pcie, &dcr_write_pcie); |
1335 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1MSKH, s, |
1336 | &dcr_read_pcie, &dcr_write_pcie); |
1337 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1MSKL, s, |
1338 | &dcr_read_pcie, &dcr_write_pcie); |
1339 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2BAH, s, |
1340 | &dcr_read_pcie, &dcr_write_pcie); |
1341 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2BAL, s, |
1342 | &dcr_read_pcie, &dcr_write_pcie); |
1343 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2MSKH, s, |
1344 | &dcr_read_pcie, &dcr_write_pcie); |
1345 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2MSKL, s, |
1346 | &dcr_read_pcie, &dcr_write_pcie); |
1347 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3BAH, s, |
1348 | &dcr_read_pcie, &dcr_write_pcie); |
1349 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3BAL, s, |
1350 | &dcr_read_pcie, &dcr_write_pcie); |
1351 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3MSKH, s, |
1352 | &dcr_read_pcie, &dcr_write_pcie); |
1353 | ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3MSKL, s, |
1354 | &dcr_read_pcie, &dcr_write_pcie); |
1355 | ppc_dcr_register(env, s->dcrn_base + PEGPL_REGBAH, s, |
1356 | &dcr_read_pcie, &dcr_write_pcie); |
1357 | ppc_dcr_register(env, s->dcrn_base + PEGPL_REGBAL, s, |
1358 | &dcr_read_pcie, &dcr_write_pcie); |
1359 | ppc_dcr_register(env, s->dcrn_base + PEGPL_REGMSK, s, |
1360 | &dcr_read_pcie, &dcr_write_pcie); |
1361 | ppc_dcr_register(env, s->dcrn_base + PEGPL_SPECIAL, s, |
1362 | &dcr_read_pcie, &dcr_write_pcie); |
1363 | ppc_dcr_register(env, s->dcrn_base + PEGPL_CFG, s, |
1364 | &dcr_read_pcie, &dcr_write_pcie); |
1365 | } |
1366 | |
1367 | void ppc460ex_pcie_init(CPUPPCState *env) |
1368 | { |
1369 | DeviceState *dev; |
1370 | |
1371 | dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST); |
1372 | qdev_prop_set_int32(dev, "dcrn-base" , DCRN_PCIE0_BASE); |
1373 | qdev_init_nofail(dev); |
1374 | object_property_set_bool(OBJECT(dev), true, "realized" , NULL); |
1375 | ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env); |
1376 | |
1377 | dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST); |
1378 | qdev_prop_set_int32(dev, "dcrn-base" , DCRN_PCIE1_BASE); |
1379 | qdev_init_nofail(dev); |
1380 | object_property_set_bool(OBJECT(dev), true, "realized" , NULL); |
1381 | ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env); |
1382 | } |
1383 | |