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