]> git.proxmox.com Git - mirror_qemu.git/blame - hw/mips_malta.c
added cpu_model parameter to cpu_init()
[mirror_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
44cbbf18
TS
27#ifdef TARGET_WORDS_BIGENDIAN
28#define BIOS_FILENAME "mips_bios.bin"
29#else
30#define BIOS_FILENAME "mipsel_bios.bin"
31#endif
32
60aa19ab 33#ifdef TARGET_MIPS64
74287114 34#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
5856de80 35#else
74287114 36#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
5856de80
TS
37#endif
38
74287114
TS
39#define ENVP_ADDR (int32_t)0x80002000
40#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
5856de80
TS
41
42#define ENVP_NB_ENTRIES 16
43#define ENVP_ENTRY_SIZE 256
44
5856de80
TS
45extern FILE *logfile;
46
47typedef struct {
48 uint32_t leds;
49 uint32_t brk;
50 uint32_t gpout;
130751ee 51 uint32_t i2cin;
5856de80
TS
52 uint32_t i2coe;
53 uint32_t i2cout;
54 uint32_t i2csel;
55 CharDriverState *display;
56 char display_text[9];
a4bc3afc 57 SerialState *uart;
5856de80
TS
58} MaltaFPGAState;
59
60static PITState *pit;
61
7df526e3
TS
62static struct _loaderparams {
63 int ram_size;
64 const char *kernel_filename;
65 const char *kernel_cmdline;
66 const char *initrd_filename;
67} loaderparams;
68
5856de80
TS
69/* Malta FPGA */
70static void malta_fpga_update_display(void *opaque)
71{
72 char leds_text[9];
73 int i;
74 MaltaFPGAState *s = opaque;
75
07cf0ba0
TS
76 for (i = 7 ; i >= 0 ; i--) {
77 if (s->leds & (1 << i))
78 leds_text[i] = '#';
79 else
80 leds_text[i] = ' ';
87ee1669 81 }
07cf0ba0
TS
82 leds_text[8] = '\0';
83
84 qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
85 qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
5856de80
TS
86}
87
130751ee
TS
88/*
89 * EEPROM 24C01 / 24C02 emulation.
90 *
91 * Emulation for serial EEPROMs:
92 * 24C01 - 1024 bit (128 x 8)
93 * 24C02 - 2048 bit (256 x 8)
94 *
95 * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
96 */
97
98//~ #define DEBUG
99
100#if defined(DEBUG)
101# define logout(fmt, args...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ##args)
102#else
103# define logout(fmt, args...) ((void)0)
104#endif
105
106struct _eeprom24c0x_t {
107 uint8_t tick;
108 uint8_t address;
109 uint8_t command;
110 uint8_t ack;
111 uint8_t scl;
112 uint8_t sda;
113 uint8_t data;
114 //~ uint16_t size;
115 uint8_t contents[256];
116};
117
118typedef struct _eeprom24c0x_t eeprom24c0x_t;
119
120static eeprom24c0x_t eeprom = {
121 contents: {
122 /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00,
123 /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
124 /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00,
125 /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40,
126 /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
127 /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
128 /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
129 /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
130 /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
131 /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
132 /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
133 /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
134 /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
135 /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
136 /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
137 /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
138 },
139};
140
141static uint8_t eeprom24c0x_read()
142{
143 logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
144 eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
145 return eeprom.sda;
146}
147
148static void eeprom24c0x_write(int scl, int sda)
149{
150 if (eeprom.scl && scl && (eeprom.sda != sda)) {
151 logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
152 eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
153 if (!sda) {
154 eeprom.tick = 1;
155 eeprom.command = 0;
156 }
157 } else if (eeprom.tick == 0 && !eeprom.ack) {
158 /* Waiting for start. */
159 logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
160 eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
161 } else if (!eeprom.scl && scl) {
162 logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
163 eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
164 if (eeprom.ack) {
165 logout("\ti2c ack bit = 0\n");
166 sda = 0;
167 eeprom.ack = 0;
168 } else if (eeprom.sda == sda) {
169 uint8_t bit = (sda != 0);
170 logout("\ti2c bit = %d\n", bit);
171 if (eeprom.tick < 9) {
172 eeprom.command <<= 1;
173 eeprom.command += bit;
174 eeprom.tick++;
175 if (eeprom.tick == 9) {
176 logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
177 eeprom.ack = 1;
178 }
179 } else if (eeprom.tick < 17) {
180 if (eeprom.command & 1) {
181 sda = ((eeprom.data & 0x80) != 0);
182 }
183 eeprom.address <<= 1;
184 eeprom.address += bit;
185 eeprom.tick++;
186 eeprom.data <<= 1;
187 if (eeprom.tick == 17) {
188 eeprom.data = eeprom.contents[eeprom.address];
189 logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
190 eeprom.ack = 1;
191 eeprom.tick = 0;
192 }
193 } else if (eeprom.tick >= 17) {
194 sda = 0;
195 }
196 } else {
197 logout("\tsda changed with raising scl\n");
198 }
199 } else {
200 logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
201 }
202 eeprom.scl = scl;
203 eeprom.sda = sda;
204}
205
5856de80
TS
206static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
207{
208 MaltaFPGAState *s = opaque;
209 uint32_t val = 0;
210 uint32_t saddr;
211
212 saddr = (addr & 0xfffff);
213
214 switch (saddr) {
215
216 /* SWITCH Register */
217 case 0x00200:
218 val = 0x00000000; /* All switches closed */
219 break;
220
221 /* STATUS Register */
222 case 0x00208:
223#ifdef TARGET_WORDS_BIGENDIAN
224 val = 0x00000012;
225#else
226 val = 0x00000010;
227#endif
228 break;
229
230 /* JMPRS Register */
231 case 0x00210:
232 val = 0x00;
233 break;
234
235 /* LEDBAR Register */
236 case 0x00408:
237 val = s->leds;
238 break;
239
240 /* BRKRES Register */
241 case 0x00508:
242 val = s->brk;
243 break;
244
b6dc7ebb 245 /* UART Registers are handled directly by the serial device */
a4bc3afc 246
5856de80
TS
247 /* GPOUT Register */
248 case 0x00a00:
249 val = s->gpout;
250 break;
251
252 /* XXX: implement a real I2C controller */
253
254 /* GPINP Register */
255 case 0x00a08:
256 /* IN = OUT until a real I2C control is implemented */
257 if (s->i2csel)
258 val = s->i2cout;
259 else
260 val = 0x00;
261 break;
262
263 /* I2CINP Register */
264 case 0x00b00:
130751ee 265 val = ((s->i2cin & ~1) | eeprom24c0x_read());
5856de80
TS
266 break;
267
268 /* I2COE Register */
269 case 0x00b08:
270 val = s->i2coe;
271 break;
272
273 /* I2COUT Register */
274 case 0x00b10:
275 val = s->i2cout;
276 break;
277
278 /* I2CSEL Register */
279 case 0x00b18:
130751ee 280 val = s->i2csel;
5856de80
TS
281 break;
282
283 default:
284#if 0
3594c774 285 printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
44cbbf18 286 addr);
5856de80
TS
287#endif
288 break;
289 }
290 return val;
291}
292
293static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
294 uint32_t val)
295{
296 MaltaFPGAState *s = opaque;
297 uint32_t saddr;
298
299 saddr = (addr & 0xfffff);
300
301 switch (saddr) {
302
303 /* SWITCH Register */
304 case 0x00200:
305 break;
306
307 /* JMPRS Register */
308 case 0x00210:
309 break;
310
311 /* LEDBAR Register */
312 /* XXX: implement a 8-LED array */
313 case 0x00408:
314 s->leds = val & 0xff;
315 break;
316
317 /* ASCIIWORD Register */
318 case 0x00410:
319 snprintf(s->display_text, 9, "%08X", val);
320 malta_fpga_update_display(s);
321 break;
322
323 /* ASCIIPOS0 to ASCIIPOS7 Registers */
324 case 0x00418:
325 case 0x00420:
326 case 0x00428:
327 case 0x00430:
328 case 0x00438:
329 case 0x00440:
330 case 0x00448:
331 case 0x00450:
332 s->display_text[(saddr - 0x00418) >> 3] = (char) val;
333 malta_fpga_update_display(s);
334 break;
335
336 /* SOFTRES Register */
337 case 0x00500:
338 if (val == 0x42)
339 qemu_system_reset_request ();
340 break;
341
342 /* BRKRES Register */
343 case 0x00508:
344 s->brk = val & 0xff;
345 break;
346
b6dc7ebb 347 /* UART Registers are handled directly by the serial device */
a4bc3afc 348
5856de80
TS
349 /* GPOUT Register */
350 case 0x00a00:
351 s->gpout = val & 0xff;
352 break;
353
354 /* I2COE Register */
355 case 0x00b08:
356 s->i2coe = val & 0x03;
357 break;
358
359 /* I2COUT Register */
360 case 0x00b10:
130751ee
TS
361 eeprom24c0x_write(val & 0x02, val & 0x01);
362 s->i2cout = val;
5856de80
TS
363 break;
364
365 /* I2CSEL Register */
366 case 0x00b18:
130751ee 367 s->i2csel = val & 0x01;
5856de80
TS
368 break;
369
370 default:
371#if 0
3594c774 372 printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
44cbbf18 373 addr);
5856de80
TS
374#endif
375 break;
376 }
377}
378
379static CPUReadMemoryFunc *malta_fpga_read[] = {
380 malta_fpga_readl,
381 malta_fpga_readl,
382 malta_fpga_readl
383};
384
385static CPUWriteMemoryFunc *malta_fpga_write[] = {
386 malta_fpga_writel,
387 malta_fpga_writel,
388 malta_fpga_writel
389};
390
391void malta_fpga_reset(void *opaque)
392{
393 MaltaFPGAState *s = opaque;
394
395 s->leds = 0x00;
396 s->brk = 0x0a;
397 s->gpout = 0x00;
130751ee 398 s->i2cin = 0x3;
5856de80
TS
399 s->i2coe = 0x0;
400 s->i2cout = 0x3;
401 s->i2csel = 0x1;
402
403 s->display_text[8] = '\0';
404 snprintf(s->display_text, 9, " ");
405 malta_fpga_update_display(s);
406}
407
a4bc3afc 408MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env)
5856de80
TS
409{
410 MaltaFPGAState *s;
a4bc3afc 411 CharDriverState *uart_chr;
5856de80
TS
412 int malta;
413
414 s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
415
416 malta = cpu_register_io_memory(0, malta_fpga_read,
417 malta_fpga_write, s);
a4bc3afc 418
b6dc7ebb
TS
419 cpu_register_physical_memory(base, 0x900, malta);
420 cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta);
5856de80 421
07cf0ba0
TS
422 s->display = qemu_chr_open("vc");
423 qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n");
424 qemu_chr_printf(s->display, "+--------+\r\n");
425 qemu_chr_printf(s->display, "+ +\r\n");
426 qemu_chr_printf(s->display, "+--------+\r\n");
427 qemu_chr_printf(s->display, "\n");
428 qemu_chr_printf(s->display, "Malta ASCII\r\n");
429 qemu_chr_printf(s->display, "+--------+\r\n");
430 qemu_chr_printf(s->display, "+ +\r\n");
431 qemu_chr_printf(s->display, "+--------+\r\n");
432
433 uart_chr = qemu_chr_open("vc");
434 qemu_chr_printf(uart_chr, "CBUS UART\r\n");
435 s->uart = serial_mm_init(base + 0x900, 3, env->irq[2], uart_chr, 1);
a4bc3afc 436
5856de80
TS
437 malta_fpga_reset(s);
438 qemu_register_reset(malta_fpga_reset, s);
439
440 return s;
441}
442
443/* Audio support */
444#ifdef HAS_AUDIO
445static void audio_init (PCIBus *pci_bus)
446{
447 struct soundhw *c;
448 int audio_enabled = 0;
449
450 for (c = soundhw; !audio_enabled && c->name; ++c) {
451 audio_enabled = c->enabled;
452 }
453
454 if (audio_enabled) {
455 AudioState *s;
456
457 s = AUD_init ();
458 if (s) {
459 for (c = soundhw; c->name; ++c) {
5066b9f1
TS
460 if (c->enabled)
461 c->init.init_pci (pci_bus, s);
5856de80
TS
462 }
463 }
464 }
465}
466#endif
467
468/* Network support */
469static void network_init (PCIBus *pci_bus)
470{
471 int i;
472 NICInfo *nd;
473
474 for(i = 0; i < nb_nics; i++) {
475 nd = &nd_table[i];
476 if (!nd->model) {
477 nd->model = "pcnet";
478 }
479 if (i == 0 && strcmp(nd->model, "pcnet") == 0) {
480 /* The malta board has a PCNet card using PCI SLOT 11 */
481 pci_nic_init(pci_bus, nd, 88);
482 } else {
483 pci_nic_init(pci_bus, nd, -1);
484 }
485 }
486}
487
488/* ROM and pseudo bootloader
489
490 The following code implements a very very simple bootloader. It first
491 loads the registers a0 to a3 to the values expected by the OS, and
492 then jump at the kernel address.
493
494 The bootloader should pass the locations of the kernel arguments and
495 environment variables tables. Those tables contain the 32-bit address
496 of NULL terminated strings. The environment variables table should be
497 terminated by a NULL address.
498
499 For a simpler implementation, the number of kernel arguments is fixed
500 to two (the name of the kernel and the command line), and the two
501 tables are actually the same one.
502
503 The registers a0 to a3 should contain the following values:
504 a0 - number of kernel arguments
505 a1 - 32-bit address of the kernel arguments table
506 a2 - 32-bit address of the environment variables table
507 a3 - RAM size in bytes
508*/
509
74287114 510static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_entry)
5856de80
TS
511{
512 uint32_t *p;
513
514 /* Small bootloader */
515 p = (uint32_t *) (phys_ram_base + bios_offset);
26ea0918 516 stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */
3ddd0065 517 stl_raw(p++, 0x00000000); /* nop */
5856de80 518
26ea0918 519 /* YAMON service vector */
3b46e624 520 stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */
26ea0918 521 stl_raw(phys_ram_base + bios_offset + 0x504, 0xbfc0083c); /* print_count: */
3b46e624 522 stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */
26ea0918
TS
523 stl_raw(phys_ram_base + bios_offset + 0x52c, 0xbfc00800); /* flush_cache: */
524 stl_raw(phys_ram_base + bios_offset + 0x534, 0xbfc00808); /* print: */
525 stl_raw(phys_ram_base + bios_offset + 0x538, 0xbfc00800); /* reg_cpu_isr: */
526 stl_raw(phys_ram_base + bios_offset + 0x53c, 0xbfc00800); /* unred_cpu_isr: */
527 stl_raw(phys_ram_base + bios_offset + 0x540, 0xbfc00800); /* reg_ic_isr: */
528 stl_raw(phys_ram_base + bios_offset + 0x544, 0xbfc00800); /* unred_ic_isr: */
529 stl_raw(phys_ram_base + bios_offset + 0x548, 0xbfc00800); /* reg_esr: */
530 stl_raw(phys_ram_base + bios_offset + 0x54c, 0xbfc00800); /* unreg_esr: */
531 stl_raw(phys_ram_base + bios_offset + 0x550, 0xbfc00800); /* getchar: */
532 stl_raw(phys_ram_base + bios_offset + 0x554, 0xbfc00800); /* syscon_read: */
533
534
5856de80 535 /* Second part of the bootloader */
26ea0918 536 p = (uint32_t *) (phys_ram_base + bios_offset + 0x580);
d52fff71
TS
537 stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */
538 stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
471ea271 539 stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */
3ddd0065 540 stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
471ea271 541 stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */
3ddd0065
TS
542 stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
543 stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
7df526e3
TS
544 stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(ram_size) */
545 stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */
2802bfe3
TS
546
547 /* Load BAR registers as done by YAMON */
a0a8793e
TS
548 stl_raw(p++, 0x3c09b400); /* lui t1, 0xb400 */
549
550#ifdef TARGET_WORDS_BIGENDIAN
551 stl_raw(p++, 0x3c08df00); /* lui t0, 0xdf00 */
552#else
553 stl_raw(p++, 0x340800df); /* ori t0, r0, 0x00df */
554#endif
555 stl_raw(p++, 0xad280068); /* sw t0, 0x0068(t1) */
556
2802bfe3
TS
557 stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */
558
559#ifdef TARGET_WORDS_BIGENDIAN
560 stl_raw(p++, 0x3c08c000); /* lui t0, 0xc000 */
561#else
562 stl_raw(p++, 0x340800c0); /* ori t0, r0, 0x00c0 */
563#endif
564 stl_raw(p++, 0xad280048); /* sw t0, 0x0048(t1) */
565#ifdef TARGET_WORDS_BIGENDIAN
566 stl_raw(p++, 0x3c084000); /* lui t0, 0x4000 */
567#else
568 stl_raw(p++, 0x34080040); /* ori t0, r0, 0x0040 */
569#endif
570 stl_raw(p++, 0xad280050); /* sw t0, 0x0050(t1) */
571
572#ifdef TARGET_WORDS_BIGENDIAN
573 stl_raw(p++, 0x3c088000); /* lui t0, 0x8000 */
574#else
575 stl_raw(p++, 0x34080080); /* ori t0, r0, 0x0080 */
576#endif
577 stl_raw(p++, 0xad280058); /* sw t0, 0x0058(t1) */
578#ifdef TARGET_WORDS_BIGENDIAN
579 stl_raw(p++, 0x3c083f00); /* lui t0, 0x3f00 */
580#else
581 stl_raw(p++, 0x3408003f); /* ori t0, r0, 0x003f */
582#endif
583 stl_raw(p++, 0xad280060); /* sw t0, 0x0060(t1) */
584
585#ifdef TARGET_WORDS_BIGENDIAN
586 stl_raw(p++, 0x3c08c100); /* lui t0, 0xc100 */
587#else
588 stl_raw(p++, 0x340800c1); /* ori t0, r0, 0x00c1 */
589#endif
590 stl_raw(p++, 0xad280080); /* sw t0, 0x0080(t1) */
591#ifdef TARGET_WORDS_BIGENDIAN
592 stl_raw(p++, 0x3c085e00); /* lui t0, 0x5e00 */
593#else
594 stl_raw(p++, 0x3408005e); /* ori t0, r0, 0x005e */
595#endif
596 stl_raw(p++, 0xad280088); /* sw t0, 0x0088(t1) */
597
598 /* Jump to kernel code */
74287114
TS
599 stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */
600 stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */
3ddd0065
TS
601 stl_raw(p++, 0x03e00008); /* jr ra */
602 stl_raw(p++, 0x00000000); /* nop */
26ea0918
TS
603
604 /* YAMON subroutines */
605 p = (uint32_t *) (phys_ram_base + bios_offset + 0x800);
606 stl_raw(p++, 0x03e00008); /* jr ra */
607 stl_raw(p++, 0x24020000); /* li v0,0 */
608 /* 808 YAMON print */
609 stl_raw(p++, 0x03e06821); /* move t5,ra */
610 stl_raw(p++, 0x00805821); /* move t3,a0 */
611 stl_raw(p++, 0x00a05021); /* move t2,a1 */
612 stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */
613 stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */
614 stl_raw(p++, 0x10800005); /* beqz a0,834 */
615 stl_raw(p++, 0x00000000); /* nop */
616 stl_raw(p++, 0x0ff0021c); /* jal 870 */
617 stl_raw(p++, 0x00000000); /* nop */
618 stl_raw(p++, 0x08000205); /* j 814 */
619 stl_raw(p++, 0x00000000); /* nop */
620 stl_raw(p++, 0x01a00008); /* jr t5 */
621 stl_raw(p++, 0x01602021); /* move a0,t3 */
622 /* 0x83c YAMON print_count */
623 stl_raw(p++, 0x03e06821); /* move t5,ra */
624 stl_raw(p++, 0x00805821); /* move t3,a0 */
625 stl_raw(p++, 0x00a05021); /* move t2,a1 */
626 stl_raw(p++, 0x00c06021); /* move t4,a2 */
627 stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */
628 stl_raw(p++, 0x0ff0021c); /* jal 870 */
629 stl_raw(p++, 0x00000000); /* nop */
630 stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */
631 stl_raw(p++, 0x258cffff); /* addiu t4,t4,-1 */
632 stl_raw(p++, 0x1580fffa); /* bnez t4,84c */
633 stl_raw(p++, 0x00000000); /* nop */
634 stl_raw(p++, 0x01a00008); /* jr t5 */
635 stl_raw(p++, 0x01602021); /* move a0,t3 */
636 /* 0x870 */
637 stl_raw(p++, 0x3c08b800); /* lui t0,0xb400 */
638 stl_raw(p++, 0x350803f8); /* ori t0,t0,0x3f8 */
639 stl_raw(p++, 0x91090005); /* lbu t1,5(t0) */
640 stl_raw(p++, 0x00000000); /* nop */
641 stl_raw(p++, 0x31290040); /* andi t1,t1,0x40 */
642 stl_raw(p++, 0x1120fffc); /* beqz t1,878 <outch+0x8> */
643 stl_raw(p++, 0x00000000); /* nop */
644 stl_raw(p++, 0x03e00008); /* jr ra */
645 stl_raw(p++, 0xa1040000); /* sb a0,0(t0) */
646
5856de80
TS
647}
648
649static void prom_set(int index, const char *string, ...)
650{
651 va_list ap;
3ddd0065
TS
652 int32_t *p;
653 int32_t table_addr;
5856de80
TS
654 char *s;
655
656 if (index >= ENVP_NB_ENTRIES)
657 return;
658
3ddd0065 659 p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
5856de80
TS
660 p += index;
661
662 if (string == NULL) {
663 stl_raw(p, 0);
664 return;
665 }
666
3ddd0065 667 table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
5856de80
TS
668 s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
669
670 stl_raw(p, table_addr);
671
672 va_start(ap, string);
673 vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
674 va_end(ap);
675}
676
677/* Kernel */
678static int64_t load_kernel (CPUState *env)
679{
74287114 680 int64_t kernel_entry, kernel_low, kernel_high;
5856de80
TS
681 int index = 0;
682 long initrd_size;
74287114 683 ram_addr_t initrd_offset;
5856de80 684
7df526e3 685 if (load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
74287114 686 &kernel_entry, &kernel_low, &kernel_high) < 0) {
5856de80 687 fprintf(stderr, "qemu: could not load kernel '%s'\n",
7df526e3 688 loaderparams.kernel_filename);
acdf72bb 689 exit(1);
5856de80
TS
690 }
691
692 /* load initrd */
693 initrd_size = 0;
74287114 694 initrd_offset = 0;
7df526e3
TS
695 if (loaderparams.initrd_filename) {
696 initrd_size = get_image_size (loaderparams.initrd_filename);
74287114
TS
697 if (initrd_size > 0) {
698 initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
7df526e3 699 if (initrd_offset + initrd_size > ram_size) {
74287114
TS
700 fprintf(stderr,
701 "qemu: memory too small for initial ram disk '%s'\n",
7df526e3 702 loaderparams.initrd_filename);
74287114
TS
703 exit(1);
704 }
7df526e3 705 initrd_size = load_image(loaderparams.initrd_filename,
74287114
TS
706 phys_ram_base + initrd_offset);
707 }
5856de80
TS
708 if (initrd_size == (target_ulong) -1) {
709 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
7df526e3 710 loaderparams.initrd_filename);
5856de80
TS
711 exit(1);
712 }
713 }
714
715 /* Store command line. */
7df526e3 716 prom_set(index++, loaderparams.kernel_filename);
5856de80 717 if (initrd_size > 0)
74287114
TS
718 prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
719 PHYS_TO_VIRT(initrd_offset), initrd_size,
7df526e3 720 loaderparams.kernel_cmdline);
5856de80 721 else
7df526e3 722 prom_set(index++, loaderparams.kernel_cmdline);
5856de80
TS
723
724 /* Setup minimum environment variables */
725 prom_set(index++, "memsize");
7df526e3 726 prom_set(index++, "%i", loaderparams.ram_size);
5856de80
TS
727 prom_set(index++, "modetty0");
728 prom_set(index++, "38400n8r");
729 prom_set(index++, NULL);
730
74287114 731 return kernel_entry;
5856de80
TS
732}
733
734static void main_cpu_reset(void *opaque)
735{
736 CPUState *env = opaque;
737 cpu_reset(env);
738
739 /* The bootload does not need to be rewritten as it is located in a
740 read only location. The kernel location and the arguments table
741 location does not change. */
7df526e3 742 if (loaderparams.kernel_filename) {
fb82fea0 743 env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
5856de80 744 load_kernel (env);
fb82fea0 745 }
5856de80
TS
746}
747
70705261 748static
6ac0e82d 749void mips_malta_init (int ram_size, int vga_ram_size, const char *boot_device,
5856de80
TS
750 DisplayState *ds, const char **fd_filename, int snapshot,
751 const char *kernel_filename, const char *kernel_cmdline,
94fc95cd 752 const char *initrd_filename, const char *cpu_model)
5856de80
TS
753{
754 char buf[1024];
755 unsigned long bios_offset;
74287114 756 int64_t kernel_entry;
5856de80
TS
757 PCIBus *pci_bus;
758 CPUState *env;
759 RTCState *rtc_state;
f1770b3e 760 /* fdctrl_t *floppy_controller; */
5856de80
TS
761 MaltaFPGAState *malta_fpga;
762 int ret;
d537cf6c 763 qemu_irq *i8259;
7b717336
TS
764 int piix4_devfn;
765 uint8_t *eeprom_buf;
766 i2c_bus *smbus;
767 int i;
5856de80 768
33d68b5f
TS
769 /* init CPUs */
770 if (cpu_model == NULL) {
60aa19ab 771#ifdef TARGET_MIPS64
c9c1a064 772 cpu_model = "20Kc";
33d68b5f 773#else
1c32f43e 774 cpu_model = "24Kf";
33d68b5f
TS
775#endif
776 }
aaed909a
FB
777 env = cpu_init(cpu_model);
778 if (!env) {
779 fprintf(stderr, "Unable to find CPU definition\n");
780 exit(1);
781 }
5856de80
TS
782 register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
783 qemu_register_reset(main_cpu_reset, env);
784
785 /* allocate RAM */
786 cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
787
788 /* Map the bios at two physical locations, as on the real board */
789 bios_offset = ram_size + vga_ram_size;
790 cpu_register_physical_memory(0x1e000000LL,
791 BIOS_SIZE, bios_offset | IO_MEM_ROM);
792 cpu_register_physical_memory(0x1fc00000LL,
793 BIOS_SIZE, bios_offset | IO_MEM_ROM);
794
070ce5ed
TS
795 /* FPGA */
796 malta_fpga = malta_fpga_init(0x1f000000LL, env);
797
798 /* Load a BIOS image unless a kernel image has been specified. */
799 if (!kernel_filename) {
1192dad8
JM
800 if (bios_name == NULL)
801 bios_name = BIOS_FILENAME;
802 snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
070ce5ed
TS
803 ret = load_image(buf, phys_ram_base + bios_offset);
804 if (ret < 0 || ret > BIOS_SIZE) {
805 fprintf(stderr,
806 "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
807 buf);
808 exit(1);
809 }
3187ef03
TS
810 /* In little endian mode the 32bit words in the bios are swapped,
811 a neat trick which allows bi-endian firmware. */
812#ifndef TARGET_WORDS_BIGENDIAN
813 {
814 uint32_t *addr;
815 for (addr = (uint32_t *)(phys_ram_base + bios_offset);
816 addr < (uint32_t *)(phys_ram_base + bios_offset + ret);
817 addr++) {
818 *addr = bswap32(*addr);
819 }
820 }
821#endif
070ce5ed
TS
822 }
823
824 /* If a kernel image has been specified, write a small bootloader
825 to the flash location. */
5856de80 826 if (kernel_filename) {
7df526e3
TS
827 loaderparams.ram_size = ram_size;
828 loaderparams.kernel_filename = kernel_filename;
829 loaderparams.kernel_cmdline = kernel_cmdline;
830 loaderparams.initrd_filename = initrd_filename;
74287114 831 kernel_entry = load_kernel(env);
fb82fea0 832 env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
74287114 833 write_bootloader(env, bios_offset, kernel_entry);
5856de80
TS
834 }
835
836 /* Board ID = 0x420 (Malta Board with CoreLV)
837 XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
838 map to the board ID. */
839 stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
840
841 /* Init internal devices */
d537cf6c 842 cpu_mips_irq_init_cpu(env);
5856de80
TS
843 cpu_mips_clock_init(env);
844 cpu_mips_irqctrl_init();
845
5856de80 846 /* Interrupt controller */
d537cf6c
PB
847 /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
848 i8259 = i8259_init(env->irq[2]);
5856de80
TS
849
850 /* Northbridge */
d537cf6c 851 pci_bus = pci_gt64120_init(i8259);
5856de80
TS
852
853 /* Southbridge */
7b717336 854 piix4_devfn = piix4_init(pci_bus, 80);
afcc3cdf
TS
855 pci_piix4_ide_init(pci_bus, bs_table, piix4_devfn + 1, i8259);
856 usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
7b717336
TS
857 smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100);
858 eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
859 for (i = 0; i < 8; i++) {
860 /* TODO: Populate SPD eeprom data. */
861 smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256));
862 }
d537cf6c 863 pit = pit_init(0x40, i8259[0]);
5856de80
TS
864 DMA_init(0);
865
866 /* Super I/O */
d537cf6c
PB
867 i8042_init(i8259[1], i8259[12], 0x60);
868 rtc_state = rtc_init(0x70, i8259[8]);
7bcc17dc 869 if (serial_hds[0])
d537cf6c 870 serial_init(0x3f8, i8259[4], serial_hds[0]);
7bcc17dc 871 if (serial_hds[1])
d537cf6c 872 serial_init(0x2f8, i8259[3], serial_hds[1]);
7bcc17dc 873 if (parallel_hds[0])
d537cf6c 874 parallel_init(0x378, i8259[7], parallel_hds[0]);
5856de80 875 /* XXX: The floppy controller does not work correctly, something is
f1770b3e 876 probably wrong.
d537cf6c 877 floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); */
5856de80
TS
878
879 /* Sound card */
880#ifdef HAS_AUDIO
881 audio_init(pci_bus);
882#endif
883
884 /* Network card */
885 network_init(pci_bus);
11f29511
TS
886
887 /* Optional PCI video card */
888 pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size,
889 ram_size, vga_ram_size);
5856de80
TS
890}
891
892QEMUMachine mips_malta_machine = {
893 "malta",
894 "MIPS Malta Core LV",
895 mips_malta_init,
896};