]> git.proxmox.com Git - mirror_qemu.git/blame - hw/mips_malta.c
Fix formatting.
[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) {
5066b9f1
TS
454 if (c->enabled)
455 c->init.init_pci (pci_bus, s);
5856de80
TS
456 }
457 }
458 }
459}
460#endif
461
462/* Network support */
463static void network_init (PCIBus *pci_bus)
464{
465 int i;
466 NICInfo *nd;
467
468 for(i = 0; i < nb_nics; i++) {
469 nd = &nd_table[i];
470 if (!nd->model) {
471 nd->model = "pcnet";
472 }
473 if (i == 0 && strcmp(nd->model, "pcnet") == 0) {
474 /* The malta board has a PCNet card using PCI SLOT 11 */
475 pci_nic_init(pci_bus, nd, 88);
476 } else {
477 pci_nic_init(pci_bus, nd, -1);
478 }
479 }
480}
481
482/* ROM and pseudo bootloader
483
484 The following code implements a very very simple bootloader. It first
485 loads the registers a0 to a3 to the values expected by the OS, and
486 then jump at the kernel address.
487
488 The bootloader should pass the locations of the kernel arguments and
489 environment variables tables. Those tables contain the 32-bit address
490 of NULL terminated strings. The environment variables table should be
491 terminated by a NULL address.
492
493 For a simpler implementation, the number of kernel arguments is fixed
494 to two (the name of the kernel and the command line), and the two
495 tables are actually the same one.
496
497 The registers a0 to a3 should contain the following values:
498 a0 - number of kernel arguments
499 a1 - 32-bit address of the kernel arguments table
500 a2 - 32-bit address of the environment variables table
501 a3 - RAM size in bytes
502*/
503
74287114 504static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_entry)
5856de80
TS
505{
506 uint32_t *p;
507
508 /* Small bootloader */
509 p = (uint32_t *) (phys_ram_base + bios_offset);
26ea0918 510 stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */
3ddd0065 511 stl_raw(p++, 0x00000000); /* nop */
5856de80 512
26ea0918
TS
513 /* YAMON service vector */
514 stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */
515 stl_raw(phys_ram_base + bios_offset + 0x504, 0xbfc0083c); /* print_count: */
516 stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */
517 stl_raw(phys_ram_base + bios_offset + 0x52c, 0xbfc00800); /* flush_cache: */
518 stl_raw(phys_ram_base + bios_offset + 0x534, 0xbfc00808); /* print: */
519 stl_raw(phys_ram_base + bios_offset + 0x538, 0xbfc00800); /* reg_cpu_isr: */
520 stl_raw(phys_ram_base + bios_offset + 0x53c, 0xbfc00800); /* unred_cpu_isr: */
521 stl_raw(phys_ram_base + bios_offset + 0x540, 0xbfc00800); /* reg_ic_isr: */
522 stl_raw(phys_ram_base + bios_offset + 0x544, 0xbfc00800); /* unred_ic_isr: */
523 stl_raw(phys_ram_base + bios_offset + 0x548, 0xbfc00800); /* reg_esr: */
524 stl_raw(phys_ram_base + bios_offset + 0x54c, 0xbfc00800); /* unreg_esr: */
525 stl_raw(phys_ram_base + bios_offset + 0x550, 0xbfc00800); /* getchar: */
526 stl_raw(phys_ram_base + bios_offset + 0x554, 0xbfc00800); /* syscon_read: */
527
528
5856de80 529 /* Second part of the bootloader */
26ea0918 530 p = (uint32_t *) (phys_ram_base + bios_offset + 0x580);
d52fff71
TS
531 stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */
532 stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
471ea271 533 stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */
3ddd0065 534 stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
471ea271 535 stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */
3ddd0065
TS
536 stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
537 stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
538 stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */
539 stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */
2802bfe3
TS
540
541 /* Load BAR registers as done by YAMON */
542 stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */
543
544#ifdef TARGET_WORDS_BIGENDIAN
545 stl_raw(p++, 0x3c08c000); /* lui t0, 0xc000 */
546#else
547 stl_raw(p++, 0x340800c0); /* ori t0, r0, 0x00c0 */
548#endif
549 stl_raw(p++, 0xad280048); /* sw t0, 0x0048(t1) */
550#ifdef TARGET_WORDS_BIGENDIAN
551 stl_raw(p++, 0x3c084000); /* lui t0, 0x4000 */
552#else
553 stl_raw(p++, 0x34080040); /* ori t0, r0, 0x0040 */
554#endif
555 stl_raw(p++, 0xad280050); /* sw t0, 0x0050(t1) */
556
557#ifdef TARGET_WORDS_BIGENDIAN
558 stl_raw(p++, 0x3c088000); /* lui t0, 0x8000 */
559#else
560 stl_raw(p++, 0x34080080); /* ori t0, r0, 0x0080 */
561#endif
562 stl_raw(p++, 0xad280058); /* sw t0, 0x0058(t1) */
563#ifdef TARGET_WORDS_BIGENDIAN
564 stl_raw(p++, 0x3c083f00); /* lui t0, 0x3f00 */
565#else
566 stl_raw(p++, 0x3408003f); /* ori t0, r0, 0x003f */
567#endif
568 stl_raw(p++, 0xad280060); /* sw t0, 0x0060(t1) */
569
570#ifdef TARGET_WORDS_BIGENDIAN
571 stl_raw(p++, 0x3c08c100); /* lui t0, 0xc100 */
572#else
573 stl_raw(p++, 0x340800c1); /* ori t0, r0, 0x00c1 */
574#endif
575 stl_raw(p++, 0xad280080); /* sw t0, 0x0080(t1) */
576#ifdef TARGET_WORDS_BIGENDIAN
577 stl_raw(p++, 0x3c085e00); /* lui t0, 0x5e00 */
578#else
579 stl_raw(p++, 0x3408005e); /* ori t0, r0, 0x005e */
580#endif
581 stl_raw(p++, 0xad280088); /* sw t0, 0x0088(t1) */
582
583 /* Jump to kernel code */
74287114
TS
584 stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */
585 stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */
3ddd0065
TS
586 stl_raw(p++, 0x03e00008); /* jr ra */
587 stl_raw(p++, 0x00000000); /* nop */
26ea0918
TS
588
589 /* YAMON subroutines */
590 p = (uint32_t *) (phys_ram_base + bios_offset + 0x800);
591 stl_raw(p++, 0x03e00008); /* jr ra */
592 stl_raw(p++, 0x24020000); /* li v0,0 */
593 /* 808 YAMON print */
594 stl_raw(p++, 0x03e06821); /* move t5,ra */
595 stl_raw(p++, 0x00805821); /* move t3,a0 */
596 stl_raw(p++, 0x00a05021); /* move t2,a1 */
597 stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */
598 stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */
599 stl_raw(p++, 0x10800005); /* beqz a0,834 */
600 stl_raw(p++, 0x00000000); /* nop */
601 stl_raw(p++, 0x0ff0021c); /* jal 870 */
602 stl_raw(p++, 0x00000000); /* nop */
603 stl_raw(p++, 0x08000205); /* j 814 */
604 stl_raw(p++, 0x00000000); /* nop */
605 stl_raw(p++, 0x01a00008); /* jr t5 */
606 stl_raw(p++, 0x01602021); /* move a0,t3 */
607 /* 0x83c YAMON print_count */
608 stl_raw(p++, 0x03e06821); /* move t5,ra */
609 stl_raw(p++, 0x00805821); /* move t3,a0 */
610 stl_raw(p++, 0x00a05021); /* move t2,a1 */
611 stl_raw(p++, 0x00c06021); /* move t4,a2 */
612 stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */
613 stl_raw(p++, 0x0ff0021c); /* jal 870 */
614 stl_raw(p++, 0x00000000); /* nop */
615 stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */
616 stl_raw(p++, 0x258cffff); /* addiu t4,t4,-1 */
617 stl_raw(p++, 0x1580fffa); /* bnez t4,84c */
618 stl_raw(p++, 0x00000000); /* nop */
619 stl_raw(p++, 0x01a00008); /* jr t5 */
620 stl_raw(p++, 0x01602021); /* move a0,t3 */
621 /* 0x870 */
622 stl_raw(p++, 0x3c08b800); /* lui t0,0xb400 */
623 stl_raw(p++, 0x350803f8); /* ori t0,t0,0x3f8 */
624 stl_raw(p++, 0x91090005); /* lbu t1,5(t0) */
625 stl_raw(p++, 0x00000000); /* nop */
626 stl_raw(p++, 0x31290040); /* andi t1,t1,0x40 */
627 stl_raw(p++, 0x1120fffc); /* beqz t1,878 <outch+0x8> */
628 stl_raw(p++, 0x00000000); /* nop */
629 stl_raw(p++, 0x03e00008); /* jr ra */
630 stl_raw(p++, 0xa1040000); /* sb a0,0(t0) */
631
5856de80
TS
632}
633
634static void prom_set(int index, const char *string, ...)
635{
636 va_list ap;
3ddd0065
TS
637 int32_t *p;
638 int32_t table_addr;
5856de80
TS
639 char *s;
640
641 if (index >= ENVP_NB_ENTRIES)
642 return;
643
3ddd0065 644 p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
5856de80
TS
645 p += index;
646
647 if (string == NULL) {
648 stl_raw(p, 0);
649 return;
650 }
651
3ddd0065 652 table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
5856de80
TS
653 s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
654
655 stl_raw(p, table_addr);
656
657 va_start(ap, string);
658 vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
659 va_end(ap);
660}
661
662/* Kernel */
663static int64_t load_kernel (CPUState *env)
664{
74287114 665 int64_t kernel_entry, kernel_low, kernel_high;
5856de80
TS
666 int index = 0;
667 long initrd_size;
74287114 668 ram_addr_t initrd_offset;
5856de80 669
74287114
TS
670 if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND,
671 &kernel_entry, &kernel_low, &kernel_high) < 0) {
5856de80
TS
672 fprintf(stderr, "qemu: could not load kernel '%s'\n",
673 env->kernel_filename);
acdf72bb 674 exit(1);
5856de80
TS
675 }
676
677 /* load initrd */
678 initrd_size = 0;
74287114 679 initrd_offset = 0;
5856de80 680 if (env->initrd_filename) {
74287114
TS
681 initrd_size = get_image_size (env->initrd_filename);
682 if (initrd_size > 0) {
683 initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
684 if (initrd_offset + initrd_size > env->ram_size) {
685 fprintf(stderr,
686 "qemu: memory too small for initial ram disk '%s'\n",
687 env->initrd_filename);
688 exit(1);
689 }
690 initrd_size = load_image(env->initrd_filename,
691 phys_ram_base + initrd_offset);
692 }
5856de80
TS
693 if (initrd_size == (target_ulong) -1) {
694 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
695 env->initrd_filename);
696 exit(1);
697 }
698 }
699
700 /* Store command line. */
701 prom_set(index++, env->kernel_filename);
702 if (initrd_size > 0)
74287114
TS
703 prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
704 PHYS_TO_VIRT(initrd_offset), initrd_size,
705 env->kernel_cmdline);
5856de80
TS
706 else
707 prom_set(index++, env->kernel_cmdline);
708
709 /* Setup minimum environment variables */
710 prom_set(index++, "memsize");
711 prom_set(index++, "%i", env->ram_size);
712 prom_set(index++, "modetty0");
713 prom_set(index++, "38400n8r");
714 prom_set(index++, NULL);
715
74287114 716 return kernel_entry;
5856de80
TS
717}
718
719static void main_cpu_reset(void *opaque)
720{
721 CPUState *env = opaque;
722 cpu_reset(env);
51b2772f 723 cpu_mips_register(env, NULL);
5856de80
TS
724
725 /* The bootload does not need to be rewritten as it is located in a
726 read only location. The kernel location and the arguments table
727 location does not change. */
fb82fea0
TS
728 if (env->kernel_filename) {
729 env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
5856de80 730 load_kernel (env);
fb82fea0 731 }
5856de80
TS
732}
733
70705261 734static
5856de80
TS
735void mips_malta_init (int ram_size, int vga_ram_size, int boot_device,
736 DisplayState *ds, const char **fd_filename, int snapshot,
737 const char *kernel_filename, const char *kernel_cmdline,
94fc95cd 738 const char *initrd_filename, const char *cpu_model)
5856de80
TS
739{
740 char buf[1024];
741 unsigned long bios_offset;
74287114 742 int64_t kernel_entry;
5856de80
TS
743 PCIBus *pci_bus;
744 CPUState *env;
745 RTCState *rtc_state;
f1770b3e 746 /* fdctrl_t *floppy_controller; */
5856de80
TS
747 MaltaFPGAState *malta_fpga;
748 int ret;
33d68b5f 749 mips_def_t *def;
d537cf6c 750 qemu_irq *i8259;
7b717336
TS
751 int piix4_devfn;
752 uint8_t *eeprom_buf;
753 i2c_bus *smbus;
754 int i;
5856de80 755
33d68b5f
TS
756 /* init CPUs */
757 if (cpu_model == NULL) {
60aa19ab 758#ifdef TARGET_MIPS64
c9c1a064 759 cpu_model = "20Kc";
33d68b5f 760#else
1c32f43e 761 cpu_model = "24Kf";
33d68b5f
TS
762#endif
763 }
764 if (mips_find_by_name(cpu_model, &def) != 0)
765 def = NULL;
5856de80 766 env = cpu_init();
33d68b5f 767 cpu_mips_register(env, def);
5856de80
TS
768 register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
769 qemu_register_reset(main_cpu_reset, env);
770
771 /* allocate RAM */
772 cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
773
774 /* Map the bios at two physical locations, as on the real board */
775 bios_offset = ram_size + vga_ram_size;
776 cpu_register_physical_memory(0x1e000000LL,
777 BIOS_SIZE, bios_offset | IO_MEM_ROM);
778 cpu_register_physical_memory(0x1fc00000LL,
779 BIOS_SIZE, bios_offset | IO_MEM_ROM);
780
781 /* Load a BIOS image except if a kernel image has been specified. In
782 the later case, just write a small bootloader to the flash
783 location. */
784 if (kernel_filename) {
785 env->ram_size = ram_size;
786 env->kernel_filename = kernel_filename;
787 env->kernel_cmdline = kernel_cmdline;
788 env->initrd_filename = initrd_filename;
74287114 789 kernel_entry = load_kernel(env);
fb82fea0 790 env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
74287114 791 write_bootloader(env, bios_offset, kernel_entry);
5856de80
TS
792 } else {
793 snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
794 ret = load_image(buf, phys_ram_base + bios_offset);
331ad6f4 795 if (ret < 0 || ret > BIOS_SIZE) {
5856de80
TS
796 fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
797 buf);
798 exit(1);
799 }
800 }
801
802 /* Board ID = 0x420 (Malta Board with CoreLV)
803 XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
804 map to the board ID. */
805 stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
806
807 /* Init internal devices */
d537cf6c 808 cpu_mips_irq_init_cpu(env);
5856de80
TS
809 cpu_mips_clock_init(env);
810 cpu_mips_irqctrl_init();
811
812 /* FPGA */
a4bc3afc 813 malta_fpga = malta_fpga_init(0x1f000000LL, env);
5856de80
TS
814
815 /* Interrupt controller */
d537cf6c
PB
816 /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
817 i8259 = i8259_init(env->irq[2]);
5856de80
TS
818
819 /* Northbridge */
d537cf6c 820 pci_bus = pci_gt64120_init(i8259);
5856de80
TS
821
822 /* Southbridge */
7b717336 823 piix4_devfn = piix4_init(pci_bus, 80);
afcc3cdf
TS
824 pci_piix4_ide_init(pci_bus, bs_table, piix4_devfn + 1, i8259);
825 usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
7b717336
TS
826 smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100);
827 eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
828 for (i = 0; i < 8; i++) {
829 /* TODO: Populate SPD eeprom data. */
830 smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256));
831 }
d537cf6c 832 pit = pit_init(0x40, i8259[0]);
5856de80
TS
833 DMA_init(0);
834
835 /* Super I/O */
d537cf6c
PB
836 i8042_init(i8259[1], i8259[12], 0x60);
837 rtc_state = rtc_init(0x70, i8259[8]);
7bcc17dc 838 if (serial_hds[0])
d537cf6c 839 serial_init(0x3f8, i8259[4], serial_hds[0]);
7bcc17dc 840 if (serial_hds[1])
d537cf6c 841 serial_init(0x2f8, i8259[3], serial_hds[1]);
7bcc17dc 842 if (parallel_hds[0])
d537cf6c 843 parallel_init(0x378, i8259[7], parallel_hds[0]);
5856de80 844 /* XXX: The floppy controller does not work correctly, something is
f1770b3e 845 probably wrong.
d537cf6c 846 floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); */
5856de80
TS
847
848 /* Sound card */
849#ifdef HAS_AUDIO
850 audio_init(pci_bus);
851#endif
852
853 /* Network card */
854 network_init(pci_bus);
11f29511
TS
855
856 /* Optional PCI video card */
857 pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size,
858 ram_size, vga_ram_size);
5856de80
TS
859}
860
861QEMUMachine mips_malta_machine = {
862 "malta",
863 "MIPS Malta Core LV",
864 mips_malta_init,
865};