Statistics
| Branch: | Revision:

root / hw / mips_malta.c @ 6d3b6d3d

History | View | Annotate | Download (33.6 kB)

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

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

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

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

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