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