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

26
//#define HARD_DEBUG_PPC_IO
27
//#define DEBUG_PPC_IO
28

B
bellard 已提交
29 30 31
#define KERNEL_LOAD_ADDR 0x01000000;
#define INITRD_LOAD_ADDR 0x01800000;

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
extern int loglevel;
extern FILE *logfile;

#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO)
#define DEBUG_PPC_IO
#endif

#if defined (HARD_DEBUG_PPC_IO)
#define PPC_IO_DPRINTF(fmt, args...)                     \
do {                                                     \
    if (loglevel > 0) {                                  \
        fprintf(logfile, "%s: " fmt, __func__ , ##args); \
    } else {                                             \
        printf("%s : " fmt, __func__ , ##args);          \
    }                                                    \
} while (0)
#elif defined (DEBUG_PPC_IO)
#define PPC_IO_DPRINTF(fmt, args...)                     \
do {                                                     \
    if (loglevel > 0) {                                  \
        fprintf(logfile, "%s: " fmt, __func__ , ##args); \
    }                                                    \
} while (0)
#else
#define PPC_IO_DPRINTF(fmt, args...) do { } while (0)
#endif

59
#define BIOS_FILENAME "ppc_rom.bin"
B
bellard 已提交
60
/* Constants for devices init */
61 62 63 64 65 66 67 68
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 13, 13 };

#define NE2000_NB_MAX 6

static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
69

B
bellard 已提交
70 71 72
//static PITState *pit;

/* ISA IO ports bridge */
73 74
#define PPC_IO_BASE 0x80000000

B
bellard 已提交
75 76 77 78 79
/* Speaker port 0x61 */
int speaker_data_on;
int dummy_refresh_clock;

static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
80
{
81
#if 0
B
bellard 已提交
82 83
    speaker_data_on = (val >> 1) & 1;
    pit_set_gate(pit, 2, val & 1);
84
#endif
85 86
}

B
bellard 已提交
87
static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
88
{
89
#if 0
B
bellard 已提交
90 91 92 93 94
    int out;
    out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
    dummy_refresh_clock ^= 1;
    return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
      (dummy_refresh_clock << 4);
95
#endif
B
bellard 已提交
96
    return 0;
97 98
}

B
bellard 已提交
99 100
/* PCI intack register */
/* Read-only register (?) */
B
bellard 已提交
101
static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value)
B
bellard 已提交
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
{
    //    printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value);
}

static inline uint32_t _PPC_intack_read (target_phys_addr_t addr)
{
    uint32_t retval = 0;

    if (addr == 0xBFFFFFF0)
        retval = pic_intack_read(NULL);
       //   printf("%s: 0x%08x <= %d\n", __func__, addr, retval);

    return retval;
}

B
bellard 已提交
117
static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr)
B
bellard 已提交
118 119 120 121
{
    return _PPC_intack_read(addr);
}

B
bellard 已提交
122
static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr)
123
{
B
bellard 已提交
124
#ifdef TARGET_WORDS_BIGENDIAN
B
bellard 已提交
125 126 127
    return bswap16(_PPC_intack_read(addr));
#else
    return _PPC_intack_read(addr);
B
bellard 已提交
128
#endif
129 130
}

B
bellard 已提交
131
static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr)
132
{
B
bellard 已提交
133
#ifdef TARGET_WORDS_BIGENDIAN
B
bellard 已提交
134 135 136
    return bswap32(_PPC_intack_read(addr));
#else
    return _PPC_intack_read(addr);
B
bellard 已提交
137
#endif
138 139
}

B
bellard 已提交
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
static CPUWriteMemoryFunc *PPC_intack_write[] = {
    &_PPC_intack_write,
    &_PPC_intack_write,
    &_PPC_intack_write,
};

static CPUReadMemoryFunc *PPC_intack_read[] = {
    &PPC_intack_readb,
    &PPC_intack_readw,
    &PPC_intack_readl,
};

/* PowerPC control and status registers */
#if 0 // Not used
static struct {
    /* IDs */
    uint32_t veni_devi;
    uint32_t revi;
    /* Control and status */
    uint32_t gcsr;
    uint32_t xcfr;
    uint32_t ct32;
    uint32_t mcsr;
    /* General purpose registers */
    uint32_t gprg[6];
    /* Exceptions */
    uint32_t feen;
    uint32_t fest;
    uint32_t fema;
    uint32_t fecl;
    uint32_t eeen;
    uint32_t eest;
    uint32_t eecl;
    uint32_t eeint;
    uint32_t eemck0;
    uint32_t eemck1;
    /* Error diagnostic */
} XCSR;
#endif

B
bellard 已提交
180
static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
B
bellard 已提交
181 182 183 184
{
    printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
}

B
bellard 已提交
185
static void PPC_XCSR_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
186
{
B
bellard 已提交
187
#ifdef TARGET_WORDS_BIGENDIAN
B
bellard 已提交
188
    value = bswap16(value);
B
bellard 已提交
189
#endif
B
bellard 已提交
190
    printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
191 192
}

B
bellard 已提交
193
static void PPC_XCSR_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
194
{
B
bellard 已提交
195
#ifdef TARGET_WORDS_BIGENDIAN
B
bellard 已提交
196
    value = bswap32(value);
B
bellard 已提交
197
#endif
B
bellard 已提交
198
    printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
199 200
}

B
bellard 已提交
201
static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr)
B
bellard 已提交
202 203
{
    uint32_t retval = 0;
204

B
bellard 已提交
205
    printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
206

B
bellard 已提交
207 208 209
    return retval;
}

B
bellard 已提交
210
static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr)
211
{
B
bellard 已提交
212 213 214 215 216 217 218 219
    uint32_t retval = 0;

    printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
#ifdef TARGET_WORDS_BIGENDIAN
    retval = bswap16(retval);
#endif

    return retval;
220 221
}

B
bellard 已提交
222
static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr)
223 224 225
{
    uint32_t retval = 0;

B
bellard 已提交
226 227 228 229
    printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
#ifdef TARGET_WORDS_BIGENDIAN
    retval = bswap32(retval);
#endif
230 231 232 233

    return retval;
}

B
bellard 已提交
234 235 236 237
static CPUWriteMemoryFunc *PPC_XCSR_write[] = {
    &PPC_XCSR_writeb,
    &PPC_XCSR_writew,
    &PPC_XCSR_writel,
238 239
};

B
bellard 已提交
240 241 242 243
static CPUReadMemoryFunc *PPC_XCSR_read[] = {
    &PPC_XCSR_readb,
    &PPC_XCSR_readw,
    &PPC_XCSR_readl,
244 245
};

B
bellard 已提交
246 247 248 249 250 251 252
/* Fake super-io ports for PREP platform (Intel 82378ZB) */
typedef struct sysctrl_t {
    m48t59_t *nvram;
    uint8_t state;
    uint8_t syscontrol;
    uint8_t fake_io[2];
} sysctrl_t;
253

B
bellard 已提交
254 255
enum {
    STATE_HARDFILE = 0x01,
256 257
};

B
bellard 已提交
258
static sysctrl_t *sysctrl;
259

260
static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val)
261
{
B
bellard 已提交
262 263 264 265
    sysctrl_t *sysctrl = opaque;

    PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val);
    sysctrl->fake_io[addr - 0x0398] = val;
266 267
}

268
static uint32_t PREP_io_read (void *opaque, uint32_t addr)
269
{
B
bellard 已提交
270
    sysctrl_t *sysctrl = opaque;
271

B
bellard 已提交
272 273 274 275
    PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE,
                   sysctrl->fake_io[addr - 0x0398]);
    return sysctrl->fake_io[addr - 0x0398];
}
276

277
static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
278
{
B
bellard 已提交
279 280 281
    sysctrl_t *sysctrl = opaque;

    PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val);
282 283 284 285
    switch (addr) {
    case 0x0092:
        /* Special port 92 */
        /* Check soft reset asked */
B
bellard 已提交
286 287
        if (val & 0x01) {
            //            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
288 289
        }
        /* Check LE mode */
B
bellard 已提交
290
        if (val & 0x02) {
291 292 293 294
            printf("Little Endian mode isn't supported (yet ?)\n");
            abort();
        }
        break;
B
bellard 已提交
295 296 297 298 299 300 301 302 303
    case 0x0800:
        /* Motorola CPU configuration register : read-only */
        break;
    case 0x0802:
        /* Motorola base module feature register : read-only */
        break;
    case 0x0803:
        /* Motorola base module status register : read-only */
        break;
304
    case 0x0808:
B
bellard 已提交
305 306 307 308 309
        /* Hardfile light register */
        if (val & 1)
            sysctrl->state |= STATE_HARDFILE;
        else
            sysctrl->state &= ~STATE_HARDFILE;
310 311 312
        break;
    case 0x0810:
        /* Password protect 1 register */
B
bellard 已提交
313 314
        if (sysctrl->nvram != NULL)
            m48t59_toggle_lock(sysctrl->nvram, 1);
315 316 317
        break;
    case 0x0812:
        /* Password protect 2 register */
B
bellard 已提交
318 319
        if (sysctrl->nvram != NULL)
            m48t59_toggle_lock(sysctrl->nvram, 2);
320 321
        break;
    case 0x0814:
B
bellard 已提交
322 323
        /* L2 invalidate register */
        //        tlb_flush(cpu_single_env, 1);
324 325 326
        break;
    case 0x081C:
        /* system control register */
B
bellard 已提交
327
        sysctrl->syscontrol = val & 0x0F;
328 329 330
        break;
    case 0x0850:
        /* I/O map type register */
B
bellard 已提交
331
        if (!(val & 0x01)) {
332 333 334 335 336
            printf("No support for non-continuous I/O map mode\n");
            abort();
        }
        break;
    default:
B
bellard 已提交
337 338
        printf("ERROR: unaffected IO port write: %04lx => %02x\n",
               (long)addr, val);
339 340 341 342
        break;
    }
}

343
static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
344
{
B
bellard 已提交
345
    sysctrl_t *sysctrl = opaque;
346 347 348 349 350
    uint32_t retval = 0xFF;

    switch (addr) {
    case 0x0092:
        /* Special port 92 */
B
bellard 已提交
351 352 353 354 355 356 357 358 359 360 361 362 363
        retval = 0x00;
        break;
    case 0x0800:
        /* Motorola CPU configuration register */
        retval = 0xEF; /* MPC750 */
        break;
    case 0x0802:
        /* Motorola Base module feature register */
        retval = 0xAD; /* No ESCC, PMC slot neither ethernet */
        break;
    case 0x0803:
        /* Motorola base module status register */
        retval = 0xE0; /* Standard MPC750 */
364 365 366 367 368 369 370 371
        break;
    case 0x080C:
        /* Equipment present register:
         *  no L2 cache
         *  no upgrade processor
         *  no cards in PCI slots
         *  SCSI fuse is bad
         */
B
bellard 已提交
372 373 374 375 376
        retval = 0x3C;
        break;
    case 0x0810:
        /* Motorola base module extended feature register */
        retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */
377 378 379 380 381 382 383 384 385
        break;
    case 0x0818:
        /* Keylock */
        retval = 0x00;
        break;
    case 0x081C:
        /* system control register
         * 7 - 6 / 1 - 0: L2 cache enable
         */
B
bellard 已提交
386
        retval = sysctrl->syscontrol;
387 388 389 390 391 392 393
        break;
    case 0x0823:
        /* */
        retval = 0x03; /* no L2 cache */
        break;
    case 0x0850:
        /* I/O map type register */
B
bellard 已提交
394
        retval = 0x01;
395 396
        break;
    default:
B
bellard 已提交
397
        printf("ERROR: unaffected IO port: %04lx read\n", (long)addr);
398 399
        break;
    }
B
bellard 已提交
400
    PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, retval);
401 402 403 404

    return retval;
}

405 406
extern CPUPPCState *global_env;

B
bellard 已提交
407
#define NVRAM_SIZE        0x2000
408

409
/* PowerPC PREP hardware initialisation */
410 411 412 413 414 415
void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
		   DisplayState *ds, const char **fd_filename, int snapshot,
		   const char *kernel_filename, const char *kernel_cmdline,
		   const char *initrd_filename)
{
    char buf[1024];
B
bellard 已提交
416 417
    //    void *openpic;
    m48t59_t *nvram;
418
    int PPC_io_memory;
B
bellard 已提交
419 420 421 422 423 424 425
    int ret, linux_boot, i, nb_nics1, fd;
    unsigned long bios_offset;
    uint32_t kernel_base, kernel_size, initrd_base, initrd_size;

    sysctrl = qemu_mallocz(sizeof(sysctrl_t));
    if (sysctrl == NULL)
	return;
426 427 428 429

    linux_boot = (kernel_filename != NULL);

    /* allocate RAM */
B
bellard 已提交
430 431 432 433 434 435 436 437 438 439 440 441 442
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);

    /* allocate and load BIOS */
    bios_offset = ram_size + vga_ram_size;
    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
    ret = load_image(buf, phys_ram_base + bios_offset);
    if (ret != BIOS_SIZE) {
        fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
        exit(1);
    }
    cpu_register_physical_memory((uint32_t)(-BIOS_SIZE), 
                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
    cpu_single_env->nip = 0xfffffffc;
443

444
    if (linux_boot) {
B
bellard 已提交
445
        kernel_base = KERNEL_LOAD_ADDR;
446
        /* now we can load the kernel */
B
bellard 已提交
447 448
        kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
        if (kernel_size < 0) {
449 450 451 452 453 454
            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
                    kernel_filename);
            exit(1);
        }
        /* load initrd */
        if (initrd_filename) {
B
bellard 已提交
455 456 457
            initrd_base = INITRD_LOAD_ADDR;
            initrd_size = load_image(initrd_filename,
                                     phys_ram_base + initrd_base);
458 459 460 461 462
            if (initrd_size < 0) {
                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
                        initrd_filename);
                exit(1);
            }
B
bellard 已提交
463 464 465
        } else {
            initrd_base = 0;
            initrd_size = 0;
466
        }
B
bellard 已提交
467
        boot_device = 'm';
468
    } else {
B
bellard 已提交
469 470 471 472
        kernel_base = 0;
        kernel_size = 0;
        initrd_base = 0;
        initrd_size = 0;
473 474
    }

B
bellard 已提交
475 476 477
    /* Register CPU as a 74x/75x */
    cpu_ppc_register(cpu_single_env, 0x00080000);
    /* Set time-base frequency to 100 Mhz */
478 479
    cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);

B
bellard 已提交
480 481 482
    isa_mem_base = 0xc0000000;
    pci_prep_init();
    /* Register 64 KB of ISA IO space */
B
bellard 已提交
483
    PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
B
bellard 已提交
484 485
    cpu_register_physical_memory(0x80000000, 0x00010000, PPC_io_memory);

486 487
    /* init basic PC hardware */
    vga_initialize(ds, phys_ram_base + ram_size, ram_size, 
B
bellard 已提交
488
                   vga_ram_size, 1);
489
    rtc_init(0x70, 8);
B
bellard 已提交
490 491
    //    openpic = openpic_init(0x00000000, 0xF0000000, 1);
    //    pic_init(openpic);
492
    pic_init();
B
bellard 已提交
493
    //    pit = pit_init(0x40, 0);
494 495 496 497 498 499 500

    fd = serial_open_device();
    serial_init(0x3f8, 4, fd);
    nb_nics1 = nb_nics;
    if (nb_nics1 > NE2000_NB_MAX)
        nb_nics1 = NE2000_NB_MAX;
    for(i = 0; i < nb_nics1; i++) {
B
bellard 已提交
501
        isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
502 503 504
    }

    for(i = 0; i < 2; i++) {
B
bellard 已提交
505 506
        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
                     bs_table[2 * i], bs_table[2 * i + 1]);
507 508 509
    }
    kbd_init();
    DMA_init();
B
bellard 已提交
510
    //    AUD_init();
511 512 513 514
    //    SB16_init();

    fdctrl_init(6, 2, 0, 0x3f0, fd_table);

B
bellard 已提交
515 516 517
    /* Register speaker port */
    register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
    register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
518
    /* Register fake IO ports for PREP */
B
bellard 已提交
519 520
    register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl);
    register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl);
521
    /* System control ports */
B
bellard 已提交
522 523 524 525 526 527
    register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl);
    register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl);
    register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl);
    register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl);
    /* PCI intack location */
    PPC_io_memory = cpu_register_io_memory(0, PPC_intack_read,
B
bellard 已提交
528
                                           PPC_intack_write, NULL);
529
    cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
B
bellard 已提交
530
    /* PowerPC control and status register group */
B
bellard 已提交
531
    PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, NULL);
B
bellard 已提交
532
    cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
533

B
bellard 已提交
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
    nvram = m48t59_init(8, 0x0074, NVRAM_SIZE);
    if (nvram == NULL)
        return;
    sysctrl->nvram = nvram;

    /* Initialise NVRAM */
    PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device,
                         kernel_base, kernel_size,
                         (uint32_t)(long)kernel_cmdline,
                         strlen(kernel_cmdline),
                         initrd_base, initrd_size,
                         /* XXX: need an option to load a NVRAM image */
                         0
                         );

    /* Special port to get debug messages from Open-Firmware */
    register_ioport_write(0xFF00, 0x04, 1, &PREP_debug_write, NULL);
    register_ioport_write(0xFF00, 0x04, 2, &PREP_debug_write, NULL);

    pci_ppc_bios_init();
554
}