Statistics
| Branch: | Revision:

root / hw / mips_malta.c @ a43f9c90

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

479 5856de80 ths
   The following code implements a very very simple bootloader. It first
480 5856de80 ths
   loads the registers a0 to a3 to the values expected by the OS, and
481 5856de80 ths
   then jump at the kernel address.
482 5856de80 ths

483 5856de80 ths
   The bootloader should pass the locations of the kernel arguments and
484 5856de80 ths
   environment variables tables. Those tables contain the 32-bit address
485 5856de80 ths
   of NULL terminated strings. The environment variables table should be
486 5856de80 ths
   terminated by a NULL address.
487 5856de80 ths

488 5856de80 ths
   For a simpler implementation, the number of kernel arguments is fixed
489 5856de80 ths
   to two (the name of the kernel and the command line), and the two
490 5856de80 ths
   tables are actually the same one.
491 5856de80 ths

492 5856de80 ths
   The registers a0 to a3 should contain the following values:
493 5856de80 ths
     a0 - number of kernel arguments
494 5856de80 ths
     a1 - 32-bit address of the kernel arguments table
495 5856de80 ths
     a2 - 32-bit address of the environment variables table
496 5856de80 ths
     a3 - RAM size in bytes
497 5856de80 ths
*/
498 5856de80 ths
499 d7585251 pbrook
static void write_bootloader (CPUState *env, uint8_t *base,
500 d7585251 pbrook
                              int64_t kernel_entry)
501 5856de80 ths
{
502 5856de80 ths
    uint32_t *p;
503 5856de80 ths
504 5856de80 ths
    /* Small bootloader */
505 d7585251 pbrook
    p = (uint32_t *)base;
506 26ea0918 ths
    stl_raw(p++, 0x0bf00160);                                      /* j 0x1fc00580 */
507 3ddd0065 ths
    stl_raw(p++, 0x00000000);                                      /* nop */
508 5856de80 ths
509 26ea0918 ths
    /* YAMON service vector */
510 d7585251 pbrook
    stl_raw(base + 0x500, 0xbfc00580);      /* start: */
511 d7585251 pbrook
    stl_raw(base + 0x504, 0xbfc0083c);      /* print_count: */
512 d7585251 pbrook
    stl_raw(base + 0x520, 0xbfc00580);      /* start: */
513 d7585251 pbrook
    stl_raw(base + 0x52c, 0xbfc00800);      /* flush_cache: */
514 d7585251 pbrook
    stl_raw(base + 0x534, 0xbfc00808);      /* print: */
515 d7585251 pbrook
    stl_raw(base + 0x538, 0xbfc00800);      /* reg_cpu_isr: */
516 d7585251 pbrook
    stl_raw(base + 0x53c, 0xbfc00800);      /* unred_cpu_isr: */
517 d7585251 pbrook
    stl_raw(base + 0x540, 0xbfc00800);      /* reg_ic_isr: */
518 d7585251 pbrook
    stl_raw(base + 0x544, 0xbfc00800);      /* unred_ic_isr: */
519 d7585251 pbrook
    stl_raw(base + 0x548, 0xbfc00800);      /* reg_esr: */
520 d7585251 pbrook
    stl_raw(base + 0x54c, 0xbfc00800);      /* unreg_esr: */
521 d7585251 pbrook
    stl_raw(base + 0x550, 0xbfc00800);      /* getchar: */
522 d7585251 pbrook
    stl_raw(base + 0x554, 0xbfc00800);      /* syscon_read: */
523 26ea0918 ths
524 26ea0918 ths
525 5856de80 ths
    /* Second part of the bootloader */
526 d7585251 pbrook
    p = (uint32_t *) (base + 0x580);
527 d52fff71 ths
    stl_raw(p++, 0x24040002);                                      /* addiu a0, zero, 2 */
528 d52fff71 ths
    stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
529 471ea271 ths
    stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
530 3ddd0065 ths
    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
531 471ea271 ths
    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a1, low(ENVP_ADDR) */
532 3ddd0065 ths
    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
533 3ddd0065 ths
    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
534 7df526e3 ths
    stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16));     /* lui a3, high(ram_size) */
535 7df526e3 ths
    stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));  /* ori a3, a3, low(ram_size) */
536 2802bfe3 ths
537 2802bfe3 ths
    /* Load BAR registers as done by YAMON */
538 a0a8793e ths
    stl_raw(p++, 0x3c09b400);                                      /* lui t1, 0xb400 */
539 a0a8793e ths
540 a0a8793e ths
#ifdef TARGET_WORDS_BIGENDIAN
541 a0a8793e ths
    stl_raw(p++, 0x3c08df00);                                      /* lui t0, 0xdf00 */
542 a0a8793e ths
#else
543 a0a8793e ths
    stl_raw(p++, 0x340800df);                                      /* ori t0, r0, 0x00df */
544 a0a8793e ths
#endif
545 a0a8793e ths
    stl_raw(p++, 0xad280068);                                      /* sw t0, 0x0068(t1) */
546 a0a8793e ths
547 2802bfe3 ths
    stl_raw(p++, 0x3c09bbe0);                                      /* lui t1, 0xbbe0 */
548 2802bfe3 ths
549 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
550 2802bfe3 ths
    stl_raw(p++, 0x3c08c000);                                      /* lui t0, 0xc000 */
551 2802bfe3 ths
#else
552 2802bfe3 ths
    stl_raw(p++, 0x340800c0);                                      /* ori t0, r0, 0x00c0 */
553 2802bfe3 ths
#endif
554 2802bfe3 ths
    stl_raw(p++, 0xad280048);                                      /* sw t0, 0x0048(t1) */
555 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
556 2802bfe3 ths
    stl_raw(p++, 0x3c084000);                                      /* lui t0, 0x4000 */
557 2802bfe3 ths
#else
558 2802bfe3 ths
    stl_raw(p++, 0x34080040);                                      /* ori t0, r0, 0x0040 */
559 2802bfe3 ths
#endif
560 2802bfe3 ths
    stl_raw(p++, 0xad280050);                                      /* sw t0, 0x0050(t1) */
561 2802bfe3 ths
562 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
563 2802bfe3 ths
    stl_raw(p++, 0x3c088000);                                      /* lui t0, 0x8000 */
564 2802bfe3 ths
#else
565 2802bfe3 ths
    stl_raw(p++, 0x34080080);                                      /* ori t0, r0, 0x0080 */
566 2802bfe3 ths
#endif
567 2802bfe3 ths
    stl_raw(p++, 0xad280058);                                      /* sw t0, 0x0058(t1) */
568 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
569 2802bfe3 ths
    stl_raw(p++, 0x3c083f00);                                      /* lui t0, 0x3f00 */
570 2802bfe3 ths
#else
571 2802bfe3 ths
    stl_raw(p++, 0x3408003f);                                      /* ori t0, r0, 0x003f */
572 2802bfe3 ths
#endif
573 2802bfe3 ths
    stl_raw(p++, 0xad280060);                                      /* sw t0, 0x0060(t1) */
574 2802bfe3 ths
575 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
576 2802bfe3 ths
    stl_raw(p++, 0x3c08c100);                                      /* lui t0, 0xc100 */
577 2802bfe3 ths
#else
578 2802bfe3 ths
    stl_raw(p++, 0x340800c1);                                      /* ori t0, r0, 0x00c1 */
579 2802bfe3 ths
#endif
580 2802bfe3 ths
    stl_raw(p++, 0xad280080);                                      /* sw t0, 0x0080(t1) */
581 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
582 2802bfe3 ths
    stl_raw(p++, 0x3c085e00);                                      /* lui t0, 0x5e00 */
583 2802bfe3 ths
#else
584 2802bfe3 ths
    stl_raw(p++, 0x3408005e);                                      /* ori t0, r0, 0x005e */
585 2802bfe3 ths
#endif
586 2802bfe3 ths
    stl_raw(p++, 0xad280088);                                      /* sw t0, 0x0088(t1) */
587 2802bfe3 ths
588 2802bfe3 ths
    /* Jump to kernel code */
589 74287114 ths
    stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff));    /* lui ra, high(kernel_entry) */
590 74287114 ths
    stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff));            /* ori ra, ra, low(kernel_entry) */
591 3ddd0065 ths
    stl_raw(p++, 0x03e00008);                                      /* jr ra */
592 3ddd0065 ths
    stl_raw(p++, 0x00000000);                                      /* nop */
593 26ea0918 ths
594 26ea0918 ths
    /* YAMON subroutines */
595 d7585251 pbrook
    p = (uint32_t *) (base + 0x800);
596 26ea0918 ths
    stl_raw(p++, 0x03e00008);                                     /* jr ra */
597 26ea0918 ths
    stl_raw(p++, 0x24020000);                                     /* li v0,0 */
598 26ea0918 ths
   /* 808 YAMON print */
599 26ea0918 ths
    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
600 26ea0918 ths
    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
601 26ea0918 ths
    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
602 26ea0918 ths
    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
603 26ea0918 ths
    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
604 26ea0918 ths
    stl_raw(p++, 0x10800005);                                     /* beqz a0,834 */
605 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
606 26ea0918 ths
    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
607 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
608 26ea0918 ths
    stl_raw(p++, 0x08000205);                                     /* j 814 */
609 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
610 26ea0918 ths
    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
611 26ea0918 ths
    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
612 26ea0918 ths
    /* 0x83c YAMON print_count */
613 26ea0918 ths
    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
614 26ea0918 ths
    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
615 26ea0918 ths
    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
616 26ea0918 ths
    stl_raw(p++, 0x00c06021);                                     /* move t4,a2 */
617 26ea0918 ths
    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
618 26ea0918 ths
    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
619 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
620 26ea0918 ths
    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
621 26ea0918 ths
    stl_raw(p++, 0x258cffff);                                     /* addiu t4,t4,-1 */
622 26ea0918 ths
    stl_raw(p++, 0x1580fffa);                                     /* bnez t4,84c */
623 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
624 26ea0918 ths
    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
625 26ea0918 ths
    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
626 26ea0918 ths
    /* 0x870 */
627 26ea0918 ths
    stl_raw(p++, 0x3c08b800);                                     /* lui t0,0xb400 */
628 26ea0918 ths
    stl_raw(p++, 0x350803f8);                                     /* ori t0,t0,0x3f8 */
629 26ea0918 ths
    stl_raw(p++, 0x91090005);                                     /* lbu t1,5(t0) */
630 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
631 26ea0918 ths
    stl_raw(p++, 0x31290040);                                     /* andi t1,t1,0x40 */
632 26ea0918 ths
    stl_raw(p++, 0x1120fffc);                                     /* beqz t1,878 <outch+0x8> */
633 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
634 26ea0918 ths
    stl_raw(p++, 0x03e00008);                                     /* jr ra */
635 26ea0918 ths
    stl_raw(p++, 0xa1040000);                                     /* sb a0,0(t0) */
636 26ea0918 ths
637 5856de80 ths
}
638 5856de80 ths
639 8b7968f7 Stefan Weil
static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
640 8b7968f7 Stefan Weil
                                        const char *string, ...)
641 5856de80 ths
{
642 5856de80 ths
    va_list ap;
643 3ddd0065 ths
    int32_t table_addr;
644 5856de80 ths
645 5856de80 ths
    if (index >= ENVP_NB_ENTRIES)
646 5856de80 ths
        return;
647 5856de80 ths
648 5856de80 ths
    if (string == NULL) {
649 c938ada2 Aurelien Jarno
        prom_buf[index] = 0;
650 5856de80 ths
        return;
651 5856de80 ths
    }
652 5856de80 ths
653 c938ada2 Aurelien Jarno
    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
654 c938ada2 Aurelien Jarno
    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
655 5856de80 ths
656 5856de80 ths
    va_start(ap, string);
657 c938ada2 Aurelien Jarno
    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
658 5856de80 ths
    va_end(ap);
659 5856de80 ths
}
660 5856de80 ths
661 5856de80 ths
/* Kernel */
662 e16ad5b0 Aurelien Jarno
static int64_t load_kernel (void)
663 5856de80 ths
{
664 409dbce5 Aurelien Jarno
    int64_t kernel_entry, kernel_high;
665 5856de80 ths
    long initrd_size;
666 c227f099 Anthony Liguori
    ram_addr_t initrd_offset;
667 ca20cf32 Blue Swirl
    int big_endian;
668 c938ada2 Aurelien Jarno
    uint32_t *prom_buf;
669 c938ada2 Aurelien Jarno
    long prom_size;
670 c938ada2 Aurelien Jarno
    int prom_index = 0;
671 ca20cf32 Blue Swirl
672 ca20cf32 Blue Swirl
#ifdef TARGET_WORDS_BIGENDIAN
673 ca20cf32 Blue Swirl
    big_endian = 1;
674 ca20cf32 Blue Swirl
#else
675 ca20cf32 Blue Swirl
    big_endian = 0;
676 ca20cf32 Blue Swirl
#endif
677 5856de80 ths
678 409dbce5 Aurelien Jarno
    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
679 409dbce5 Aurelien Jarno
                 (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
680 409dbce5 Aurelien Jarno
                 big_endian, ELF_MACHINE, 1) < 0) {
681 5856de80 ths
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
682 7df526e3 ths
                loaderparams.kernel_filename);
683 acdf72bb ths
        exit(1);
684 5856de80 ths
    }
685 5856de80 ths
686 5856de80 ths
    /* load initrd */
687 5856de80 ths
    initrd_size = 0;
688 74287114 ths
    initrd_offset = 0;
689 7df526e3 ths
    if (loaderparams.initrd_filename) {
690 7df526e3 ths
        initrd_size = get_image_size (loaderparams.initrd_filename);
691 74287114 ths
        if (initrd_size > 0) {
692 74287114 ths
            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
693 7df526e3 ths
            if (initrd_offset + initrd_size > ram_size) {
694 74287114 ths
                fprintf(stderr,
695 74287114 ths
                        "qemu: memory too small for initial ram disk '%s'\n",
696 7df526e3 ths
                        loaderparams.initrd_filename);
697 74287114 ths
                exit(1);
698 74287114 ths
            }
699 dcac9679 pbrook
            initrd_size = load_image_targphys(loaderparams.initrd_filename,
700 dcac9679 pbrook
                                              initrd_offset,
701 dcac9679 pbrook
                                              ram_size - initrd_offset);
702 74287114 ths
        }
703 5856de80 ths
        if (initrd_size == (target_ulong) -1) {
704 5856de80 ths
            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
705 7df526e3 ths
                    loaderparams.initrd_filename);
706 5856de80 ths
            exit(1);
707 5856de80 ths
        }
708 5856de80 ths
    }
709 5856de80 ths
710 c938ada2 Aurelien Jarno
    /* Setup prom parameters. */
711 c938ada2 Aurelien Jarno
    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
712 c938ada2 Aurelien Jarno
    prom_buf = qemu_malloc(prom_size);
713 c938ada2 Aurelien Jarno
714 f36d53ef Stefan Weil
    prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
715 c938ada2 Aurelien Jarno
    if (initrd_size > 0) {
716 409dbce5 Aurelien Jarno
        prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
717 409dbce5 Aurelien Jarno
                 cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
718 7df526e3 ths
                 loaderparams.kernel_cmdline);
719 c938ada2 Aurelien Jarno
    } else {
720 f36d53ef Stefan Weil
        prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
721 c938ada2 Aurelien Jarno
    }
722 c938ada2 Aurelien Jarno
723 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "memsize");
724 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size);
725 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "modetty0");
726 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "38400n8r");
727 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, NULL);
728 c938ada2 Aurelien Jarno
729 c938ada2 Aurelien Jarno
    rom_add_blob_fixed("prom", prom_buf, prom_size,
730 409dbce5 Aurelien Jarno
                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
731 5856de80 ths
732 74287114 ths
    return kernel_entry;
733 5856de80 ths
}
734 5856de80 ths
735 5856de80 ths
static void main_cpu_reset(void *opaque)
736 5856de80 ths
{
737 5856de80 ths
    CPUState *env = opaque;
738 5856de80 ths
    cpu_reset(env);
739 5856de80 ths
740 5c43485f Aurelien Jarno
    /* The bootloader does not need to be rewritten as it is located in a
741 5856de80 ths
       read only location. The kernel location and the arguments table
742 5856de80 ths
       location does not change. */
743 7df526e3 ths
    if (loaderparams.kernel_filename) {
744 fb82fea0 ths
        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
745 fb82fea0 ths
    }
746 5856de80 ths
}
747 5856de80 ths
748 4556bd8b Blue Swirl
static void cpu_request_exit(void *opaque, int irq, int level)
749 4556bd8b Blue Swirl
{
750 4556bd8b Blue Swirl
    CPUState *env = cpu_single_env;
751 4556bd8b Blue Swirl
752 4556bd8b Blue Swirl
    if (env && level) {
753 4556bd8b Blue Swirl
        cpu_exit(env);
754 4556bd8b Blue Swirl
    }
755 4556bd8b Blue Swirl
}
756 4556bd8b Blue Swirl
757 70705261 ths
static
758 c227f099 Anthony Liguori
void mips_malta_init (ram_addr_t ram_size,
759 3023f332 aliguori
                      const char *boot_device,
760 5856de80 ths
                      const char *kernel_filename, const char *kernel_cmdline,
761 94fc95cd j_mayer
                      const char *initrd_filename, const char *cpu_model)
762 5856de80 ths
{
763 5cea8590 Paul Brook
    char *filename;
764 c227f099 Anthony Liguori
    ram_addr_t ram_offset;
765 c227f099 Anthony Liguori
    ram_addr_t bios_offset;
766 c8b153d7 ths
    target_long bios_size;
767 74287114 ths
    int64_t kernel_entry;
768 5856de80 ths
    PCIBus *pci_bus;
769 5856de80 ths
    CPUState *env;
770 d537cf6c pbrook
    qemu_irq *i8259;
771 4556bd8b Blue Swirl
    qemu_irq *cpu_exit_irq;
772 7b717336 ths
    int piix4_devfn;
773 7b717336 ths
    uint8_t *eeprom_buf;
774 7b717336 ths
    i2c_bus *smbus;
775 7b717336 ths
    int i;
776 751c6a17 Gerd Hoffmann
    DriveInfo *dinfo;
777 f455e98c Gerd Hoffmann
    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
778 fd8014e1 Gerd Hoffmann
    DriveInfo *fd[MAX_FD];
779 c8b153d7 ths
    int fl_idx = 0;
780 c8b153d7 ths
    int fl_sectors = 0;
781 3d08ff69 Blue Swirl
    int be;
782 5856de80 ths
783 ffabf037 Aurelien Jarno
    /* Make sure the first 3 serial ports are associated with a device. */
784 ffabf037 Aurelien Jarno
    for(i = 0; i < 3; i++) {
785 ffabf037 Aurelien Jarno
        if (!serial_hds[i]) {
786 ffabf037 Aurelien Jarno
            char label[32];
787 ffabf037 Aurelien Jarno
            snprintf(label, sizeof(label), "serial%d", i);
788 ffabf037 Aurelien Jarno
            serial_hds[i] = qemu_chr_open(label, "null", NULL);
789 ffabf037 Aurelien Jarno
        }
790 ffabf037 Aurelien Jarno
    }
791 ffabf037 Aurelien Jarno
792 33d68b5f ths
    /* init CPUs */
793 33d68b5f ths
    if (cpu_model == NULL) {
794 60aa19ab ths
#ifdef TARGET_MIPS64
795 c9c1a064 ths
        cpu_model = "20Kc";
796 33d68b5f ths
#else
797 1c32f43e ths
        cpu_model = "24Kf";
798 33d68b5f ths
#endif
799 33d68b5f ths
    }
800 aaed909a bellard
    env = cpu_init(cpu_model);
801 aaed909a bellard
    if (!env) {
802 aaed909a bellard
        fprintf(stderr, "Unable to find CPU definition\n");
803 aaed909a bellard
        exit(1);
804 aaed909a bellard
    }
805 a08d4367 Jan Kiszka
    qemu_register_reset(main_cpu_reset, env);
806 5856de80 ths
807 5856de80 ths
    /* allocate RAM */
808 0ccff151 aurel32
    if (ram_size > (256 << 20)) {
809 0ccff151 aurel32
        fprintf(stderr,
810 0ccff151 aurel32
                "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
811 0ccff151 aurel32
                ((unsigned int)ram_size / (1 << 20)));
812 0ccff151 aurel32
        exit(1);
813 0ccff151 aurel32
    }
814 1724f049 Alex Williamson
    ram_offset = qemu_ram_alloc(NULL, "mips_malta.ram", ram_size);
815 1724f049 Alex Williamson
    bios_offset = qemu_ram_alloc(NULL, "mips_malta.bios", BIOS_SIZE);
816 dcac9679 pbrook
817 dcac9679 pbrook
818 dcac9679 pbrook
    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
819 5856de80 ths
820 c8b153d7 ths
    /* Map the bios at two physical locations, as on the real board. */
821 5856de80 ths
    cpu_register_physical_memory(0x1e000000LL,
822 5856de80 ths
                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
823 5856de80 ths
    cpu_register_physical_memory(0x1fc00000LL,
824 5856de80 ths
                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
825 5856de80 ths
826 3d08ff69 Blue Swirl
#ifdef TARGET_WORDS_BIGENDIAN
827 3d08ff69 Blue Swirl
    be = 1;
828 3d08ff69 Blue Swirl
#else
829 3d08ff69 Blue Swirl
    be = 0;
830 3d08ff69 Blue Swirl
#endif
831 070ce5ed ths
    /* FPGA */
832 49a2942d Blue Swirl
    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 3d08ff69 Blue Swirl
                                  4, 0x0000, 0x0000, 0x0000, 0x0000, be);
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 d30df5ce Aurelien Jarno
    stl_p(qemu_get_ram_ptr(bios_offset) + 0x10, 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 c2dd2a23 Aurelien Jarno
    pci_bus = gt64120_register(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 ee951a37 Jan Kiszka
    smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(9),
923 53b67b30 Blue Swirl
                          NULL, NULL, 0);
924 7b717336 ths
    eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
925 7b717336 ths
    for (i = 0; i < 8; i++) {
926 7b717336 ths
        /* TODO: Populate SPD eeprom data.  */
927 1ea96673 Paul Brook
        DeviceState *eeprom;
928 02e2da45 Paul Brook
        eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
929 5b7f5327 Juan Quintela
        qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
930 ee6847d1 Gerd Hoffmann
        qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
931 e23a1b33 Markus Armbruster
        qdev_init_nofail(eeprom);
932 7b717336 ths
    }
933 64d7e9a4 Blue Swirl
    pit = pit_init(0x40, 0);
934 4556bd8b Blue Swirl
    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
935 4556bd8b Blue Swirl
    DMA_init(0, cpu_exit_irq);
936 5856de80 ths
937 5856de80 ths
    /* Super I/O */
938 49a2942d Blue Swirl
    isa_create_simple("i8042");
939 49a2942d Blue Swirl
940 49a2942d Blue Swirl
    rtc_init(2000, NULL);
941 ac0be998 Gerd Hoffmann
    serial_isa_init(0, serial_hds[0]);
942 ac0be998 Gerd Hoffmann
    serial_isa_init(1, serial_hds[1]);
943 7bcc17dc ths
    if (parallel_hds[0])
944 021f0674 Gerd Hoffmann
        parallel_init(0, parallel_hds[0]);
945 e4bcb14c ths
    for(i = 0; i < MAX_FD; i++) {
946 fd8014e1 Gerd Hoffmann
        fd[i] = drive_get(IF_FLOPPY, 0, i);
947 e4bcb14c ths
    }
948 49a2942d Blue Swirl
    fdctrl_init_isa(fd);
949 5856de80 ths
950 5856de80 ths
    /* Sound card */
951 0dfa5ef9 Isaku Yamahata
    audio_init(NULL, pci_bus);
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 7ba7e49e Blue Swirl
        if (!pci_vmsvga_init(pci_bus)) {
961 7ba7e49e Blue Swirl
            fprintf(stderr, "Warning: vmware_vga not available,"
962 7ba7e49e Blue Swirl
                    " using standard VGA instead\n");
963 7ba7e49e Blue Swirl
            pci_vga_init(pci_bus);
964 7ba7e49e Blue Swirl
        }
965 1f605a76 aurel32
    } else if (std_vga_enabled) {
966 78895427 Gerd Hoffmann
        pci_vga_init(pci_bus);
967 1f605a76 aurel32
    }
968 5856de80 ths
}
969 5856de80 ths
970 f80f9ec9 Anthony Liguori
static QEMUMachine mips_malta_machine = {
971 eec2743e ths
    .name = "malta",
972 eec2743e ths
    .desc = "MIPS Malta Core LV",
973 eec2743e ths
    .init = mips_malta_init,
974 0c257437 Anthony Liguori
    .is_default = 1,
975 5856de80 ths
};
976 f80f9ec9 Anthony Liguori
977 f80f9ec9 Anthony Liguori
static void mips_malta_machine_init(void)
978 f80f9ec9 Anthony Liguori
{
979 f80f9ec9 Anthony Liguori
    qemu_register_machine(&mips_malta_machine);
980 f80f9ec9 Anthony Liguori
}
981 f80f9ec9 Anthony Liguori
982 f80f9ec9 Anthony Liguori
machine_init(mips_malta_machine_init);