]> Git Repo - qemu.git/blame - hw/mips_malta.c
Split out SDL X keymap, by Bernhard Fischer.
[qemu.git] / hw / mips_malta.c
CommitLineData
5856de80
TS
1/*
2 * QEMU Malta board support
3 *
4 * Copyright (c) 2006 Aurelien Jarno
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "vl.h"
26
27#define BIOS_FILENAME "mips_bios.bin"
28#ifdef MIPS_HAS_MIPS64
29#define INITRD_LOAD_ADDR (uint64_t)0x80800000
30#define ENVP_ADDR (uint64_t)0x80002000
31#else
32#define INITRD_LOAD_ADDR (uint32_t)0x80800000
33#define ENVP_ADDR (uint32_t)0x80002000
34#endif
35
36#define VIRT_TO_PHYS_ADDEND (-((uint64_t)(uint32_t)0x80000000))
37
38#define ENVP_NB_ENTRIES 16
39#define ENVP_ENTRY_SIZE 256
40
41
42extern FILE *logfile;
43
44typedef struct {
45 uint32_t leds;
46 uint32_t brk;
47 uint32_t gpout;
48 uint32_t i2coe;
49 uint32_t i2cout;
50 uint32_t i2csel;
51 CharDriverState *display;
52 char display_text[9];
53} MaltaFPGAState;
54
55static PITState *pit;
56
4de9b249 57/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
5856de80
TS
58static void pic_irq_request(void *opaque, int level)
59{
4de9b249 60 cpu_mips_irq_request(opaque, 2, level);
5856de80
TS
61}
62
63/* Malta FPGA */
64static void malta_fpga_update_display(void *opaque)
65{
66 char leds_text[9];
67 int i;
68 MaltaFPGAState *s = opaque;
69
70 for (i = 7 ; i >= 0 ; i--) {
71 if (s->leds & (1 << i))
72 leds_text[i] = '#';
73 else
74 leds_text[i] = ' ';
75 }
76 leds_text[8] = '\0';
77
472c5273
TS
78 qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
79 qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
5856de80
TS
80}
81
82static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
83{
84 MaltaFPGAState *s = opaque;
85 uint32_t val = 0;
86 uint32_t saddr;
87
88 saddr = (addr & 0xfffff);
89
90 switch (saddr) {
91
92 /* SWITCH Register */
93 case 0x00200:
94 val = 0x00000000; /* All switches closed */
95 break;
96
97 /* STATUS Register */
98 case 0x00208:
99#ifdef TARGET_WORDS_BIGENDIAN
100 val = 0x00000012;
101#else
102 val = 0x00000010;
103#endif
104 break;
105
106 /* JMPRS Register */
107 case 0x00210:
108 val = 0x00;
109 break;
110
111 /* LEDBAR Register */
112 case 0x00408:
113 val = s->leds;
114 break;
115
116 /* BRKRES Register */
117 case 0x00508:
118 val = s->brk;
119 break;
120
121 /* GPOUT Register */
122 case 0x00a00:
123 val = s->gpout;
124 break;
125
126 /* XXX: implement a real I2C controller */
127
128 /* GPINP Register */
129 case 0x00a08:
130 /* IN = OUT until a real I2C control is implemented */
131 if (s->i2csel)
132 val = s->i2cout;
133 else
134 val = 0x00;
135 break;
136
137 /* I2CINP Register */
138 case 0x00b00:
139 val = 0x00000003;
140 break;
141
142 /* I2COE Register */
143 case 0x00b08:
144 val = s->i2coe;
145 break;
146
147 /* I2COUT Register */
148 case 0x00b10:
149 val = s->i2cout;
150 break;
151
152 /* I2CSEL Register */
153 case 0x00b18:
154 val = s->i2cout;
155 break;
156
157 default:
158#if 0
159 printf ("malta_fpga_read: Bad register offset 0x%x\n", (int)addr);
160#endif
161 break;
162 }
163 return val;
164}
165
166static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
167 uint32_t val)
168{
169 MaltaFPGAState *s = opaque;
170 uint32_t saddr;
171
172 saddr = (addr & 0xfffff);
173
174 switch (saddr) {
175
176 /* SWITCH Register */
177 case 0x00200:
178 break;
179
180 /* JMPRS Register */
181 case 0x00210:
182 break;
183
184 /* LEDBAR Register */
185 /* XXX: implement a 8-LED array */
186 case 0x00408:
187 s->leds = val & 0xff;
188 break;
189
190 /* ASCIIWORD Register */
191 case 0x00410:
192 snprintf(s->display_text, 9, "%08X", val);
193 malta_fpga_update_display(s);
194 break;
195
196 /* ASCIIPOS0 to ASCIIPOS7 Registers */
197 case 0x00418:
198 case 0x00420:
199 case 0x00428:
200 case 0x00430:
201 case 0x00438:
202 case 0x00440:
203 case 0x00448:
204 case 0x00450:
205 s->display_text[(saddr - 0x00418) >> 3] = (char) val;
206 malta_fpga_update_display(s);
207 break;
208
209 /* SOFTRES Register */
210 case 0x00500:
211 if (val == 0x42)
212 qemu_system_reset_request ();
213 break;
214
215 /* BRKRES Register */
216 case 0x00508:
217 s->brk = val & 0xff;
218 break;
219
220 /* GPOUT Register */
221 case 0x00a00:
222 s->gpout = val & 0xff;
223 break;
224
225 /* I2COE Register */
226 case 0x00b08:
227 s->i2coe = val & 0x03;
228 break;
229
230 /* I2COUT Register */
231 case 0x00b10:
232 s->i2cout = val & 0x03;
233 break;
234
235 /* I2CSEL Register */
236 case 0x00b18:
237 s->i2cout = val & 0x01;
238 break;
239
240 default:
241#if 0
242 printf ("malta_fpga_write: Bad register offset 0x%x\n", (int)addr);
243#endif
244 break;
245 }
246}
247
248static CPUReadMemoryFunc *malta_fpga_read[] = {
249 malta_fpga_readl,
250 malta_fpga_readl,
251 malta_fpga_readl
252};
253
254static CPUWriteMemoryFunc *malta_fpga_write[] = {
255 malta_fpga_writel,
256 malta_fpga_writel,
257 malta_fpga_writel
258};
259
260void malta_fpga_reset(void *opaque)
261{
262 MaltaFPGAState *s = opaque;
263
264 s->leds = 0x00;
265 s->brk = 0x0a;
266 s->gpout = 0x00;
267 s->i2coe = 0x0;
268 s->i2cout = 0x3;
269 s->i2csel = 0x1;
270
271 s->display_text[8] = '\0';
272 snprintf(s->display_text, 9, " ");
273 malta_fpga_update_display(s);
274}
275
276MaltaFPGAState *malta_fpga_init(target_phys_addr_t base)
277{
278 MaltaFPGAState *s;
279 int malta;
280
281 s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
282
283 malta = cpu_register_io_memory(0, malta_fpga_read,
284 malta_fpga_write, s);
285 cpu_register_physical_memory(base, 0x100000, malta);
286
287 s->display = qemu_chr_open("vc");
af23902b 288 qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n");
5856de80
TS
289 qemu_chr_printf(s->display, "+--------+\r\n");
290 qemu_chr_printf(s->display, "+ +\r\n");
291 qemu_chr_printf(s->display, "+--------+\r\n");
292 qemu_chr_printf(s->display, "\n");
293 qemu_chr_printf(s->display, "Malta ASCII\r\n");
294 qemu_chr_printf(s->display, "+--------+\r\n");
295 qemu_chr_printf(s->display, "+ +\r\n");
296 qemu_chr_printf(s->display, "+--------+\r\n");
297
298 malta_fpga_reset(s);
299 qemu_register_reset(malta_fpga_reset, s);
300
301 return s;
302}
303
304/* Audio support */
305#ifdef HAS_AUDIO
306static void audio_init (PCIBus *pci_bus)
307{
308 struct soundhw *c;
309 int audio_enabled = 0;
310
311 for (c = soundhw; !audio_enabled && c->name; ++c) {
312 audio_enabled = c->enabled;
313 }
314
315 if (audio_enabled) {
316 AudioState *s;
317
318 s = AUD_init ();
319 if (s) {
320 for (c = soundhw; c->name; ++c) {
321 if (c->enabled) {
322 if (c->isa) {
323 fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name);
324 exit(1);
325 }
326 else {
327 if (pci_bus) {
328 c->init.init_pci (pci_bus, s);
329 }
330 }
331 }
332 }
333 }
334 }
335}
336#endif
337
338/* Network support */
339static void network_init (PCIBus *pci_bus)
340{
341 int i;
342 NICInfo *nd;
343
344 for(i = 0; i < nb_nics; i++) {
345 nd = &nd_table[i];
346 if (!nd->model) {
347 nd->model = "pcnet";
348 }
349 if (i == 0 && strcmp(nd->model, "pcnet") == 0) {
350 /* The malta board has a PCNet card using PCI SLOT 11 */
351 pci_nic_init(pci_bus, nd, 88);
352 } else {
353 pci_nic_init(pci_bus, nd, -1);
354 }
355 }
356}
357
358/* ROM and pseudo bootloader
359
360 The following code implements a very very simple bootloader. It first
361 loads the registers a0 to a3 to the values expected by the OS, and
362 then jump at the kernel address.
363
364 The bootloader should pass the locations of the kernel arguments and
365 environment variables tables. Those tables contain the 32-bit address
366 of NULL terminated strings. The environment variables table should be
367 terminated by a NULL address.
368
369 For a simpler implementation, the number of kernel arguments is fixed
370 to two (the name of the kernel and the command line), and the two
371 tables are actually the same one.
372
373 The registers a0 to a3 should contain the following values:
374 a0 - number of kernel arguments
375 a1 - 32-bit address of the kernel arguments table
376 a2 - 32-bit address of the environment variables table
377 a3 - RAM size in bytes
378*/
379
380static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr)
381{
382 uint32_t *p;
383
384 /* Small bootloader */
385 p = (uint32_t *) (phys_ram_base + bios_offset);
386 stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */
387 stl_raw(p++, 0x00000000); /* nop */
388
389 /* Second part of the bootloader */
390 p = (uint32_t *) (phys_ram_base + bios_offset + 0x040);
391 stl_raw(p++, 0x3c040000); /* lui a0, 0 */
392 stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */
393 stl_raw(p++, 0x3c050000 | ((ENVP_ADDR) >> 16)); /* lui a1, high(ENVP_ADDR) */
394 stl_raw(p++, 0x34a50000 | ((ENVP_ADDR) & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */
395 stl_raw(p++, 0x3c060000 | ((ENVP_ADDR + 8) >> 16)); /* lui a2, high(ENVP_ADDR + 8) */
396 stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
397 stl_raw(p++, 0x3c070000 | ((env->ram_size) >> 16)); /* lui a3, high(env->ram_size) */
398 stl_raw(p++, 0x34e70000 | ((env->ram_size) & 0xffff)); /* ori a3, a3, low(env->ram_size) */
399 stl_raw(p++, 0x3c1f0000 | ((kernel_addr) >> 16)); /* lui ra, high(kernel_addr) */;
400 stl_raw(p++, 0x37ff0000 | ((kernel_addr) & 0xffff)); /* ori ra, ra, low(kernel_addr) */
401 stl_raw(p++, 0x03e00008); /* jr ra */
402 stl_raw(p++, 0x00000000); /* nop */
403}
404
405static void prom_set(int index, const char *string, ...)
406{
407 va_list ap;
408 uint32_t *p;
409 uint32_t table_addr;
410 char *s;
411
412 if (index >= ENVP_NB_ENTRIES)
413 return;
414
415 p = (uint32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
416 p += index;
417
418 if (string == NULL) {
419 stl_raw(p, 0);
420 return;
421 }
422
423 table_addr = ENVP_ADDR + sizeof(uint32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
424 s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
425
426 stl_raw(p, table_addr);
427
428 va_start(ap, string);
429 vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
430 va_end(ap);
431}
432
433/* Kernel */
434static int64_t load_kernel (CPUState *env)
435{
436 int64_t kernel_addr = 0;
437 int index = 0;
438 long initrd_size;
439
440 if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) {
441 fprintf(stderr, "qemu: could not load kernel '%s'\n",
442 env->kernel_filename);
443 exit(1);
444 }
445
446 /* load initrd */
447 initrd_size = 0;
448 if (env->initrd_filename) {
449 initrd_size = load_image(env->initrd_filename,
450 phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
451 if (initrd_size == (target_ulong) -1) {
452 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
453 env->initrd_filename);
454 exit(1);
455 }
456 }
457
458 /* Store command line. */
459 prom_set(index++, env->kernel_filename);
460 if (initrd_size > 0)
461 prom_set(index++, "rd_start=0x%08x rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline);
462 else
463 prom_set(index++, env->kernel_cmdline);
464
465 /* Setup minimum environment variables */
466 prom_set(index++, "memsize");
467 prom_set(index++, "%i", env->ram_size);
468 prom_set(index++, "modetty0");
469 prom_set(index++, "38400n8r");
470 prom_set(index++, NULL);
471
472 return kernel_addr;
473}
474
475static void main_cpu_reset(void *opaque)
476{
477 CPUState *env = opaque;
478 cpu_reset(env);
479
480 /* The bootload does not need to be rewritten as it is located in a
481 read only location. The kernel location and the arguments table
482 location does not change. */
483 if (env->kernel_filename)
484 load_kernel (env);
485}
486
487void mips_malta_init (int ram_size, int vga_ram_size, int boot_device,
488 DisplayState *ds, const char **fd_filename, int snapshot,
489 const char *kernel_filename, const char *kernel_cmdline,
490 const char *initrd_filename)
491{
492 char buf[1024];
493 unsigned long bios_offset;
494 int64_t kernel_addr;
495 PCIBus *pci_bus;
496 CPUState *env;
497 RTCState *rtc_state;
f1770b3e 498 /* fdctrl_t *floppy_controller; */
5856de80
TS
499 MaltaFPGAState *malta_fpga;
500 int ret;
501
502 env = cpu_init();
503 register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
504 qemu_register_reset(main_cpu_reset, env);
505
506 /* allocate RAM */
507 cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
508
509 /* Map the bios at two physical locations, as on the real board */
510 bios_offset = ram_size + vga_ram_size;
511 cpu_register_physical_memory(0x1e000000LL,
512 BIOS_SIZE, bios_offset | IO_MEM_ROM);
513 cpu_register_physical_memory(0x1fc00000LL,
514 BIOS_SIZE, bios_offset | IO_MEM_ROM);
515
516 /* Load a BIOS image except if a kernel image has been specified. In
517 the later case, just write a small bootloader to the flash
518 location. */
519 if (kernel_filename) {
520 env->ram_size = ram_size;
521 env->kernel_filename = kernel_filename;
522 env->kernel_cmdline = kernel_cmdline;
523 env->initrd_filename = initrd_filename;
524 kernel_addr = load_kernel(env);
525 write_bootloader(env, bios_offset, kernel_addr);
526 } else {
527 snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
528 ret = load_image(buf, phys_ram_base + bios_offset);
529 if (ret != BIOS_SIZE) {
530 fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
531 buf);
532 exit(1);
533 }
534 }
535
536 /* Board ID = 0x420 (Malta Board with CoreLV)
537 XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
538 map to the board ID. */
539 stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
540
541 /* Init internal devices */
542 cpu_mips_clock_init(env);
543 cpu_mips_irqctrl_init();
544
545 /* FPGA */
546 malta_fpga = malta_fpga_init(0x1f000000LL);
547
548 /* Interrupt controller */
549 isa_pic = pic_init(pic_irq_request, env);
550
551 /* Northbridge */
552 pci_bus = pci_gt64120_init(isa_pic);
553
554 /* Southbridge */
555 piix4_init(pci_bus, 80);
556 pci_piix3_ide_init(pci_bus, bs_table, 81);
557 usb_uhci_init(pci_bus, 82);
558 piix4_pm_init(pci_bus, 83);
559 pit = pit_init(0x40, 0);
560 DMA_init(0);
561
562 /* Super I/O */
563 kbd_init();
564 rtc_state = rtc_init(0x70, 8);
565 serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
566 parallel_init(0x378, 7, parallel_hds[0]);
567 /* XXX: The floppy controller does not work correctly, something is
f1770b3e
TS
568 probably wrong.
569 floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */
5856de80
TS
570
571 /* Sound card */
572#ifdef HAS_AUDIO
573 audio_init(pci_bus);
574#endif
575
576 /* Network card */
577 network_init(pci_bus);
578}
579
580QEMUMachine mips_malta_machine = {
581 "malta",
582 "MIPS Malta Core LV",
583 mips_malta_init,
584};
This page took 0.080374 seconds and 4 git commands to generate.