Statistics
| Branch: | Revision:

root / hw / mips_malta.c @ a1bc20df

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

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

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

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

503 5856de80 ths
   The registers a0 to a3 should contain the following values:
504 5856de80 ths
     a0 - number of kernel arguments
505 5856de80 ths
     a1 - 32-bit address of the kernel arguments table
506 5856de80 ths
     a2 - 32-bit address of the environment variables table
507 5856de80 ths
     a3 - RAM size in bytes
508 5856de80 ths
*/
509 5856de80 ths
510 61c56c8c Andreas Färber
static void write_bootloader (CPUMIPSState *env, uint8_t *base,
511 d7585251 pbrook
                              int64_t kernel_entry)
512 5856de80 ths
{
513 5856de80 ths
    uint32_t *p;
514 5856de80 ths
515 5856de80 ths
    /* Small bootloader */
516 d7585251 pbrook
    p = (uint32_t *)base;
517 26ea0918 ths
    stl_raw(p++, 0x0bf00160);                                      /* j 0x1fc00580 */
518 3ddd0065 ths
    stl_raw(p++, 0x00000000);                                      /* nop */
519 5856de80 ths
520 26ea0918 ths
    /* YAMON service vector */
521 d7585251 pbrook
    stl_raw(base + 0x500, 0xbfc00580);      /* start: */
522 d7585251 pbrook
    stl_raw(base + 0x504, 0xbfc0083c);      /* print_count: */
523 d7585251 pbrook
    stl_raw(base + 0x520, 0xbfc00580);      /* start: */
524 d7585251 pbrook
    stl_raw(base + 0x52c, 0xbfc00800);      /* flush_cache: */
525 d7585251 pbrook
    stl_raw(base + 0x534, 0xbfc00808);      /* print: */
526 d7585251 pbrook
    stl_raw(base + 0x538, 0xbfc00800);      /* reg_cpu_isr: */
527 d7585251 pbrook
    stl_raw(base + 0x53c, 0xbfc00800);      /* unred_cpu_isr: */
528 d7585251 pbrook
    stl_raw(base + 0x540, 0xbfc00800);      /* reg_ic_isr: */
529 d7585251 pbrook
    stl_raw(base + 0x544, 0xbfc00800);      /* unred_ic_isr: */
530 d7585251 pbrook
    stl_raw(base + 0x548, 0xbfc00800);      /* reg_esr: */
531 d7585251 pbrook
    stl_raw(base + 0x54c, 0xbfc00800);      /* unreg_esr: */
532 d7585251 pbrook
    stl_raw(base + 0x550, 0xbfc00800);      /* getchar: */
533 d7585251 pbrook
    stl_raw(base + 0x554, 0xbfc00800);      /* syscon_read: */
534 26ea0918 ths
535 26ea0918 ths
536 5856de80 ths
    /* Second part of the bootloader */
537 d7585251 pbrook
    p = (uint32_t *) (base + 0x580);
538 d52fff71 ths
    stl_raw(p++, 0x24040002);                                      /* addiu a0, zero, 2 */
539 d52fff71 ths
    stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
540 471ea271 ths
    stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
541 3ddd0065 ths
    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
542 471ea271 ths
    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a1, low(ENVP_ADDR) */
543 3ddd0065 ths
    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
544 3ddd0065 ths
    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
545 7df526e3 ths
    stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16));     /* lui a3, high(ram_size) */
546 7df526e3 ths
    stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));  /* ori a3, a3, low(ram_size) */
547 2802bfe3 ths
548 2802bfe3 ths
    /* Load BAR registers as done by YAMON */
549 a0a8793e ths
    stl_raw(p++, 0x3c09b400);                                      /* lui t1, 0xb400 */
550 a0a8793e ths
551 a0a8793e ths
#ifdef TARGET_WORDS_BIGENDIAN
552 a0a8793e ths
    stl_raw(p++, 0x3c08df00);                                      /* lui t0, 0xdf00 */
553 a0a8793e ths
#else
554 a0a8793e ths
    stl_raw(p++, 0x340800df);                                      /* ori t0, r0, 0x00df */
555 a0a8793e ths
#endif
556 a0a8793e ths
    stl_raw(p++, 0xad280068);                                      /* sw t0, 0x0068(t1) */
557 a0a8793e ths
558 2802bfe3 ths
    stl_raw(p++, 0x3c09bbe0);                                      /* lui t1, 0xbbe0 */
559 2802bfe3 ths
560 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
561 2802bfe3 ths
    stl_raw(p++, 0x3c08c000);                                      /* lui t0, 0xc000 */
562 2802bfe3 ths
#else
563 2802bfe3 ths
    stl_raw(p++, 0x340800c0);                                      /* ori t0, r0, 0x00c0 */
564 2802bfe3 ths
#endif
565 2802bfe3 ths
    stl_raw(p++, 0xad280048);                                      /* sw t0, 0x0048(t1) */
566 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
567 2802bfe3 ths
    stl_raw(p++, 0x3c084000);                                      /* lui t0, 0x4000 */
568 2802bfe3 ths
#else
569 2802bfe3 ths
    stl_raw(p++, 0x34080040);                                      /* ori t0, r0, 0x0040 */
570 2802bfe3 ths
#endif
571 2802bfe3 ths
    stl_raw(p++, 0xad280050);                                      /* sw t0, 0x0050(t1) */
572 2802bfe3 ths
573 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
574 2802bfe3 ths
    stl_raw(p++, 0x3c088000);                                      /* lui t0, 0x8000 */
575 2802bfe3 ths
#else
576 2802bfe3 ths
    stl_raw(p++, 0x34080080);                                      /* ori t0, r0, 0x0080 */
577 2802bfe3 ths
#endif
578 2802bfe3 ths
    stl_raw(p++, 0xad280058);                                      /* sw t0, 0x0058(t1) */
579 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
580 2802bfe3 ths
    stl_raw(p++, 0x3c083f00);                                      /* lui t0, 0x3f00 */
581 2802bfe3 ths
#else
582 2802bfe3 ths
    stl_raw(p++, 0x3408003f);                                      /* ori t0, r0, 0x003f */
583 2802bfe3 ths
#endif
584 2802bfe3 ths
    stl_raw(p++, 0xad280060);                                      /* sw t0, 0x0060(t1) */
585 2802bfe3 ths
586 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
587 2802bfe3 ths
    stl_raw(p++, 0x3c08c100);                                      /* lui t0, 0xc100 */
588 2802bfe3 ths
#else
589 2802bfe3 ths
    stl_raw(p++, 0x340800c1);                                      /* ori t0, r0, 0x00c1 */
590 2802bfe3 ths
#endif
591 2802bfe3 ths
    stl_raw(p++, 0xad280080);                                      /* sw t0, 0x0080(t1) */
592 2802bfe3 ths
#ifdef TARGET_WORDS_BIGENDIAN
593 2802bfe3 ths
    stl_raw(p++, 0x3c085e00);                                      /* lui t0, 0x5e00 */
594 2802bfe3 ths
#else
595 2802bfe3 ths
    stl_raw(p++, 0x3408005e);                                      /* ori t0, r0, 0x005e */
596 2802bfe3 ths
#endif
597 2802bfe3 ths
    stl_raw(p++, 0xad280088);                                      /* sw t0, 0x0088(t1) */
598 2802bfe3 ths
599 2802bfe3 ths
    /* Jump to kernel code */
600 74287114 ths
    stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff));    /* lui ra, high(kernel_entry) */
601 74287114 ths
    stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff));            /* ori ra, ra, low(kernel_entry) */
602 3ddd0065 ths
    stl_raw(p++, 0x03e00008);                                      /* jr ra */
603 3ddd0065 ths
    stl_raw(p++, 0x00000000);                                      /* nop */
604 26ea0918 ths
605 26ea0918 ths
    /* YAMON subroutines */
606 d7585251 pbrook
    p = (uint32_t *) (base + 0x800);
607 26ea0918 ths
    stl_raw(p++, 0x03e00008);                                     /* jr ra */
608 26ea0918 ths
    stl_raw(p++, 0x24020000);                                     /* li v0,0 */
609 26ea0918 ths
   /* 808 YAMON print */
610 26ea0918 ths
    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
611 26ea0918 ths
    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
612 26ea0918 ths
    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
613 26ea0918 ths
    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
614 26ea0918 ths
    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
615 26ea0918 ths
    stl_raw(p++, 0x10800005);                                     /* beqz a0,834 */
616 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
617 26ea0918 ths
    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
618 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
619 26ea0918 ths
    stl_raw(p++, 0x08000205);                                     /* j 814 */
620 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
621 26ea0918 ths
    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
622 26ea0918 ths
    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
623 26ea0918 ths
    /* 0x83c YAMON print_count */
624 26ea0918 ths
    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
625 26ea0918 ths
    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
626 26ea0918 ths
    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
627 26ea0918 ths
    stl_raw(p++, 0x00c06021);                                     /* move t4,a2 */
628 26ea0918 ths
    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
629 26ea0918 ths
    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
630 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
631 26ea0918 ths
    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
632 26ea0918 ths
    stl_raw(p++, 0x258cffff);                                     /* addiu t4,t4,-1 */
633 26ea0918 ths
    stl_raw(p++, 0x1580fffa);                                     /* bnez t4,84c */
634 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
635 26ea0918 ths
    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
636 26ea0918 ths
    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
637 26ea0918 ths
    /* 0x870 */
638 26ea0918 ths
    stl_raw(p++, 0x3c08b800);                                     /* lui t0,0xb400 */
639 26ea0918 ths
    stl_raw(p++, 0x350803f8);                                     /* ori t0,t0,0x3f8 */
640 26ea0918 ths
    stl_raw(p++, 0x91090005);                                     /* lbu t1,5(t0) */
641 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
642 26ea0918 ths
    stl_raw(p++, 0x31290040);                                     /* andi t1,t1,0x40 */
643 26ea0918 ths
    stl_raw(p++, 0x1120fffc);                                     /* beqz t1,878 <outch+0x8> */
644 26ea0918 ths
    stl_raw(p++, 0x00000000);                                     /* nop */
645 26ea0918 ths
    stl_raw(p++, 0x03e00008);                                     /* jr ra */
646 26ea0918 ths
    stl_raw(p++, 0xa1040000);                                     /* sb a0,0(t0) */
647 26ea0918 ths
648 5856de80 ths
}
649 5856de80 ths
650 8b7968f7 Stefan Weil
static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
651 8b7968f7 Stefan Weil
                                        const char *string, ...)
652 5856de80 ths
{
653 5856de80 ths
    va_list ap;
654 3ddd0065 ths
    int32_t table_addr;
655 5856de80 ths
656 5856de80 ths
    if (index >= ENVP_NB_ENTRIES)
657 5856de80 ths
        return;
658 5856de80 ths
659 5856de80 ths
    if (string == NULL) {
660 c938ada2 Aurelien Jarno
        prom_buf[index] = 0;
661 5856de80 ths
        return;
662 5856de80 ths
    }
663 5856de80 ths
664 c938ada2 Aurelien Jarno
    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
665 c938ada2 Aurelien Jarno
    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
666 5856de80 ths
667 5856de80 ths
    va_start(ap, string);
668 c938ada2 Aurelien Jarno
    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
669 5856de80 ths
    va_end(ap);
670 5856de80 ths
}
671 5856de80 ths
672 5856de80 ths
/* Kernel */
673 e16ad5b0 Aurelien Jarno
static int64_t load_kernel (void)
674 5856de80 ths
{
675 409dbce5 Aurelien Jarno
    int64_t kernel_entry, kernel_high;
676 5856de80 ths
    long initrd_size;
677 c227f099 Anthony Liguori
    ram_addr_t initrd_offset;
678 ca20cf32 Blue Swirl
    int big_endian;
679 c938ada2 Aurelien Jarno
    uint32_t *prom_buf;
680 c938ada2 Aurelien Jarno
    long prom_size;
681 c938ada2 Aurelien Jarno
    int prom_index = 0;
682 ca20cf32 Blue Swirl
683 ca20cf32 Blue Swirl
#ifdef TARGET_WORDS_BIGENDIAN
684 ca20cf32 Blue Swirl
    big_endian = 1;
685 ca20cf32 Blue Swirl
#else
686 ca20cf32 Blue Swirl
    big_endian = 0;
687 ca20cf32 Blue Swirl
#endif
688 5856de80 ths
689 409dbce5 Aurelien Jarno
    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
690 409dbce5 Aurelien Jarno
                 (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
691 409dbce5 Aurelien Jarno
                 big_endian, ELF_MACHINE, 1) < 0) {
692 5856de80 ths
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
693 7df526e3 ths
                loaderparams.kernel_filename);
694 acdf72bb ths
        exit(1);
695 5856de80 ths
    }
696 5856de80 ths
697 5856de80 ths
    /* load initrd */
698 5856de80 ths
    initrd_size = 0;
699 74287114 ths
    initrd_offset = 0;
700 7df526e3 ths
    if (loaderparams.initrd_filename) {
701 7df526e3 ths
        initrd_size = get_image_size (loaderparams.initrd_filename);
702 74287114 ths
        if (initrd_size > 0) {
703 74287114 ths
            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
704 7df526e3 ths
            if (initrd_offset + initrd_size > ram_size) {
705 74287114 ths
                fprintf(stderr,
706 74287114 ths
                        "qemu: memory too small for initial ram disk '%s'\n",
707 7df526e3 ths
                        loaderparams.initrd_filename);
708 74287114 ths
                exit(1);
709 74287114 ths
            }
710 dcac9679 pbrook
            initrd_size = load_image_targphys(loaderparams.initrd_filename,
711 dcac9679 pbrook
                                              initrd_offset,
712 dcac9679 pbrook
                                              ram_size - initrd_offset);
713 74287114 ths
        }
714 5856de80 ths
        if (initrd_size == (target_ulong) -1) {
715 5856de80 ths
            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
716 7df526e3 ths
                    loaderparams.initrd_filename);
717 5856de80 ths
            exit(1);
718 5856de80 ths
        }
719 5856de80 ths
    }
720 5856de80 ths
721 c938ada2 Aurelien Jarno
    /* Setup prom parameters. */
722 c938ada2 Aurelien Jarno
    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
723 7267c094 Anthony Liguori
    prom_buf = g_malloc(prom_size);
724 c938ada2 Aurelien Jarno
725 f36d53ef Stefan Weil
    prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
726 c938ada2 Aurelien Jarno
    if (initrd_size > 0) {
727 409dbce5 Aurelien Jarno
        prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
728 409dbce5 Aurelien Jarno
                 cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
729 7df526e3 ths
                 loaderparams.kernel_cmdline);
730 c938ada2 Aurelien Jarno
    } else {
731 f36d53ef Stefan Weil
        prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
732 c938ada2 Aurelien Jarno
    }
733 c938ada2 Aurelien Jarno
734 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "memsize");
735 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size);
736 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "modetty0");
737 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, "38400n8r");
738 c938ada2 Aurelien Jarno
    prom_set(prom_buf, prom_index++, NULL);
739 c938ada2 Aurelien Jarno
740 c938ada2 Aurelien Jarno
    rom_add_blob_fixed("prom", prom_buf, prom_size,
741 409dbce5 Aurelien Jarno
                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
742 5856de80 ths
743 74287114 ths
    return kernel_entry;
744 5856de80 ths
}
745 5856de80 ths
746 61c56c8c Andreas Färber
static void malta_mips_config(CPUMIPSState *env)
747 c4cb2578 Edgar E. Iglesias
{
748 c4cb2578 Edgar E. Iglesias
    env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) |
749 c4cb2578 Edgar E. Iglesias
                         ((smp_cpus * env->nr_threads - 1) << CP0MVPC0_PTC);
750 c4cb2578 Edgar E. Iglesias
}
751 c4cb2578 Edgar E. Iglesias
752 5856de80 ths
static void main_cpu_reset(void *opaque)
753 5856de80 ths
{
754 1004ee8d Andreas Färber
    MIPSCPU *cpu = opaque;
755 1004ee8d Andreas Färber
    CPUMIPSState *env = &cpu->env;
756 1004ee8d Andreas Färber
757 1004ee8d Andreas Färber
    cpu_reset(CPU(cpu));
758 5856de80 ths
759 5c43485f Aurelien Jarno
    /* The bootloader does not need to be rewritten as it is located in a
760 5856de80 ths
       read only location. The kernel location and the arguments table
761 5856de80 ths
       location does not change. */
762 7df526e3 ths
    if (loaderparams.kernel_filename) {
763 fb82fea0 ths
        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
764 fb82fea0 ths
    }
765 c4cb2578 Edgar E. Iglesias
766 c4cb2578 Edgar E. Iglesias
    malta_mips_config(env);
767 5856de80 ths
}
768 5856de80 ths
769 4556bd8b Blue Swirl
static void cpu_request_exit(void *opaque, int irq, int level)
770 4556bd8b Blue Swirl
{
771 61c56c8c Andreas Färber
    CPUMIPSState *env = cpu_single_env;
772 4556bd8b Blue Swirl
773 4556bd8b Blue Swirl
    if (env && level) {
774 4556bd8b Blue Swirl
        cpu_exit(env);
775 4556bd8b Blue Swirl
    }
776 4556bd8b Blue Swirl
}
777 4556bd8b Blue Swirl
778 70705261 ths
static
779 5f072e1f Eduardo Habkost
void mips_malta_init(QEMUMachineInitArgs *args)
780 5856de80 ths
{
781 5f072e1f Eduardo Habkost
    ram_addr_t ram_size = args->ram_size;
782 5f072e1f Eduardo Habkost
    const char *cpu_model = args->cpu_model;
783 5f072e1f Eduardo Habkost
    const char *kernel_filename = args->kernel_filename;
784 5f072e1f Eduardo Habkost
    const char *kernel_cmdline = args->kernel_cmdline;
785 5f072e1f Eduardo Habkost
    const char *initrd_filename = args->initrd_filename;
786 5cea8590 Paul Brook
    char *filename;
787 cfe5f011 Avi Kivity
    pflash_t *fl;
788 cfe5f011 Avi Kivity
    MemoryRegion *system_memory = get_system_memory();
789 ea85df72 Avi Kivity
    MemoryRegion *ram = g_new(MemoryRegion, 1);
790 cfe5f011 Avi Kivity
    MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1);
791 03a1a8e1 Stefan Weil
    target_long bios_size = FLASH_SIZE;
792 74287114 ths
    int64_t kernel_entry;
793 5856de80 ths
    PCIBus *pci_bus;
794 48a18b3c Hervé Poussineau
    ISABus *isa_bus;
795 7688b134 Andreas Färber
    MIPSCPU *cpu;
796 61c56c8c Andreas Färber
    CPUMIPSState *env;
797 e9b40fd3 Stefan Weil
    qemu_irq *isa_irq;
798 4556bd8b Blue Swirl
    qemu_irq *cpu_exit_irq;
799 7b717336 ths
    int piix4_devfn;
800 7b717336 ths
    i2c_bus *smbus;
801 7b717336 ths
    int i;
802 751c6a17 Gerd Hoffmann
    DriveInfo *dinfo;
803 f455e98c Gerd Hoffmann
    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
804 fd8014e1 Gerd Hoffmann
    DriveInfo *fd[MAX_FD];
805 c8b153d7 ths
    int fl_idx = 0;
806 bb4b3358 Stefan Weil
    int fl_sectors = bios_size >> 16;
807 01e0451a Anthony Liguori
    int be;
808 5856de80 ths
809 e9b40fd3 Stefan Weil
    DeviceState *dev = qdev_create(NULL, "mips-malta");
810 e9b40fd3 Stefan Weil
    MaltaState *s = DO_UPCAST(MaltaState, busdev.qdev, dev);
811 e9b40fd3 Stefan Weil
812 e9b40fd3 Stefan Weil
    qdev_init_nofail(dev);
813 e9b40fd3 Stefan Weil
814 ffabf037 Aurelien Jarno
    /* Make sure the first 3 serial ports are associated with a device. */
815 ffabf037 Aurelien Jarno
    for(i = 0; i < 3; i++) {
816 ffabf037 Aurelien Jarno
        if (!serial_hds[i]) {
817 ffabf037 Aurelien Jarno
            char label[32];
818 ffabf037 Aurelien Jarno
            snprintf(label, sizeof(label), "serial%d", i);
819 27143a44 Anthony Liguori
            serial_hds[i] = qemu_chr_new(label, "null", NULL);
820 ffabf037 Aurelien Jarno
        }
821 ffabf037 Aurelien Jarno
    }
822 ffabf037 Aurelien Jarno
823 33d68b5f ths
    /* init CPUs */
824 33d68b5f ths
    if (cpu_model == NULL) {
825 60aa19ab ths
#ifdef TARGET_MIPS64
826 c9c1a064 ths
        cpu_model = "20Kc";
827 33d68b5f ths
#else
828 1c32f43e ths
        cpu_model = "24Kf";
829 33d68b5f ths
#endif
830 33d68b5f ths
    }
831 c4cb2578 Edgar E. Iglesias
832 c4cb2578 Edgar E. Iglesias
    for (i = 0; i < smp_cpus; i++) {
833 7688b134 Andreas Färber
        cpu = cpu_mips_init(cpu_model);
834 7688b134 Andreas Färber
        if (cpu == NULL) {
835 c4cb2578 Edgar E. Iglesias
            fprintf(stderr, "Unable to find CPU definition\n");
836 c4cb2578 Edgar E. Iglesias
            exit(1);
837 c4cb2578 Edgar E. Iglesias
        }
838 7688b134 Andreas Färber
        env = &cpu->env;
839 7688b134 Andreas Färber
840 c4cb2578 Edgar E. Iglesias
        /* Init internal devices */
841 c4cb2578 Edgar E. Iglesias
        cpu_mips_irq_init_cpu(env);
842 c4cb2578 Edgar E. Iglesias
        cpu_mips_clock_init(env);
843 1004ee8d Andreas Färber
        qemu_register_reset(main_cpu_reset, cpu);
844 aaed909a bellard
    }
845 c4cb2578 Edgar E. Iglesias
    env = first_cpu;
846 5856de80 ths
847 5856de80 ths
    /* allocate RAM */
848 0ccff151 aurel32
    if (ram_size > (256 << 20)) {
849 0ccff151 aurel32
        fprintf(stderr,
850 0ccff151 aurel32
                "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
851 0ccff151 aurel32
                ((unsigned int)ram_size / (1 << 20)));
852 0ccff151 aurel32
        exit(1);
853 0ccff151 aurel32
    }
854 c5705a77 Avi Kivity
    memory_region_init_ram(ram, "mips_malta.ram", ram_size);
855 c5705a77 Avi Kivity
    vmstate_register_ram_global(ram);
856 ea85df72 Avi Kivity
    memory_region_add_subregion(system_memory, 0, ram);
857 5856de80 ths
858 01e0451a Anthony Liguori
#ifdef TARGET_WORDS_BIGENDIAN
859 01e0451a Anthony Liguori
    be = 1;
860 01e0451a Anthony Liguori
#else
861 01e0451a Anthony Liguori
    be = 0;
862 01e0451a Anthony Liguori
#endif
863 070ce5ed ths
    /* FPGA */
864 03a1a8e1 Stefan Weil
    malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[2], serial_hds[2]);
865 070ce5ed ths
866 bb4b3358 Stefan Weil
    /* Load firmware in flash / BIOS. */
867 bb4b3358 Stefan Weil
    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
868 bb4b3358 Stefan Weil
#ifdef DEBUG_BOARD_INIT
869 bb4b3358 Stefan Weil
    if (dinfo) {
870 bb4b3358 Stefan Weil
        printf("Register parallel flash %d size " TARGET_FMT_lx " at "
871 bb4b3358 Stefan Weil
               "addr %08llx '%s' %x\n",
872 03a1a8e1 Stefan Weil
               fl_idx, bios_size, FLASH_ADDRESS,
873 bb4b3358 Stefan Weil
               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
874 bb4b3358 Stefan Weil
    }
875 bb4b3358 Stefan Weil
#endif
876 03a1a8e1 Stefan Weil
    fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios",
877 bb4b3358 Stefan Weil
                               BIOS_SIZE, dinfo ? dinfo->bdrv : NULL,
878 bb4b3358 Stefan Weil
                               65536, fl_sectors,
879 bb4b3358 Stefan Weil
                               4, 0x0000, 0x0000, 0x0000, 0x0000, be);
880 bb4b3358 Stefan Weil
    bios = pflash_cfi01_get_memory(fl);
881 bb4b3358 Stefan Weil
    fl_idx++;
882 c8b153d7 ths
    if (kernel_filename) {
883 c8b153d7 ths
        /* Write a small bootloader to the flash location. */
884 c8b153d7 ths
        loaderparams.ram_size = ram_size;
885 c8b153d7 ths
        loaderparams.kernel_filename = kernel_filename;
886 c8b153d7 ths
        loaderparams.kernel_cmdline = kernel_cmdline;
887 c8b153d7 ths
        loaderparams.initrd_filename = initrd_filename;
888 e16ad5b0 Aurelien Jarno
        kernel_entry = load_kernel();
889 cfe5f011 Avi Kivity
        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
890 c8b153d7 ths
    } else {
891 bb4b3358 Stefan Weil
        /* Load firmware from flash. */
892 bb4b3358 Stefan Weil
        if (!dinfo) {
893 c8b153d7 ths
            /* Load a BIOS image. */
894 bb4b3358 Stefan Weil
            if (bios_name == NULL) {
895 c8b153d7 ths
                bios_name = BIOS_FILENAME;
896 bb4b3358 Stefan Weil
            }
897 5cea8590 Paul Brook
            filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
898 5cea8590 Paul Brook
            if (filename) {
899 03a1a8e1 Stefan Weil
                bios_size = load_image_targphys(filename, FLASH_ADDRESS,
900 5cea8590 Paul Brook
                                                BIOS_SIZE);
901 7267c094 Anthony Liguori
                g_free(filename);
902 5cea8590 Paul Brook
            } else {
903 5cea8590 Paul Brook
                bios_size = -1;
904 5cea8590 Paul Brook
            }
905 c8b153d7 ths
            if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
906 c8b153d7 ths
                fprintf(stderr,
907 c8b153d7 ths
                        "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
908 5cea8590 Paul Brook
                        bios_name);
909 c8b153d7 ths
                exit(1);
910 c8b153d7 ths
            }
911 070ce5ed ths
        }
912 3187ef03 ths
        /* In little endian mode the 32bit words in the bios are swapped,
913 3187ef03 ths
           a neat trick which allows bi-endian firmware. */
914 3187ef03 ths
#ifndef TARGET_WORDS_BIGENDIAN
915 3187ef03 ths
        {
916 cfe5f011 Avi Kivity
            uint32_t *addr = memory_region_get_ram_ptr(bios);
917 d7585251 pbrook
            uint32_t *end = addr + bios_size;
918 d7585251 pbrook
            while (addr < end) {
919 d7585251 pbrook
                bswap32s(addr);
920 a30cfee5 Chen Rui
                addr++;
921 3187ef03 ths
            }
922 3187ef03 ths
        }
923 3187ef03 ths
#endif
924 070ce5ed ths
    }
925 070ce5ed ths
926 82a9807b Stefan Weil
    /* Map the BIOS at a 2nd physical location, as on the real board. */
927 82a9807b Stefan Weil
    memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE);
928 03a1a8e1 Stefan Weil
    memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_alias);
929 82a9807b Stefan Weil
930 5856de80 ths
    /* Board ID = 0x420 (Malta Board with CoreLV)
931 5856de80 ths
       XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
932 5856de80 ths
       map to the board ID. */
933 cfe5f011 Avi Kivity
    stl_p(memory_region_get_ram_ptr(bios) + 0x10, 0x00000420);
934 5856de80 ths
935 5856de80 ths
    /* Init internal devices */
936 d537cf6c pbrook
    cpu_mips_irq_init_cpu(env);
937 5856de80 ths
    cpu_mips_clock_init(env);
938 5856de80 ths
939 5632ae46 Avi Kivity
    /*
940 5632ae46 Avi Kivity
     * We have a circular dependency problem: pci_bus depends on isa_irq,
941 5632ae46 Avi Kivity
     * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
942 5632ae46 Avi Kivity
     * on piix4, and piix4 depends on pci_bus.  To stop the cycle we have
943 5632ae46 Avi Kivity
     * qemu_irq_proxy() adds an extra bit of indirection, allowing us
944 5632ae46 Avi Kivity
     * to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
945 5632ae46 Avi Kivity
     */
946 e9b40fd3 Stefan Weil
    isa_irq = qemu_irq_proxy(&s->i8259, 16);
947 5856de80 ths
948 5856de80 ths
    /* Northbridge */
949 5632ae46 Avi Kivity
    pci_bus = gt64120_register(isa_irq);
950 5856de80 ths
951 5856de80 ths
    /* Southbridge */
952 75717903 Isaku Yamahata
    ide_drive_get(hd, MAX_IDE_BUS);
953 e4bcb14c ths
954 142e9787 Hervé Poussineau
    piix4_devfn = piix4_init(pci_bus, &isa_bus, 80);
955 5632ae46 Avi Kivity
956 5632ae46 Avi Kivity
    /* Interrupt controller */
957 5632ae46 Avi Kivity
    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
958 e9b40fd3 Stefan Weil
    s->i8259 = i8259_init(isa_bus, env->irq[2]);
959 5632ae46 Avi Kivity
960 e9b40fd3 Stefan Weil
    isa_bus_irqs(isa_bus, s->i8259);
961 ae027ad3 Stefan Weil
    pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
962 afb9a60e Gerd Hoffmann
    pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
963 48a18b3c Hervé Poussineau
    smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
964 459ae5ea Gleb Natapov
                          isa_get_irq(NULL, 9), NULL, 0, NULL);
965 a88df0b9 Isaku Yamahata
    /* TODO: Populate SPD eeprom data.  */
966 a88df0b9 Isaku Yamahata
    smbus_eeprom_init(smbus, 8, NULL, 0);
967 319ba9f5 Jan Kiszka
    pit = pit_init(isa_bus, 0x40, 0, NULL);
968 4556bd8b Blue Swirl
    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
969 4556bd8b Blue Swirl
    DMA_init(0, cpu_exit_irq);
970 5856de80 ths
971 5856de80 ths
    /* Super I/O */
972 48a18b3c Hervé Poussineau
    isa_create_simple(isa_bus, "i8042");
973 49a2942d Blue Swirl
974 48a18b3c Hervé Poussineau
    rtc_init(isa_bus, 2000, NULL);
975 48a18b3c Hervé Poussineau
    serial_isa_init(isa_bus, 0, serial_hds[0]);
976 48a18b3c Hervé Poussineau
    serial_isa_init(isa_bus, 1, serial_hds[1]);
977 7bcc17dc ths
    if (parallel_hds[0])
978 48a18b3c Hervé Poussineau
        parallel_init(isa_bus, 0, parallel_hds[0]);
979 e4bcb14c ths
    for(i = 0; i < MAX_FD; i++) {
980 fd8014e1 Gerd Hoffmann
        fd[i] = drive_get(IF_FLOPPY, 0, i);
981 e4bcb14c ths
    }
982 48a18b3c Hervé Poussineau
    fdctrl_init_isa(isa_bus, fd);
983 5856de80 ths
984 5856de80 ths
    /* Sound card */
985 4a0f031d Hervé Poussineau
    audio_init(isa_bus, pci_bus);
986 5856de80 ths
987 5856de80 ths
    /* Network card */
988 5607c388 Markus Armbruster
    network_init();
989 11f29511 ths
990 11f29511 ths
    /* Optional PCI video card */
991 9c59864d Aurelien Jarno
    pci_vga_init(pci_bus);
992 5856de80 ths
}
993 5856de80 ths
994 e9b40fd3 Stefan Weil
static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
995 e9b40fd3 Stefan Weil
{
996 e9b40fd3 Stefan Weil
    return 0;
997 e9b40fd3 Stefan Weil
}
998 e9b40fd3 Stefan Weil
999 999e12bb Anthony Liguori
static void mips_malta_class_init(ObjectClass *klass, void *data)
1000 999e12bb Anthony Liguori
{
1001 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
1002 999e12bb Anthony Liguori
1003 999e12bb Anthony Liguori
    k->init = mips_malta_sysbus_device_init;
1004 999e12bb Anthony Liguori
}
1005 999e12bb Anthony Liguori
1006 39bffca2 Anthony Liguori
static TypeInfo mips_malta_device = {
1007 39bffca2 Anthony Liguori
    .name          = "mips-malta",
1008 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
1009 39bffca2 Anthony Liguori
    .instance_size = sizeof(MaltaState),
1010 39bffca2 Anthony Liguori
    .class_init    = mips_malta_class_init,
1011 e9b40fd3 Stefan Weil
};
1012 e9b40fd3 Stefan Weil
1013 f80f9ec9 Anthony Liguori
static QEMUMachine mips_malta_machine = {
1014 eec2743e ths
    .name = "malta",
1015 eec2743e ths
    .desc = "MIPS Malta Core LV",
1016 eec2743e ths
    .init = mips_malta_init,
1017 c4cb2578 Edgar E. Iglesias
    .max_cpus = 16,
1018 0c257437 Anthony Liguori
    .is_default = 1,
1019 5856de80 ths
};
1020 f80f9ec9 Anthony Liguori
1021 83f7d43a Andreas Färber
static void mips_malta_register_types(void)
1022 e9b40fd3 Stefan Weil
{
1023 39bffca2 Anthony Liguori
    type_register_static(&mips_malta_device);
1024 e9b40fd3 Stefan Weil
}
1025 e9b40fd3 Stefan Weil
1026 f80f9ec9 Anthony Liguori
static void mips_malta_machine_init(void)
1027 f80f9ec9 Anthony Liguori
{
1028 f80f9ec9 Anthony Liguori
    qemu_register_machine(&mips_malta_machine);
1029 f80f9ec9 Anthony Liguori
}
1030 f80f9ec9 Anthony Liguori
1031 83f7d43a Andreas Färber
type_init(mips_malta_register_types)
1032 f80f9ec9 Anthony Liguori
machine_init(mips_malta_machine_init);