1 | /* |
2 | * QEMU PowerPC 4xx embedded processors shared devices emulation |
3 | * |
4 | * Copyright (c) 2007 Jocelyn Mayer |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | * of this software and associated documentation files (the "Software"), to deal |
8 | * in the Software without restriction, including without limitation the rights |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | * copies of the Software, and to permit persons to whom the Software is |
11 | * furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | * THE SOFTWARE. |
23 | */ |
24 | |
25 | #include "qemu/osdep.h" |
26 | #include "qemu/units.h" |
27 | #include "sysemu/reset.h" |
28 | #include "cpu.h" |
29 | #include "hw/irq.h" |
30 | #include "hw/ppc/ppc.h" |
31 | #include "hw/ppc/ppc4xx.h" |
32 | #include "hw/boards.h" |
33 | #include "qemu/log.h" |
34 | #include "exec/address-spaces.h" |
35 | #include "qemu/error-report.h" |
36 | |
37 | /*#define DEBUG_UIC*/ |
38 | |
39 | #ifdef DEBUG_UIC |
40 | # define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) |
41 | #else |
42 | # define LOG_UIC(...) do { } while (0) |
43 | #endif |
44 | |
45 | static void ppc4xx_reset(void *opaque) |
46 | { |
47 | PowerPCCPU *cpu = opaque; |
48 | |
49 | cpu_reset(CPU(cpu)); |
50 | } |
51 | |
52 | /*****************************************************************************/ |
53 | /* Generic PowerPC 4xx processor instantiation */ |
54 | PowerPCCPU *ppc4xx_init(const char *cpu_type, |
55 | clk_setup_t *cpu_clk, clk_setup_t *tb_clk, |
56 | uint32_t sysclk) |
57 | { |
58 | PowerPCCPU *cpu; |
59 | CPUPPCState *env; |
60 | |
61 | /* init CPUs */ |
62 | cpu = POWERPC_CPU(cpu_create(cpu_type)); |
63 | env = &cpu->env; |
64 | |
65 | cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ |
66 | cpu_clk->opaque = env; |
67 | /* Set time-base frequency to sysclk */ |
68 | tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT); |
69 | tb_clk->opaque = env; |
70 | ppc_dcr_init(env, NULL, NULL); |
71 | /* Register qemu callbacks */ |
72 | qemu_register_reset(ppc4xx_reset, cpu); |
73 | |
74 | return cpu; |
75 | } |
76 | |
77 | /*****************************************************************************/ |
78 | /* "Universal" Interrupt controller */ |
79 | enum { |
80 | DCR_UICSR = 0x000, |
81 | DCR_UICSRS = 0x001, |
82 | DCR_UICER = 0x002, |
83 | DCR_UICCR = 0x003, |
84 | DCR_UICPR = 0x004, |
85 | DCR_UICTR = 0x005, |
86 | DCR_UICMSR = 0x006, |
87 | DCR_UICVR = 0x007, |
88 | DCR_UICVCR = 0x008, |
89 | DCR_UICMAX = 0x009, |
90 | }; |
91 | |
92 | #define UIC_MAX_IRQ 32 |
93 | typedef struct ppcuic_t ppcuic_t; |
94 | struct ppcuic_t { |
95 | uint32_t dcr_base; |
96 | int use_vectors; |
97 | uint32_t level; /* Remembers the state of level-triggered interrupts. */ |
98 | uint32_t uicsr; /* Status register */ |
99 | uint32_t uicer; /* Enable register */ |
100 | uint32_t uiccr; /* Critical register */ |
101 | uint32_t uicpr; /* Polarity register */ |
102 | uint32_t uictr; /* Triggering register */ |
103 | uint32_t uicvcr; /* Vector configuration register */ |
104 | uint32_t uicvr; |
105 | qemu_irq *irqs; |
106 | }; |
107 | |
108 | static void ppcuic_trigger_irq (ppcuic_t *uic) |
109 | { |
110 | uint32_t ir, cr; |
111 | int start, end, inc, i; |
112 | |
113 | /* Trigger interrupt if any is pending */ |
114 | ir = uic->uicsr & uic->uicer & (~uic->uiccr); |
115 | cr = uic->uicsr & uic->uicer & uic->uiccr; |
116 | LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32 |
117 | " uiccr %08" PRIx32 "\n" |
118 | " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n" , |
119 | __func__, uic->uicsr, uic->uicer, uic->uiccr, |
120 | uic->uicsr & uic->uicer, ir, cr); |
121 | if (ir != 0x0000000) { |
122 | LOG_UIC("Raise UIC interrupt\n" ); |
123 | qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); |
124 | } else { |
125 | LOG_UIC("Lower UIC interrupt\n" ); |
126 | qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); |
127 | } |
128 | /* Trigger critical interrupt if any is pending and update vector */ |
129 | if (cr != 0x0000000) { |
130 | qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); |
131 | if (uic->use_vectors) { |
132 | /* Compute critical IRQ vector */ |
133 | if (uic->uicvcr & 1) { |
134 | start = 31; |
135 | end = 0; |
136 | inc = -1; |
137 | } else { |
138 | start = 0; |
139 | end = 31; |
140 | inc = 1; |
141 | } |
142 | uic->uicvr = uic->uicvcr & 0xFFFFFFFC; |
143 | for (i = start; i <= end; i += inc) { |
144 | if (cr & (1 << i)) { |
145 | uic->uicvr += (i - start) * 512 * inc; |
146 | break; |
147 | } |
148 | } |
149 | } |
150 | LOG_UIC("Raise UIC critical interrupt - " |
151 | "vector %08" PRIx32 "\n" , uic->uicvr); |
152 | } else { |
153 | LOG_UIC("Lower UIC critical interrupt\n" ); |
154 | qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); |
155 | uic->uicvr = 0x00000000; |
156 | } |
157 | } |
158 | |
159 | static void ppcuic_set_irq (void *opaque, int irq_num, int level) |
160 | { |
161 | ppcuic_t *uic; |
162 | uint32_t mask, sr; |
163 | |
164 | uic = opaque; |
165 | mask = 1U << (31-irq_num); |
166 | LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32 |
167 | " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n" , |
168 | __func__, irq_num, level, |
169 | uic->uicsr, mask, uic->uicsr & mask, level << irq_num); |
170 | if (irq_num < 0 || irq_num > 31) |
171 | return; |
172 | sr = uic->uicsr; |
173 | |
174 | /* Update status register */ |
175 | if (uic->uictr & mask) { |
176 | /* Edge sensitive interrupt */ |
177 | if (level == 1) |
178 | uic->uicsr |= mask; |
179 | } else { |
180 | /* Level sensitive interrupt */ |
181 | if (level == 1) { |
182 | uic->uicsr |= mask; |
183 | uic->level |= mask; |
184 | } else { |
185 | uic->uicsr &= ~mask; |
186 | uic->level &= ~mask; |
187 | } |
188 | } |
189 | LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => " |
190 | "%08" PRIx32 "\n" , __func__, irq_num, level, uic->uicsr, sr); |
191 | if (sr != uic->uicsr) |
192 | ppcuic_trigger_irq(uic); |
193 | } |
194 | |
195 | static uint32_t dcr_read_uic (void *opaque, int dcrn) |
196 | { |
197 | ppcuic_t *uic; |
198 | uint32_t ret; |
199 | |
200 | uic = opaque; |
201 | dcrn -= uic->dcr_base; |
202 | switch (dcrn) { |
203 | case DCR_UICSR: |
204 | case DCR_UICSRS: |
205 | ret = uic->uicsr; |
206 | break; |
207 | case DCR_UICER: |
208 | ret = uic->uicer; |
209 | break; |
210 | case DCR_UICCR: |
211 | ret = uic->uiccr; |
212 | break; |
213 | case DCR_UICPR: |
214 | ret = uic->uicpr; |
215 | break; |
216 | case DCR_UICTR: |
217 | ret = uic->uictr; |
218 | break; |
219 | case DCR_UICMSR: |
220 | ret = uic->uicsr & uic->uicer; |
221 | break; |
222 | case DCR_UICVR: |
223 | if (!uic->use_vectors) |
224 | goto no_read; |
225 | ret = uic->uicvr; |
226 | break; |
227 | case DCR_UICVCR: |
228 | if (!uic->use_vectors) |
229 | goto no_read; |
230 | ret = uic->uicvcr; |
231 | break; |
232 | default: |
233 | no_read: |
234 | ret = 0x00000000; |
235 | break; |
236 | } |
237 | |
238 | return ret; |
239 | } |
240 | |
241 | static void dcr_write_uic (void *opaque, int dcrn, uint32_t val) |
242 | { |
243 | ppcuic_t *uic; |
244 | |
245 | uic = opaque; |
246 | dcrn -= uic->dcr_base; |
247 | LOG_UIC("%s: dcr %d val 0x%x\n" , __func__, dcrn, val); |
248 | switch (dcrn) { |
249 | case DCR_UICSR: |
250 | uic->uicsr &= ~val; |
251 | uic->uicsr |= uic->level; |
252 | ppcuic_trigger_irq(uic); |
253 | break; |
254 | case DCR_UICSRS: |
255 | uic->uicsr |= val; |
256 | ppcuic_trigger_irq(uic); |
257 | break; |
258 | case DCR_UICER: |
259 | uic->uicer = val; |
260 | ppcuic_trigger_irq(uic); |
261 | break; |
262 | case DCR_UICCR: |
263 | uic->uiccr = val; |
264 | ppcuic_trigger_irq(uic); |
265 | break; |
266 | case DCR_UICPR: |
267 | uic->uicpr = val; |
268 | break; |
269 | case DCR_UICTR: |
270 | uic->uictr = val; |
271 | ppcuic_trigger_irq(uic); |
272 | break; |
273 | case DCR_UICMSR: |
274 | break; |
275 | case DCR_UICVR: |
276 | break; |
277 | case DCR_UICVCR: |
278 | uic->uicvcr = val & 0xFFFFFFFD; |
279 | ppcuic_trigger_irq(uic); |
280 | break; |
281 | } |
282 | } |
283 | |
284 | static void ppcuic_reset (void *opaque) |
285 | { |
286 | ppcuic_t *uic; |
287 | |
288 | uic = opaque; |
289 | uic->uiccr = 0x00000000; |
290 | uic->uicer = 0x00000000; |
291 | uic->uicpr = 0x00000000; |
292 | uic->uicsr = 0x00000000; |
293 | uic->uictr = 0x00000000; |
294 | if (uic->use_vectors) { |
295 | uic->uicvcr = 0x00000000; |
296 | uic->uicvr = 0x0000000; |
297 | } |
298 | } |
299 | |
300 | qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs, |
301 | uint32_t dcr_base, int has_ssr, int has_vr) |
302 | { |
303 | ppcuic_t *uic; |
304 | int i; |
305 | |
306 | uic = g_malloc0(sizeof(ppcuic_t)); |
307 | uic->dcr_base = dcr_base; |
308 | uic->irqs = irqs; |
309 | if (has_vr) |
310 | uic->use_vectors = 1; |
311 | for (i = 0; i < DCR_UICMAX; i++) { |
312 | ppc_dcr_register(env, dcr_base + i, uic, |
313 | &dcr_read_uic, &dcr_write_uic); |
314 | } |
315 | qemu_register_reset(ppcuic_reset, uic); |
316 | |
317 | return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); |
318 | } |
319 | |
320 | /*****************************************************************************/ |
321 | /* SDRAM controller */ |
322 | typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; |
323 | struct ppc4xx_sdram_t { |
324 | uint32_t addr; |
325 | int nbanks; |
326 | MemoryRegion containers[4]; /* used for clipping */ |
327 | MemoryRegion *ram_memories; |
328 | hwaddr ram_bases[4]; |
329 | hwaddr ram_sizes[4]; |
330 | uint32_t besr0; |
331 | uint32_t besr1; |
332 | uint32_t bear; |
333 | uint32_t cfg; |
334 | uint32_t status; |
335 | uint32_t rtr; |
336 | uint32_t pmit; |
337 | uint32_t bcr[4]; |
338 | uint32_t tr; |
339 | uint32_t ecccfg; |
340 | uint32_t eccesr; |
341 | qemu_irq irq; |
342 | }; |
343 | |
344 | enum { |
345 | SDRAM0_CFGADDR = 0x010, |
346 | SDRAM0_CFGDATA = 0x011, |
347 | }; |
348 | |
349 | /* XXX: TOFIX: some patches have made this code become inconsistent: |
350 | * there are type inconsistencies, mixing hwaddr, target_ulong |
351 | * and uint32_t |
352 | */ |
353 | static uint32_t sdram_bcr (hwaddr ram_base, |
354 | hwaddr ram_size) |
355 | { |
356 | uint32_t bcr; |
357 | |
358 | switch (ram_size) { |
359 | case 4 * MiB: |
360 | bcr = 0x00000000; |
361 | break; |
362 | case 8 * MiB: |
363 | bcr = 0x00020000; |
364 | break; |
365 | case 16 * MiB: |
366 | bcr = 0x00040000; |
367 | break; |
368 | case 32 * MiB: |
369 | bcr = 0x00060000; |
370 | break; |
371 | case 64 * MiB: |
372 | bcr = 0x00080000; |
373 | break; |
374 | case 128 * MiB: |
375 | bcr = 0x000A0000; |
376 | break; |
377 | case 256 * MiB: |
378 | bcr = 0x000C0000; |
379 | break; |
380 | default: |
381 | printf("%s: invalid RAM size " TARGET_FMT_plx "\n" , __func__, |
382 | ram_size); |
383 | return 0x00000000; |
384 | } |
385 | bcr |= ram_base & 0xFF800000; |
386 | bcr |= 1; |
387 | |
388 | return bcr; |
389 | } |
390 | |
391 | static inline hwaddr sdram_base(uint32_t bcr) |
392 | { |
393 | return bcr & 0xFF800000; |
394 | } |
395 | |
396 | static target_ulong sdram_size (uint32_t bcr) |
397 | { |
398 | target_ulong size; |
399 | int sh; |
400 | |
401 | sh = (bcr >> 17) & 0x7; |
402 | if (sh == 7) |
403 | size = -1; |
404 | else |
405 | size = (4 * MiB) << sh; |
406 | |
407 | return size; |
408 | } |
409 | |
410 | static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i, |
411 | uint32_t bcr, int enabled) |
412 | { |
413 | if (sdram->bcr[i] & 0x00000001) { |
414 | /* Unmap RAM */ |
415 | #ifdef DEBUG_SDRAM |
416 | printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n" , |
417 | __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); |
418 | #endif |
419 | memory_region_del_subregion(get_system_memory(), |
420 | &sdram->containers[i]); |
421 | memory_region_del_subregion(&sdram->containers[i], |
422 | &sdram->ram_memories[i]); |
423 | object_unparent(OBJECT(&sdram->containers[i])); |
424 | } |
425 | sdram->bcr[i] = bcr & 0xFFDEE001; |
426 | if (enabled && (bcr & 0x00000001)) { |
427 | #ifdef DEBUG_SDRAM |
428 | printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n" , |
429 | __func__, sdram_base(bcr), sdram_size(bcr)); |
430 | #endif |
431 | memory_region_init(&sdram->containers[i], NULL, "sdram-containers" , |
432 | sdram_size(bcr)); |
433 | memory_region_add_subregion(&sdram->containers[i], 0, |
434 | &sdram->ram_memories[i]); |
435 | memory_region_add_subregion(get_system_memory(), |
436 | sdram_base(bcr), |
437 | &sdram->containers[i]); |
438 | } |
439 | } |
440 | |
441 | static void sdram_map_bcr (ppc4xx_sdram_t *sdram) |
442 | { |
443 | int i; |
444 | |
445 | for (i = 0; i < sdram->nbanks; i++) { |
446 | if (sdram->ram_sizes[i] != 0) { |
447 | sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], |
448 | sdram->ram_sizes[i]), 1); |
449 | } else { |
450 | sdram_set_bcr(sdram, i, 0x00000000, 0); |
451 | } |
452 | } |
453 | } |
454 | |
455 | static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) |
456 | { |
457 | int i; |
458 | |
459 | for (i = 0; i < sdram->nbanks; i++) { |
460 | #ifdef DEBUG_SDRAM |
461 | printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n" , |
462 | __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); |
463 | #endif |
464 | memory_region_del_subregion(get_system_memory(), |
465 | &sdram->ram_memories[i]); |
466 | } |
467 | } |
468 | |
469 | static uint32_t dcr_read_sdram (void *opaque, int dcrn) |
470 | { |
471 | ppc4xx_sdram_t *sdram; |
472 | uint32_t ret; |
473 | |
474 | sdram = opaque; |
475 | switch (dcrn) { |
476 | case SDRAM0_CFGADDR: |
477 | ret = sdram->addr; |
478 | break; |
479 | case SDRAM0_CFGDATA: |
480 | switch (sdram->addr) { |
481 | case 0x00: /* SDRAM_BESR0 */ |
482 | ret = sdram->besr0; |
483 | break; |
484 | case 0x08: /* SDRAM_BESR1 */ |
485 | ret = sdram->besr1; |
486 | break; |
487 | case 0x10: /* SDRAM_BEAR */ |
488 | ret = sdram->bear; |
489 | break; |
490 | case 0x20: /* SDRAM_CFG */ |
491 | ret = sdram->cfg; |
492 | break; |
493 | case 0x24: /* SDRAM_STATUS */ |
494 | ret = sdram->status; |
495 | break; |
496 | case 0x30: /* SDRAM_RTR */ |
497 | ret = sdram->rtr; |
498 | break; |
499 | case 0x34: /* SDRAM_PMIT */ |
500 | ret = sdram->pmit; |
501 | break; |
502 | case 0x40: /* SDRAM_B0CR */ |
503 | ret = sdram->bcr[0]; |
504 | break; |
505 | case 0x44: /* SDRAM_B1CR */ |
506 | ret = sdram->bcr[1]; |
507 | break; |
508 | case 0x48: /* SDRAM_B2CR */ |
509 | ret = sdram->bcr[2]; |
510 | break; |
511 | case 0x4C: /* SDRAM_B3CR */ |
512 | ret = sdram->bcr[3]; |
513 | break; |
514 | case 0x80: /* SDRAM_TR */ |
515 | ret = -1; /* ? */ |
516 | break; |
517 | case 0x94: /* SDRAM_ECCCFG */ |
518 | ret = sdram->ecccfg; |
519 | break; |
520 | case 0x98: /* SDRAM_ECCESR */ |
521 | ret = sdram->eccesr; |
522 | break; |
523 | default: /* Error */ |
524 | ret = -1; |
525 | break; |
526 | } |
527 | break; |
528 | default: |
529 | /* Avoid gcc warning */ |
530 | ret = 0x00000000; |
531 | break; |
532 | } |
533 | |
534 | return ret; |
535 | } |
536 | |
537 | static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) |
538 | { |
539 | ppc4xx_sdram_t *sdram; |
540 | |
541 | sdram = opaque; |
542 | switch (dcrn) { |
543 | case SDRAM0_CFGADDR: |
544 | sdram->addr = val; |
545 | break; |
546 | case SDRAM0_CFGDATA: |
547 | switch (sdram->addr) { |
548 | case 0x00: /* SDRAM_BESR0 */ |
549 | sdram->besr0 &= ~val; |
550 | break; |
551 | case 0x08: /* SDRAM_BESR1 */ |
552 | sdram->besr1 &= ~val; |
553 | break; |
554 | case 0x10: /* SDRAM_BEAR */ |
555 | sdram->bear = val; |
556 | break; |
557 | case 0x20: /* SDRAM_CFG */ |
558 | val &= 0xFFE00000; |
559 | if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { |
560 | #ifdef DEBUG_SDRAM |
561 | printf("%s: enable SDRAM controller\n" , __func__); |
562 | #endif |
563 | /* validate all RAM mappings */ |
564 | sdram_map_bcr(sdram); |
565 | sdram->status &= ~0x80000000; |
566 | } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { |
567 | #ifdef DEBUG_SDRAM |
568 | printf("%s: disable SDRAM controller\n" , __func__); |
569 | #endif |
570 | /* invalidate all RAM mappings */ |
571 | sdram_unmap_bcr(sdram); |
572 | sdram->status |= 0x80000000; |
573 | } |
574 | if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) |
575 | sdram->status |= 0x40000000; |
576 | else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) |
577 | sdram->status &= ~0x40000000; |
578 | sdram->cfg = val; |
579 | break; |
580 | case 0x24: /* SDRAM_STATUS */ |
581 | /* Read-only register */ |
582 | break; |
583 | case 0x30: /* SDRAM_RTR */ |
584 | sdram->rtr = val & 0x3FF80000; |
585 | break; |
586 | case 0x34: /* SDRAM_PMIT */ |
587 | sdram->pmit = (val & 0xF8000000) | 0x07C00000; |
588 | break; |
589 | case 0x40: /* SDRAM_B0CR */ |
590 | sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000); |
591 | break; |
592 | case 0x44: /* SDRAM_B1CR */ |
593 | sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000); |
594 | break; |
595 | case 0x48: /* SDRAM_B2CR */ |
596 | sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000); |
597 | break; |
598 | case 0x4C: /* SDRAM_B3CR */ |
599 | sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000); |
600 | break; |
601 | case 0x80: /* SDRAM_TR */ |
602 | sdram->tr = val & 0x018FC01F; |
603 | break; |
604 | case 0x94: /* SDRAM_ECCCFG */ |
605 | sdram->ecccfg = val & 0x00F00000; |
606 | break; |
607 | case 0x98: /* SDRAM_ECCESR */ |
608 | val &= 0xFFF0F000; |
609 | if (sdram->eccesr == 0 && val != 0) |
610 | qemu_irq_raise(sdram->irq); |
611 | else if (sdram->eccesr != 0 && val == 0) |
612 | qemu_irq_lower(sdram->irq); |
613 | sdram->eccesr = val; |
614 | break; |
615 | default: /* Error */ |
616 | break; |
617 | } |
618 | break; |
619 | } |
620 | } |
621 | |
622 | static void sdram_reset (void *opaque) |
623 | { |
624 | ppc4xx_sdram_t *sdram; |
625 | |
626 | sdram = opaque; |
627 | sdram->addr = 0x00000000; |
628 | sdram->bear = 0x00000000; |
629 | sdram->besr0 = 0x00000000; /* No error */ |
630 | sdram->besr1 = 0x00000000; /* No error */ |
631 | sdram->cfg = 0x00000000; |
632 | sdram->ecccfg = 0x00000000; /* No ECC */ |
633 | sdram->eccesr = 0x00000000; /* No error */ |
634 | sdram->pmit = 0x07C00000; |
635 | sdram->rtr = 0x05F00000; |
636 | sdram->tr = 0x00854009; |
637 | /* We pre-initialize RAM banks */ |
638 | sdram->status = 0x00000000; |
639 | sdram->cfg = 0x00800000; |
640 | } |
641 | |
642 | void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, |
643 | MemoryRegion *ram_memories, |
644 | hwaddr *ram_bases, |
645 | hwaddr *ram_sizes, |
646 | int do_init) |
647 | { |
648 | ppc4xx_sdram_t *sdram; |
649 | |
650 | sdram = g_malloc0(sizeof(ppc4xx_sdram_t)); |
651 | sdram->irq = irq; |
652 | sdram->nbanks = nbanks; |
653 | sdram->ram_memories = ram_memories; |
654 | memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr)); |
655 | memcpy(sdram->ram_bases, ram_bases, |
656 | nbanks * sizeof(hwaddr)); |
657 | memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr)); |
658 | memcpy(sdram->ram_sizes, ram_sizes, |
659 | nbanks * sizeof(hwaddr)); |
660 | qemu_register_reset(&sdram_reset, sdram); |
661 | ppc_dcr_register(env, SDRAM0_CFGADDR, |
662 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
663 | ppc_dcr_register(env, SDRAM0_CFGDATA, |
664 | sdram, &dcr_read_sdram, &dcr_write_sdram); |
665 | if (do_init) |
666 | sdram_map_bcr(sdram); |
667 | } |
668 | |
669 | /* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory. |
670 | * |
671 | * sdram_bank_sizes[] must be 0-terminated. |
672 | * |
673 | * The 4xx SDRAM controller supports a small number of banks, and each bank |
674 | * must be one of a small set of sizes. The number of banks and the supported |
675 | * sizes varies by SoC. */ |
676 | ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, |
677 | MemoryRegion ram_memories[], |
678 | hwaddr ram_bases[], |
679 | hwaddr ram_sizes[], |
680 | const ram_addr_t sdram_bank_sizes[]) |
681 | { |
682 | MemoryRegion *ram = g_malloc0(sizeof(*ram)); |
683 | ram_addr_t size_left = ram_size; |
684 | ram_addr_t base = 0; |
685 | ram_addr_t bank_size; |
686 | int i; |
687 | int j; |
688 | |
689 | for (i = 0; i < nr_banks; i++) { |
690 | for (j = 0; sdram_bank_sizes[j] != 0; j++) { |
691 | bank_size = sdram_bank_sizes[j]; |
692 | if (bank_size <= size_left) { |
693 | size_left -= bank_size; |
694 | } |
695 | } |
696 | if (!size_left) { |
697 | /* No need to use the remaining banks. */ |
698 | break; |
699 | } |
700 | } |
701 | |
702 | ram_size -= size_left; |
703 | if (size_left) { |
704 | error_report("Truncating memory to %" PRId64 " MiB to fit SDRAM" |
705 | " controller limits" , ram_size / MiB); |
706 | } |
707 | |
708 | memory_region_allocate_system_memory(ram, NULL, "ppc4xx.sdram" , ram_size); |
709 | |
710 | size_left = ram_size; |
711 | for (i = 0; i < nr_banks && size_left; i++) { |
712 | for (j = 0; sdram_bank_sizes[j] != 0; j++) { |
713 | bank_size = sdram_bank_sizes[j]; |
714 | |
715 | if (bank_size <= size_left) { |
716 | char name[32]; |
717 | snprintf(name, sizeof(name), "ppc4xx.sdram%d" , i); |
718 | memory_region_init_alias(&ram_memories[i], NULL, name, ram, |
719 | base, bank_size); |
720 | ram_bases[i] = base; |
721 | ram_sizes[i] = bank_size; |
722 | base += bank_size; |
723 | size_left -= bank_size; |
724 | break; |
725 | } |
726 | } |
727 | } |
728 | |
729 | return ram_size; |
730 | } |
731 | |
732 | /*****************************************************************************/ |
733 | /* MAL */ |
734 | |
735 | enum { |
736 | MAL0_CFG = 0x180, |
737 | MAL0_ESR = 0x181, |
738 | MAL0_IER = 0x182, |
739 | MAL0_TXCASR = 0x184, |
740 | MAL0_TXCARR = 0x185, |
741 | MAL0_TXEOBISR = 0x186, |
742 | MAL0_TXDEIR = 0x187, |
743 | MAL0_RXCASR = 0x190, |
744 | MAL0_RXCARR = 0x191, |
745 | MAL0_RXEOBISR = 0x192, |
746 | MAL0_RXDEIR = 0x193, |
747 | MAL0_TXCTP0R = 0x1A0, |
748 | MAL0_RXCTP0R = 0x1C0, |
749 | MAL0_RCBS0 = 0x1E0, |
750 | MAL0_RCBS1 = 0x1E1, |
751 | }; |
752 | |
753 | typedef struct ppc4xx_mal_t ppc4xx_mal_t; |
754 | struct ppc4xx_mal_t { |
755 | qemu_irq irqs[4]; |
756 | uint32_t cfg; |
757 | uint32_t esr; |
758 | uint32_t ier; |
759 | uint32_t txcasr; |
760 | uint32_t txcarr; |
761 | uint32_t txeobisr; |
762 | uint32_t txdeir; |
763 | uint32_t rxcasr; |
764 | uint32_t rxcarr; |
765 | uint32_t rxeobisr; |
766 | uint32_t rxdeir; |
767 | uint32_t *txctpr; |
768 | uint32_t *rxctpr; |
769 | uint32_t *rcbs; |
770 | uint8_t txcnum; |
771 | uint8_t rxcnum; |
772 | }; |
773 | |
774 | static void ppc4xx_mal_reset(void *opaque) |
775 | { |
776 | ppc4xx_mal_t *mal; |
777 | |
778 | mal = opaque; |
779 | mal->cfg = 0x0007C000; |
780 | mal->esr = 0x00000000; |
781 | mal->ier = 0x00000000; |
782 | mal->rxcasr = 0x00000000; |
783 | mal->rxdeir = 0x00000000; |
784 | mal->rxeobisr = 0x00000000; |
785 | mal->txcasr = 0x00000000; |
786 | mal->txdeir = 0x00000000; |
787 | mal->txeobisr = 0x00000000; |
788 | } |
789 | |
790 | static uint32_t dcr_read_mal(void *opaque, int dcrn) |
791 | { |
792 | ppc4xx_mal_t *mal; |
793 | uint32_t ret; |
794 | |
795 | mal = opaque; |
796 | switch (dcrn) { |
797 | case MAL0_CFG: |
798 | ret = mal->cfg; |
799 | break; |
800 | case MAL0_ESR: |
801 | ret = mal->esr; |
802 | break; |
803 | case MAL0_IER: |
804 | ret = mal->ier; |
805 | break; |
806 | case MAL0_TXCASR: |
807 | ret = mal->txcasr; |
808 | break; |
809 | case MAL0_TXCARR: |
810 | ret = mal->txcarr; |
811 | break; |
812 | case MAL0_TXEOBISR: |
813 | ret = mal->txeobisr; |
814 | break; |
815 | case MAL0_TXDEIR: |
816 | ret = mal->txdeir; |
817 | break; |
818 | case MAL0_RXCASR: |
819 | ret = mal->rxcasr; |
820 | break; |
821 | case MAL0_RXCARR: |
822 | ret = mal->rxcarr; |
823 | break; |
824 | case MAL0_RXEOBISR: |
825 | ret = mal->rxeobisr; |
826 | break; |
827 | case MAL0_RXDEIR: |
828 | ret = mal->rxdeir; |
829 | break; |
830 | default: |
831 | ret = 0; |
832 | break; |
833 | } |
834 | if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { |
835 | ret = mal->txctpr[dcrn - MAL0_TXCTP0R]; |
836 | } |
837 | if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { |
838 | ret = mal->rxctpr[dcrn - MAL0_RXCTP0R]; |
839 | } |
840 | if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { |
841 | ret = mal->rcbs[dcrn - MAL0_RCBS0]; |
842 | } |
843 | |
844 | return ret; |
845 | } |
846 | |
847 | static void dcr_write_mal(void *opaque, int dcrn, uint32_t val) |
848 | { |
849 | ppc4xx_mal_t *mal; |
850 | |
851 | mal = opaque; |
852 | switch (dcrn) { |
853 | case MAL0_CFG: |
854 | if (val & 0x80000000) { |
855 | ppc4xx_mal_reset(mal); |
856 | } |
857 | mal->cfg = val & 0x00FFC087; |
858 | break; |
859 | case MAL0_ESR: |
860 | /* Read/clear */ |
861 | mal->esr &= ~val; |
862 | break; |
863 | case MAL0_IER: |
864 | mal->ier = val & 0x0000001F; |
865 | break; |
866 | case MAL0_TXCASR: |
867 | mal->txcasr = val & 0xF0000000; |
868 | break; |
869 | case MAL0_TXCARR: |
870 | mal->txcarr = val & 0xF0000000; |
871 | break; |
872 | case MAL0_TXEOBISR: |
873 | /* Read/clear */ |
874 | mal->txeobisr &= ~val; |
875 | break; |
876 | case MAL0_TXDEIR: |
877 | /* Read/clear */ |
878 | mal->txdeir &= ~val; |
879 | break; |
880 | case MAL0_RXCASR: |
881 | mal->rxcasr = val & 0xC0000000; |
882 | break; |
883 | case MAL0_RXCARR: |
884 | mal->rxcarr = val & 0xC0000000; |
885 | break; |
886 | case MAL0_RXEOBISR: |
887 | /* Read/clear */ |
888 | mal->rxeobisr &= ~val; |
889 | break; |
890 | case MAL0_RXDEIR: |
891 | /* Read/clear */ |
892 | mal->rxdeir &= ~val; |
893 | break; |
894 | } |
895 | if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { |
896 | mal->txctpr[dcrn - MAL0_TXCTP0R] = val; |
897 | } |
898 | if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { |
899 | mal->rxctpr[dcrn - MAL0_RXCTP0R] = val; |
900 | } |
901 | if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { |
902 | mal->rcbs[dcrn - MAL0_RCBS0] = val & 0x000000FF; |
903 | } |
904 | } |
905 | |
906 | void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, |
907 | qemu_irq irqs[4]) |
908 | { |
909 | ppc4xx_mal_t *mal; |
910 | int i; |
911 | |
912 | assert(txcnum <= 32 && rxcnum <= 32); |
913 | mal = g_malloc0(sizeof(*mal)); |
914 | mal->txcnum = txcnum; |
915 | mal->rxcnum = rxcnum; |
916 | mal->txctpr = g_new0(uint32_t, txcnum); |
917 | mal->rxctpr = g_new0(uint32_t, rxcnum); |
918 | mal->rcbs = g_new0(uint32_t, rxcnum); |
919 | for (i = 0; i < 4; i++) { |
920 | mal->irqs[i] = irqs[i]; |
921 | } |
922 | qemu_register_reset(&ppc4xx_mal_reset, mal); |
923 | ppc_dcr_register(env, MAL0_CFG, |
924 | mal, &dcr_read_mal, &dcr_write_mal); |
925 | ppc_dcr_register(env, MAL0_ESR, |
926 | mal, &dcr_read_mal, &dcr_write_mal); |
927 | ppc_dcr_register(env, MAL0_IER, |
928 | mal, &dcr_read_mal, &dcr_write_mal); |
929 | ppc_dcr_register(env, MAL0_TXCASR, |
930 | mal, &dcr_read_mal, &dcr_write_mal); |
931 | ppc_dcr_register(env, MAL0_TXCARR, |
932 | mal, &dcr_read_mal, &dcr_write_mal); |
933 | ppc_dcr_register(env, MAL0_TXEOBISR, |
934 | mal, &dcr_read_mal, &dcr_write_mal); |
935 | ppc_dcr_register(env, MAL0_TXDEIR, |
936 | mal, &dcr_read_mal, &dcr_write_mal); |
937 | ppc_dcr_register(env, MAL0_RXCASR, |
938 | mal, &dcr_read_mal, &dcr_write_mal); |
939 | ppc_dcr_register(env, MAL0_RXCARR, |
940 | mal, &dcr_read_mal, &dcr_write_mal); |
941 | ppc_dcr_register(env, MAL0_RXEOBISR, |
942 | mal, &dcr_read_mal, &dcr_write_mal); |
943 | ppc_dcr_register(env, MAL0_RXDEIR, |
944 | mal, &dcr_read_mal, &dcr_write_mal); |
945 | for (i = 0; i < txcnum; i++) { |
946 | ppc_dcr_register(env, MAL0_TXCTP0R + i, |
947 | mal, &dcr_read_mal, &dcr_write_mal); |
948 | } |
949 | for (i = 0; i < rxcnum; i++) { |
950 | ppc_dcr_register(env, MAL0_RXCTP0R + i, |
951 | mal, &dcr_read_mal, &dcr_write_mal); |
952 | } |
953 | for (i = 0; i < rxcnum; i++) { |
954 | ppc_dcr_register(env, MAL0_RCBS0 + i, |
955 | mal, &dcr_read_mal, &dcr_write_mal); |
956 | } |
957 | } |
958 | |