Statistics
| Branch: | Revision:

root / hw / versatilepb.c @ 56bebe70

History | View | Annotate | Download (8.8 kB)

1 cdbdb648 pbrook
/* 
2 cdbdb648 pbrook
 * ARM Versatile Platform Baseboard System emulation.
3 cdbdb648 pbrook
 *
4 cdbdb648 pbrook
 * Copyright (c) 2005-2006 CodeSourcery.
5 cdbdb648 pbrook
 * Written by Paul Brook
6 cdbdb648 pbrook
 *
7 cdbdb648 pbrook
 * This code is licenced under the GPL.
8 cdbdb648 pbrook
 */
9 cdbdb648 pbrook
10 cdbdb648 pbrook
#include "vl.h"
11 cdbdb648 pbrook
#include "arm_pic.h"
12 cdbdb648 pbrook
13 cdbdb648 pbrook
#define KERNEL_ARGS_ADDR 0x100
14 cdbdb648 pbrook
#define KERNEL_LOAD_ADDR 0x00010000
15 cdbdb648 pbrook
#define INITRD_LOAD_ADDR 0x00800000
16 cdbdb648 pbrook
17 cdbdb648 pbrook
/* Primary interrupt controller.  */
18 cdbdb648 pbrook
19 cdbdb648 pbrook
typedef struct vpb_sic_state
20 cdbdb648 pbrook
{
21 cdbdb648 pbrook
  arm_pic_handler handler;
22 cdbdb648 pbrook
  uint32_t base;
23 cdbdb648 pbrook
  uint32_t level;
24 cdbdb648 pbrook
  uint32_t mask;
25 cdbdb648 pbrook
  uint32_t pic_enable;
26 cdbdb648 pbrook
  void *parent;
27 cdbdb648 pbrook
  int irq;
28 cdbdb648 pbrook
} vpb_sic_state;
29 cdbdb648 pbrook
30 cdbdb648 pbrook
static void vpb_sic_update(vpb_sic_state *s)
31 cdbdb648 pbrook
{
32 cdbdb648 pbrook
    uint32_t flags;
33 cdbdb648 pbrook
34 cdbdb648 pbrook
    flags = s->level & s->mask;
35 cdbdb648 pbrook
    pic_set_irq_new(s->parent, s->irq, flags != 0);
36 cdbdb648 pbrook
}
37 cdbdb648 pbrook
38 cdbdb648 pbrook
static void vpb_sic_update_pic(vpb_sic_state *s)
39 cdbdb648 pbrook
{
40 cdbdb648 pbrook
    int i;
41 cdbdb648 pbrook
    uint32_t mask;
42 cdbdb648 pbrook
43 cdbdb648 pbrook
    for (i = 21; i <= 30; i++) {
44 cdbdb648 pbrook
        mask = 1u << i;
45 cdbdb648 pbrook
        if (!(s->pic_enable & mask))
46 cdbdb648 pbrook
            continue;
47 cdbdb648 pbrook
        pic_set_irq_new(s->parent, i, (s->level & mask) != 0);
48 cdbdb648 pbrook
    }
49 cdbdb648 pbrook
}
50 cdbdb648 pbrook
51 cdbdb648 pbrook
static void vpb_sic_set_irq(void *opaque, int irq, int level)
52 cdbdb648 pbrook
{
53 cdbdb648 pbrook
    vpb_sic_state *s = (vpb_sic_state *)opaque;
54 cdbdb648 pbrook
    if (level)
55 cdbdb648 pbrook
        s->level |= 1u << irq;
56 cdbdb648 pbrook
    else
57 cdbdb648 pbrook
        s->level &= ~(1u << irq);
58 cdbdb648 pbrook
    if (s->pic_enable & (1u << irq))
59 cdbdb648 pbrook
        pic_set_irq_new(s->parent, irq, level);
60 cdbdb648 pbrook
    vpb_sic_update(s);
61 cdbdb648 pbrook
}
62 cdbdb648 pbrook
63 cdbdb648 pbrook
static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset)
64 cdbdb648 pbrook
{
65 cdbdb648 pbrook
    vpb_sic_state *s = (vpb_sic_state *)opaque;
66 cdbdb648 pbrook
67 cdbdb648 pbrook
    offset -= s->base;
68 cdbdb648 pbrook
    switch (offset >> 2) {
69 cdbdb648 pbrook
    case 0: /* STATUS */
70 cdbdb648 pbrook
        return s->level & s->mask;
71 cdbdb648 pbrook
    case 1: /* RAWSTAT */
72 cdbdb648 pbrook
        return s->level;
73 cdbdb648 pbrook
    case 2: /* ENABLE */
74 cdbdb648 pbrook
        return s->mask;
75 cdbdb648 pbrook
    case 4: /* SOFTINT */
76 cdbdb648 pbrook
        return s->level & 1;
77 cdbdb648 pbrook
    case 8: /* PICENABLE */
78 cdbdb648 pbrook
        return s->pic_enable;
79 cdbdb648 pbrook
    default:
80 cdbdb648 pbrook
        printf ("vpb_sic_read: Bad register offset 0x%x\n", offset);
81 cdbdb648 pbrook
        return 0;
82 cdbdb648 pbrook
    }
83 cdbdb648 pbrook
}
84 cdbdb648 pbrook
85 cdbdb648 pbrook
static void vpb_sic_write(void *opaque, target_phys_addr_t offset,
86 cdbdb648 pbrook
                          uint32_t value)
87 cdbdb648 pbrook
{
88 cdbdb648 pbrook
    vpb_sic_state *s = (vpb_sic_state *)opaque;
89 cdbdb648 pbrook
    offset -= s->base;
90 cdbdb648 pbrook
91 cdbdb648 pbrook
    switch (offset >> 2) {
92 cdbdb648 pbrook
    case 2: /* ENSET */
93 cdbdb648 pbrook
        s->mask |= value;
94 cdbdb648 pbrook
        break;
95 cdbdb648 pbrook
    case 3: /* ENCLR */
96 cdbdb648 pbrook
        s->mask &= ~value;
97 cdbdb648 pbrook
        break;
98 cdbdb648 pbrook
    case 4: /* SOFTINTSET */
99 cdbdb648 pbrook
        if (value)
100 cdbdb648 pbrook
            s->mask |= 1;
101 cdbdb648 pbrook
        break;
102 cdbdb648 pbrook
    case 5: /* SOFTINTCLR */
103 cdbdb648 pbrook
        if (value)
104 cdbdb648 pbrook
            s->mask &= ~1u;
105 cdbdb648 pbrook
        break;
106 cdbdb648 pbrook
    case 8: /* PICENSET */
107 cdbdb648 pbrook
        s->pic_enable |= (value & 0x7fe00000);
108 cdbdb648 pbrook
        vpb_sic_update_pic(s);
109 cdbdb648 pbrook
        break;
110 cdbdb648 pbrook
    case 9: /* PICENCLR */
111 cdbdb648 pbrook
        s->pic_enable &= ~value;
112 cdbdb648 pbrook
        vpb_sic_update_pic(s);
113 cdbdb648 pbrook
        break;
114 cdbdb648 pbrook
    default:
115 cdbdb648 pbrook
        printf ("vpb_sic_write: Bad register offset 0x%x\n", offset);
116 cdbdb648 pbrook
        return;
117 cdbdb648 pbrook
    }
118 cdbdb648 pbrook
    vpb_sic_update(s);
119 cdbdb648 pbrook
}
120 cdbdb648 pbrook
121 cdbdb648 pbrook
static CPUReadMemoryFunc *vpb_sic_readfn[] = {
122 cdbdb648 pbrook
   vpb_sic_read,
123 cdbdb648 pbrook
   vpb_sic_read,
124 cdbdb648 pbrook
   vpb_sic_read
125 cdbdb648 pbrook
};
126 cdbdb648 pbrook
127 cdbdb648 pbrook
static CPUWriteMemoryFunc *vpb_sic_writefn[] = {
128 cdbdb648 pbrook
   vpb_sic_write,
129 cdbdb648 pbrook
   vpb_sic_write,
130 cdbdb648 pbrook
   vpb_sic_write
131 cdbdb648 pbrook
};
132 cdbdb648 pbrook
133 cdbdb648 pbrook
static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
134 cdbdb648 pbrook
{
135 cdbdb648 pbrook
    vpb_sic_state *s;
136 cdbdb648 pbrook
    int iomemtype;
137 cdbdb648 pbrook
138 cdbdb648 pbrook
    s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state));
139 cdbdb648 pbrook
    if (!s)
140 cdbdb648 pbrook
        return NULL;
141 cdbdb648 pbrook
    s->handler = vpb_sic_set_irq;
142 cdbdb648 pbrook
    s->base = base;
143 cdbdb648 pbrook
    s->parent = parent;
144 cdbdb648 pbrook
    s->irq = irq;
145 cdbdb648 pbrook
    iomemtype = cpu_register_io_memory(0, vpb_sic_readfn,
146 cdbdb648 pbrook
                                       vpb_sic_writefn, s);
147 cdbdb648 pbrook
    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
148 cdbdb648 pbrook
    /* ??? Save/restore.  */
149 cdbdb648 pbrook
    return s;
150 cdbdb648 pbrook
}
151 cdbdb648 pbrook
152 cdbdb648 pbrook
/* Board init.  */
153 cdbdb648 pbrook
154 cdbdb648 pbrook
/* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
155 cdbdb648 pbrook
static uint32_t bootloader[] = {
156 cdbdb648 pbrook
  0xe3a00000, /* mov     r0, #0 */
157 cdbdb648 pbrook
  0xe3a01083, /* mov     r1, #0x83 */
158 cdbdb648 pbrook
  0xe3811c01, /* orr     r1, r1, #0x100 */
159 cdbdb648 pbrook
  0xe59f2000, /* ldr     r2, [pc, #0] */
160 cdbdb648 pbrook
  0xe59ff000, /* ldr     pc, [pc, #0] */
161 cdbdb648 pbrook
  0, /* Address of kernel args.  Set by integratorcp_init.  */
162 cdbdb648 pbrook
  0  /* Kernel entry point.  Set by integratorcp_init.  */
163 cdbdb648 pbrook
};
164 cdbdb648 pbrook
165 cdbdb648 pbrook
static void set_kernel_args(uint32_t ram_size, int initrd_size,
166 cdbdb648 pbrook
                            const char *kernel_cmdline)
167 cdbdb648 pbrook
{
168 cdbdb648 pbrook
    uint32_t *p;
169 cdbdb648 pbrook
170 cdbdb648 pbrook
    p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR);
171 cdbdb648 pbrook
    /* ATAG_CORE */
172 cdbdb648 pbrook
    stl_raw(p++, 5);
173 cdbdb648 pbrook
    stl_raw(p++, 0x54410001);
174 cdbdb648 pbrook
    stl_raw(p++, 1);
175 cdbdb648 pbrook
    stl_raw(p++, 0x1000);
176 cdbdb648 pbrook
    stl_raw(p++, 0);
177 cdbdb648 pbrook
    /* ATAG_MEM */
178 cdbdb648 pbrook
    stl_raw(p++, 4);
179 cdbdb648 pbrook
    stl_raw(p++, 0x54410002);
180 cdbdb648 pbrook
    stl_raw(p++, ram_size);
181 cdbdb648 pbrook
    stl_raw(p++, 0);
182 cdbdb648 pbrook
    if (initrd_size) {
183 cdbdb648 pbrook
        /* ATAG_INITRD2 */
184 cdbdb648 pbrook
        stl_raw(p++, 4);
185 cdbdb648 pbrook
        stl_raw(p++, 0x54420005);
186 cdbdb648 pbrook
        stl_raw(p++, INITRD_LOAD_ADDR);
187 cdbdb648 pbrook
        stl_raw(p++, initrd_size);
188 cdbdb648 pbrook
    }
189 cdbdb648 pbrook
    if (kernel_cmdline && *kernel_cmdline) {
190 cdbdb648 pbrook
        /* ATAG_CMDLINE */
191 cdbdb648 pbrook
        int cmdline_size;
192 cdbdb648 pbrook
193 cdbdb648 pbrook
        cmdline_size = strlen(kernel_cmdline);
194 cdbdb648 pbrook
        memcpy (p + 2, kernel_cmdline, cmdline_size + 1);
195 cdbdb648 pbrook
        cmdline_size = (cmdline_size >> 2) + 1;
196 cdbdb648 pbrook
        stl_raw(p++, cmdline_size + 2);
197 cdbdb648 pbrook
        stl_raw(p++, 0x54410009);
198 cdbdb648 pbrook
        p += cmdline_size;
199 cdbdb648 pbrook
    }
200 cdbdb648 pbrook
    /* ATAG_END */
201 cdbdb648 pbrook
    stl_raw(p++, 0);
202 cdbdb648 pbrook
    stl_raw(p++, 0);
203 cdbdb648 pbrook
}
204 cdbdb648 pbrook
205 cdbdb648 pbrook
static void vpb_init(int ram_size, int vga_ram_size, int boot_device,
206 cdbdb648 pbrook
                     DisplayState *ds, const char **fd_filename, int snapshot,
207 cdbdb648 pbrook
                     const char *kernel_filename, const char *kernel_cmdline,
208 cdbdb648 pbrook
                     const char *initrd_filename)
209 cdbdb648 pbrook
{
210 cdbdb648 pbrook
    CPUState *env;
211 cdbdb648 pbrook
    int kernel_size;
212 cdbdb648 pbrook
    int initrd_size;
213 cdbdb648 pbrook
    int n;
214 cdbdb648 pbrook
    void *pic;
215 cdbdb648 pbrook
    void *sic;
216 cdbdb648 pbrook
217 cdbdb648 pbrook
    env = cpu_init();
218 cdbdb648 pbrook
    cpu_arm_set_model(env, ARM_CPUID_ARM926);
219 cdbdb648 pbrook
    /* ??? RAM shoud repeat to fill physical memory space.  */
220 cdbdb648 pbrook
    /* SDRAM at address zero.  */
221 cdbdb648 pbrook
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
222 cdbdb648 pbrook
223 cdbdb648 pbrook
    pic = arm_pic_init_cpu(env);
224 cdbdb648 pbrook
    pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
225 cdbdb648 pbrook
    sic = vpb_sic_init(0x10003000, pic, 31);
226 cdbdb648 pbrook
    pl050_init(0x10006000, sic, 3, 0);
227 cdbdb648 pbrook
    pl050_init(0x10007000, sic, 4, 1);
228 cdbdb648 pbrook
229 cdbdb648 pbrook
    /* TODO: Init PCI NICs.  */
230 cdbdb648 pbrook
    if (nd_table[0].vlan) {
231 cdbdb648 pbrook
        if (nd_table[0].model == NULL
232 cdbdb648 pbrook
            || strcmp(nd_table[0].model, "smc91c111") == 0) {
233 cdbdb648 pbrook
            smc91c111_init(&nd_table[0], 0x10010000, sic, 25);
234 cdbdb648 pbrook
        } else {
235 cdbdb648 pbrook
            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
236 cdbdb648 pbrook
            exit (1);
237 cdbdb648 pbrook
        }
238 cdbdb648 pbrook
    }
239 cdbdb648 pbrook
240 cdbdb648 pbrook
    pl011_init(0x101f1000, pic, 12, serial_hds[0]);
241 cdbdb648 pbrook
    pl011_init(0x101f2000, pic, 13, serial_hds[1]);
242 cdbdb648 pbrook
    pl011_init(0x101f3000, pic, 14, serial_hds[2]);
243 cdbdb648 pbrook
    pl011_init(0x10009000, sic, 6, serial_hds[3]);
244 cdbdb648 pbrook
245 cdbdb648 pbrook
    pl080_init(0x10130000, pic, 17);
246 cdbdb648 pbrook
    sp804_init(0x101e2000, pic, 4);
247 cdbdb648 pbrook
    sp804_init(0x101e3000, pic, 5);
248 cdbdb648 pbrook
249 cdbdb648 pbrook
    /* The versatile/PB actually has a modified Color LCD controller
250 cdbdb648 pbrook
       that includes hardware cursor support from the PL111.  */
251 cdbdb648 pbrook
    pl110_init(ds, 0x10120000, pic, 16, 1);
252 cdbdb648 pbrook
253 cdbdb648 pbrook
    /* 0x10000000 System registers.  */
254 cdbdb648 pbrook
    /* 0x10001000 PCI controller config registers.  */
255 cdbdb648 pbrook
    /* 0x10002000 Serial bus interface.  */
256 cdbdb648 pbrook
    /*  0x10003000 Secondary interrupt controller.  */
257 cdbdb648 pbrook
    /* 0x10004000 AACI (audio).  */
258 cdbdb648 pbrook
    /* 0x10005000 MMCI0.  */
259 cdbdb648 pbrook
    /*  0x10006000 KMI0 (keyboard).  */
260 cdbdb648 pbrook
    /*  0x10007000 KMI1 (mouse).  */
261 cdbdb648 pbrook
    /* 0x10008000 Character LCD Interface.  */
262 cdbdb648 pbrook
    /*  0x10009000 UART3.  */
263 cdbdb648 pbrook
    /* 0x1000a000 Smart card 1.  */
264 cdbdb648 pbrook
    /* 0x1000b000 MMCI1.  */
265 cdbdb648 pbrook
    /*  0x10010000 Ethernet.  */
266 cdbdb648 pbrook
    /* 0x10020000 USB.  */
267 cdbdb648 pbrook
    /* 0x10100000 SSMC.  */
268 cdbdb648 pbrook
    /* 0x10110000 MPMC.  */
269 cdbdb648 pbrook
    /*  0x10120000 CLCD Controller.  */
270 cdbdb648 pbrook
    /*  0x10130000 DMA Controller.  */
271 cdbdb648 pbrook
    /*  0x10140000 Vectored interrupt controller.  */
272 cdbdb648 pbrook
    /* 0x101d0000 AHB Monitor Interface.  */
273 cdbdb648 pbrook
    /* 0x101e0000 System Controller.  */
274 cdbdb648 pbrook
    /* 0x101e1000 Watchdog Interface.  */
275 cdbdb648 pbrook
    /* 0x101e2000 Timer 0/1.  */
276 cdbdb648 pbrook
    /* 0x101e3000 Timer 2/3.  */
277 cdbdb648 pbrook
    /* 0x101e4000 GPIO port 0.  */
278 cdbdb648 pbrook
    /* 0x101e5000 GPIO port 1.  */
279 cdbdb648 pbrook
    /* 0x101e6000 GPIO port 2.  */
280 cdbdb648 pbrook
    /* 0x101e7000 GPIO port 3.  */
281 cdbdb648 pbrook
    /* 0x101e8000 RTC.  */
282 cdbdb648 pbrook
    /* 0x101f0000 Smart card 0.  */
283 cdbdb648 pbrook
    /*  0x101f1000 UART0.  */
284 cdbdb648 pbrook
    /*  0x101f2000 UART1.  */
285 cdbdb648 pbrook
    /*  0x101f3000 UART2.  */
286 cdbdb648 pbrook
    /* 0x101f4000 SSPI.  */
287 cdbdb648 pbrook
288 cdbdb648 pbrook
    /* Load the kernel.  */
289 cdbdb648 pbrook
    if (!kernel_filename) {
290 cdbdb648 pbrook
        fprintf(stderr, "Kernel image must be specified\n");
291 cdbdb648 pbrook
        exit(1);
292 cdbdb648 pbrook
    }
293 cdbdb648 pbrook
    kernel_size = load_image(kernel_filename,
294 cdbdb648 pbrook
                             phys_ram_base + KERNEL_LOAD_ADDR);
295 cdbdb648 pbrook
    if (kernel_size < 0) {
296 cdbdb648 pbrook
        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
297 cdbdb648 pbrook
        exit(1);
298 cdbdb648 pbrook
    }
299 cdbdb648 pbrook
    if (initrd_filename) {
300 cdbdb648 pbrook
        initrd_size = load_image(initrd_filename,
301 cdbdb648 pbrook
                                 phys_ram_base + INITRD_LOAD_ADDR);
302 cdbdb648 pbrook
        if (initrd_size < 0) {
303 cdbdb648 pbrook
            fprintf(stderr, "qemu: could not load initrd '%s'\n",
304 cdbdb648 pbrook
                    initrd_filename);
305 cdbdb648 pbrook
            exit(1);
306 cdbdb648 pbrook
        }
307 cdbdb648 pbrook
    } else {
308 cdbdb648 pbrook
        initrd_size = 0;
309 cdbdb648 pbrook
    }
310 cdbdb648 pbrook
    bootloader[5] = KERNEL_ARGS_ADDR;
311 cdbdb648 pbrook
    bootloader[6] = KERNEL_LOAD_ADDR;
312 cdbdb648 pbrook
    for (n = 0; n < sizeof(bootloader) / 4; n++)
313 cdbdb648 pbrook
        stl_raw(phys_ram_base + (n * 4), bootloader[n]);
314 cdbdb648 pbrook
    set_kernel_args(ram_size, initrd_size, kernel_cmdline);
315 cdbdb648 pbrook
}
316 cdbdb648 pbrook
317 cdbdb648 pbrook
QEMUMachine versatilepb_machine = {
318 cdbdb648 pbrook
    "versatilepb",
319 cdbdb648 pbrook
    "ARM Versatile/PB (ARM926EJ-S)",
320 cdbdb648 pbrook
    vpb_init,
321 cdbdb648 pbrook
};