Statistics
| Branch: | Revision:

root / hw / mips_malta.c @ 0b8f9be6

History | View | Annotate | Download (31.9 kB)

1 5856de80 ths
/*
2 5856de80 ths
 * QEMU Malta board support
3 5856de80 ths
 *
4 5856de80 ths
 * Copyright (c) 2006 Aurelien Jarno
5 5856de80 ths
 *
6 5856de80 ths
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 5856de80 ths
 * of this software and associated documentation files (the "Software"), to deal
8 5856de80 ths
 * in the Software without restriction, including without limitation the rights
9 5856de80 ths
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 5856de80 ths
 * copies of the Software, and to permit persons to whom the Software is
11 5856de80 ths
 * furnished to do so, subject to the following conditions:
12 5856de80 ths
 *
13 5856de80 ths
 * The above copyright notice and this permission notice shall be included in
14 5856de80 ths
 * all copies or substantial portions of the Software.
15 5856de80 ths
 *
16 5856de80 ths
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 5856de80 ths
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 5856de80 ths
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 5856de80 ths
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 5856de80 ths
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 5856de80 ths
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 5856de80 ths
 * THE SOFTWARE.
23 5856de80 ths
 */
24 5856de80 ths
25 87ecb68b pbrook
#include "hw.h"
26 87ecb68b pbrook
#include "pc.h"
27 ded7ba9c ths
#include "fdc.h"
28 87ecb68b pbrook
#include "net.h"
29 87ecb68b pbrook
#include "boards.h"
30 87ecb68b pbrook
#include "smbus.h"
31 c8b153d7 ths
#include "block.h"
32 c8b153d7 ths
#include "flash.h"
33 87ecb68b pbrook
#include "mips.h"
34 b970ea8f Blue Swirl
#include "mips_cpudevs.h"
35 87ecb68b pbrook
#include "pci.h"
36 18e08a55 Michael S. Tsirkin
#include "usb-uhci.h"
37 18e08a55 Michael S. Tsirkin
#include "vmware_vga.h"
38 87ecb68b pbrook
#include "qemu-char.h"
39 87ecb68b pbrook
#include "sysemu.h"
40 87ecb68b pbrook
#include "audio/audio.h"
41 87ecb68b pbrook
#include "boards.h"
42 3b3fb322 blueswir1
#include "qemu-log.h"
43 bba831e8 Paul Brook
#include "mips-bios.h"
44 977e1244 Gerd Hoffmann
#include "ide.h"
45 ca20cf32 Blue Swirl
#include "loader.h"
46 ca20cf32 Blue Swirl
#include "elf.h"
47 1d914fa0 Isaku Yamahata
#include "mc146818rtc.h"
48 5856de80 ths
49 c8b153d7 ths
//#define DEBUG_BOARD_INIT
50 c8b153d7 ths
51 409dbce5 Aurelien Jarno
#define ENVP_ADDR                0x80002000l
52 5856de80 ths
#define ENVP_NB_ENTRIES                 16
53 5856de80 ths
#define ENVP_ENTRY_SIZE                 256
54 5856de80 ths
55 e4bcb14c ths
#define MAX_IDE_BUS 2
56 e4bcb14c ths
57 5856de80 ths
typedef struct {
58 5856de80 ths
    uint32_t leds;
59 5856de80 ths
    uint32_t brk;
60 5856de80 ths
    uint32_t gpout;
61 130751ee ths
    uint32_t i2cin;
62 5856de80 ths
    uint32_t i2coe;
63 5856de80 ths
    uint32_t i2cout;
64 5856de80 ths
    uint32_t i2csel;
65 5856de80 ths
    CharDriverState *display;
66 5856de80 ths
    char display_text[9];
67 a4bc3afc ths
    SerialState *uart;
68 5856de80 ths
} MaltaFPGAState;
69 5856de80 ths
70 5856de80 ths
static PITState *pit;
71 5856de80 ths
72 7df526e3 ths
static struct _loaderparams {
73 7df526e3 ths
    int ram_size;
74 7df526e3 ths
    const char *kernel_filename;
75 7df526e3 ths
    const char *kernel_cmdline;
76 7df526e3 ths
    const char *initrd_filename;
77 7df526e3 ths
} loaderparams;
78 7df526e3 ths
79 5856de80 ths
/* Malta FPGA */
80 5856de80 ths
static void malta_fpga_update_display(void *opaque)
81 5856de80 ths
{
82 5856de80 ths
    char leds_text[9];
83 5856de80 ths
    int i;
84 5856de80 ths
    MaltaFPGAState *s = opaque;
85 5856de80 ths
86 07cf0ba0 ths
    for (i = 7 ; i >= 0 ; i--) {
87 07cf0ba0 ths
        if (s->leds & (1 << i))
88 07cf0ba0 ths
            leds_text[i] = '#';
89 07cf0ba0 ths
        else
90 07cf0ba0 ths
            leds_text[i] = ' ';
91 87ee1669 ths
    }
92 07cf0ba0 ths
    leds_text[8] = '\0';
93 07cf0ba0 ths
94 07cf0ba0 ths
    qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
95 07cf0ba0 ths
    qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
96 5856de80 ths
}
97 5856de80 ths
98 130751ee ths
/*
99 130751ee ths
 * EEPROM 24C01 / 24C02 emulation.
100 130751ee ths
 *
101 130751ee ths
 * Emulation for serial EEPROMs:
102 130751ee ths
 * 24C01 - 1024 bit (128 x 8)
103 130751ee ths
 * 24C02 - 2048 bit (256 x 8)
104 130751ee ths
 *
105 130751ee ths
 * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
106 130751ee ths
 */
107 130751ee ths
108 130751ee ths
//~ #define DEBUG
109 130751ee ths
110 130751ee ths
#if defined(DEBUG)
111 001faf32 Blue Swirl
#  define logout(fmt, ...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ## __VA_ARGS__)
112 130751ee ths
#else
113 001faf32 Blue Swirl
#  define logout(fmt, ...) ((void)0)
114 130751ee ths
#endif
115 130751ee ths
116 c227f099 Anthony Liguori
struct _eeprom24c0x_t {
117 130751ee ths
  uint8_t tick;
118 130751ee ths
  uint8_t address;
119 130751ee ths
  uint8_t command;
120 130751ee ths
  uint8_t ack;
121 130751ee ths
  uint8_t scl;
122 130751ee ths
  uint8_t sda;
123 130751ee ths
  uint8_t data;
124 130751ee ths
  //~ uint16_t size;
125 130751ee ths
  uint8_t contents[256];
126 130751ee ths
};
127 130751ee ths
128 c227f099 Anthony Liguori
typedef struct _eeprom24c0x_t eeprom24c0x_t;
129 130751ee ths
130 c227f099 Anthony Liguori
static eeprom24c0x_t eeprom = {
131 284b08f1 Blue Swirl
    .contents = {
132 130751ee ths
        /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00,
133 130751ee ths
        /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
134 130751ee ths
        /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00,
135 130751ee ths
        /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40,
136 130751ee ths
        /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
137 130751ee ths
        /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
138 130751ee ths
        /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
139 130751ee ths
        /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
140 130751ee ths
        /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
141 130751ee ths
        /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
142 130751ee ths
        /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
143 130751ee ths
        /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
144 130751ee ths
        /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
145 130751ee ths
        /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
146 130751ee ths
        /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
147 130751ee ths
        /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
148 130751ee ths
    },
149 130751ee ths
};
150 130751ee ths
151 a5f1b965 blueswir1
static uint8_t eeprom24c0x_read(void)
152 130751ee ths
{
153 130751ee ths
    logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
154 130751ee ths
        eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
155 130751ee ths
    return eeprom.sda;
156 130751ee ths
}
157 130751ee ths
158 130751ee ths
static void eeprom24c0x_write(int scl, int sda)
159 130751ee ths
{
160 130751ee ths
    if (eeprom.scl && scl && (eeprom.sda != sda)) {
161 130751ee ths
        logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
162 130751ee ths
                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
163 130751ee ths
        if (!sda) {
164 130751ee ths
            eeprom.tick = 1;
165 130751ee ths
            eeprom.command = 0;
166 130751ee ths
        }
167 130751ee ths
    } else if (eeprom.tick == 0 && !eeprom.ack) {
168 130751ee ths
        /* Waiting for start. */
169 130751ee ths
        logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
170 130751ee ths
                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
171 130751ee ths
    } else if (!eeprom.scl && scl) {
172 130751ee ths
        logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
173 130751ee ths
                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
174 130751ee ths
        if (eeprom.ack) {
175 130751ee ths
            logout("\ti2c ack bit = 0\n");
176 130751ee ths
            sda = 0;
177 130751ee ths
            eeprom.ack = 0;
178 130751ee ths
        } else if (eeprom.sda == sda) {
179 130751ee ths
            uint8_t bit = (sda != 0);
180 130751ee ths
            logout("\ti2c bit = %d\n", bit);
181 130751ee ths
            if (eeprom.tick < 9) {
182 130751ee ths
                eeprom.command <<= 1;
183 130751ee ths
                eeprom.command += bit;
184 130751ee ths
                eeprom.tick++;
185 130751ee ths
                if (eeprom.tick == 9) {
186 130751ee ths
                    logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
187 130751ee ths
                    eeprom.ack = 1;
188 130751ee ths
                }
189 130751ee ths
            } else if (eeprom.tick < 17) {
190 130751ee ths
                if (eeprom.command & 1) {
191 130751ee ths
                    sda = ((eeprom.data & 0x80) != 0);
192 130751ee ths
                }
193 130751ee ths
                eeprom.address <<= 1;
194 130751ee ths
                eeprom.address += bit;
195 130751ee ths
                eeprom.tick++;
196 130751ee ths
                eeprom.data <<= 1;
197 130751ee ths
                if (eeprom.tick == 17) {
198 130751ee ths
                    eeprom.data = eeprom.contents[eeprom.address];
199 130751ee ths
                    logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
200 130751ee ths
                    eeprom.ack = 1;
201 130751ee ths
                    eeprom.tick = 0;
202 130751ee ths
                }
203 130751ee ths
            } else if (eeprom.tick >= 17) {
204 130751ee ths
                sda = 0;
205 130751ee ths
            }
206 130751ee ths
        } else {
207 130751ee ths
            logout("\tsda changed with raising scl\n");
208 130751ee ths
        }
209 130751ee ths
    } else {
210 130751ee ths
        logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
211 130751ee ths
    }
212 130751ee ths
    eeprom.scl = scl;
213 130751ee ths
    eeprom.sda = sda;
214 130751ee ths
}
215 130751ee ths
216 c227f099 Anthony Liguori
static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
217 5856de80 ths
{
218 5856de80 ths
    MaltaFPGAState *s = opaque;
219 5856de80 ths
    uint32_t val = 0;
220 5856de80 ths
    uint32_t saddr;
221 5856de80 ths
222 5856de80 ths
    saddr = (addr & 0xfffff);
223 5856de80 ths
224 5856de80 ths
    switch (saddr) {
225 5856de80 ths
226 5856de80 ths
    /* SWITCH Register */
227 5856de80 ths
    case 0x00200:
228 5856de80 ths
        val = 0x00000000;                /* All switches closed */
229 593c0d10 Aurelien Jarno
        break;
230 5856de80 ths
231 5856de80 ths
    /* STATUS Register */
232 5856de80 ths
    case 0x00208:
233 5856de80 ths
#ifdef TARGET_WORDS_BIGENDIAN
234 5856de80 ths
        val = 0x00000012;
235 5856de80 ths
#else
236 5856de80 ths
        val = 0x00000010;
237 5856de80 ths
#endif
238 5856de80 ths
        break;
239 5856de80 ths
240 5856de80 ths
    /* JMPRS Register */
241 5856de80 ths
    case 0x00210:
242 5856de80 ths
        val = 0x00;
243 5856de80 ths
        break;
244 5856de80 ths
245 5856de80 ths
    /* LEDBAR Register */
246 5856de80 ths
    case 0x00408:
247 5856de80 ths
        val = s->leds;
248 5856de80 ths
        break;
249 5856de80 ths
250 5856de80 ths
    /* BRKRES Register */
251 5856de80 ths
    case 0x00508:
252 5856de80 ths
        val = s->brk;
253 5856de80 ths
        break;
254 5856de80 ths
255 b6dc7ebb ths
    /* UART Registers are handled directly by the serial device */
256 a4bc3afc ths
257 5856de80 ths
    /* GPOUT Register */
258 5856de80 ths
    case 0x00a00:
259 5856de80 ths
        val = s->gpout;
260 5856de80 ths
        break;
261 5856de80 ths
262 5856de80 ths
    /* XXX: implement a real I2C controller */
263 5856de80 ths
264 5856de80 ths
    /* GPINP Register */
265 5856de80 ths
    case 0x00a08:
266 5856de80 ths
        /* IN = OUT until a real I2C control is implemented */
267 5856de80 ths
        if (s->i2csel)
268 5856de80 ths
            val = s->i2cout;
269 5856de80 ths
        else
270 5856de80 ths
            val = 0x00;
271 5856de80 ths
        break;
272 5856de80 ths
273 5856de80 ths
    /* I2CINP Register */
274 5856de80 ths
    case 0x00b00:
275 130751ee ths
        val = ((s->i2cin & ~1) | eeprom24c0x_read());
276 5856de80 ths
        break;
277 5856de80 ths
278 5856de80 ths
    /* I2COE Register */
279 5856de80 ths
    case 0x00b08:
280 5856de80 ths
        val = s->i2coe;
281 5856de80 ths
        break;
282 5856de80 ths
283 5856de80 ths
    /* I2COUT Register */
284 5856de80 ths
    case 0x00b10:
285 5856de80 ths
        val = s->i2cout;
286 5856de80 ths
        break;
287 5856de80 ths
288 5856de80 ths
    /* I2CSEL Register */
289 5856de80 ths
    case 0x00b18:
290 130751ee ths
        val = s->i2csel;
291 5856de80 ths
        break;
292 5856de80 ths
293 5856de80 ths
    default:
294 5856de80 ths
#if 0
295 3594c774 ths
        printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
296 593c0d10 Aurelien Jarno
                addr);
297 5856de80 ths
#endif
298 5856de80 ths
        break;
299 5856de80 ths
    }
300 5856de80 ths
    return val;
301 5856de80 ths
}
302 5856de80 ths
303 c227f099 Anthony Liguori
static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
304 5856de80 ths
                              uint32_t val)
305 5856de80 ths
{
306 5856de80 ths
    MaltaFPGAState *s = opaque;
307 5856de80 ths
    uint32_t saddr;
308 5856de80 ths
309 5856de80 ths
    saddr = (addr & 0xfffff);
310 5856de80 ths
311 5856de80 ths
    switch (saddr) {
312 5856de80 ths
313 5856de80 ths
    /* SWITCH Register */
314 5856de80 ths
    case 0x00200:
315 5856de80 ths
        break;
316 5856de80 ths
317 5856de80 ths
    /* JMPRS Register */
318 5856de80 ths
    case 0x00210:
319 5856de80 ths
        break;
320 5856de80 ths
321 5856de80 ths
    /* LEDBAR Register */
322 5856de80 ths
    /* XXX: implement a 8-LED array */
323 5856de80 ths
    case 0x00408:
324 5856de80 ths
        s->leds = val & 0xff;
325 5856de80 ths
        break;
326 5856de80 ths
327 5856de80 ths
    /* ASCIIWORD Register */
328 5856de80 ths
    case 0x00410:
329 5856de80 ths
        snprintf(s->display_text, 9, "%08X", val);
330 5856de80 ths
        malta_fpga_update_display(s);
331 5856de80 ths
        break;
332 5856de80 ths
333 5856de80 ths
    /* ASCIIPOS0 to ASCIIPOS7 Registers */
334 5856de80 ths
    case 0x00418:
335 5856de80 ths
    case 0x00420:
336 5856de80 ths
    case 0x00428:
337 5856de80 ths
    case 0x00430:
338 5856de80 ths
    case 0x00438:
339 5856de80 ths
    case 0x00440:
340 5856de80 ths
    case 0x00448:
341 5856de80 ths
    case 0x00450:
342 5856de80 ths
        s->display_text[(saddr - 0x00418) >> 3] = (char) val;
343 5856de80 ths
        malta_fpga_update_display(s);
344 5856de80 ths
        break;
345 5856de80 ths
346 5856de80 ths
    /* SOFTRES Register */
347 5856de80 ths
    case 0x00500:
348 5856de80 ths
        if (val == 0x42)
349 5856de80 ths
            qemu_system_reset_request ();
350 5856de80 ths
        break;
351 5856de80 ths
352 5856de80 ths
    /* BRKRES Register */
353 5856de80 ths
    case 0x00508:
354 5856de80 ths
        s->brk = val & 0xff;
355 5856de80 ths
        break;
356 5856de80 ths
357 b6dc7ebb ths
    /* UART Registers are handled directly by the serial device */
358 a4bc3afc ths
359 5856de80 ths
    /* GPOUT Register */
360 5856de80 ths
    case 0x00a00:
361 5856de80 ths
        s->gpout = val & 0xff;
362 5856de80 ths
        break;
363 5856de80 ths
364 5856de80 ths
    /* I2COE Register */
365 5856de80 ths
    case 0x00b08:
366 5856de80 ths
        s->i2coe = val & 0x03;
367 5856de80 ths
        break;
368 5856de80 ths
369 5856de80 ths
    /* I2COUT Register */
370 5856de80 ths
    case 0x00b10:
371 130751ee ths
        eeprom24c0x_write(val & 0x02, val & 0x01);
372 130751ee ths
        s->i2cout = val;
373 5856de80 ths
        break;
374 5856de80 ths
375 5856de80 ths
    /* I2CSEL Register */
376 5856de80 ths
    case 0x00b18:
377 130751ee ths
        s->i2csel = val & 0x01;
378 5856de80 ths
        break;
379 5856de80 ths
380 5856de80 ths
    default:
381 5856de80 ths
#if 0
382 3594c774 ths
        printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
383 593c0d10 Aurelien Jarno
                addr);
384 5856de80 ths
#endif
385 5856de80 ths
        break;
386 5856de80 ths
    }
387 5856de80 ths
}
388 5856de80 ths
389 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const malta_fpga_read[] = {
390 5856de80 ths
   malta_fpga_readl,
391 5856de80 ths
   malta_fpga_readl,
392 5856de80 ths
   malta_fpga_readl
393 5856de80 ths
};
394 5856de80 ths
395 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const malta_fpga_write[] = {
396 5856de80 ths
   malta_fpga_writel,
397 5856de80 ths
   malta_fpga_writel,
398 5856de80 ths
   malta_fpga_writel
399 5856de80 ths
};
400 5856de80 ths
401 9596ebb7 pbrook
static void malta_fpga_reset(void *opaque)
402 5856de80 ths
{
403 5856de80 ths
    MaltaFPGAState *s = opaque;
404 5856de80 ths
405 5856de80 ths
    s->leds   = 0x00;
406 5856de80 ths
    s->brk    = 0x0a;
407 5856de80 ths
    s->gpout  = 0x00;
408 130751ee ths
    s->i2cin  = 0x3;
409 5856de80 ths
    s->i2coe  = 0x0;
410 5856de80 ths
    s->i2cout = 0x3;
411 5856de80 ths
    s->i2csel = 0x1;
412 5856de80 ths
413 5856de80 ths
    s->display_text[8] = '\0';
414 5856de80 ths
    snprintf(s->display_text, 9, "        ");
415 ceecf1d1 aurel32
}
416 ceecf1d1 aurel32
417 ceecf1d1 aurel32
static void malta_fpga_led_init(CharDriverState *chr)
418 ceecf1d1 aurel32
{
419 ceecf1d1 aurel32
    qemu_chr_printf(chr, "\e[HMalta LEDBAR\r\n");
420 ceecf1d1 aurel32
    qemu_chr_printf(chr, "+--------+\r\n");
421 ceecf1d1 aurel32
    qemu_chr_printf(chr, "+        +\r\n");
422 ceecf1d1 aurel32
    qemu_chr_printf(chr, "+--------+\r\n");
423 ceecf1d1 aurel32
    qemu_chr_printf(chr, "\n");
424 ceecf1d1 aurel32
    qemu_chr_printf(chr, "Malta ASCII\r\n");
425 ceecf1d1 aurel32
    qemu_chr_printf(chr, "+--------+\r\n");
426 ceecf1d1 aurel32
    qemu_chr_printf(chr, "+        +\r\n");
427 ceecf1d1 aurel32
    qemu_chr_printf(chr, "+--------+\r\n");
428 5856de80 ths
}
429 5856de80 ths
430 c227f099 Anthony Liguori
static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_irq, CharDriverState *uart_chr)
431 5856de80 ths
{
432 5856de80 ths
    MaltaFPGAState *s;
433 5856de80 ths
    int malta;
434 5856de80 ths
435 5856de80 ths
    s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
436 5856de80 ths
437 1eed09cb Avi Kivity
    malta = cpu_register_io_memory(malta_fpga_read,
438 5856de80 ths
                                   malta_fpga_write, s);
439 a4bc3afc ths
440 b6dc7ebb ths
    cpu_register_physical_memory(base, 0x900, malta);
441 8da3ff18 pbrook
    /* 0xa00 is less than a page, so will still get the right offsets.  */
442 b6dc7ebb ths
    cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta);
443 5856de80 ths
444 ceecf1d1 aurel32
    s->display = qemu_chr_open("fpga", "vc:320x200", malta_fpga_led_init);
445 ceecf1d1 aurel32
446 2d48377a Blue Swirl
#ifdef TARGET_WORDS_BIGENDIAN
447 2d48377a Blue Swirl
    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 1);
448 2d48377a Blue Swirl
#else
449 2d48377a Blue Swirl
    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 0);
450 2d48377a Blue Swirl
#endif
451 a4bc3afc ths
452 5856de80 ths
    malta_fpga_reset(s);
453 a08d4367 Jan Kiszka
    qemu_register_reset(malta_fpga_reset, s);
454 5856de80 ths
455 5856de80 ths
    return s;
456 5856de80 ths
}
457 5856de80 ths
458 5856de80 ths
/* Audio support */
459 5856de80 ths
#ifdef HAS_AUDIO
460 5856de80 ths
static void audio_init (PCIBus *pci_bus)
461 5856de80 ths
{
462 5856de80 ths
    struct soundhw *c;
463 5856de80 ths
    int audio_enabled = 0;
464 5856de80 ths
465 5856de80 ths
    for (c = soundhw; !audio_enabled && c->name; ++c) {
466 5856de80 ths
        audio_enabled = c->enabled;
467 5856de80 ths
    }
468 5856de80 ths
469 5856de80 ths
    if (audio_enabled) {
470 0d9acba8 Paul Brook
        for (c = soundhw; c->name; ++c) {
471 0d9acba8 Paul Brook
            if (c->enabled) {
472 22d83b14 Paul Brook
                c->init.init_pci(pci_bus);
473 5856de80 ths
            }
474 5856de80 ths
        }
475 5856de80 ths
    }
476 5856de80 ths
}
477 5856de80 ths
#endif
478 5856de80 ths
479 5856de80 ths
/* Network support */
480 5607c388 Markus Armbruster
static void network_init(void)
481 5856de80 ths
{
482 5856de80 ths
    int i;
483 5856de80 ths
484 5856de80 ths
    for(i = 0; i < nb_nics; i++) {
485 cb457d76 aliguori
        NICInfo *nd = &nd_table[i];
486 5607c388 Markus Armbruster
        const char *default_devaddr = NULL;
487 cb457d76 aliguori
488 cb457d76 aliguori
        if (i == 0 && (!nd->model || strcmp(nd->model, "pcnet") == 0))
489 5856de80 ths
            /* The malta board has a PCNet card using PCI SLOT 11 */
490 5607c388 Markus Armbruster
            default_devaddr = "0b";
491 cb457d76 aliguori
492 07caea31 Markus Armbruster
        pci_nic_init_nofail(nd, "pcnet", default_devaddr);
493 5856de80 ths
    }
494 5856de80 ths
}
495 5856de80 ths
496 5856de80 ths
/* ROM and pseudo bootloader
497 5856de80 ths

498 5856de80 ths
   The following code implements a very very simple bootloader. It first
499 5856de80 ths
   loads the registers a0 to a3 to the values expected by the OS, and
500 5856de80 ths
   then jump at the kernel address.
501 5856de80 ths

502 5856de80 ths
   The bootloader should pass the locations of the kernel arguments and
503 5856de80 ths
   environment variables tables. Those tables contain the 32-bit address
504 5856de80 ths
   of NULL terminated strings. The environment variables table should be
505 5856de80 ths
   terminated by a NULL address.
506 5856de80 ths

507 5856de80 ths
   For a simpler implementation, the number of kernel arguments is fixed
508 5856de80 ths
   to two (the name of the kernel and the command line), and the two
509 5856de80 ths
   tables are actually the same one.
510 5856de80 ths

511 5856de80 ths
   The registers a0 to a3 should contain the following values:
512 5856de80 ths
     a0 - number of kernel arguments
513 5856de80 ths
     a1 - 32-bit address of the kernel arguments table
514 5856de80 ths
     a2 - 32-bit address of the environment variables table
515 5856de80 ths
     a3 - RAM size in bytes
516 5856de80 ths
*/
517 5856de80 ths
518 d7585251 pbrook
static void write_bootloader (CPUState *env, uint8_t *base,
519 d7585251 pbrook
                              int64_t kernel_entry)
520 5856de80 ths
{
521 5856de80 ths
    uint32_t *p;
522 5856de80 ths
523 5856de80 ths
    /* Small bootloader */
524 d7585251 pbrook
    p = (uint32_t *)base;
525 26ea0918 ths
    stl_raw(p++, 0x0bf00160);                                      /* j 0x1fc00580 */
526 3ddd0065 ths
    stl_raw(p++, 0x00000000);                                      /* nop */
527 5856de80 ths
528 26ea0918 ths
    /* YAMON service vector */
529 d7585251 pbrook
    stl_raw(base + 0x500, 0xbfc00580);      /* start: */
530 d7585251 pbrook
    stl_raw(base + 0x504, 0xbfc0083c);      /* print_count: */
531 d7585251 pbrook
    stl_raw(base + 0x520, 0xbfc00580);      /* start: */
532 d7585251 pbrook
    stl_raw(base + 0x52c, 0xbfc00800);      /* flush_cache: */
533 d7585251 pbrook
    stl_raw(base + 0x534, 0xbfc00808);      /* print: */
534 d7585251 pbrook
    stl_raw(base + 0x538, 0xbfc00800);      /* reg_cpu_isr: */
535 d7585251 pbrook
    stl_raw(base + 0x53c, 0xbfc00800);      /* unred_cpu_isr: */
536 d7585251 pbrook
    stl_raw(base + 0x540, 0xbfc00800);      /* reg_ic_isr: */
537 d7585251 pbrook
    stl_raw(base + 0x544, 0xbfc00800);      /* unred_ic_isr: */
538 d7585251 pbrook
    stl_raw(base + 0x548, 0xbfc00800);      /* reg_esr: */
539 d7585251 pbrook
    stl_raw(base + 0x54c, 0xbfc00800);      /* unreg_esr: */
540 d7585251 pbrook
    stl_raw(base + 0x550, 0xbfc00800);      /* getchar: */
541 d7585251 pbrook
    stl_raw(base + 0x554, 0xbfc00800);      /* syscon_read: */
542 26ea0918 ths
543 26ea0918 ths
544 5856de80 ths
    /* Second part of the bootloader */
545 d7585251 pbrook
    p = (uint32_t *) (base + 0x580);
546 d52fff71 ths
    stl_raw(p++, 0x24040002);                                      /* addiu a0, zero, 2 */
547 d52fff71 ths
    stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
548 471ea271 ths
    stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
549 3ddd0065 ths
    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
550 471ea271 ths
    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a1, low(ENVP_ADDR) */
551 3ddd0065 ths
    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
552 3ddd0065 ths
    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
553 7df526e3 ths
    stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16));     /* lui a3, high(ram_size) */
554 7df526e3 ths
    stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));  /* ori a3, a3, low(ram_size) */
555 2802bfe3 ths
556 2802bfe3 ths
    /* Load BAR registers as done by YAMON */
557 a0a8793e ths
    stl_raw(p++, 0x3c09b400);                                      /* lui t1, 0xb400 */
558 a0a8793e ths
559 a0a8793e ths
#ifdef TARGET_WORDS_BIGENDIAN
560 a0a8793e ths
    stl_raw(p++, 0x3c08df00);                                      /* lui t0, 0xdf00 */
561 a0a8793e ths
#else
562 a0a8793e ths
    stl_raw(p++, 0x340800df);                                      /* ori t0, r0, 0x00df */
563 a0a8793e ths
#endif
564 a0a8793e ths
    stl_raw(p++, 0xad280068);                                      /* sw t0, 0x0068(t1) */
565 a0a8793e ths
566 2802bfe3 ths
    stl_raw(p++, 0x3c09bbe0);                                      /* lui t1, 0xbbe0 */
567 2802bfe3 ths
568 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
569 2802bfe3 ths
    stl_raw(p++, 0x3c08c000);                                      /* lui t0, 0xc000 */
570 2802bfe3 ths
#else
571 2802bfe3 ths
    stl_raw(p++, 0x340800c0);                                      /* ori t0, r0, 0x00c0 */
572 2802bfe3 ths
#endif
573 2802bfe3 ths
    stl_raw(p++, 0xad280048);                                      /* sw t0, 0x0048(t1) */
574 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
575 2802bfe3 ths
    stl_raw(p++, 0x3c084000);                                      /* lui t0, 0x4000 */
576 2802bfe3 ths
#else
577 2802bfe3 ths
    stl_raw(p++, 0x34080040);                                      /* ori t0, r0, 0x0040 */
578 2802bfe3 ths
#endif
579 2802bfe3 ths
    stl_raw(p++, 0xad280050);                                      /* sw t0, 0x0050(t1) */
580 2802bfe3 ths
581 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
582 2802bfe3 ths
    stl_raw(p++, 0x3c088000);                                      /* lui t0, 0x8000 */
583 2802bfe3 ths
#else
584 2802bfe3 ths
    stl_raw(p++, 0x34080080);                                      /* ori t0, r0, 0x0080 */
585 2802bfe3 ths
#endif
586 2802bfe3 ths
    stl_raw(p++, 0xad280058);                                      /* sw t0, 0x0058(t1) */
587 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
588 2802bfe3 ths
    stl_raw(p++, 0x3c083f00);                                      /* lui t0, 0x3f00 */
589 2802bfe3 ths
#else
590 2802bfe3 ths
    stl_raw(p++, 0x3408003f);                                      /* ori t0, r0, 0x003f */
591 2802bfe3 ths
#endif
592 2802bfe3 ths
    stl_raw(p++, 0xad280060);                                      /* sw t0, 0x0060(t1) */
593 2802bfe3 ths
594 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
595 2802bfe3 ths
    stl_raw(p++, 0x3c08c100);                                      /* lui t0, 0xc100 */
596 2802bfe3 ths
#else
597 2802bfe3 ths
    stl_raw(p++, 0x340800c1);                                      /* ori t0, r0, 0x00c1 */
598 2802bfe3 ths
#endif
599 2802bfe3 ths
    stl_raw(p++, 0xad280080);                                      /* sw t0, 0x0080(t1) */
600 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
601 2802bfe3 ths
    stl_raw(p++, 0x3c085e00);                                      /* lui t0, 0x5e00 */
602 2802bfe3 ths
#else
603 2802bfe3 ths
    stl_raw(p++, 0x3408005e);                                      /* ori t0, r0, 0x005e */
604 2802bfe3 ths
#endif
605 2802bfe3 ths
    stl_raw(p++, 0xad280088);                                      /* sw t0, 0x0088(t1) */
606 2802bfe3 ths
607 2802bfe3 ths
    /* Jump to kernel code */
608 74287114 ths
    stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff));    /* lui ra, high(kernel_entry) */
609 74287114 ths
    stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff));            /* ori ra, ra, low(kernel_entry) */
610 3ddd0065 ths
    stl_raw(p++, 0x03e00008);                                      /* jr ra */
611 3ddd0065 ths
    stl_raw(p++, 0x00000000);                                      /* nop */
612 26ea0918 ths
613 26ea0918 ths
    /* YAMON subroutines */
614 d7585251 pbrook
    p = (uint32_t *) (base + 0x800);
615 26ea0918 ths
    stl_raw(p++, 0x03e00008);                                     /* jr ra */
616 26ea0918 ths
    stl_raw(p++, 0x24020000);                                     /* li v0,0 */
617 26ea0918 ths
   /* 808 YAMON print */
618 26ea0918 ths
    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
619 26ea0918 ths
    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
620 26ea0918 ths
    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
621 26ea0918 ths
    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
622 26ea0918 ths
    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
623 26ea0918 ths
    stl_raw(p++, 0x10800005);                                     /* beqz a0,834 */
624 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
625 26ea0918 ths
    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
626 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
627 26ea0918 ths
    stl_raw(p++, 0x08000205);                                     /* j 814 */
628 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
629 26ea0918 ths
    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
630 26ea0918 ths
    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
631 26ea0918 ths
    /* 0x83c YAMON print_count */
632 26ea0918 ths
    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
633 26ea0918 ths
    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
634 26ea0918 ths
    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
635 26ea0918 ths
    stl_raw(p++, 0x00c06021);                                     /* move t4,a2 */
636 26ea0918 ths
    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
637 26ea0918 ths
    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
638 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
639 26ea0918 ths
    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
640 26ea0918 ths
    stl_raw(p++, 0x258cffff);                                     /* addiu t4,t4,-1 */
641 26ea0918 ths
    stl_raw(p++, 0x1580fffa);                                     /* bnez t4,84c */
642 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
643 26ea0918 ths
    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
644 26ea0918 ths
    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
645 26ea0918 ths
    /* 0x870 */
646 26ea0918 ths
    stl_raw(p++, 0x3c08b800);                                     /* lui t0,0xb400 */
647 26ea0918 ths
    stl_raw(p++, 0x350803f8);                                     /* ori t0,t0,0x3f8 */
648 26ea0918 ths
    stl_raw(p++, 0x91090005);                                     /* lbu t1,5(t0) */
649 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
650 26ea0918 ths
    stl_raw(p++, 0x31290040);                                     /* andi t1,t1,0x40 */
651 26ea0918 ths
    stl_raw(p++, 0x1120fffc);                                     /* beqz t1,878 <outch+0x8> */
652 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
653 26ea0918 ths
    stl_raw(p++, 0x03e00008);                                     /* jr ra */
654 26ea0918 ths
    stl_raw(p++, 0xa1040000);                                     /* sb a0,0(t0) */
655 26ea0918 ths
656 5856de80 ths
}
657 5856de80 ths
658 c938ada2 Aurelien Jarno
static void prom_set(uint32_t* prom_buf, int index, const char *string, ...)
659 5856de80 ths
{
660 5856de80 ths
    va_list ap;
661 3ddd0065 ths
    int32_t table_addr;
662 5856de80 ths
663 5856de80 ths
    if (index >= ENVP_NB_ENTRIES)
664 5856de80 ths
        return;
665 5856de80 ths
666 5856de80 ths
    if (string == NULL) {
667 c938ada2 Aurelien Jarno
        prom_buf[index] = 0;
668 5856de80 ths
        return;
669 5856de80 ths
    }
670 5856de80 ths
671 c938ada2 Aurelien Jarno
    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
672 c938ada2 Aurelien Jarno
    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
673 5856de80 ths
674 5856de80 ths
    va_start(ap, string);
675 c938ada2 Aurelien Jarno
    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
676 5856de80 ths
    va_end(ap);
677 5856de80 ths
}
678 5856de80 ths
679 5856de80 ths
/* Kernel */
680 e16ad5b0 Aurelien Jarno
static int64_t load_kernel (void)
681 5856de80 ths
{
682 409dbce5 Aurelien Jarno
    int64_t kernel_entry, kernel_high;
683 5856de80 ths
    long initrd_size;
684 c227f099 Anthony Liguori
    ram_addr_t initrd_offset;
685 ca20cf32 Blue Swirl
    int big_endian;
686 c938ada2 Aurelien Jarno
    uint32_t *prom_buf;
687 c938ada2 Aurelien Jarno
    long prom_size;
688 c938ada2 Aurelien Jarno
    int prom_index = 0;
689 ca20cf32 Blue Swirl
690 ca20cf32 Blue Swirl
#ifdef TARGET_WORDS_BIGENDIAN
691 ca20cf32 Blue Swirl
    big_endian = 1;
692 ca20cf32 Blue Swirl
#else
693 ca20cf32 Blue Swirl
    big_endian = 0;
694 ca20cf32 Blue Swirl
#endif
695 5856de80 ths
696 409dbce5 Aurelien Jarno
    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
697 409dbce5 Aurelien Jarno
                 (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
698 409dbce5 Aurelien Jarno
                 big_endian, ELF_MACHINE, 1) < 0) {
699 5856de80 ths
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
700 7df526e3 ths
                loaderparams.kernel_filename);
701 acdf72bb ths
        exit(1);
702 5856de80 ths
    }
703 5856de80 ths
704 5856de80 ths
    /* load initrd */
705 5856de80 ths
    initrd_size = 0;
706 74287114 ths
    initrd_offset = 0;
707 7df526e3 ths
    if (loaderparams.initrd_filename) {
708 7df526e3 ths
        initrd_size = get_image_size (loaderparams.initrd_filename);
709 74287114 ths
        if (initrd_size > 0) {
710 74287114 ths
            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
711 7df526e3 ths
            if (initrd_offset + initrd_size > ram_size) {
712 74287114 ths
                fprintf(stderr,
713 74287114 ths
                        "qemu: memory too small for initial ram disk '%s'\n",
714 7df526e3 ths
                        loaderparams.initrd_filename);
715 74287114 ths
                exit(1);
716 74287114 ths
            }
717 dcac9679 pbrook
            initrd_size = load_image_targphys(loaderparams.initrd_filename,
718 dcac9679 pbrook
                                              initrd_offset,
719 dcac9679 pbrook
                                              ram_size - initrd_offset);
720 74287114 ths
        }
721 5856de80 ths
        if (initrd_size == (target_ulong) -1) {
722 5856de80 ths
            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
723 7df526e3 ths
                    loaderparams.initrd_filename);
724 5856de80 ths
            exit(1);
725 5856de80 ths
        }
726 5856de80 ths
    }
727 5856de80 ths
728 c938ada2 Aurelien Jarno
    /* Setup prom parameters. */
729 c938ada2 Aurelien Jarno
    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
730 c938ada2 Aurelien Jarno
    prom_buf = qemu_malloc(prom_size);
731 c938ada2 Aurelien Jarno
732 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, loaderparams.kernel_filename);
733 c938ada2 Aurelien Jarno
    if (initrd_size > 0) {
734 409dbce5 Aurelien Jarno
        prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
735 409dbce5 Aurelien Jarno
                 cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
736 7df526e3 ths
                 loaderparams.kernel_cmdline);
737 c938ada2 Aurelien Jarno
    } else {
738 c938ada2 Aurelien Jarno
        prom_set(prom_buf, prom_index++, loaderparams.kernel_cmdline);
739 c938ada2 Aurelien Jarno
    }
740 c938ada2 Aurelien Jarno
741 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "memsize");
742 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size);
743 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "modetty0");
744 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "38400n8r");
745 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, NULL);
746 c938ada2 Aurelien Jarno
747 c938ada2 Aurelien Jarno
    rom_add_blob_fixed("prom", prom_buf, prom_size,
748 409dbce5 Aurelien Jarno
                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
749 5856de80 ths
750 74287114 ths
    return kernel_entry;
751 5856de80 ths
}
752 5856de80 ths
753 5856de80 ths
static void main_cpu_reset(void *opaque)
754 5856de80 ths
{
755 5856de80 ths
    CPUState *env = opaque;
756 5856de80 ths
    cpu_reset(env);
757 5856de80 ths
758 5c43485f Aurelien Jarno
    /* The bootloader does not need to be rewritten as it is located in a
759 5856de80 ths
       read only location. The kernel location and the arguments table
760 5856de80 ths
       location does not change. */
761 7df526e3 ths
    if (loaderparams.kernel_filename) {
762 fb82fea0 ths
        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
763 fb82fea0 ths
    }
764 5856de80 ths
}
765 5856de80 ths
766 70705261 ths
static
767 c227f099 Anthony Liguori
void mips_malta_init (ram_addr_t ram_size,
768 3023f332 aliguori
                      const char *boot_device,
769 5856de80 ths
                      const char *kernel_filename, const char *kernel_cmdline,
770 94fc95cd j_mayer
                      const char *initrd_filename, const char *cpu_model)
771 5856de80 ths
{
772 5cea8590 Paul Brook
    char *filename;
773 c227f099 Anthony Liguori
    ram_addr_t ram_offset;
774 c227f099 Anthony Liguori
    ram_addr_t bios_offset;
775 c8b153d7 ths
    target_long bios_size;
776 74287114 ths
    int64_t kernel_entry;
777 5856de80 ths
    PCIBus *pci_bus;
778 ae027ad3 Stefan Weil
    ISADevice *isa_dev;
779 5856de80 ths
    CPUState *env;
780 1d914fa0 Isaku Yamahata
    ISADevice *rtc_state;
781 5c02c033 Blue Swirl
    FDCtrl *floppy_controller;
782 5856de80 ths
    MaltaFPGAState *malta_fpga;
783 d537cf6c pbrook
    qemu_irq *i8259;
784 7b717336 ths
    int piix4_devfn;
785 7b717336 ths
    uint8_t *eeprom_buf;
786 7b717336 ths
    i2c_bus *smbus;
787 7b717336 ths
    int i;
788 751c6a17 Gerd Hoffmann
    DriveInfo *dinfo;
789 f455e98c Gerd Hoffmann
    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
790 fd8014e1 Gerd Hoffmann
    DriveInfo *fd[MAX_FD];
791 c8b153d7 ths
    int fl_idx = 0;
792 c8b153d7 ths
    int fl_sectors = 0;
793 3d08ff69 Blue Swirl
    int be;
794 5856de80 ths
795 ffabf037 Aurelien Jarno
    /* Make sure the first 3 serial ports are associated with a device. */
796 ffabf037 Aurelien Jarno
    for(i = 0; i < 3; i++) {
797 ffabf037 Aurelien Jarno
        if (!serial_hds[i]) {
798 ffabf037 Aurelien Jarno
            char label[32];
799 ffabf037 Aurelien Jarno
            snprintf(label, sizeof(label), "serial%d", i);
800 ffabf037 Aurelien Jarno
            serial_hds[i] = qemu_chr_open(label, "null", NULL);
801 ffabf037 Aurelien Jarno
        }
802 ffabf037 Aurelien Jarno
    }
803 ffabf037 Aurelien Jarno
804 33d68b5f ths
    /* init CPUs */
805 33d68b5f ths
    if (cpu_model == NULL) {
806 60aa19ab ths
#ifdef TARGET_MIPS64
807 c9c1a064 ths
        cpu_model = "20Kc";
808 33d68b5f ths
#else
809 1c32f43e ths
        cpu_model = "24Kf";
810 33d68b5f ths
#endif
811 33d68b5f ths
    }
812 aaed909a bellard
    env = cpu_init(cpu_model);
813 aaed909a bellard
    if (!env) {
814 aaed909a bellard
        fprintf(stderr, "Unable to find CPU definition\n");
815 aaed909a bellard
        exit(1);
816 aaed909a bellard
    }
817 a08d4367 Jan Kiszka
    qemu_register_reset(main_cpu_reset, env);
818 5856de80 ths
819 5856de80 ths
    /* allocate RAM */
820 0ccff151 aurel32
    if (ram_size > (256 << 20)) {
821 0ccff151 aurel32
        fprintf(stderr,
822 0ccff151 aurel32
                "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
823 0ccff151 aurel32
                ((unsigned int)ram_size / (1 << 20)));
824 0ccff151 aurel32
        exit(1);
825 0ccff151 aurel32
    }
826 dcac9679 pbrook
    ram_offset = qemu_ram_alloc(ram_size);
827 dcac9679 pbrook
    bios_offset = qemu_ram_alloc(BIOS_SIZE);
828 dcac9679 pbrook
829 dcac9679 pbrook
830 dcac9679 pbrook
    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
831 5856de80 ths
832 c8b153d7 ths
    /* Map the bios at two physical locations, as on the real board. */
833 5856de80 ths
    cpu_register_physical_memory(0x1e000000LL,
834 5856de80 ths
                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
835 5856de80 ths
    cpu_register_physical_memory(0x1fc00000LL,
836 5856de80 ths
                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
837 5856de80 ths
838 3d08ff69 Blue Swirl
#ifdef TARGET_WORDS_BIGENDIAN
839 3d08ff69 Blue Swirl
    be = 1;
840 3d08ff69 Blue Swirl
#else
841 3d08ff69 Blue Swirl
    be = 0;
842 3d08ff69 Blue Swirl
#endif
843 070ce5ed ths
    /* FPGA */
844 470d86b7 aurel32
    malta_fpga = malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
845 070ce5ed ths
846 c8b153d7 ths
    /* Load firmware in flash / BIOS unless we boot directly into a kernel. */
847 c8b153d7 ths
    if (kernel_filename) {
848 c8b153d7 ths
        /* Write a small bootloader to the flash location. */
849 c8b153d7 ths
        loaderparams.ram_size = ram_size;
850 c8b153d7 ths
        loaderparams.kernel_filename = kernel_filename;
851 c8b153d7 ths
        loaderparams.kernel_cmdline = kernel_cmdline;
852 c8b153d7 ths
        loaderparams.initrd_filename = initrd_filename;
853 e16ad5b0 Aurelien Jarno
        kernel_entry = load_kernel();
854 d7585251 pbrook
        write_bootloader(env, qemu_get_ram_ptr(bios_offset), kernel_entry);
855 c8b153d7 ths
    } else {
856 751c6a17 Gerd Hoffmann
        dinfo = drive_get(IF_PFLASH, 0, fl_idx);
857 751c6a17 Gerd Hoffmann
        if (dinfo) {
858 c8b153d7 ths
            /* Load firmware from flash. */
859 c8b153d7 ths
            bios_size = 0x400000;
860 c8b153d7 ths
            fl_sectors = bios_size >> 16;
861 c8b153d7 ths
#ifdef DEBUG_BOARD_INIT
862 c8b153d7 ths
            printf("Register parallel flash %d size " TARGET_FMT_lx " at "
863 c8b153d7 ths
                   "offset %08lx addr %08llx '%s' %x\n",
864 c8b153d7 ths
                   fl_idx, bios_size, bios_offset, 0x1e000000LL,
865 751c6a17 Gerd Hoffmann
                   bdrv_get_device_name(dinfo->bdrv), fl_sectors);
866 c8b153d7 ths
#endif
867 c8b153d7 ths
            pflash_cfi01_register(0x1e000000LL, bios_offset,
868 751c6a17 Gerd Hoffmann
                                  dinfo->bdrv, 65536, fl_sectors,
869 3d08ff69 Blue Swirl
                                  4, 0x0000, 0x0000, 0x0000, 0x0000, be);
870 c8b153d7 ths
            fl_idx++;
871 c8b153d7 ths
        } else {
872 c8b153d7 ths
            /* Load a BIOS image. */
873 c8b153d7 ths
            if (bios_name == NULL)
874 c8b153d7 ths
                bios_name = BIOS_FILENAME;
875 5cea8590 Paul Brook
            filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
876 5cea8590 Paul Brook
            if (filename) {
877 5cea8590 Paul Brook
                bios_size = load_image_targphys(filename, 0x1fc00000LL,
878 5cea8590 Paul Brook
                                                BIOS_SIZE);
879 5cea8590 Paul Brook
                qemu_free(filename);
880 5cea8590 Paul Brook
            } else {
881 5cea8590 Paul Brook
                bios_size = -1;
882 5cea8590 Paul Brook
            }
883 c8b153d7 ths
            if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
884 c8b153d7 ths
                fprintf(stderr,
885 c8b153d7 ths
                        "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
886 5cea8590 Paul Brook
                        bios_name);
887 c8b153d7 ths
                exit(1);
888 c8b153d7 ths
            }
889 070ce5ed ths
        }
890 3187ef03 ths
        /* In little endian mode the 32bit words in the bios are swapped,
891 3187ef03 ths
           a neat trick which allows bi-endian firmware. */
892 3187ef03 ths
#ifndef TARGET_WORDS_BIGENDIAN
893 3187ef03 ths
        {
894 d7585251 pbrook
            uint32_t *addr = qemu_get_ram_ptr(bios_offset);;
895 d7585251 pbrook
            uint32_t *end = addr + bios_size;
896 d7585251 pbrook
            while (addr < end) {
897 d7585251 pbrook
                bswap32s(addr);
898 3187ef03 ths
            }
899 3187ef03 ths
        }
900 3187ef03 ths
#endif
901 070ce5ed ths
    }
902 070ce5ed ths
903 5856de80 ths
    /* Board ID = 0x420 (Malta Board with CoreLV)
904 5856de80 ths
       XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
905 5856de80 ths
       map to the board ID. */
906 d7585251 pbrook
    stl_phys(0x1fc00010LL, 0x00000420);
907 5856de80 ths
908 5856de80 ths
    /* Init internal devices */
909 d537cf6c pbrook
    cpu_mips_irq_init_cpu(env);
910 5856de80 ths
    cpu_mips_clock_init(env);
911 5856de80 ths
912 5856de80 ths
    /* Interrupt controller */
913 d537cf6c pbrook
    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
914 d537cf6c pbrook
    i8259 = i8259_init(env->irq[2]);
915 5856de80 ths
916 5856de80 ths
    /* Northbridge */
917 d537cf6c pbrook
    pci_bus = pci_gt64120_init(i8259);
918 5856de80 ths
919 5856de80 ths
    /* Southbridge */
920 e4bcb14c ths
921 e4bcb14c ths
    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
922 e4bcb14c ths
        fprintf(stderr, "qemu: too many IDE bus\n");
923 e4bcb14c ths
        exit(1);
924 e4bcb14c ths
    }
925 e4bcb14c ths
926 e4bcb14c ths
    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
927 f455e98c Gerd Hoffmann
        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
928 e4bcb14c ths
    }
929 e4bcb14c ths
930 7b717336 ths
    piix4_devfn = piix4_init(pci_bus, 80);
931 ae027ad3 Stefan Weil
    isa_bus_irqs(i8259);
932 ae027ad3 Stefan Weil
    pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
933 afcc3cdf ths
    usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
934 53b67b30 Blue Swirl
    smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_reserve_irq(9),
935 53b67b30 Blue Swirl
                          NULL, NULL, 0);
936 7b717336 ths
    eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
937 7b717336 ths
    for (i = 0; i < 8; i++) {
938 7b717336 ths
        /* TODO: Populate SPD eeprom data.  */
939 1ea96673 Paul Brook
        DeviceState *eeprom;
940 02e2da45 Paul Brook
        eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
941 5b7f5327 Juan Quintela
        qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
942 ee6847d1 Gerd Hoffmann
        qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
943 e23a1b33 Markus Armbruster
        qdev_init_nofail(eeprom);
944 7b717336 ths
    }
945 ae027ad3 Stefan Weil
    pit = pit_init(0x40, isa_reserve_irq(0));
946 5856de80 ths
    DMA_init(0);
947 5856de80 ths
948 5856de80 ths
    /* Super I/O */
949 2e15e23b Gerd Hoffmann
    isa_dev = isa_create_simple("i8042");
950 ae027ad3 Stefan Weil
 
951 32e0c826 Gerd Hoffmann
    rtc_state = rtc_init(2000);
952 ac0be998 Gerd Hoffmann
    serial_isa_init(0, serial_hds[0]);
953 ac0be998 Gerd Hoffmann
    serial_isa_init(1, serial_hds[1]);
954 7bcc17dc ths
    if (parallel_hds[0])
955 021f0674 Gerd Hoffmann
        parallel_init(0, parallel_hds[0]);
956 e4bcb14c ths
    for(i = 0; i < MAX_FD; i++) {
957 fd8014e1 Gerd Hoffmann
        fd[i] = drive_get(IF_FLOPPY, 0, i);
958 e4bcb14c ths
    }
959 86c86157 Gerd Hoffmann
    floppy_controller = fdctrl_init_isa(fd);
960 5856de80 ths
961 5856de80 ths
    /* Sound card */
962 5856de80 ths
#ifdef HAS_AUDIO
963 5856de80 ths
    audio_init(pci_bus);
964 5856de80 ths
#endif
965 5856de80 ths
966 5856de80 ths
    /* Network card */
967 5607c388 Markus Armbruster
    network_init();
968 11f29511 ths
969 11f29511 ths
    /* Optional PCI video card */
970 1f605a76 aurel32
    if (cirrus_vga_enabled) {
971 fbe1b595 Paul Brook
        pci_cirrus_vga_init(pci_bus);
972 1f605a76 aurel32
    } else if (vmsvga_enabled) {
973 fbe1b595 Paul Brook
        pci_vmsvga_init(pci_bus);
974 1f605a76 aurel32
    } else if (std_vga_enabled) {
975 fbe1b595 Paul Brook
        pci_vga_init(pci_bus, 0, 0);
976 1f605a76 aurel32
    }
977 5856de80 ths
}
978 5856de80 ths
979 f80f9ec9 Anthony Liguori
static QEMUMachine mips_malta_machine = {
980 eec2743e ths
    .name = "malta",
981 eec2743e ths
    .desc = "MIPS Malta Core LV",
982 eec2743e ths
    .init = mips_malta_init,
983 0c257437 Anthony Liguori
    .is_default = 1,
984 5856de80 ths
};
985 f80f9ec9 Anthony Liguori
986 f80f9ec9 Anthony Liguori
static void mips_malta_machine_init(void)
987 f80f9ec9 Anthony Liguori
{
988 f80f9ec9 Anthony Liguori
    qemu_register_machine(&mips_malta_machine);
989 f80f9ec9 Anthony Liguori
}
990 f80f9ec9 Anthony Liguori
991 f80f9ec9 Anthony Liguori
machine_init(mips_malta_machine_init);