|
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 #include "hw.h" |
|
25 #include "ppc.h" |
|
26 #include "ppc4xx.h" |
|
27 #include "sysemu.h" |
|
28 #include "qemu-log.h" |
|
29 |
|
30 //#define DEBUG_MMIO |
|
31 //#define DEBUG_UNASSIGNED |
|
32 #define DEBUG_UIC |
|
33 |
|
34 /*****************************************************************************/ |
|
35 /* Generic PowerPC 4xx processor instanciation */ |
|
36 CPUState *ppc4xx_init (const char *cpu_model, |
|
37 clk_setup_t *cpu_clk, clk_setup_t *tb_clk, |
|
38 uint32_t sysclk) |
|
39 { |
|
40 CPUState *env; |
|
41 |
|
42 /* init CPUs */ |
|
43 env = cpu_init(cpu_model); |
|
44 if (!env) { |
|
45 fprintf(stderr, "Unable to find PowerPC %s CPU definition\n", |
|
46 cpu_model); |
|
47 exit(1); |
|
48 } |
|
49 cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ |
|
50 cpu_clk->opaque = env; |
|
51 /* Set time-base frequency to sysclk */ |
|
52 tb_clk->cb = ppc_emb_timers_init(env, sysclk); |
|
53 tb_clk->opaque = env; |
|
54 ppc_dcr_init(env, NULL, NULL); |
|
55 /* Register qemu callbacks */ |
|
56 qemu_register_reset(&cpu_ppc_reset, env); |
|
57 |
|
58 return env; |
|
59 } |
|
60 |
|
61 /*****************************************************************************/ |
|
62 /* Fake device used to map multiple devices in a single memory page */ |
|
63 #define MMIO_AREA_BITS 8 |
|
64 #define MMIO_AREA_LEN (1 << MMIO_AREA_BITS) |
|
65 #define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS)) |
|
66 #define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1)) |
|
67 struct ppc4xx_mmio_t { |
|
68 target_phys_addr_t base; |
|
69 CPUReadMemoryFunc **mem_read[MMIO_AREA_NB]; |
|
70 CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB]; |
|
71 void *opaque[MMIO_AREA_NB]; |
|
72 }; |
|
73 |
|
74 static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr) |
|
75 { |
|
76 #ifdef DEBUG_UNASSIGNED |
|
77 ppc4xx_mmio_t *mmio; |
|
78 |
|
79 mmio = opaque; |
|
80 printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n", |
|
81 addr, mmio->base); |
|
82 #endif |
|
83 |
|
84 return 0; |
|
85 } |
|
86 |
|
87 static void unassigned_mmio_writeb (void *opaque, |
|
88 target_phys_addr_t addr, uint32_t val) |
|
89 { |
|
90 #ifdef DEBUG_UNASSIGNED |
|
91 ppc4xx_mmio_t *mmio; |
|
92 |
|
93 mmio = opaque; |
|
94 printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n", |
|
95 addr, val, mmio->base); |
|
96 #endif |
|
97 } |
|
98 |
|
99 static CPUReadMemoryFunc *unassigned_mmio_read[3] = { |
|
100 unassigned_mmio_readb, |
|
101 unassigned_mmio_readb, |
|
102 unassigned_mmio_readb, |
|
103 }; |
|
104 |
|
105 static CPUWriteMemoryFunc *unassigned_mmio_write[3] = { |
|
106 unassigned_mmio_writeb, |
|
107 unassigned_mmio_writeb, |
|
108 unassigned_mmio_writeb, |
|
109 }; |
|
110 |
|
111 static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio, |
|
112 target_phys_addr_t addr, int len) |
|
113 { |
|
114 CPUReadMemoryFunc **mem_read; |
|
115 uint32_t ret; |
|
116 int idx; |
|
117 |
|
118 idx = MMIO_IDX(addr); |
|
119 #if defined(DEBUG_MMIO) |
|
120 printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__, |
|
121 mmio, len, addr, idx); |
|
122 #endif |
|
123 mem_read = mmio->mem_read[idx]; |
|
124 ret = (*mem_read[len])(mmio->opaque[idx], addr); |
|
125 |
|
126 return ret; |
|
127 } |
|
128 |
|
129 static void mmio_writelen (ppc4xx_mmio_t *mmio, |
|
130 target_phys_addr_t addr, uint32_t value, int len) |
|
131 { |
|
132 CPUWriteMemoryFunc **mem_write; |
|
133 int idx; |
|
134 |
|
135 idx = MMIO_IDX(addr); |
|
136 #if defined(DEBUG_MMIO) |
|
137 printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08" PRIx32 "\n", |
|
138 __func__, mmio, len, addr, idx, value); |
|
139 #endif |
|
140 mem_write = mmio->mem_write[idx]; |
|
141 (*mem_write[len])(mmio->opaque[idx], addr, value); |
|
142 } |
|
143 |
|
144 static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr) |
|
145 { |
|
146 #if defined(DEBUG_MMIO) |
|
147 printf("%s: addr " PADDRX "\n", __func__, addr); |
|
148 #endif |
|
149 |
|
150 return mmio_readlen(opaque, addr, 0); |
|
151 } |
|
152 |
|
153 static void mmio_writeb (void *opaque, |
|
154 target_phys_addr_t addr, uint32_t value) |
|
155 { |
|
156 #if defined(DEBUG_MMIO) |
|
157 printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); |
|
158 #endif |
|
159 mmio_writelen(opaque, addr, value, 0); |
|
160 } |
|
161 |
|
162 static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr) |
|
163 { |
|
164 #if defined(DEBUG_MMIO) |
|
165 printf("%s: addr " PADDRX "\n", __func__, addr); |
|
166 #endif |
|
167 |
|
168 return mmio_readlen(opaque, addr, 1); |
|
169 } |
|
170 |
|
171 static void mmio_writew (void *opaque, |
|
172 target_phys_addr_t addr, uint32_t value) |
|
173 { |
|
174 #if defined(DEBUG_MMIO) |
|
175 printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); |
|
176 #endif |
|
177 mmio_writelen(opaque, addr, value, 1); |
|
178 } |
|
179 |
|
180 static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr) |
|
181 { |
|
182 #if defined(DEBUG_MMIO) |
|
183 printf("%s: addr " PADDRX "\n", __func__, addr); |
|
184 #endif |
|
185 |
|
186 return mmio_readlen(opaque, addr, 2); |
|
187 } |
|
188 |
|
189 static void mmio_writel (void *opaque, |
|
190 target_phys_addr_t addr, uint32_t value) |
|
191 { |
|
192 #if defined(DEBUG_MMIO) |
|
193 printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); |
|
194 #endif |
|
195 mmio_writelen(opaque, addr, value, 2); |
|
196 } |
|
197 |
|
198 static CPUReadMemoryFunc *mmio_read[] = { |
|
199 &mmio_readb, |
|
200 &mmio_readw, |
|
201 &mmio_readl, |
|
202 }; |
|
203 |
|
204 static CPUWriteMemoryFunc *mmio_write[] = { |
|
205 &mmio_writeb, |
|
206 &mmio_writew, |
|
207 &mmio_writel, |
|
208 }; |
|
209 |
|
210 int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, |
|
211 target_phys_addr_t offset, uint32_t len, |
|
212 CPUReadMemoryFunc **mem_read, |
|
213 CPUWriteMemoryFunc **mem_write, void *opaque) |
|
214 { |
|
215 target_phys_addr_t end; |
|
216 int idx, eidx; |
|
217 |
|
218 if ((offset + len) > TARGET_PAGE_SIZE) |
|
219 return -1; |
|
220 idx = MMIO_IDX(offset); |
|
221 end = offset + len - 1; |
|
222 eidx = MMIO_IDX(end); |
|
223 #if defined(DEBUG_MMIO) |
|
224 printf("%s: offset " PADDRX " len %08" PRIx32 " " PADDRX " %d %d\n", |
|
225 __func__, offset, len, end, idx, eidx); |
|
226 #endif |
|
227 for (; idx <= eidx; idx++) { |
|
228 mmio->mem_read[idx] = mem_read; |
|
229 mmio->mem_write[idx] = mem_write; |
|
230 mmio->opaque[idx] = opaque; |
|
231 } |
|
232 |
|
233 return 0; |
|
234 } |
|
235 |
|
236 ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base) |
|
237 { |
|
238 ppc4xx_mmio_t *mmio; |
|
239 int mmio_memory; |
|
240 |
|
241 mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t)); |
|
242 if (mmio != NULL) { |
|
243 mmio->base = base; |
|
244 mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio); |
|
245 #if defined(DEBUG_MMIO) |
|
246 printf("%s: base " PADDRX " len %08x %d\n", __func__, |
|
247 base, TARGET_PAGE_SIZE, mmio_memory); |
|
248 #endif |
|
249 cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory); |
|
250 ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE, |
|
251 unassigned_mmio_read, unassigned_mmio_write, |
|
252 mmio); |
|
253 } |
|
254 |
|
255 return mmio; |
|
256 } |
|
257 |
|
258 /*****************************************************************************/ |
|
259 /* "Universal" Interrupt controller */ |
|
260 enum { |
|
261 DCR_UICSR = 0x000, |
|
262 DCR_UICSRS = 0x001, |
|
263 DCR_UICER = 0x002, |
|
264 DCR_UICCR = 0x003, |
|
265 DCR_UICPR = 0x004, |
|
266 DCR_UICTR = 0x005, |
|
267 DCR_UICMSR = 0x006, |
|
268 DCR_UICVR = 0x007, |
|
269 DCR_UICVCR = 0x008, |
|
270 DCR_UICMAX = 0x009, |
|
271 }; |
|
272 |
|
273 #define UIC_MAX_IRQ 32 |
|
274 typedef struct ppcuic_t ppcuic_t; |
|
275 struct ppcuic_t { |
|
276 uint32_t dcr_base; |
|
277 int use_vectors; |
|
278 uint32_t level; /* Remembers the state of level-triggered interrupts. */ |
|
279 uint32_t uicsr; /* Status register */ |
|
280 uint32_t uicer; /* Enable register */ |
|
281 uint32_t uiccr; /* Critical register */ |
|
282 uint32_t uicpr; /* Polarity register */ |
|
283 uint32_t uictr; /* Triggering register */ |
|
284 uint32_t uicvcr; /* Vector configuration register */ |
|
285 uint32_t uicvr; |
|
286 qemu_irq *irqs; |
|
287 }; |
|
288 |
|
289 static void ppcuic_trigger_irq (ppcuic_t *uic) |
|
290 { |
|
291 uint32_t ir, cr; |
|
292 int start, end, inc, i; |
|
293 |
|
294 /* Trigger interrupt if any is pending */ |
|
295 ir = uic->uicsr & uic->uicer & (~uic->uiccr); |
|
296 cr = uic->uicsr & uic->uicer & uic->uiccr; |
|
297 #ifdef DEBUG_UIC |
|
298 if (loglevel & CPU_LOG_INT) { |
|
299 fprintf(logfile, "%s: uicsr %08" PRIx32 " uicer %08" PRIx32 |
|
300 " uiccr %08" PRIx32 "\n" |
|
301 " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n", |
|
302 __func__, uic->uicsr, uic->uicer, uic->uiccr, |
|
303 uic->uicsr & uic->uicer, ir, cr); |
|
304 } |
|
305 #endif |
|
306 if (ir != 0x0000000) { |
|
307 #ifdef DEBUG_UIC |
|
308 if (loglevel & CPU_LOG_INT) { |
|
309 fprintf(logfile, "Raise UIC interrupt\n"); |
|
310 } |
|
311 #endif |
|
312 qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); |
|
313 } else { |
|
314 #ifdef DEBUG_UIC |
|
315 if (loglevel & CPU_LOG_INT) { |
|
316 fprintf(logfile, "Lower UIC interrupt\n"); |
|
317 } |
|
318 #endif |
|
319 qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); |
|
320 } |
|
321 /* Trigger critical interrupt if any is pending and update vector */ |
|
322 if (cr != 0x0000000) { |
|
323 qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); |
|
324 if (uic->use_vectors) { |
|
325 /* Compute critical IRQ vector */ |
|
326 if (uic->uicvcr & 1) { |
|
327 start = 31; |
|
328 end = 0; |
|
329 inc = -1; |
|
330 } else { |
|
331 start = 0; |
|
332 end = 31; |
|
333 inc = 1; |
|
334 } |
|
335 uic->uicvr = uic->uicvcr & 0xFFFFFFFC; |
|
336 for (i = start; i <= end; i += inc) { |
|
337 if (cr & (1 << i)) { |
|
338 uic->uicvr += (i - start) * 512 * inc; |
|
339 break; |
|
340 } |
|
341 } |
|
342 } |
|
343 #ifdef DEBUG_UIC |
|
344 if (loglevel & CPU_LOG_INT) { |
|
345 fprintf(logfile, "Raise UIC critical interrupt - " |
|
346 "vector %08" PRIx32 "\n", uic->uicvr); |
|
347 } |
|
348 #endif |
|
349 } else { |
|
350 #ifdef DEBUG_UIC |
|
351 if (loglevel & CPU_LOG_INT) { |
|
352 fprintf(logfile, "Lower UIC critical interrupt\n"); |
|
353 } |
|
354 #endif |
|
355 qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); |
|
356 uic->uicvr = 0x00000000; |
|
357 } |
|
358 } |
|
359 |
|
360 static void ppcuic_set_irq (void *opaque, int irq_num, int level) |
|
361 { |
|
362 ppcuic_t *uic; |
|
363 uint32_t mask, sr; |
|
364 |
|
365 uic = opaque; |
|
366 mask = 1 << (31-irq_num); |
|
367 #ifdef DEBUG_UIC |
|
368 if (loglevel & CPU_LOG_INT) { |
|
369 fprintf(logfile, "%s: irq %d level %d uicsr %08" PRIx32 |
|
370 " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", |
|
371 __func__, irq_num, level, |
|
372 uic->uicsr, mask, uic->uicsr & mask, level << irq_num); |
|
373 } |
|
374 #endif |
|
375 if (irq_num < 0 || irq_num > 31) |
|
376 return; |
|
377 sr = uic->uicsr; |
|
378 |
|
379 /* Update status register */ |
|
380 if (uic->uictr & mask) { |
|
381 /* Edge sensitive interrupt */ |
|
382 if (level == 1) |
|
383 uic->uicsr |= mask; |
|
384 } else { |
|
385 /* Level sensitive interrupt */ |
|
386 if (level == 1) { |
|
387 uic->uicsr |= mask; |
|
388 uic->level |= mask; |
|
389 } else { |
|
390 uic->uicsr &= ~mask; |
|
391 uic->level &= ~mask; |
|
392 } |
|
393 } |
|
394 #ifdef DEBUG_UIC |
|
395 if (loglevel & CPU_LOG_INT) { |
|
396 fprintf(logfile, "%s: irq %d level %d sr %" PRIx32 " => " |
|
397 "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr); |
|
398 } |
|
399 #endif |
|
400 if (sr != uic->uicsr) |
|
401 ppcuic_trigger_irq(uic); |
|
402 } |
|
403 |
|
404 static target_ulong dcr_read_uic (void *opaque, int dcrn) |
|
405 { |
|
406 ppcuic_t *uic; |
|
407 target_ulong ret; |
|
408 |
|
409 uic = opaque; |
|
410 dcrn -= uic->dcr_base; |
|
411 switch (dcrn) { |
|
412 case DCR_UICSR: |
|
413 case DCR_UICSRS: |
|
414 ret = uic->uicsr; |
|
415 break; |
|
416 case DCR_UICER: |
|
417 ret = uic->uicer; |
|
418 break; |
|
419 case DCR_UICCR: |
|
420 ret = uic->uiccr; |
|
421 break; |
|
422 case DCR_UICPR: |
|
423 ret = uic->uicpr; |
|
424 break; |
|
425 case DCR_UICTR: |
|
426 ret = uic->uictr; |
|
427 break; |
|
428 case DCR_UICMSR: |
|
429 ret = uic->uicsr & uic->uicer; |
|
430 break; |
|
431 case DCR_UICVR: |
|
432 if (!uic->use_vectors) |
|
433 goto no_read; |
|
434 ret = uic->uicvr; |
|
435 break; |
|
436 case DCR_UICVCR: |
|
437 if (!uic->use_vectors) |
|
438 goto no_read; |
|
439 ret = uic->uicvcr; |
|
440 break; |
|
441 default: |
|
442 no_read: |
|
443 ret = 0x00000000; |
|
444 break; |
|
445 } |
|
446 |
|
447 return ret; |
|
448 } |
|
449 |
|
450 static void dcr_write_uic (void *opaque, int dcrn, target_ulong val) |
|
451 { |
|
452 ppcuic_t *uic; |
|
453 |
|
454 uic = opaque; |
|
455 dcrn -= uic->dcr_base; |
|
456 #ifdef DEBUG_UIC |
|
457 if (loglevel & CPU_LOG_INT) { |
|
458 fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val); |
|
459 } |
|
460 #endif |
|
461 switch (dcrn) { |
|
462 case DCR_UICSR: |
|
463 uic->uicsr &= ~val; |
|
464 uic->uicsr |= uic->level; |
|
465 ppcuic_trigger_irq(uic); |
|
466 break; |
|
467 case DCR_UICSRS: |
|
468 uic->uicsr |= val; |
|
469 ppcuic_trigger_irq(uic); |
|
470 break; |
|
471 case DCR_UICER: |
|
472 uic->uicer = val; |
|
473 ppcuic_trigger_irq(uic); |
|
474 break; |
|
475 case DCR_UICCR: |
|
476 uic->uiccr = val; |
|
477 ppcuic_trigger_irq(uic); |
|
478 break; |
|
479 case DCR_UICPR: |
|
480 uic->uicpr = val; |
|
481 break; |
|
482 case DCR_UICTR: |
|
483 uic->uictr = val; |
|
484 ppcuic_trigger_irq(uic); |
|
485 break; |
|
486 case DCR_UICMSR: |
|
487 break; |
|
488 case DCR_UICVR: |
|
489 break; |
|
490 case DCR_UICVCR: |
|
491 uic->uicvcr = val & 0xFFFFFFFD; |
|
492 ppcuic_trigger_irq(uic); |
|
493 break; |
|
494 } |
|
495 } |
|
496 |
|
497 static void ppcuic_reset (void *opaque) |
|
498 { |
|
499 ppcuic_t *uic; |
|
500 |
|
501 uic = opaque; |
|
502 uic->uiccr = 0x00000000; |
|
503 uic->uicer = 0x00000000; |
|
504 uic->uicpr = 0x00000000; |
|
505 uic->uicsr = 0x00000000; |
|
506 uic->uictr = 0x00000000; |
|
507 if (uic->use_vectors) { |
|
508 uic->uicvcr = 0x00000000; |
|
509 uic->uicvr = 0x0000000; |
|
510 } |
|
511 } |
|
512 |
|
513 qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, |
|
514 uint32_t dcr_base, int has_ssr, int has_vr) |
|
515 { |
|
516 ppcuic_t *uic; |
|
517 int i; |
|
518 |
|
519 uic = qemu_mallocz(sizeof(ppcuic_t)); |
|
520 if (uic != NULL) { |
|
521 uic->dcr_base = dcr_base; |
|
522 uic->irqs = irqs; |
|
523 if (has_vr) |
|
524 uic->use_vectors = 1; |
|
525 for (i = 0; i < DCR_UICMAX; i++) { |
|
526 ppc_dcr_register(env, dcr_base + i, uic, |
|
527 &dcr_read_uic, &dcr_write_uic); |
|
528 } |
|
529 qemu_register_reset(ppcuic_reset, uic); |
|
530 ppcuic_reset(uic); |
|
531 } |
|
532 |
|
533 return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); |
|
534 } |
|
535 |
|
536 /*****************************************************************************/ |
|
537 /* SDRAM controller */ |
|
538 typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; |
|
539 struct ppc4xx_sdram_t { |
|
540 uint32_t addr; |
|
541 int nbanks; |
|
542 target_phys_addr_t ram_bases[4]; |
|
543 target_phys_addr_t ram_sizes[4]; |
|
544 uint32_t besr0; |
|
545 uint32_t besr1; |
|
546 uint32_t bear; |
|
547 uint32_t cfg; |
|
548 uint32_t status; |
|
549 uint32_t rtr; |
|
550 uint32_t pmit; |
|
551 uint32_t bcr[4]; |
|
552 uint32_t tr; |
|
553 uint32_t ecccfg; |
|
554 uint32_t eccesr; |
|
555 qemu_irq irq; |
|
556 }; |
|
557 |
|
558 enum { |
|
559 SDRAM0_CFGADDR = 0x010, |
|
560 SDRAM0_CFGDATA = 0x011, |
|
561 }; |
|
562 |
|
563 /* XXX: TOFIX: some patches have made this code become inconsistent: |
|
564 * there are type inconsistencies, mixing target_phys_addr_t, target_ulong |
|
565 * and uint32_t |
|
566 */ |
|
567 static uint32_t sdram_bcr (target_phys_addr_t ram_base, |
|
568 target_phys_addr_t ram_size) |
|
569 { |
|
570 uint32_t bcr; |
|
571 |
|
572 switch (ram_size) { |
|
573 case (4 * 1024 * 1024): |
|
574 bcr = 0x00000000; |
|
575 break; |
|
576 case (8 * 1024 * 1024): |
|
577 bcr = 0x00020000; |
|
578 break; |
|
579 case (16 * 1024 * 1024): |
|
580 bcr = 0x00040000; |
|
581 break; |
|
582 case (32 * 1024 * 1024): |
|
583 bcr = 0x00060000; |
|
584 break; |
|
585 case (64 * 1024 * 1024): |
|
586 bcr = 0x00080000; |
|
587 break; |
|
588 case (128 * 1024 * 1024): |
|
589 bcr = 0x000A0000; |
|
590 break; |
|
591 case (256 * 1024 * 1024): |
|
592 bcr = 0x000C0000; |
|
593 break; |
|
594 default: |
|
595 printf("%s: invalid RAM size " PADDRX "\n", __func__, ram_size); |
|
596 return 0x00000000; |
|
597 } |
|
598 bcr |= ram_base & 0xFF800000; |
|
599 bcr |= 1; |
|
600 |
|
601 return bcr; |
|
602 } |
|
603 |
|
604 static always_inline target_phys_addr_t sdram_base (uint32_t bcr) |
|
605 { |
|
606 return bcr & 0xFF800000; |
|
607 } |
|
608 |
|
609 static target_ulong sdram_size (uint32_t bcr) |
|
610 { |
|
611 target_ulong size; |
|
612 int sh; |
|
613 |
|
614 sh = (bcr >> 17) & 0x7; |
|
615 if (sh == 7) |
|
616 size = -1; |
|
617 else |
|
618 size = (4 * 1024 * 1024) << sh; |
|
619 |
|
620 return size; |
|
621 } |
|
622 |
|
623 static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled) |
|
624 { |
|
625 if (*bcrp & 0x00000001) { |
|
626 /* Unmap RAM */ |
|
627 #ifdef DEBUG_SDRAM |
|
628 printf("%s: unmap RAM area " PADDRX " " ADDRX "\n", |
|
629 __func__, sdram_base(*bcrp), sdram_size(*bcrp)); |
|
630 #endif |
|
631 cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp), |
|
632 IO_MEM_UNASSIGNED); |
|
633 } |
|
634 *bcrp = bcr & 0xFFDEE001; |
|
635 if (enabled && (bcr & 0x00000001)) { |
|
636 #ifdef DEBUG_SDRAM |
|
637 printf("%s: Map RAM area " PADDRX " " ADDRX "\n", |
|
638 __func__, sdram_base(bcr), sdram_size(bcr)); |
|
639 #endif |
|
640 cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr), |
|
641 sdram_base(bcr) | IO_MEM_RAM); |
|
642 } |
|
643 } |
|
644 |
|
645 static void sdram_map_bcr (ppc4xx_sdram_t *sdram) |
|
646 { |
|
647 int i; |
|
648 |
|
649 for (i = 0; i < sdram->nbanks; i++) { |
|
650 if (sdram->ram_sizes[i] != 0) { |
|
651 sdram_set_bcr(&sdram->bcr[i], |
|
652 sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]), |
|
653 1); |
|
654 } else { |
|
655 sdram_set_bcr(&sdram->bcr[i], 0x00000000, 0); |
|
656 } |
|
657 } |
|
658 } |
|
659 |
|
660 static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) |
|
661 { |
|
662 int i; |
|
663 |
|
664 for (i = 0; i < sdram->nbanks; i++) { |
|
665 #ifdef DEBUG_SDRAM |
|
666 printf("%s: Unmap RAM area " PADDRX " " ADDRX "\n", |
|
667 __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); |
|
668 #endif |
|
669 cpu_register_physical_memory(sdram_base(sdram->bcr[i]), |
|
670 sdram_size(sdram->bcr[i]), |
|
671 IO_MEM_UNASSIGNED); |
|
672 } |
|
673 } |
|
674 |
|
675 static target_ulong dcr_read_sdram (void *opaque, int dcrn) |
|
676 { |
|
677 ppc4xx_sdram_t *sdram; |
|
678 target_ulong ret; |
|
679 |
|
680 sdram = opaque; |
|
681 switch (dcrn) { |
|
682 case SDRAM0_CFGADDR: |
|
683 ret = sdram->addr; |
|
684 break; |
|
685 case SDRAM0_CFGDATA: |
|
686 switch (sdram->addr) { |
|
687 case 0x00: /* SDRAM_BESR0 */ |
|
688 ret = sdram->besr0; |
|
689 break; |
|
690 case 0x08: /* SDRAM_BESR1 */ |
|
691 ret = sdram->besr1; |
|
692 break; |
|
693 case 0x10: /* SDRAM_BEAR */ |
|
694 ret = sdram->bear; |
|
695 break; |
|
696 case 0x20: /* SDRAM_CFG */ |
|
697 ret = sdram->cfg; |
|
698 break; |
|
699 case 0x24: /* SDRAM_STATUS */ |
|
700 ret = sdram->status; |
|
701 break; |
|
702 case 0x30: /* SDRAM_RTR */ |
|
703 ret = sdram->rtr; |
|
704 break; |
|
705 case 0x34: /* SDRAM_PMIT */ |
|
706 ret = sdram->pmit; |
|
707 break; |
|
708 case 0x40: /* SDRAM_B0CR */ |
|
709 ret = sdram->bcr[0]; |
|
710 break; |
|
711 case 0x44: /* SDRAM_B1CR */ |
|
712 ret = sdram->bcr[1]; |
|
713 break; |
|
714 case 0x48: /* SDRAM_B2CR */ |
|
715 ret = sdram->bcr[2]; |
|
716 break; |
|
717 case 0x4C: /* SDRAM_B3CR */ |
|
718 ret = sdram->bcr[3]; |
|
719 break; |
|
720 case 0x80: /* SDRAM_TR */ |
|
721 ret = -1; /* ? */ |
|
722 break; |
|
723 case 0x94: /* SDRAM_ECCCFG */ |
|
724 ret = sdram->ecccfg; |
|
725 break; |
|
726 case 0x98: /* SDRAM_ECCESR */ |
|
727 ret = sdram->eccesr; |
|
728 break; |
|
729 default: /* Error */ |
|
730 ret = -1; |
|
731 break; |
|
732 } |
|
733 break; |
|
734 default: |
|
735 /* Avoid gcc warning */ |
|
736 ret = 0x00000000; |
|
737 break; |
|
738 } |
|
739 |
|
740 return ret; |
|
741 } |
|
742 |
|
743 static void dcr_write_sdram (void *opaque, int dcrn, target_ulong val) |
|
744 { |
|
745 ppc4xx_sdram_t *sdram; |
|
746 |
|
747 sdram = opaque; |
|
748 switch (dcrn) { |
|
749 case SDRAM0_CFGADDR: |
|
750 sdram->addr = val; |
|
751 break; |
|
752 case SDRAM0_CFGDATA: |
|
753 switch (sdram->addr) { |
|
754 case 0x00: /* SDRAM_BESR0 */ |
|
755 sdram->besr0 &= ~val; |
|
756 break; |
|
757 case 0x08: /* SDRAM_BESR1 */ |
|
758 sdram->besr1 &= ~val; |
|
759 break; |
|
760 case 0x10: /* SDRAM_BEAR */ |
|
761 sdram->bear = val; |
|
762 break; |
|
763 case 0x20: /* SDRAM_CFG */ |
|
764 val &= 0xFFE00000; |
|
765 if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { |
|
766 #ifdef DEBUG_SDRAM |
|
767 printf("%s: enable SDRAM controller\n", __func__); |
|
768 #endif |
|
769 /* validate all RAM mappings */ |
|
770 sdram_map_bcr(sdram); |
|
771 sdram->status &= ~0x80000000; |
|
772 } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { |
|
773 #ifdef DEBUG_SDRAM |
|
774 printf("%s: disable SDRAM controller\n", __func__); |
|
775 #endif |
|
776 /* invalidate all RAM mappings */ |
|
777 sdram_unmap_bcr(sdram); |
|
778 sdram->status |= 0x80000000; |
|
779 } |
|
780 if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) |
|
781 sdram->status |= 0x40000000; |
|
782 else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) |
|
783 sdram->status &= ~0x40000000; |
|
784 sdram->cfg = val; |
|
785 break; |
|
786 case 0x24: /* SDRAM_STATUS */ |
|
787 /* Read-only register */ |
|
788 break; |
|
789 case 0x30: /* SDRAM_RTR */ |
|
790 sdram->rtr = val & 0x3FF80000; |
|
791 break; |
|
792 case 0x34: /* SDRAM_PMIT */ |
|
793 sdram->pmit = (val & 0xF8000000) | 0x07C00000; |
|
794 break; |
|
795 case 0x40: /* SDRAM_B0CR */ |
|
796 sdram_set_bcr(&sdram->bcr[0], val, sdram->cfg & 0x80000000); |
|
797 break; |
|
798 case 0x44: /* SDRAM_B1CR */ |
|
799 sdram_set_bcr(&sdram->bcr[1], val, sdram->cfg & 0x80000000); |
|
800 break; |
|
801 case 0x48: /* SDRAM_B2CR */ |
|
802 sdram_set_bcr(&sdram->bcr[2], val, sdram->cfg & 0x80000000); |
|
803 break; |
|
804 case 0x4C: /* SDRAM_B3CR */ |
|
805 sdram_set_bcr(&sdram->bcr[3], val, sdram->cfg & 0x80000000); |
|
806 break; |
|
807 case 0x80: /* SDRAM_TR */ |
|
808 sdram->tr = val & 0x018FC01F; |
|
809 break; |
|
810 case 0x94: /* SDRAM_ECCCFG */ |
|
811 sdram->ecccfg = val & 0x00F00000; |
|
812 break; |
|
813 case 0x98: /* SDRAM_ECCESR */ |
|
814 val &= 0xFFF0F000; |
|
815 if (sdram->eccesr == 0 && val != 0) |
|
816 qemu_irq_raise(sdram->irq); |
|
817 else if (sdram->eccesr != 0 && val == 0) |
|
818 qemu_irq_lower(sdram->irq); |
|
819 sdram->eccesr = val; |
|
820 break; |
|
821 default: /* Error */ |
|
822 break; |
|
823 } |
|
824 break; |
|
825 } |
|
826 } |
|
827 |
|
828 static void sdram_reset (void *opaque) |
|
829 { |
|
830 ppc4xx_sdram_t *sdram; |
|
831 |
|
832 sdram = opaque; |
|
833 sdram->addr = 0x00000000; |
|
834 sdram->bear = 0x00000000; |
|
835 sdram->besr0 = 0x00000000; /* No error */ |
|
836 sdram->besr1 = 0x00000000; /* No error */ |
|
837 sdram->cfg = 0x00000000; |
|
838 sdram->ecccfg = 0x00000000; /* No ECC */ |
|
839 sdram->eccesr = 0x00000000; /* No error */ |
|
840 sdram->pmit = 0x07C00000; |
|
841 sdram->rtr = 0x05F00000; |
|
842 sdram->tr = 0x00854009; |
|
843 /* We pre-initialize RAM banks */ |
|
844 sdram->status = 0x00000000; |
|
845 sdram->cfg = 0x00800000; |
|
846 sdram_unmap_bcr(sdram); |
|
847 } |
|
848 |
|
849 void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks, |
|
850 target_phys_addr_t *ram_bases, |
|
851 target_phys_addr_t *ram_sizes, |
|
852 int do_init) |
|
853 { |
|
854 ppc4xx_sdram_t *sdram; |
|
855 |
|
856 sdram = qemu_mallocz(sizeof(ppc4xx_sdram_t)); |
|
857 if (sdram != NULL) { |
|
858 sdram->irq = irq; |
|
859 sdram->nbanks = nbanks; |
|
860 memset(sdram->ram_bases, 0, 4 * sizeof(target_phys_addr_t)); |
|
861 memcpy(sdram->ram_bases, ram_bases, |
|
862 nbanks * sizeof(target_phys_addr_t)); |
|
863 memset(sdram->ram_sizes, 0, 4 * sizeof(target_phys_addr_t)); |
|
864 memcpy(sdram->ram_sizes, ram_sizes, |
|
865 nbanks * sizeof(target_phys_addr_t)); |
|
866 sdram_reset(sdram); |
|
867 qemu_register_reset(&sdram_reset, sdram); |
|
868 ppc_dcr_register(env, SDRAM0_CFGADDR, |
|
869 sdram, &dcr_read_sdram, &dcr_write_sdram); |
|
870 ppc_dcr_register(env, SDRAM0_CFGDATA, |
|
871 sdram, &dcr_read_sdram, &dcr_write_sdram); |
|
872 if (do_init) |
|
873 sdram_map_bcr(sdram); |
|
874 } |
|
875 } |
|
876 |
|
877 /* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory. |
|
878 * |
|
879 * sdram_bank_sizes[] must be 0-terminated. |
|
880 * |
|
881 * The 4xx SDRAM controller supports a small number of banks, and each bank |
|
882 * must be one of a small set of sizes. The number of banks and the supported |
|
883 * sizes varies by SoC. */ |
|
884 ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, |
|
885 target_phys_addr_t ram_bases[], |
|
886 target_phys_addr_t ram_sizes[], |
|
887 const unsigned int sdram_bank_sizes[]) |
|
888 { |
|
889 ram_addr_t ram_end = 0; |
|
890 int i; |
|
891 int j; |
|
892 |
|
893 for (i = 0; i < nr_banks; i++) { |
|
894 for (j = 0; sdram_bank_sizes[j] != 0; j++) { |
|
895 unsigned int bank_size = sdram_bank_sizes[j]; |
|
896 |
|
897 if (bank_size <= ram_size) { |
|
898 ram_bases[i] = ram_end; |
|
899 ram_sizes[i] = bank_size; |
|
900 ram_end += bank_size; |
|
901 ram_size -= bank_size; |
|
902 break; |
|
903 } |
|
904 } |
|
905 |
|
906 if (!ram_size) { |
|
907 /* No need to use the remaining banks. */ |
|
908 break; |
|
909 } |
|
910 } |
|
911 |
|
912 if (ram_size) |
|
913 printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n", |
|
914 (int)(ram_end >> 20)); |
|
915 |
|
916 return ram_end; |
|
917 } |