|
1 /* |
|
2 * ARM Integrator CP System emulation. |
|
3 * |
|
4 * Copyright (c) 2005-2007 CodeSourcery. |
|
5 * Written by Paul Brook |
|
6 * |
|
7 * This code is licenced under the GPL |
|
8 */ |
|
9 |
|
10 #include "hw.h" |
|
11 #include "primecell.h" |
|
12 #include "devices.h" |
|
13 #include "sysemu.h" |
|
14 #include "boards.h" |
|
15 #include "arm-misc.h" |
|
16 #include "net.h" |
|
17 |
|
18 typedef struct { |
|
19 uint32_t flash_offset; |
|
20 uint32_t cm_osc; |
|
21 uint32_t cm_ctrl; |
|
22 uint32_t cm_lock; |
|
23 uint32_t cm_auxosc; |
|
24 uint32_t cm_sdram; |
|
25 uint32_t cm_init; |
|
26 uint32_t cm_flags; |
|
27 uint32_t cm_nvflags; |
|
28 uint32_t int_level; |
|
29 uint32_t irq_enabled; |
|
30 uint32_t fiq_enabled; |
|
31 } integratorcm_state; |
|
32 |
|
33 static uint8_t integrator_spd[128] = { |
|
34 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1, |
|
35 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 |
|
36 }; |
|
37 |
|
38 static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset) |
|
39 { |
|
40 integratorcm_state *s = (integratorcm_state *)opaque; |
|
41 if (offset >= 0x100 && offset < 0x200) { |
|
42 /* CM_SPD */ |
|
43 if (offset >= 0x180) |
|
44 return 0; |
|
45 return integrator_spd[offset >> 2]; |
|
46 } |
|
47 switch (offset >> 2) { |
|
48 case 0: /* CM_ID */ |
|
49 return 0x411a3001; |
|
50 case 1: /* CM_PROC */ |
|
51 return 0; |
|
52 case 2: /* CM_OSC */ |
|
53 return s->cm_osc; |
|
54 case 3: /* CM_CTRL */ |
|
55 return s->cm_ctrl; |
|
56 case 4: /* CM_STAT */ |
|
57 return 0x00100000; |
|
58 case 5: /* CM_LOCK */ |
|
59 if (s->cm_lock == 0xa05f) { |
|
60 return 0x1a05f; |
|
61 } else { |
|
62 return s->cm_lock; |
|
63 } |
|
64 case 6: /* CM_LMBUSCNT */ |
|
65 /* ??? High frequency timer. */ |
|
66 cpu_abort(cpu_single_env, "integratorcm_read: CM_LMBUSCNT"); |
|
67 case 7: /* CM_AUXOSC */ |
|
68 return s->cm_auxosc; |
|
69 case 8: /* CM_SDRAM */ |
|
70 return s->cm_sdram; |
|
71 case 9: /* CM_INIT */ |
|
72 return s->cm_init; |
|
73 case 10: /* CM_REFCT */ |
|
74 /* ??? High frequency timer. */ |
|
75 cpu_abort(cpu_single_env, "integratorcm_read: CM_REFCT"); |
|
76 case 12: /* CM_FLAGS */ |
|
77 return s->cm_flags; |
|
78 case 14: /* CM_NVFLAGS */ |
|
79 return s->cm_nvflags; |
|
80 case 16: /* CM_IRQ_STAT */ |
|
81 return s->int_level & s->irq_enabled; |
|
82 case 17: /* CM_IRQ_RSTAT */ |
|
83 return s->int_level; |
|
84 case 18: /* CM_IRQ_ENSET */ |
|
85 return s->irq_enabled; |
|
86 case 20: /* CM_SOFT_INTSET */ |
|
87 return s->int_level & 1; |
|
88 case 24: /* CM_FIQ_STAT */ |
|
89 return s->int_level & s->fiq_enabled; |
|
90 case 25: /* CM_FIQ_RSTAT */ |
|
91 return s->int_level; |
|
92 case 26: /* CM_FIQ_ENSET */ |
|
93 return s->fiq_enabled; |
|
94 case 32: /* CM_VOLTAGE_CTL0 */ |
|
95 case 33: /* CM_VOLTAGE_CTL1 */ |
|
96 case 34: /* CM_VOLTAGE_CTL2 */ |
|
97 case 35: /* CM_VOLTAGE_CTL3 */ |
|
98 /* ??? Voltage control unimplemented. */ |
|
99 return 0; |
|
100 default: |
|
101 cpu_abort (cpu_single_env, |
|
102 "integratorcm_read: Unimplemented offset 0x%x\n", (int)offset); |
|
103 return 0; |
|
104 } |
|
105 } |
|
106 |
|
107 static void integratorcm_do_remap(integratorcm_state *s, int flash) |
|
108 { |
|
109 if (flash) { |
|
110 cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM); |
|
111 } else { |
|
112 cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM); |
|
113 } |
|
114 //??? tlb_flush (cpu_single_env, 1); |
|
115 } |
|
116 |
|
117 static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) |
|
118 { |
|
119 if (value & 8) { |
|
120 cpu_abort(cpu_single_env, "Board reset\n"); |
|
121 } |
|
122 if ((s->cm_init ^ value) & 4) { |
|
123 integratorcm_do_remap(s, (value & 4) == 0); |
|
124 } |
|
125 if ((s->cm_init ^ value) & 1) { |
|
126 printf("Green LED %s\n", (value & 1) ? "on" : "off"); |
|
127 } |
|
128 s->cm_init = (s->cm_init & ~ 5) | (value ^ 5); |
|
129 } |
|
130 |
|
131 static void integratorcm_update(integratorcm_state *s) |
|
132 { |
|
133 /* ??? The CPU irq/fiq is raised when either the core module or base PIC |
|
134 are active. */ |
|
135 if (s->int_level & (s->irq_enabled | s->fiq_enabled)) |
|
136 cpu_abort(cpu_single_env, "Core module interrupt\n"); |
|
137 } |
|
138 |
|
139 static void integratorcm_write(void *opaque, target_phys_addr_t offset, |
|
140 uint32_t value) |
|
141 { |
|
142 integratorcm_state *s = (integratorcm_state *)opaque; |
|
143 switch (offset >> 2) { |
|
144 case 2: /* CM_OSC */ |
|
145 if (s->cm_lock == 0xa05f) |
|
146 s->cm_osc = value; |
|
147 break; |
|
148 case 3: /* CM_CTRL */ |
|
149 integratorcm_set_ctrl(s, value); |
|
150 break; |
|
151 case 5: /* CM_LOCK */ |
|
152 s->cm_lock = value & 0xffff; |
|
153 break; |
|
154 case 7: /* CM_AUXOSC */ |
|
155 if (s->cm_lock == 0xa05f) |
|
156 s->cm_auxosc = value; |
|
157 break; |
|
158 case 8: /* CM_SDRAM */ |
|
159 s->cm_sdram = value; |
|
160 break; |
|
161 case 9: /* CM_INIT */ |
|
162 /* ??? This can change the memory bus frequency. */ |
|
163 s->cm_init = value; |
|
164 break; |
|
165 case 12: /* CM_FLAGSS */ |
|
166 s->cm_flags |= value; |
|
167 break; |
|
168 case 13: /* CM_FLAGSC */ |
|
169 s->cm_flags &= ~value; |
|
170 break; |
|
171 case 14: /* CM_NVFLAGSS */ |
|
172 s->cm_nvflags |= value; |
|
173 break; |
|
174 case 15: /* CM_NVFLAGSS */ |
|
175 s->cm_nvflags &= ~value; |
|
176 break; |
|
177 case 18: /* CM_IRQ_ENSET */ |
|
178 s->irq_enabled |= value; |
|
179 integratorcm_update(s); |
|
180 break; |
|
181 case 19: /* CM_IRQ_ENCLR */ |
|
182 s->irq_enabled &= ~value; |
|
183 integratorcm_update(s); |
|
184 break; |
|
185 case 20: /* CM_SOFT_INTSET */ |
|
186 s->int_level |= (value & 1); |
|
187 integratorcm_update(s); |
|
188 break; |
|
189 case 21: /* CM_SOFT_INTCLR */ |
|
190 s->int_level &= ~(value & 1); |
|
191 integratorcm_update(s); |
|
192 break; |
|
193 case 26: /* CM_FIQ_ENSET */ |
|
194 s->fiq_enabled |= value; |
|
195 integratorcm_update(s); |
|
196 break; |
|
197 case 27: /* CM_FIQ_ENCLR */ |
|
198 s->fiq_enabled &= ~value; |
|
199 integratorcm_update(s); |
|
200 break; |
|
201 case 32: /* CM_VOLTAGE_CTL0 */ |
|
202 case 33: /* CM_VOLTAGE_CTL1 */ |
|
203 case 34: /* CM_VOLTAGE_CTL2 */ |
|
204 case 35: /* CM_VOLTAGE_CTL3 */ |
|
205 /* ??? Voltage control unimplemented. */ |
|
206 break; |
|
207 default: |
|
208 cpu_abort (cpu_single_env, |
|
209 "integratorcm_write: Unimplemented offset 0x%x\n", (int)offset); |
|
210 break; |
|
211 } |
|
212 } |
|
213 |
|
214 /* Integrator/CM control registers. */ |
|
215 |
|
216 static CPUReadMemoryFunc *integratorcm_readfn[] = { |
|
217 integratorcm_read, |
|
218 integratorcm_read, |
|
219 integratorcm_read |
|
220 }; |
|
221 |
|
222 static CPUWriteMemoryFunc *integratorcm_writefn[] = { |
|
223 integratorcm_write, |
|
224 integratorcm_write, |
|
225 integratorcm_write |
|
226 }; |
|
227 |
|
228 static void integratorcm_init(int memsz) |
|
229 { |
|
230 int iomemtype; |
|
231 integratorcm_state *s; |
|
232 |
|
233 s = (integratorcm_state *)qemu_mallocz(sizeof(integratorcm_state)); |
|
234 s->cm_osc = 0x01000048; |
|
235 /* ??? What should the high bits of this value be? */ |
|
236 s->cm_auxosc = 0x0007feff; |
|
237 s->cm_sdram = 0x00011122; |
|
238 if (memsz >= 256) { |
|
239 integrator_spd[31] = 64; |
|
240 s->cm_sdram |= 0x10; |
|
241 } else if (memsz >= 128) { |
|
242 integrator_spd[31] = 32; |
|
243 s->cm_sdram |= 0x0c; |
|
244 } else if (memsz >= 64) { |
|
245 integrator_spd[31] = 16; |
|
246 s->cm_sdram |= 0x08; |
|
247 } else if (memsz >= 32) { |
|
248 integrator_spd[31] = 4; |
|
249 s->cm_sdram |= 0x04; |
|
250 } else { |
|
251 integrator_spd[31] = 2; |
|
252 } |
|
253 memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); |
|
254 s->cm_init = 0x00000112; |
|
255 s->flash_offset = qemu_ram_alloc(0x100000); |
|
256 |
|
257 iomemtype = cpu_register_io_memory(0, integratorcm_readfn, |
|
258 integratorcm_writefn, s); |
|
259 cpu_register_physical_memory(0x10000000, 0x00800000, iomemtype); |
|
260 integratorcm_do_remap(s, 1); |
|
261 /* ??? Save/restore. */ |
|
262 } |
|
263 |
|
264 /* Integrator/CP hardware emulation. */ |
|
265 /* Primary interrupt controller. */ |
|
266 |
|
267 typedef struct icp_pic_state |
|
268 { |
|
269 uint32_t level; |
|
270 uint32_t irq_enabled; |
|
271 uint32_t fiq_enabled; |
|
272 qemu_irq parent_irq; |
|
273 qemu_irq parent_fiq; |
|
274 } icp_pic_state; |
|
275 |
|
276 static void icp_pic_update(icp_pic_state *s) |
|
277 { |
|
278 uint32_t flags; |
|
279 |
|
280 flags = (s->level & s->irq_enabled); |
|
281 qemu_set_irq(s->parent_irq, flags != 0); |
|
282 flags = (s->level & s->fiq_enabled); |
|
283 qemu_set_irq(s->parent_fiq, flags != 0); |
|
284 } |
|
285 |
|
286 static void icp_pic_set_irq(void *opaque, int irq, int level) |
|
287 { |
|
288 icp_pic_state *s = (icp_pic_state *)opaque; |
|
289 if (level) |
|
290 s->level |= 1 << irq; |
|
291 else |
|
292 s->level &= ~(1 << irq); |
|
293 icp_pic_update(s); |
|
294 } |
|
295 |
|
296 static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset) |
|
297 { |
|
298 icp_pic_state *s = (icp_pic_state *)opaque; |
|
299 |
|
300 switch (offset >> 2) { |
|
301 case 0: /* IRQ_STATUS */ |
|
302 return s->level & s->irq_enabled; |
|
303 case 1: /* IRQ_RAWSTAT */ |
|
304 return s->level; |
|
305 case 2: /* IRQ_ENABLESET */ |
|
306 return s->irq_enabled; |
|
307 case 4: /* INT_SOFTSET */ |
|
308 return s->level & 1; |
|
309 case 8: /* FRQ_STATUS */ |
|
310 return s->level & s->fiq_enabled; |
|
311 case 9: /* FRQ_RAWSTAT */ |
|
312 return s->level; |
|
313 case 10: /* FRQ_ENABLESET */ |
|
314 return s->fiq_enabled; |
|
315 case 3: /* IRQ_ENABLECLR */ |
|
316 case 5: /* INT_SOFTCLR */ |
|
317 case 11: /* FRQ_ENABLECLR */ |
|
318 default: |
|
319 printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); |
|
320 return 0; |
|
321 } |
|
322 } |
|
323 |
|
324 static void icp_pic_write(void *opaque, target_phys_addr_t offset, |
|
325 uint32_t value) |
|
326 { |
|
327 icp_pic_state *s = (icp_pic_state *)opaque; |
|
328 |
|
329 switch (offset >> 2) { |
|
330 case 2: /* IRQ_ENABLESET */ |
|
331 s->irq_enabled |= value; |
|
332 break; |
|
333 case 3: /* IRQ_ENABLECLR */ |
|
334 s->irq_enabled &= ~value; |
|
335 break; |
|
336 case 4: /* INT_SOFTSET */ |
|
337 if (value & 1) |
|
338 icp_pic_set_irq(s, 0, 1); |
|
339 break; |
|
340 case 5: /* INT_SOFTCLR */ |
|
341 if (value & 1) |
|
342 icp_pic_set_irq(s, 0, 0); |
|
343 break; |
|
344 case 10: /* FRQ_ENABLESET */ |
|
345 s->fiq_enabled |= value; |
|
346 break; |
|
347 case 11: /* FRQ_ENABLECLR */ |
|
348 s->fiq_enabled &= ~value; |
|
349 break; |
|
350 case 0: /* IRQ_STATUS */ |
|
351 case 1: /* IRQ_RAWSTAT */ |
|
352 case 8: /* FRQ_STATUS */ |
|
353 case 9: /* FRQ_RAWSTAT */ |
|
354 default: |
|
355 printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); |
|
356 return; |
|
357 } |
|
358 icp_pic_update(s); |
|
359 } |
|
360 |
|
361 static CPUReadMemoryFunc *icp_pic_readfn[] = { |
|
362 icp_pic_read, |
|
363 icp_pic_read, |
|
364 icp_pic_read |
|
365 }; |
|
366 |
|
367 static CPUWriteMemoryFunc *icp_pic_writefn[] = { |
|
368 icp_pic_write, |
|
369 icp_pic_write, |
|
370 icp_pic_write |
|
371 }; |
|
372 |
|
373 static qemu_irq *icp_pic_init(uint32_t base, |
|
374 qemu_irq parent_irq, qemu_irq parent_fiq) |
|
375 { |
|
376 icp_pic_state *s; |
|
377 int iomemtype; |
|
378 qemu_irq *qi; |
|
379 |
|
380 s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state)); |
|
381 if (!s) |
|
382 return NULL; |
|
383 qi = qemu_allocate_irqs(icp_pic_set_irq, s, 32); |
|
384 s->parent_irq = parent_irq; |
|
385 s->parent_fiq = parent_fiq; |
|
386 iomemtype = cpu_register_io_memory(0, icp_pic_readfn, |
|
387 icp_pic_writefn, s); |
|
388 cpu_register_physical_memory(base, 0x00800000, iomemtype); |
|
389 /* ??? Save/restore. */ |
|
390 return qi; |
|
391 } |
|
392 |
|
393 /* CP control registers. */ |
|
394 static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset) |
|
395 { |
|
396 switch (offset >> 2) { |
|
397 case 0: /* CP_IDFIELD */ |
|
398 return 0x41034003; |
|
399 case 1: /* CP_FLASHPROG */ |
|
400 return 0; |
|
401 case 2: /* CP_INTREG */ |
|
402 return 0; |
|
403 case 3: /* CP_DECODE */ |
|
404 return 0x11; |
|
405 default: |
|
406 cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", |
|
407 (int)offset); |
|
408 return 0; |
|
409 } |
|
410 } |
|
411 |
|
412 static void icp_control_write(void *opaque, target_phys_addr_t offset, |
|
413 uint32_t value) |
|
414 { |
|
415 switch (offset >> 2) { |
|
416 case 1: /* CP_FLASHPROG */ |
|
417 case 2: /* CP_INTREG */ |
|
418 case 3: /* CP_DECODE */ |
|
419 /* Nothing interesting implemented yet. */ |
|
420 break; |
|
421 default: |
|
422 cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", |
|
423 (int)offset); |
|
424 } |
|
425 } |
|
426 static CPUReadMemoryFunc *icp_control_readfn[] = { |
|
427 icp_control_read, |
|
428 icp_control_read, |
|
429 icp_control_read |
|
430 }; |
|
431 |
|
432 static CPUWriteMemoryFunc *icp_control_writefn[] = { |
|
433 icp_control_write, |
|
434 icp_control_write, |
|
435 icp_control_write |
|
436 }; |
|
437 |
|
438 static void icp_control_init(uint32_t base) |
|
439 { |
|
440 int iomemtype; |
|
441 |
|
442 iomemtype = cpu_register_io_memory(0, icp_control_readfn, |
|
443 icp_control_writefn, NULL); |
|
444 cpu_register_physical_memory(base, 0x00800000, iomemtype); |
|
445 /* ??? Save/restore. */ |
|
446 } |
|
447 |
|
448 |
|
449 /* Board init. */ |
|
450 |
|
451 static struct arm_boot_info integrator_binfo = { |
|
452 .loader_start = 0x0, |
|
453 .board_id = 0x113, |
|
454 }; |
|
455 |
|
456 static void integratorcp_init(ram_addr_t ram_size, int vga_ram_size, |
|
457 const char *boot_device, DisplayState *ds, |
|
458 const char *kernel_filename, const char *kernel_cmdline, |
|
459 const char *initrd_filename, const char *cpu_model) |
|
460 { |
|
461 CPUState *env; |
|
462 uint32_t ram_offset; |
|
463 qemu_irq *pic; |
|
464 qemu_irq *cpu_pic; |
|
465 int sd; |
|
466 |
|
467 if (!cpu_model) |
|
468 cpu_model = "arm926"; |
|
469 env = cpu_init(cpu_model); |
|
470 if (!env) { |
|
471 fprintf(stderr, "Unable to find CPU definition\n"); |
|
472 exit(1); |
|
473 } |
|
474 ram_offset = qemu_ram_alloc(ram_size); |
|
475 /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ |
|
476 /* ??? RAM should repeat to fill physical memory space. */ |
|
477 /* SDRAM at address zero*/ |
|
478 cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM); |
|
479 /* And again at address 0x80000000 */ |
|
480 cpu_register_physical_memory(0x80000000, ram_size, ram_offset | IO_MEM_RAM); |
|
481 |
|
482 integratorcm_init(ram_size >> 20); |
|
483 cpu_pic = arm_pic_init_cpu(env); |
|
484 pic = icp_pic_init(0x14000000, cpu_pic[ARM_PIC_CPU_IRQ], |
|
485 cpu_pic[ARM_PIC_CPU_FIQ]); |
|
486 icp_pic_init(0xca000000, pic[26], NULL); |
|
487 icp_pit_init(0x13000000, pic, 5); |
|
488 pl031_init(0x15000000, pic[8]); |
|
489 pl011_init(0x16000000, pic[1], serial_hds[0], PL011_ARM); |
|
490 pl011_init(0x17000000, pic[2], serial_hds[1], PL011_ARM); |
|
491 icp_control_init(0xcb000000); |
|
492 pl050_init(0x18000000, pic[3], 0); |
|
493 pl050_init(0x19000000, pic[4], 1); |
|
494 sd = drive_get_index(IF_SD, 0, 0); |
|
495 if (sd == -1) { |
|
496 fprintf(stderr, "qemu: missing SecureDigital card\n"); |
|
497 exit(1); |
|
498 } |
|
499 pl181_init(0x1c000000, drives_table[sd].bdrv, pic[23], pic[24]); |
|
500 if (nd_table[0].vlan) { |
|
501 if (nd_table[0].model == NULL |
|
502 || strcmp(nd_table[0].model, "smc91c111") == 0) { |
|
503 smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); |
|
504 } else if (strcmp(nd_table[0].model, "?") == 0) { |
|
505 fprintf(stderr, "qemu: Supported NICs: smc91c111\n"); |
|
506 exit (1); |
|
507 } else { |
|
508 fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); |
|
509 exit (1); |
|
510 } |
|
511 } |
|
512 pl110_init(ds, 0xc0000000, pic[22], 0); |
|
513 |
|
514 integrator_binfo.ram_size = ram_size; |
|
515 integrator_binfo.kernel_filename = kernel_filename; |
|
516 integrator_binfo.kernel_cmdline = kernel_cmdline; |
|
517 integrator_binfo.initrd_filename = initrd_filename; |
|
518 arm_load_kernel(env, &integrator_binfo); |
|
519 } |
|
520 |
|
521 QEMUMachine integratorcp_machine = { |
|
522 .name = "integratorcp", |
|
523 .desc = "ARM Integrator/CP (ARM926EJ-S)", |
|
524 .init = integratorcp_init, |
|
525 .ram_require = 0x100000, |
|
526 }; |