Statistics
| Branch: | Revision:

root / hw / mips_malta.c @ 70705261

History | View | Annotate | Download (15.9 kB)

1
/*
2
 * QEMU Malta board support
3
 *
4
 * Copyright (c) 2006 Aurelien Jarno
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

    
25
#include "vl.h"
26

    
27
#ifdef TARGET_WORDS_BIGENDIAN
28
#define BIOS_FILENAME "mips_bios.bin"
29
#else
30
#define BIOS_FILENAME "mipsel_bios.bin"
31
#endif
32

    
33
#ifdef MIPS_HAS_MIPS64
34
#define INITRD_LOAD_ADDR         (int64_t)0x80800000
35
#else
36
#define INITRD_LOAD_ADDR         (int32_t)0x80800000
37
#endif
38

    
39
#define ENVP_ADDR                (int32_t)0x80002000
40
#define VIRT_TO_PHYS_ADDEND         (-((int64_t)(int32_t)0x80000000))
41

    
42
#define ENVP_NB_ENTRIES                 16
43
#define ENVP_ENTRY_SIZE                 256
44

    
45

    
46
extern FILE *logfile;
47

    
48
typedef struct {
49
    uint32_t leds;
50
    uint32_t brk;
51
    uint32_t gpout;
52
    uint32_t i2coe;
53
    uint32_t i2cout;
54
    uint32_t i2csel;
55
    CharDriverState *display;
56
    char display_text[9];
57
} MaltaFPGAState;
58

    
59
static PITState *pit;
60

    
61
/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
62
static void pic_irq_request(void *opaque, int level)
63
{
64
    cpu_mips_irq_request(opaque, 2, level);
65
}
66

    
67
/* Malta FPGA */
68
static void malta_fpga_update_display(void *opaque)
69
{
70
    char leds_text[9];
71
    int i;
72
    MaltaFPGAState *s = opaque;
73

    
74
    for (i = 7 ; i >= 0 ; i--) {
75
        if (s->leds & (1 << i))
76
            leds_text[i] = '#';
77
        else
78
            leds_text[i] = ' ';
79
    }
80
    leds_text[8] = '\0';
81

    
82
    qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
83
    qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
84
}
85

    
86
static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
87
{
88
    MaltaFPGAState *s = opaque;
89
    uint32_t val = 0;
90
    uint32_t saddr;
91

    
92
    saddr = (addr & 0xfffff);
93

    
94
    switch (saddr) {
95

    
96
    /* SWITCH Register */
97
    case 0x00200:
98
        val = 0x00000000;                /* All switches closed */
99
        break;
100

    
101
    /* STATUS Register */
102
    case 0x00208:
103
#ifdef TARGET_WORDS_BIGENDIAN
104
        val = 0x00000012;
105
#else
106
        val = 0x00000010;
107
#endif
108
        break;
109

    
110
    /* JMPRS Register */
111
    case 0x00210:
112
        val = 0x00;
113
        break;
114

    
115
    /* LEDBAR Register */
116
    case 0x00408:
117
        val = s->leds;
118
        break;
119

    
120
    /* BRKRES Register */
121
    case 0x00508:
122
        val = s->brk;
123
        break;
124

    
125
    /* GPOUT Register */
126
    case 0x00a00:
127
        val = s->gpout;
128
        break;
129

    
130
    /* XXX: implement a real I2C controller */
131

    
132
    /* GPINP Register */
133
    case 0x00a08:
134
        /* IN = OUT until a real I2C control is implemented */
135
        if (s->i2csel)
136
            val = s->i2cout;
137
        else
138
            val = 0x00;
139
        break;
140

    
141
    /* I2CINP Register */
142
    case 0x00b00:
143
        val = 0x00000003;
144
        break;
145

    
146
    /* I2COE Register */
147
    case 0x00b08:
148
        val = s->i2coe;
149
        break;
150

    
151
    /* I2COUT Register */
152
    case 0x00b10:
153
        val = s->i2cout;
154
        break;
155

    
156
    /* I2CSEL Register */
157
    case 0x00b18:
158
        val = s->i2cout;
159
        break;
160

    
161
    default:
162
#if 0
163
        printf ("malta_fpga_read: Bad register offset 0x" TLSZ "\n",
164
                addr);
165
#endif
166
        break;
167
    }
168
    return val;
169
}
170

    
171
static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
172
                              uint32_t val)
173
{
174
    MaltaFPGAState *s = opaque;
175
    uint32_t saddr;
176

    
177
    saddr = (addr & 0xfffff);
178

    
179
    switch (saddr) {
180

    
181
    /* SWITCH Register */
182
    case 0x00200:
183
        break;
184

    
185
    /* JMPRS Register */
186
    case 0x00210:
187
        break;
188

    
189
    /* LEDBAR Register */
190
    /* XXX: implement a 8-LED array */
191
    case 0x00408:
192
        s->leds = val & 0xff;
193
        break;
194

    
195
    /* ASCIIWORD Register */
196
    case 0x00410:
197
        snprintf(s->display_text, 9, "%08X", val);
198
        malta_fpga_update_display(s);
199
        break;
200

    
201
    /* ASCIIPOS0 to ASCIIPOS7 Registers */
202
    case 0x00418:
203
    case 0x00420:
204
    case 0x00428:
205
    case 0x00430:
206
    case 0x00438:
207
    case 0x00440:
208
    case 0x00448:
209
    case 0x00450:
210
        s->display_text[(saddr - 0x00418) >> 3] = (char) val;
211
        malta_fpga_update_display(s);
212
        break;
213

    
214
    /* SOFTRES Register */
215
    case 0x00500:
216
        if (val == 0x42)
217
            qemu_system_reset_request ();
218
        break;
219

    
220
    /* BRKRES Register */
221
    case 0x00508:
222
        s->brk = val & 0xff;
223
        break;
224

    
225
    /* GPOUT Register */
226
    case 0x00a00:
227
        s->gpout = val & 0xff;
228
        break;
229

    
230
    /* I2COE Register */
231
    case 0x00b08:
232
        s->i2coe = val & 0x03;
233
        break;
234

    
235
    /* I2COUT Register */
236
    case 0x00b10:
237
        s->i2cout = val & 0x03;
238
        break;
239

    
240
    /* I2CSEL Register */
241
    case 0x00b18:
242
        s->i2cout = val & 0x01;
243
        break;
244

    
245
    default:
246
#if 0
247
        printf ("malta_fpga_write: Bad register offset 0x" TLSZ "\n",
248
                addr);
249
#endif
250
        break;
251
    }
252
}
253

    
254
static CPUReadMemoryFunc *malta_fpga_read[] = {
255
   malta_fpga_readl,
256
   malta_fpga_readl,
257
   malta_fpga_readl
258
};
259

    
260
static CPUWriteMemoryFunc *malta_fpga_write[] = {
261
   malta_fpga_writel,
262
   malta_fpga_writel,
263
   malta_fpga_writel
264
};
265

    
266
void malta_fpga_reset(void *opaque)
267
{
268
    MaltaFPGAState *s = opaque;
269

    
270
    s->leds   = 0x00;
271
    s->brk    = 0x0a;
272
    s->gpout  = 0x00;
273
    s->i2coe  = 0x0;
274
    s->i2cout = 0x3;
275
    s->i2csel = 0x1;
276

    
277
    s->display_text[8] = '\0';
278
    snprintf(s->display_text, 9, "        ");
279
    malta_fpga_update_display(s);
280
}
281

    
282
MaltaFPGAState *malta_fpga_init(target_phys_addr_t base)
283
{
284
    MaltaFPGAState *s;
285
    int malta;
286

    
287
    s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
288

    
289
    malta = cpu_register_io_memory(0, malta_fpga_read,
290
                                   malta_fpga_write, s);
291
    cpu_register_physical_memory(base, 0x100000, malta);
292

    
293
    s->display = qemu_chr_open("vc");
294
    qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n");
295
    qemu_chr_printf(s->display, "+--------+\r\n");
296
    qemu_chr_printf(s->display, "+        +\r\n");
297
    qemu_chr_printf(s->display, "+--------+\r\n");
298
    qemu_chr_printf(s->display, "\n");
299
    qemu_chr_printf(s->display, "Malta ASCII\r\n");
300
    qemu_chr_printf(s->display, "+--------+\r\n");
301
    qemu_chr_printf(s->display, "+        +\r\n");
302
    qemu_chr_printf(s->display, "+--------+\r\n");
303

    
304
    malta_fpga_reset(s);
305
    qemu_register_reset(malta_fpga_reset, s);
306

    
307
    return s;
308
}
309

    
310
/* Audio support */
311
#ifdef HAS_AUDIO
312
static void audio_init (PCIBus *pci_bus)
313
{
314
    struct soundhw *c;
315
    int audio_enabled = 0;
316

    
317
    for (c = soundhw; !audio_enabled && c->name; ++c) {
318
        audio_enabled = c->enabled;
319
    }
320

    
321
    if (audio_enabled) {
322
        AudioState *s;
323

    
324
        s = AUD_init ();
325
        if (s) {
326
            for (c = soundhw; c->name; ++c) {
327
                if (c->enabled) {
328
                    if (c->isa) {
329
                        fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name);
330
                        exit(1);
331
                    }
332
                    else {
333
                        if (pci_bus) {
334
                            c->init.init_pci (pci_bus, s);
335
                        }
336
                    }
337
                }
338
            }
339
        }
340
    }
341
}
342
#endif
343

    
344
/* Network support */
345
static void network_init (PCIBus *pci_bus)
346
{
347
    int i;
348
    NICInfo *nd;
349

    
350
    for(i = 0; i < nb_nics; i++) {
351
        nd = &nd_table[i];
352
        if (!nd->model) {
353
            nd->model = "pcnet";
354
        }
355
        if (i == 0  && strcmp(nd->model, "pcnet") == 0) {
356
            /* The malta board has a PCNet card using PCI SLOT 11 */
357
            pci_nic_init(pci_bus, nd, 88);
358
        } else {
359
            pci_nic_init(pci_bus, nd, -1);
360
        }
361
    }
362
}
363

    
364
/* ROM and pseudo bootloader
365

366
   The following code implements a very very simple bootloader. It first
367
   loads the registers a0 to a3 to the values expected by the OS, and
368
   then jump at the kernel address.
369

370
   The bootloader should pass the locations of the kernel arguments and
371
   environment variables tables. Those tables contain the 32-bit address
372
   of NULL terminated strings. The environment variables table should be
373
   terminated by a NULL address.
374

375
   For a simpler implementation, the number of kernel arguments is fixed
376
   to two (the name of the kernel and the command line), and the two
377
   tables are actually the same one.
378

379
   The registers a0 to a3 should contain the following values:
380
     a0 - number of kernel arguments
381
     a1 - 32-bit address of the kernel arguments table
382
     a2 - 32-bit address of the environment variables table
383
     a3 - RAM size in bytes
384
*/
385

    
386
static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr)
387
{
388
    uint32_t *p;
389

    
390
    /* Small bootloader */
391
    p = (uint32_t *) (phys_ram_base + bios_offset);
392
    stl_raw(p++, 0x0bf00010);                                      /* j 0x1fc00040 */
393
    stl_raw(p++, 0x00000000);                                      /* nop */
394

    
395
    /* Second part of the bootloader */
396
    p = (uint32_t *) (phys_ram_base + bios_offset + 0x040);
397
    stl_raw(p++, 0x3c040000);                                      /* lui a0, 0 */
398
    stl_raw(p++, 0x34840002);                                      /* ori a0, a0, 2 */
399
    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
400
    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a0, low(ENVP_ADDR) */
401
    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
402
    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
403
    stl_raw(p++, 0x3c070000 | (env->ram_size >> 16));              /* lui a3, high(env->ram_size) */
404
    stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff));           /* ori a3, a3, low(env->ram_size) */
405
    stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff));     /* lui ra, high(kernel_addr) */;
406
    stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff));             /* ori ra, ra, low(kernel_addr) */
407
    stl_raw(p++, 0x03e00008);                                      /* jr ra */
408
    stl_raw(p++, 0x00000000);                                      /* nop */
409
}
410

    
411
static void prom_set(int index, const char *string, ...)
412
{
413
    va_list ap;
414
    int32_t *p;
415
    int32_t table_addr;
416
    char *s;
417

    
418
    if (index >= ENVP_NB_ENTRIES)
419
        return;
420

    
421
    p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
422
    p += index;
423

    
424
    if (string == NULL) {
425
        stl_raw(p, 0);
426
        return;
427
    }
428

    
429
    table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
430
    s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
431

    
432
    stl_raw(p, table_addr);
433

    
434
    va_start(ap, string);
435
    vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
436
    va_end(ap);
437
}
438

    
439
/* Kernel */
440
static int64_t load_kernel (CPUState *env)
441
{
442
    int64_t kernel_addr = 0;
443
    int index = 0;
444
    long initrd_size;
445

    
446
    if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) {
447
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
448
                env->kernel_filename);
449
      exit(1);
450
    }
451

    
452
    /* load initrd */
453
    initrd_size = 0;
454
    if (env->initrd_filename) {
455
        initrd_size = load_image(env->initrd_filename,
456
                                 phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
457
        if (initrd_size == (target_ulong) -1) {
458
            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
459
                    env->initrd_filename);
460
            exit(1);
461
        }
462
    }
463

    
464
    /* Store command line.  */
465
    prom_set(index++, env->kernel_filename);
466
    if (initrd_size > 0)
467
        prom_set(index++, "rd_start=0x" TLSZ " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline);
468
    else
469
        prom_set(index++, env->kernel_cmdline);
470

    
471
    /* Setup minimum environment variables */
472
    prom_set(index++, "memsize");
473
    prom_set(index++, "%i", env->ram_size);
474
    prom_set(index++, "modetty0");
475
    prom_set(index++, "38400n8r");
476
    prom_set(index++, NULL);
477

    
478
    return kernel_addr;
479
}
480

    
481
static void main_cpu_reset(void *opaque)
482
{
483
    CPUState *env = opaque;
484
    cpu_reset(env);
485

    
486
    /* The bootload does not need to be rewritten as it is located in a
487
       read only location. The kernel location and the arguments table
488
       location does not change. */
489
    if (env->kernel_filename)
490
        load_kernel (env);
491
}
492

    
493
static
494
void mips_malta_init (int ram_size, int vga_ram_size, int boot_device,
495
                      DisplayState *ds, const char **fd_filename, int snapshot,
496
                      const char *kernel_filename, const char *kernel_cmdline,
497
                      const char *initrd_filename)
498
{
499
    char buf[1024];
500
    unsigned long bios_offset;
501
    int64_t kernel_addr;
502
    PCIBus *pci_bus;
503
    CPUState *env;
504
    RTCState *rtc_state;
505
    /* fdctrl_t *floppy_controller; */
506
    MaltaFPGAState *malta_fpga;
507
    int ret;
508

    
509
    env = cpu_init();
510
    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
511
    qemu_register_reset(main_cpu_reset, env);
512

    
513
    /* allocate RAM */
514
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
515

    
516
    /* Map the bios at two physical locations, as on the real board */
517
    bios_offset = ram_size + vga_ram_size;
518
    cpu_register_physical_memory(0x1e000000LL,
519
                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
520
    cpu_register_physical_memory(0x1fc00000LL,
521
                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
522

    
523
    /* Load a BIOS image except if a kernel image has been specified. In
524
       the later case, just write a small bootloader to the flash
525
       location. */
526
    if (kernel_filename) {
527
        env->ram_size = ram_size;
528
        env->kernel_filename = kernel_filename;
529
        env->kernel_cmdline = kernel_cmdline;
530
        env->initrd_filename = initrd_filename;
531
        kernel_addr = load_kernel(env);
532
        write_bootloader(env, bios_offset, kernel_addr);
533
    } else {
534
        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
535
        ret = load_image(buf, phys_ram_base + bios_offset);
536
        if (ret != BIOS_SIZE) {
537
            fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
538
                    buf);
539
            exit(1);
540
        }
541
    }
542

    
543
    /* Board ID = 0x420 (Malta Board with CoreLV)
544
       XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
545
       map to the board ID. */
546
    stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
547

    
548
    /* Init internal devices */
549
    cpu_mips_clock_init(env);
550
    cpu_mips_irqctrl_init();
551

    
552
    /* FPGA */
553
    malta_fpga = malta_fpga_init(0x1f000000LL);
554

    
555
    /* Interrupt controller */
556
    isa_pic = pic_init(pic_irq_request, env);
557

    
558
    /* Northbridge */
559
    pci_bus = pci_gt64120_init(isa_pic);
560

    
561
    /* Southbridge */
562
    piix4_init(pci_bus, 80);
563
    pci_piix3_ide_init(pci_bus, bs_table, 81);
564
    usb_uhci_init(pci_bus, 82);
565
    piix4_pm_init(pci_bus, 83);
566
    pit = pit_init(0x40, 0);
567
    DMA_init(0);
568

    
569
    /* Super I/O */
570
    kbd_init();
571
    rtc_state = rtc_init(0x70, 8);
572
    serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
573
    parallel_init(0x378, 7, parallel_hds[0]);
574
    /* XXX: The floppy controller does not work correctly, something is
575
       probably wrong.
576
    floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */
577

    
578
    /* Sound card */
579
#ifdef HAS_AUDIO
580
    audio_init(pci_bus);
581
#endif
582

    
583
    /* Network card */
584
    network_init(pci_bus);
585
}
586

    
587
QEMUMachine mips_malta_machine = {
588
    "malta",
589
    "MIPS Malta Core LV",
590
    mips_malta_init,
591
};