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