2 * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
4 * Copyright (c) 2007 CodeSourcery.
6 * This code is licensed under the GPL
10 #include "qemu-timer.h"
12 #include "exec-memory.h"
14 /* General purpose timer module. */
35 static void m5206_timer_update(m5206_timer_state
*s
)
37 if ((s
->tmr
& TMR_ORI
) != 0 && (s
->ter
& TER_REF
))
38 qemu_irq_raise(s
->irq
);
40 qemu_irq_lower(s
->irq
);
43 static void m5206_timer_reset(m5206_timer_state
*s
)
49 static void m5206_timer_recalibrate(m5206_timer_state
*s
)
54 ptimer_stop(s
->timer
);
56 if ((s
->tmr
& TMR_RST
) == 0)
59 prescale
= (s
->tmr
>> 8) + 1;
60 mode
= (s
->tmr
>> 1) & 3;
64 if (mode
== 3 || mode
== 0)
65 hw_error("m5206_timer: mode %d not implemented\n", mode
);
66 if ((s
->tmr
& TMR_FRR
) == 0)
67 hw_error("m5206_timer: free running mode not implemented\n");
69 /* Assume 66MHz system clock. */
70 ptimer_set_freq(s
->timer
, 66000000 / prescale
);
72 ptimer_set_limit(s
->timer
, s
->trr
, 0);
74 ptimer_run(s
->timer
, 0);
77 static void m5206_timer_trigger(void *opaque
)
79 m5206_timer_state
*s
= (m5206_timer_state
*)opaque
;
81 m5206_timer_update(s
);
84 static uint32_t m5206_timer_read(m5206_timer_state
*s
, uint32_t addr
)
94 return s
->trr
- ptimer_get_count(s
->timer
);
102 static void m5206_timer_write(m5206_timer_state
*s
, uint32_t addr
, uint32_t val
)
106 if ((s
->tmr
& TMR_RST
) != 0 && (val
& TMR_RST
) == 0) {
107 m5206_timer_reset(s
);
110 m5206_timer_recalibrate(s
);
114 m5206_timer_recalibrate(s
);
120 ptimer_set_count(s
->timer
, val
);
128 m5206_timer_update(s
);
131 static m5206_timer_state
*m5206_timer_init(qemu_irq irq
)
133 m5206_timer_state
*s
;
136 s
= (m5206_timer_state
*)g_malloc0(sizeof(m5206_timer_state
));
137 bh
= qemu_bh_new(m5206_timer_trigger
, s
);
138 s
->timer
= ptimer_init(bh
);
140 m5206_timer_reset(s
);
144 /* System Integration Module. */
149 m5206_timer_state
*timer
[2];
153 uint16_t imr
; /* 1 == interrupt is masked. */
158 /* Include the UART vector registers here. */
162 /* Interrupt controller. */
164 static int m5206_find_pending_irq(m5206_mbar_state
*s
)
173 active
= s
->ipr
& ~s
->imr
;
177 for (i
= 1; i
< 14; i
++) {
178 if (active
& (1 << i
)) {
179 if ((s
->icr
[i
] & 0x1f) > level
) {
180 level
= s
->icr
[i
] & 0x1f;
192 static void m5206_mbar_update(m5206_mbar_state
*s
)
198 irq
= m5206_find_pending_irq(s
);
202 level
= (tmp
>> 2) & 7;
218 /* Unknown vector. */
219 fprintf(stderr
, "Unhandled vector for IRQ %d\n", irq
);
228 m68k_set_irq_level(s
->env
, level
, vector
);
231 static void m5206_mbar_set_irq(void *opaque
, int irq
, int level
)
233 m5206_mbar_state
*s
= (m5206_mbar_state
*)opaque
;
237 s
->ipr
&= ~(1 << irq
);
239 m5206_mbar_update(s
);
242 /* System Integration Module. */
244 static void m5206_mbar_reset(m5206_mbar_state
*s
)
266 static uint64_t m5206_mbar_read(m5206_mbar_state
*s
,
267 uint64_t offset
, unsigned size
)
269 if (offset
>= 0x100 && offset
< 0x120) {
270 return m5206_timer_read(s
->timer
[0], offset
- 0x100);
271 } else if (offset
>= 0x120 && offset
< 0x140) {
272 return m5206_timer_read(s
->timer
[1], offset
- 0x120);
273 } else if (offset
>= 0x140 && offset
< 0x160) {
274 return mcf_uart_read(s
->uart
[0], offset
- 0x140, size
);
275 } else if (offset
>= 0x180 && offset
< 0x1a0) {
276 return mcf_uart_read(s
->uart
[1], offset
- 0x180, size
);
279 case 0x03: return s
->scr
;
280 case 0x14 ... 0x20: return s
->icr
[offset
- 0x13];
281 case 0x36: return s
->imr
;
282 case 0x3a: return s
->ipr
;
283 case 0x40: return s
->rsr
;
285 case 0x42: return s
->swivr
;
287 /* DRAM mask register. */
288 /* FIXME: currently hardcoded to 128Mb. */
291 while (mask
> ram_size
)
293 return mask
& 0x0ffe0000;
295 case 0x5c: return 1; /* DRAM bank 1 empty. */
296 case 0xcb: return s
->par
;
297 case 0x170: return s
->uivr
[0];
298 case 0x1b0: return s
->uivr
[1];
300 hw_error("Bad MBAR read offset 0x%x", (int)offset
);
304 static void m5206_mbar_write(m5206_mbar_state
*s
, uint32_t offset
,
305 uint64_t value
, unsigned size
)
307 if (offset
>= 0x100 && offset
< 0x120) {
308 m5206_timer_write(s
->timer
[0], offset
- 0x100, value
);
310 } else if (offset
>= 0x120 && offset
< 0x140) {
311 m5206_timer_write(s
->timer
[1], offset
- 0x120, value
);
313 } else if (offset
>= 0x140 && offset
< 0x160) {
314 mcf_uart_write(s
->uart
[0], offset
- 0x140, value
, size
);
316 } else if (offset
>= 0x180 && offset
< 0x1a0) {
317 mcf_uart_write(s
->uart
[1], offset
- 0x180, value
, size
);
325 s
->icr
[offset
- 0x13] = value
;
326 m5206_mbar_update(s
);
330 m5206_mbar_update(s
);
336 /* TODO: implement watchdog. */
347 case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
348 /* Not implemented: UART Output port bits. */
354 hw_error("Bad MBAR write offset 0x%x", (int)offset
);
359 /* Internal peripherals use a variety of register widths.
360 This lookup table allows a single routine to handle all of them. */
361 static const int m5206_mbar_width
[] =
363 /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
364 /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2,
365 /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4,
366 /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367 /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0,
368 /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
369 /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
370 /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
373 static uint32_t m5206_mbar_readw(void *opaque
, target_phys_addr_t offset
);
374 static uint32_t m5206_mbar_readl(void *opaque
, target_phys_addr_t offset
);
376 static uint32_t m5206_mbar_readb(void *opaque
, target_phys_addr_t offset
)
378 m5206_mbar_state
*s
= (m5206_mbar_state
*)opaque
;
380 if (offset
> 0x200) {
381 hw_error("Bad MBAR read offset 0x%x", (int)offset
);
383 if (m5206_mbar_width
[offset
>> 2] > 1) {
385 val
= m5206_mbar_readw(opaque
, offset
& ~1);
386 if ((offset
& 1) == 0) {
391 return m5206_mbar_read(s
, offset
, 1);
394 static uint32_t m5206_mbar_readw(void *opaque
, target_phys_addr_t offset
)
396 m5206_mbar_state
*s
= (m5206_mbar_state
*)opaque
;
399 if (offset
> 0x200) {
400 hw_error("Bad MBAR read offset 0x%x", (int)offset
);
402 width
= m5206_mbar_width
[offset
>> 2];
405 val
= m5206_mbar_readl(opaque
, offset
& ~3);
406 if ((offset
& 3) == 0)
409 } else if (width
< 2) {
411 val
= m5206_mbar_readb(opaque
, offset
) << 8;
412 val
|= m5206_mbar_readb(opaque
, offset
+ 1);
415 return m5206_mbar_read(s
, offset
, 2);
418 static uint32_t m5206_mbar_readl(void *opaque
, target_phys_addr_t offset
)
420 m5206_mbar_state
*s
= (m5206_mbar_state
*)opaque
;
423 if (offset
> 0x200) {
424 hw_error("Bad MBAR read offset 0x%x", (int)offset
);
426 width
= m5206_mbar_width
[offset
>> 2];
429 val
= m5206_mbar_readw(opaque
, offset
) << 16;
430 val
|= m5206_mbar_readw(opaque
, offset
+ 2);
433 return m5206_mbar_read(s
, offset
, 4);
436 static void m5206_mbar_writew(void *opaque
, target_phys_addr_t offset
,
438 static void m5206_mbar_writel(void *opaque
, target_phys_addr_t offset
,
441 static void m5206_mbar_writeb(void *opaque
, target_phys_addr_t offset
,
444 m5206_mbar_state
*s
= (m5206_mbar_state
*)opaque
;
447 if (offset
> 0x200) {
448 hw_error("Bad MBAR write offset 0x%x", (int)offset
);
450 width
= m5206_mbar_width
[offset
>> 2];
453 tmp
= m5206_mbar_readw(opaque
, offset
& ~1);
455 tmp
= (tmp
& 0xff00) | value
;
457 tmp
= (tmp
& 0x00ff) | (value
<< 8);
459 m5206_mbar_writew(opaque
, offset
& ~1, tmp
);
462 m5206_mbar_write(s
, offset
, value
, 1);
465 static void m5206_mbar_writew(void *opaque
, target_phys_addr_t offset
,
468 m5206_mbar_state
*s
= (m5206_mbar_state
*)opaque
;
471 if (offset
> 0x200) {
472 hw_error("Bad MBAR write offset 0x%x", (int)offset
);
474 width
= m5206_mbar_width
[offset
>> 2];
477 tmp
= m5206_mbar_readl(opaque
, offset
& ~3);
479 tmp
= (tmp
& 0xffff0000) | value
;
481 tmp
= (tmp
& 0x0000ffff) | (value
<< 16);
483 m5206_mbar_writel(opaque
, offset
& ~3, tmp
);
485 } else if (width
< 2) {
486 m5206_mbar_writeb(opaque
, offset
, value
>> 8);
487 m5206_mbar_writeb(opaque
, offset
+ 1, value
& 0xff);
490 m5206_mbar_write(s
, offset
, value
, 2);
493 static void m5206_mbar_writel(void *opaque
, target_phys_addr_t offset
,
496 m5206_mbar_state
*s
= (m5206_mbar_state
*)opaque
;
499 if (offset
> 0x200) {
500 hw_error("Bad MBAR write offset 0x%x", (int)offset
);
502 width
= m5206_mbar_width
[offset
>> 2];
504 m5206_mbar_writew(opaque
, offset
, value
>> 16);
505 m5206_mbar_writew(opaque
, offset
+ 2, value
& 0xffff);
508 m5206_mbar_write(s
, offset
, value
, 4);
511 static const MemoryRegionOps m5206_mbar_ops
= {
524 .endianness
= DEVICE_NATIVE_ENDIAN
,
527 qemu_irq
*mcf5206_init(MemoryRegion
*sysmem
, uint32_t base
, CPUState
*env
)
532 s
= (m5206_mbar_state
*)g_malloc0(sizeof(m5206_mbar_state
));
534 memory_region_init_io(&s
->iomem
, &m5206_mbar_ops
, s
,
536 memory_region_add_subregion(sysmem
, base
, &s
->iomem
);
538 pic
= qemu_allocate_irqs(m5206_mbar_set_irq
, s
, 14);
539 s
->timer
[0] = m5206_timer_init(pic
[9]);
540 s
->timer
[1] = m5206_timer_init(pic
[10]);
541 s
->uart
[0] = mcf_uart_init(pic
[12], serial_hds
[0]);
542 s
->uart
[1] = mcf_uart_init(pic
[13], serial_hds
[1]);