Statistics
| Branch: | Revision:

root / hw / mips_malta.c @ 8ec68b06

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

492 5856de80 ths
   The following code implements a very very simple bootloader. It first
493 5856de80 ths
   loads the registers a0 to a3 to the values expected by the OS, and
494 5856de80 ths
   then jump at the kernel address.
495 5856de80 ths

496 5856de80 ths
   The bootloader should pass the locations of the kernel arguments and
497 5856de80 ths
   environment variables tables. Those tables contain the 32-bit address
498 5856de80 ths
   of NULL terminated strings. The environment variables table should be
499 5856de80 ths
   terminated by a NULL address.
500 5856de80 ths

501 5856de80 ths
   For a simpler implementation, the number of kernel arguments is fixed
502 5856de80 ths
   to two (the name of the kernel and the command line), and the two
503 5856de80 ths
   tables are actually the same one.
504 5856de80 ths

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