Statistics
| Branch: | Revision:

root / hw / mcf5206.c @ 3f6ffb6a

History | View | Annotate | Download (14 kB)

1
/*
2
 * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
3
 *
4
 * Copyright (c) 2007 CodeSourcery.
5
 *
6
 * This code is licenced under the GPL
7
 */
8
#include "vl.h"
9

    
10
/* General purpose timer module.  */
11
typedef struct {
12
    uint16_t tmr;
13
    uint16_t trr;
14
    uint16_t tcr;
15
    uint16_t ter;
16
    ptimer_state *timer;
17
    qemu_irq irq;
18
    int irq_state;
19
} m5206_timer_state;
20

    
21
#define TMR_RST 0x01
22
#define TMR_CLK 0x06
23
#define TMR_FRR 0x08
24
#define TMR_ORI 0x10
25
#define TMR_OM  0x20
26
#define TMR_CE  0xc0
27

    
28
#define TER_CAP 0x01
29
#define TER_REF 0x02
30

    
31
static void m5206_timer_update(m5206_timer_state *s)
32
{
33
    if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
34
        qemu_irq_raise(s->irq);
35
    else
36
        qemu_irq_lower(s->irq);
37
}
38

    
39
static void m5206_timer_reset(m5206_timer_state *s)
40
{
41
    s->tmr = 0;
42
    s->trr = 0;
43
}
44

    
45
static void m5206_timer_recalibrate(m5206_timer_state *s)
46
{
47
    int prescale;
48
    int mode;
49

    
50
    ptimer_stop(s->timer);
51

    
52
    if ((s->tmr & TMR_RST) == 0)
53
        return;
54

    
55
    prescale = (s->tmr >> 8) + 1;
56
    mode = (s->tmr >> 1) & 3;
57
    if (mode == 2)
58
        prescale *= 16;
59

    
60
    if (mode == 3 || mode == 0)
61
        cpu_abort(cpu_single_env,
62
                  "m5206_timer: mode %d not implemented\n", mode);
63
    if ((s->tmr & TMR_FRR) == 0)
64
        cpu_abort(cpu_single_env,
65
                  "m5206_timer: free running mode not implemented\n");
66

    
67
    /* Assume 66MHz system clock.  */
68
    ptimer_set_freq(s->timer, 66000000 / prescale);
69

    
70
    ptimer_set_limit(s->timer, s->trr, 0);
71

    
72
    ptimer_run(s->timer, 0);
73
}
74

    
75
static void m5206_timer_trigger(void *opaque)
76
{
77
    m5206_timer_state *s = (m5206_timer_state *)opaque;
78
    s->ter |= TER_REF;
79
    m5206_timer_update(s);
80
}
81

    
82
static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr)
83
{
84
    switch (addr) {
85
    case 0:
86
        return s->tmr;
87
    case 4:
88
        return s->trr;
89
    case 8:
90
        return s->tcr;
91
    case 0xc:
92
        return s->trr - ptimer_get_count(s->timer);
93
    case 0x11:
94
        return s->ter;
95
    default:
96
        return 0;
97
    }
98
}
99

    
100
static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
101
{
102
    switch (addr) {
103
    case 0:
104
        if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) {
105
            m5206_timer_reset(s);
106
        }
107
        s->tmr = val;
108
        m5206_timer_recalibrate(s);
109
        break;
110
    case 4:
111
        s->trr = val;
112
        m5206_timer_recalibrate(s);
113
        break;
114
    case 8:
115
        s->tcr = val;
116
        break;
117
    case 0xc:
118
        ptimer_set_count(s->timer, val);
119
        break;
120
    case 0x11:
121
        s->ter &= ~val;
122
        break;
123
    default:
124
        break;
125
    }
126
    m5206_timer_update(s);
127
}
128

    
129
static m5206_timer_state *m5206_timer_init(qemu_irq irq)
130
{
131
    m5206_timer_state *s;
132
    QEMUBH *bh;
133

    
134
    s = (m5206_timer_state *)qemu_mallocz(sizeof(m5206_timer_state));
135
    bh = qemu_bh_new(m5206_timer_trigger, s);
136
    s->timer = ptimer_init(bh);
137
    s->irq = irq;
138
    m5206_timer_reset(s);
139
    return s;
140
}
141

    
142
/* System Integration Module.  */
143

    
144
typedef struct {
145
    CPUState *env;
146
    m5206_timer_state *timer[2];
147
    void *uart[2];
148
    uint8_t scr;
149
    uint8_t icr[14];
150
    uint16_t imr; /* 1 == interrupt is masked.  */
151
    uint16_t ipr;
152
    uint8_t rsr;
153
    uint8_t swivr;
154
    uint8_t par;
155
    /* Include the UART vector registers here.  */
156
    uint8_t uivr[2];
157
} m5206_mbar_state;
158

    
159
/* Interrupt controller.  */
160

    
161
static int m5206_find_pending_irq(m5206_mbar_state *s)
162
{
163
    int level;
164
    int vector;
165
    uint16_t active;
166
    int i;
167

    
168
    level = 0;
169
    vector = 0;
170
    active = s->ipr & ~s->imr;
171
    if (!active)
172
        return 0;
173

    
174
    for (i = 1; i < 14; i++) {
175
        if (active & (1 << i)) {
176
            if ((s->icr[i] & 0x1f) > level) {
177
                level = s->icr[i] & 0x1f;
178
                vector = i;
179
            }
180
        }
181
    }
182

    
183
    if (level < 4)
184
        vector = 0;
185

    
186
    return vector;
187
}
188

    
189
static void m5206_mbar_update(m5206_mbar_state *s)
190
{
191
    int irq;
192
    int vector;
193
    int level;
194

    
195
    irq = m5206_find_pending_irq(s);
196
    if (irq) {
197
        int tmp;
198
        tmp = s->icr[irq];
199
        level = (tmp >> 2) & 7;
200
        if (tmp & 0x80) {
201
            /* Autovector.  */
202
            vector = 24 + level;
203
        } else {
204
            switch (irq) {
205
            case 8: /* SWT */
206
                vector = s->swivr;
207
                break;
208
            case 12: /* UART1 */
209
                vector = s->uivr[0];
210
                break;
211
            case 13: /* UART2 */
212
                vector = s->uivr[1];
213
                break;
214
            default:
215
                /* Unknown vector.  */
216
                fprintf(stderr, "Unhandled vector for IRQ %d\n", irq);
217
                vector = 0xf;
218
                break;
219
            }
220
        }
221
    } else {
222
        level = 0;
223
        vector = 0;
224
    }
225
    m68k_set_irq_level(s->env, level, vector);
226
}
227

    
228
static void m5206_mbar_set_irq(void *opaque, int irq, int level)
229
{
230
    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
231
    if (level) {
232
        s->ipr |= 1 << irq;
233
    } else {
234
        s->ipr &= ~(1 << irq);
235
    }
236
    m5206_mbar_update(s);
237
}
238

    
239
/* System Integration Module.  */
240

    
241
static void m5206_mbar_reset(m5206_mbar_state *s)
242
{
243
    s->scr = 0xc0;
244
    s->icr[1] = 0x04;
245
    s->icr[2] = 0x08;
246
    s->icr[3] = 0x0c;
247
    s->icr[4] = 0x10;
248
    s->icr[5] = 0x14;
249
    s->icr[6] = 0x18;
250
    s->icr[7] = 0x1c;
251
    s->icr[8] = 0x1c;
252
    s->icr[9] = 0x80;
253
    s->icr[10] = 0x80;
254
    s->icr[11] = 0x80;
255
    s->icr[12] = 0x00;
256
    s->icr[13] = 0x00;
257
    s->imr = 0x3ffe;
258
    s->rsr = 0x80;
259
    s->swivr = 0x0f;
260
    s->par = 0;
261
}
262

    
263
static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset)
264
{
265
    if (offset >= 0x100 && offset < 0x120) {
266
        return m5206_timer_read(s->timer[0], offset - 0x100);
267
    } else if (offset >= 0x120 && offset < 0x140) {
268
        return m5206_timer_read(s->timer[1], offset - 0x120);
269
    } else if (offset >= 0x140 && offset < 0x160) {
270
        return mcf_uart_read(s->uart[0], offset - 0x140);
271
    } else if (offset >= 0x180 && offset < 0x1a0) {
272
        return mcf_uart_read(s->uart[1], offset - 0x180);
273
    }
274
    switch (offset) {
275
    case 0x03: return s->scr;
276
    case 0x14 ... 0x20: return s->icr[offset - 0x13];
277
    case 0x36: return s->imr;
278
    case 0x3a: return s->ipr;
279
    case 0x40: return s->rsr;
280
    case 0x41: return 0;
281
    case 0x42: return s->swivr;
282
    case 0x50:
283
        /* DRAM mask register.  */
284
        /* FIXME: currently hardcoded to 128Mb.  */
285
        {
286
            uint32_t mask = ~0;
287
            while (mask > ram_size)
288
                mask >>= 1;
289
            return mask & 0x0ffe0000;
290
        }
291
    case 0x5c: return 1; /* DRAM bank 1 empty.  */
292
    case 0xcb: return s->par;
293
    case 0x170: return s->uivr[0];
294
    case 0x1b0: return s->uivr[1];
295
    }
296
    cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
297
    return 0;
298
}
299

    
300
static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
301
                             uint32_t value)
302
{
303
    if (offset >= 0x100 && offset < 0x120) {
304
        m5206_timer_write(s->timer[0], offset - 0x100, value);
305
        return;
306
    } else if (offset >= 0x120 && offset < 0x140) {
307
        m5206_timer_write(s->timer[1], offset - 0x120, value);
308
        return;
309
    } else if (offset >= 0x140 && offset < 0x160) {
310
        mcf_uart_write(s->uart[0], offset - 0x140, value);
311
        return;
312
    } else if (offset >= 0x180 && offset < 0x1a0) {
313
        mcf_uart_write(s->uart[1], offset - 0x180, value);
314
        return;
315
    }
316
    switch (offset) {
317
    case 0x03:
318
        s->scr = value;
319
        break;
320
    case 0x14 ... 0x20:
321
        s->icr[offset - 0x13] = value;
322
        m5206_mbar_update(s);
323
        break;
324
    case 0x36:
325
        s->imr = value;
326
        m5206_mbar_update(s);
327
        break;
328
    case 0x40:
329
        s->rsr &= ~value;
330
        break;
331
    case 0x41:
332
        /* TODO: implement watchdog.  */
333
        break;
334
    case 0x42:
335
        s->swivr = value;
336
        break;
337
    case 0xcb:
338
        s->par = value;
339
        break;
340
    case 0x170:
341
        s->uivr[0] = value;
342
        break;
343
    case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
344
        /* Not implemented: UART Output port bits.  */
345
        break;
346
    case 0x1b0:
347
        s->uivr[1] = value;
348
        break;
349
    default:
350
        cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
351
        break;
352
    }
353
}
354

    
355
/* Internal peripherals use a variety of register widths.
356
   This lookup table allows a single routine to handle all of them.  */
357
static const int m5206_mbar_width[] =
358
{
359
  /* 000-040 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  2, 2, 2, 2,
360
  /* 040-080 */ 1, 2, 2, 2,  4, 1, 2, 4,  1, 2, 4, 2,  2, 4, 2, 2,
361
  /* 080-0c0 */ 4, 2, 2, 4,  2, 2, 4, 2,  2, 4, 2, 2,  4, 2, 2, 4,
362
  /* 0c0-100 */ 2, 2, 1, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
363
  /* 100-140 */ 2, 2, 2, 2,  1, 0, 0, 0,  2, 2, 2, 2,  1, 0, 0, 0,
364
  /* 140-180 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
365
  /* 180-1c0 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
366
  /* 1c0-200 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
367
};
368

    
369
static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset);
370
static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset);
371

    
372
static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
373
{
374
    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
375
    offset &= 0x3ff;
376
    if (offset > 0x200) {
377
        cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
378
    }
379
    if (m5206_mbar_width[offset >> 2] > 1) {
380
        uint16_t val;
381
        val = m5206_mbar_readw(opaque, offset & ~1);
382
        if ((offset & 1) == 0) {
383
            val >>= 8;
384
        }
385
        return val & 0xff;
386
    }
387
    return m5206_mbar_read(s, offset);
388
}
389

    
390
static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
391
{
392
    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
393
    int width;
394
    offset &= 0x3ff;
395
    if (offset > 0x200) {
396
        cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
397
    }
398
    width = m5206_mbar_width[offset >> 2];
399
    if (width > 2) {
400
        uint32_t val;
401
        val = m5206_mbar_readl(opaque, offset & ~3);
402
        if ((offset & 3) == 0)
403
            val >>= 16;
404
        return val & 0xffff;
405
    } else if (width < 2) {
406
        uint16_t val;
407
        val = m5206_mbar_readb(opaque, offset) << 8;
408
        val |= m5206_mbar_readb(opaque, offset + 1);
409
        return val;
410
    }
411
    return m5206_mbar_read(s, offset);
412
}
413

    
414
static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
415
{
416
    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
417
    int width;
418
    offset &= 0x3ff;
419
    if (offset > 0x200) {
420
        cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
421
    }
422
    width = m5206_mbar_width[offset >> 2];
423
    if (width < 4) {
424
        uint32_t val;
425
        val = m5206_mbar_readw(opaque, offset) << 16;
426
        val |= m5206_mbar_readw(opaque, offset + 2);
427
        return val;
428
    }
429
    return m5206_mbar_read(s, offset);
430
}
431

    
432
static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
433
                              uint32_t value);
434
static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
435
                              uint32_t value);
436

    
437
static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset,
438
                              uint32_t value)
439
{
440
    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
441
    int width;
442
    offset &= 0x3ff;
443
    if (offset > 0x200) {
444
        cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
445
    }
446
    width = m5206_mbar_width[offset >> 2];
447
    if (width > 1) {
448
        uint32_t tmp;
449
        tmp = m5206_mbar_readw(opaque, offset & ~1);
450
        if (offset & 1) {
451
            tmp = (tmp & 0xff00) | value;
452
        } else {
453
            tmp = (tmp & 0x00ff) | (value << 8);
454
        }
455
        m5206_mbar_writew(opaque, offset & ~1, tmp);
456
        return;
457
    }
458
    m5206_mbar_write(s, offset, value);
459
}
460

    
461
static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
462
                              uint32_t value)
463
{
464
    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
465
    int width;
466
    offset &= 0x3ff;
467
    if (offset > 0x200) {
468
        cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
469
    }
470
    width = m5206_mbar_width[offset >> 2];
471
    if (width > 2) {
472
        uint32_t tmp;
473
        tmp = m5206_mbar_readl(opaque, offset & ~3);
474
        if (offset & 3) {
475
            tmp = (tmp & 0xffff0000) | value;
476
        } else {
477
            tmp = (tmp & 0x0000ffff) | (value << 16);
478
        }
479
        m5206_mbar_writel(opaque, offset & ~3, tmp);
480
        return;
481
    } else if (width < 2) {
482
        m5206_mbar_writeb(opaque, offset, value >> 8);
483
        m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
484
        return;
485
    }
486
    m5206_mbar_write(s, offset, value);
487
}
488

    
489
static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
490
                              uint32_t value)
491
{
492
    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
493
    int width;
494
    offset &= 0x3ff;
495
    if (offset > 0x200) {
496
        cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
497
    }
498
    width = m5206_mbar_width[offset >> 2];
499
    if (width < 4) {
500
        m5206_mbar_writew(opaque, offset, value >> 16);
501
        m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
502
        return;
503
    }
504
    m5206_mbar_write(s, offset, value);
505
}
506

    
507
static CPUReadMemoryFunc *m5206_mbar_readfn[] = {
508
   m5206_mbar_readb,
509
   m5206_mbar_readw,
510
   m5206_mbar_readl
511
};
512

    
513
static CPUWriteMemoryFunc *m5206_mbar_writefn[] = {
514
   m5206_mbar_writeb,
515
   m5206_mbar_writew,
516
   m5206_mbar_writel
517
};
518

    
519
qemu_irq *mcf5206_init(uint32_t base, CPUState *env)
520
{
521
    m5206_mbar_state *s;
522
    qemu_irq *pic;
523
    int iomemtype;
524

    
525
    s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state));
526
    iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn,
527
                                       m5206_mbar_writefn, s);
528
    cpu_register_physical_memory(base, 0x00001000, iomemtype);
529

    
530
    pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
531
    s->timer[0] = m5206_timer_init(pic[9]);
532
    s->timer[1] = m5206_timer_init(pic[10]);
533
    s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]);
534
    s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]);
535
    s->env = env;
536

    
537
    m5206_mbar_reset(s);
538
    return pic;
539
}
540