Statistics
| Branch: | Revision:

root / hw / versatilepb.c @ 0d92ed30

History | View | Annotate | Download (12.5 kB)

1
/* 
2
 * ARM Versatile Platform/Application Baseboard System emulation.
3
 *
4
 * Copyright (c) 2005-2006 CodeSourcery.
5
 * Written by Paul Brook
6
 *
7
 * This code is licenced under the GPL.
8
 */
9

    
10
#include "vl.h"
11
#include "arm_pic.h"
12

    
13
#define LOCK_VALUE 0xa05f
14

    
15
/* Primary interrupt controller.  */
16

    
17
typedef struct vpb_sic_state
18
{
19
  arm_pic_handler handler;
20
  uint32_t base;
21
  uint32_t level;
22
  uint32_t mask;
23
  uint32_t pic_enable;
24
  void *parent;
25
  int irq;
26
} vpb_sic_state;
27

    
28
static void vpb_sic_update(vpb_sic_state *s)
29
{
30
    uint32_t flags;
31

    
32
    flags = s->level & s->mask;
33
    pic_set_irq_new(s->parent, s->irq, flags != 0);
34
}
35

    
36
static void vpb_sic_update_pic(vpb_sic_state *s)
37
{
38
    int i;
39
    uint32_t mask;
40

    
41
    for (i = 21; i <= 30; i++) {
42
        mask = 1u << i;
43
        if (!(s->pic_enable & mask))
44
            continue;
45
        pic_set_irq_new(s->parent, i, (s->level & mask) != 0);
46
    }
47
}
48

    
49
static void vpb_sic_set_irq(void *opaque, int irq, int level)
50
{
51
    vpb_sic_state *s = (vpb_sic_state *)opaque;
52
    if (level)
53
        s->level |= 1u << irq;
54
    else
55
        s->level &= ~(1u << irq);
56
    if (s->pic_enable & (1u << irq))
57
        pic_set_irq_new(s->parent, irq, level);
58
    vpb_sic_update(s);
59
}
60

    
61
static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset)
62
{
63
    vpb_sic_state *s = (vpb_sic_state *)opaque;
64

    
65
    offset -= s->base;
66
    switch (offset >> 2) {
67
    case 0: /* STATUS */
68
        return s->level & s->mask;
69
    case 1: /* RAWSTAT */
70
        return s->level;
71
    case 2: /* ENABLE */
72
        return s->mask;
73
    case 4: /* SOFTINT */
74
        return s->level & 1;
75
    case 8: /* PICENABLE */
76
        return s->pic_enable;
77
    default:
78
        printf ("vpb_sic_read: Bad register offset 0x%x\n", offset);
79
        return 0;
80
    }
81
}
82

    
83
static void vpb_sic_write(void *opaque, target_phys_addr_t offset,
84
                          uint32_t value)
85
{
86
    vpb_sic_state *s = (vpb_sic_state *)opaque;
87
    offset -= s->base;
88

    
89
    switch (offset >> 2) {
90
    case 2: /* ENSET */
91
        s->mask |= value;
92
        break;
93
    case 3: /* ENCLR */
94
        s->mask &= ~value;
95
        break;
96
    case 4: /* SOFTINTSET */
97
        if (value)
98
            s->mask |= 1;
99
        break;
100
    case 5: /* SOFTINTCLR */
101
        if (value)
102
            s->mask &= ~1u;
103
        break;
104
    case 8: /* PICENSET */
105
        s->pic_enable |= (value & 0x7fe00000);
106
        vpb_sic_update_pic(s);
107
        break;
108
    case 9: /* PICENCLR */
109
        s->pic_enable &= ~value;
110
        vpb_sic_update_pic(s);
111
        break;
112
    default:
113
        printf ("vpb_sic_write: Bad register offset 0x%x\n", offset);
114
        return;
115
    }
116
    vpb_sic_update(s);
117
}
118

    
119
static CPUReadMemoryFunc *vpb_sic_readfn[] = {
120
   vpb_sic_read,
121
   vpb_sic_read,
122
   vpb_sic_read
123
};
124

    
125
static CPUWriteMemoryFunc *vpb_sic_writefn[] = {
126
   vpb_sic_write,
127
   vpb_sic_write,
128
   vpb_sic_write
129
};
130

    
131
static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
132
{
133
    vpb_sic_state *s;
134
    int iomemtype;
135

    
136
    s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state));
137
    if (!s)
138
        return NULL;
139
    s->handler = vpb_sic_set_irq;
140
    s->base = base;
141
    s->parent = parent;
142
    s->irq = irq;
143
    iomemtype = cpu_register_io_memory(0, vpb_sic_readfn,
144
                                       vpb_sic_writefn, s);
145
    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
146
    /* ??? Save/restore.  */
147
    return s;
148
}
149

    
150
/* System controller.  */
151

    
152
typedef struct {
153
    uint32_t base;
154
    uint32_t leds;
155
    uint16_t lockval;
156
    uint32_t cfgdata1;
157
    uint32_t cfgdata2;
158
    uint32_t flags;
159
    uint32_t nvflags;
160
    uint32_t resetlevel;
161
} vpb_sys_state;
162

    
163
static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset)
164
{
165
    vpb_sys_state *s = (vpb_sys_state *)opaque;
166

    
167
    offset -= s->base;
168
    switch (offset) {
169
    case 0x00: /* ID */
170
        return 0x41007004;
171
    case 0x04: /* SW */
172
        /* General purpose hardware switches.
173
           We don't have a useful way of exposing these to the user.  */
174
        return 0;
175
    case 0x08: /* LED */
176
        return s->leds;
177
    case 0x20: /* LOCK */
178
        return s->lockval;
179
    case 0x0c: /* OSC0 */
180
    case 0x10: /* OSC1 */
181
    case 0x14: /* OSC2 */
182
    case 0x18: /* OSC3 */
183
    case 0x1c: /* OSC4 */
184
    case 0x24: /* 100HZ */
185
        /* ??? Implement these.  */
186
        return 0;
187
    case 0x28: /* CFGDATA1 */
188
        return s->cfgdata1;
189
    case 0x2c: /* CFGDATA2 */
190
        return s->cfgdata2;
191
    case 0x30: /* FLAGS */
192
        return s->flags;
193
    case 0x38: /* NVFLAGS */
194
        return s->nvflags;
195
    case 0x40: /* RESETCTL */
196
        return s->resetlevel;
197
    case 0x44: /* PCICTL */
198
        return 1;
199
    case 0x48: /* MCI */
200
        return 0;
201
    case 0x4c: /* FLASH */
202
        return 0;
203
    case 0x50: /* CLCD */
204
        return 0x1000;
205
    case 0x54: /* CLCDSER */
206
        return 0;
207
    case 0x58: /* BOOTCS */
208
        return 0;
209
    case 0x5c: /* 24MHz */
210
        /* ??? not implemented.  */
211
        return 0;
212
    case 0x60: /* MISC */
213
        return 0;
214
    case 0x64: /* DMAPSR0 */
215
    case 0x68: /* DMAPSR1 */
216
    case 0x6c: /* DMAPSR2 */
217
    case 0x8c: /* OSCRESET0 */
218
    case 0x90: /* OSCRESET1 */
219
    case 0x94: /* OSCRESET2 */
220
    case 0x98: /* OSCRESET3 */
221
    case 0x9c: /* OSCRESET4 */
222
    case 0xc0: /* SYS_TEST_OSC0 */
223
    case 0xc4: /* SYS_TEST_OSC1 */
224
    case 0xc8: /* SYS_TEST_OSC2 */
225
    case 0xcc: /* SYS_TEST_OSC3 */
226
    case 0xd0: /* SYS_TEST_OSC4 */
227
        return 0;
228
    default:
229
        printf ("vpb_sys_read: Bad register offset 0x%x\n", offset);
230
        return 0;
231
    }
232
}
233

    
234
static void vpb_sys_write(void *opaque, target_phys_addr_t offset,
235
                          uint32_t val)
236
{
237
    vpb_sys_state *s = (vpb_sys_state *)opaque;
238
    offset -= s->base;
239

    
240
    switch (offset) {
241
    case 0x08: /* LED */
242
        s->leds = val;
243
    case 0x0c: /* OSC0 */
244
    case 0x10: /* OSC1 */
245
    case 0x14: /* OSC2 */
246
    case 0x18: /* OSC3 */
247
    case 0x1c: /* OSC4 */
248
        /* ??? */
249
        break;
250
    case 0x20: /* LOCK */
251
        if (val == LOCK_VALUE)
252
            s->lockval = val;
253
        else
254
            s->lockval = val & 0x7fff;
255
        break;
256
    case 0x28: /* CFGDATA1 */
257
        /* ??? Need to implement this.  */
258
        s->cfgdata1 = val;
259
        break;
260
    case 0x2c: /* CFGDATA2 */
261
        /* ??? Need to implement this.  */
262
        s->cfgdata2 = val;
263
        break;
264
    case 0x30: /* FLAGSSET */
265
        s->flags |= val;
266
        break;
267
    case 0x34: /* FLAGSCLR */
268
        s->flags &= ~val;
269
        break;
270
    case 0x38: /* NVFLAGSSET */
271
        s->nvflags |= val;
272
        break;
273
    case 0x3c: /* NVFLAGSCLR */
274
        s->nvflags &= ~val;
275
        break;
276
    case 0x40: /* RESETCTL */
277
        if (s->lockval == LOCK_VALUE) {
278
            s->resetlevel = val;
279
            if (val & 0x100)
280
                cpu_abort(cpu_single_env, "Board reset\n");
281
        }
282
        break;
283
    case 0x44: /* PCICTL */
284
        /* nothing to do.  */
285
        break;
286
    case 0x4c: /* FLASH */
287
    case 0x50: /* CLCD */
288
    case 0x54: /* CLCDSER */
289
    case 0x64: /* DMAPSR0 */
290
    case 0x68: /* DMAPSR1 */
291
    case 0x6c: /* DMAPSR2 */
292
    case 0x8c: /* OSCRESET0 */
293
    case 0x90: /* OSCRESET1 */
294
    case 0x94: /* OSCRESET2 */
295
    case 0x98: /* OSCRESET3 */
296
    case 0x9c: /* OSCRESET4 */
297
        break;
298
    default:
299
        printf ("vpb_sys_write: Bad register offset 0x%x\n", offset);
300
        return;
301
    }
302
}
303

    
304
static CPUReadMemoryFunc *vpb_sys_readfn[] = {
305
   vpb_sys_read,
306
   vpb_sys_read,
307
   vpb_sys_read
308
};
309

    
310
static CPUWriteMemoryFunc *vpb_sys_writefn[] = {
311
   vpb_sys_write,
312
   vpb_sys_write,
313
   vpb_sys_write
314
};
315

    
316
static vpb_sys_state *vpb_sys_init(uint32_t base)
317
{
318
    vpb_sys_state *s;
319
    int iomemtype;
320

    
321
    s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state));
322
    if (!s)
323
        return NULL;
324
    s->base = base;
325
    iomemtype = cpu_register_io_memory(0, vpb_sys_readfn,
326
                                       vpb_sys_writefn, s);
327
    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
328
    /* ??? Save/restore.  */
329
    return s;
330
}
331

    
332
/* Board init.  */
333

    
334
/* The AB and PB boards both use the same core, just with different
335
   peripherans and expansion busses.  For now we emulate a subset of the
336
   PB peripherals and just change the board ID.  */
337

    
338
static void versatile_init(int ram_size, int vga_ram_size, int boot_device,
339
                     DisplayState *ds, const char **fd_filename, int snapshot,
340
                     const char *kernel_filename, const char *kernel_cmdline,
341
                     const char *initrd_filename, int board_id)
342
{
343
    CPUState *env;
344
    void *pic;
345
    void *sic;
346
    PCIBus *pci_bus;
347
    NICInfo *nd;
348
    int n;
349
    int done_smc = 0;
350

    
351
    env = cpu_init();
352
    cpu_arm_set_model(env, ARM_CPUID_ARM926);
353
    /* ??? RAM shoud repeat to fill physical memory space.  */
354
    /* SDRAM at address zero.  */
355
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
356

    
357
    vpb_sys_init(0x10000000);
358
    pic = arm_pic_init_cpu(env);
359
    pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
360
    sic = vpb_sic_init(0x10003000, pic, 31);
361
    pl050_init(0x10006000, sic, 3, 0);
362
    pl050_init(0x10007000, sic, 4, 1);
363

    
364
    pci_bus = pci_vpb_init(sic);
365
    /* The Versatile PCI bridge does not provide access to PCI IO space,
366
       so many of the qemu PCI devices are not useable.  */
367
    for(n = 0; n < nb_nics; n++) {
368
        nd = &nd_table[n];
369
        if (!nd->model)
370
            nd->model = done_smc ? "rtl8139" : "smc91c111";
371
        if (strcmp(nd->model, "smc91c111") == 0) {
372
            smc91c111_init(nd, 0x10010000, sic, 25);
373
        } else {
374
            pci_nic_init(pci_bus, nd);
375
        }
376
    }
377
    if (usb_enabled) {
378
        usb_ohci_init(pci_bus, 3, -1);
379
    }
380

    
381
    pl011_init(0x101f1000, pic, 12, serial_hds[0]);
382
    pl011_init(0x101f2000, pic, 13, serial_hds[1]);
383
    pl011_init(0x101f3000, pic, 14, serial_hds[2]);
384
    pl011_init(0x10009000, sic, 6, serial_hds[3]);
385

    
386
    pl080_init(0x10130000, pic, 17);
387
    sp804_init(0x101e2000, pic, 4);
388
    sp804_init(0x101e3000, pic, 5);
389

    
390
    /* The versatile/PB actually has a modified Color LCD controller
391
       that includes hardware cursor support from the PL111.  */
392
    pl110_init(ds, 0x10120000, pic, 16, 1);
393

    
394
    /* Memory map for Versatile/PB:  */
395
    /* 0x10000000 System registers.  */
396
    /* 0x10001000 PCI controller config registers.  */
397
    /* 0x10002000 Serial bus interface.  */
398
    /*  0x10003000 Secondary interrupt controller.  */
399
    /* 0x10004000 AACI (audio).  */
400
    /* 0x10005000 MMCI0.  */
401
    /*  0x10006000 KMI0 (keyboard).  */
402
    /*  0x10007000 KMI1 (mouse).  */
403
    /* 0x10008000 Character LCD Interface.  */
404
    /*  0x10009000 UART3.  */
405
    /* 0x1000a000 Smart card 1.  */
406
    /* 0x1000b000 MMCI1.  */
407
    /*  0x10010000 Ethernet.  */
408
    /* 0x10020000 USB.  */
409
    /* 0x10100000 SSMC.  */
410
    /* 0x10110000 MPMC.  */
411
    /*  0x10120000 CLCD Controller.  */
412
    /*  0x10130000 DMA Controller.  */
413
    /*  0x10140000 Vectored interrupt controller.  */
414
    /* 0x101d0000 AHB Monitor Interface.  */
415
    /* 0x101e0000 System Controller.  */
416
    /* 0x101e1000 Watchdog Interface.  */
417
    /* 0x101e2000 Timer 0/1.  */
418
    /* 0x101e3000 Timer 2/3.  */
419
    /* 0x101e4000 GPIO port 0.  */
420
    /* 0x101e5000 GPIO port 1.  */
421
    /* 0x101e6000 GPIO port 2.  */
422
    /* 0x101e7000 GPIO port 3.  */
423
    /* 0x101e8000 RTC.  */
424
    /* 0x101f0000 Smart card 0.  */
425
    /*  0x101f1000 UART0.  */
426
    /*  0x101f2000 UART1.  */
427
    /*  0x101f3000 UART2.  */
428
    /* 0x101f4000 SSPI.  */
429

    
430
    arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
431
                    initrd_filename, board_id);
432
}
433

    
434
static void vpb_init(int ram_size, int vga_ram_size, int boot_device,
435
                     DisplayState *ds, const char **fd_filename, int snapshot,
436
                     const char *kernel_filename, const char *kernel_cmdline,
437
                     const char *initrd_filename)
438
{
439
    versatile_init(ram_size, vga_ram_size, boot_device,
440
                   ds, fd_filename, snapshot,
441
                   kernel_filename, kernel_cmdline,
442
                   initrd_filename, 0x183);
443
}
444

    
445
static void vab_init(int ram_size, int vga_ram_size, int boot_device,
446
                     DisplayState *ds, const char **fd_filename, int snapshot,
447
                     const char *kernel_filename, const char *kernel_cmdline,
448
                     const char *initrd_filename)
449
{
450
    versatile_init(ram_size, vga_ram_size, boot_device,
451
                   ds, fd_filename, snapshot,
452
                   kernel_filename, kernel_cmdline,
453
                   initrd_filename, 0x25e);
454
}
455

    
456
QEMUMachine versatilepb_machine = {
457
    "versatilepb",
458
    "ARM Versatile/PB (ARM926EJ-S)",
459
    vpb_init,
460
};
461

    
462
QEMUMachine versatileab_machine = {
463
    "versatileab",
464
    "ARM Versatile/AB (ARM926EJ-S)",
465
    vab_init,
466
};