qemu/hw/ppc/ppc405_boards.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC 405 evaluation boards emulation
   3 *
   4 * Copyright (c) 2007 Jocelyn Mayer
   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#include "qemu/osdep.h"
  25#include "qemu/units.h"
  26#include "qapi/error.h"
  27#include "qemu-common.h"
  28#include "cpu.h"
  29#include "hw/hw.h"
  30#include "hw/ppc/ppc.h"
  31#include "ppc405.h"
  32#include "hw/timer/m48t59.h"
  33#include "hw/block/flash.h"
  34#include "sysemu/sysemu.h"
  35#include "sysemu/qtest.h"
  36#include "sysemu/block-backend.h"
  37#include "hw/boards.h"
  38#include "qemu/log.h"
  39#include "qemu/error-report.h"
  40#include "hw/loader.h"
  41#include "exec/address-spaces.h"
  42
  43#define BIOS_FILENAME "ppc405_rom.bin"
  44#define BIOS_SIZE (2 * MiB)
  45
  46#define KERNEL_LOAD_ADDR 0x00000000
  47#define INITRD_LOAD_ADDR 0x01800000
  48
  49#define USE_FLASH_BIOS
  50
  51/*****************************************************************************/
  52/* PPC405EP reference board (IBM) */
  53/* Standalone board with:
  54 * - PowerPC 405EP CPU
  55 * - SDRAM (0x00000000)
  56 * - Flash (0xFFF80000)
  57 * - SRAM  (0xFFF00000)
  58 * - NVRAM (0xF0000000)
  59 * - FPGA  (0xF0300000)
  60 */
  61typedef struct ref405ep_fpga_t ref405ep_fpga_t;
  62struct ref405ep_fpga_t {
  63    uint8_t reg0;
  64    uint8_t reg1;
  65};
  66
  67static uint64_t ref405ep_fpga_readb(void *opaque, hwaddr addr, unsigned size)
  68{
  69    ref405ep_fpga_t *fpga;
  70    uint32_t ret;
  71
  72    fpga = opaque;
  73    switch (addr) {
  74    case 0x0:
  75        ret = fpga->reg0;
  76        break;
  77    case 0x1:
  78        ret = fpga->reg1;
  79        break;
  80    default:
  81        ret = 0;
  82        break;
  83    }
  84
  85    return ret;
  86}
  87
  88static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
  89                                 unsigned size)
  90{
  91    ref405ep_fpga_t *fpga;
  92
  93    fpga = opaque;
  94    switch (addr) {
  95    case 0x0:
  96        /* Read only */
  97        break;
  98    case 0x1:
  99        fpga->reg1 = value;
 100        break;
 101    default:
 102        break;
 103    }
 104}
 105
 106static const MemoryRegionOps ref405ep_fpga_ops = {
 107    .read = ref405ep_fpga_readb,
 108    .write = ref405ep_fpga_writeb,
 109    .impl.min_access_size = 1,
 110    .impl.max_access_size = 1,
 111    .valid.min_access_size = 1,
 112    .valid.max_access_size = 4,
 113    .endianness = DEVICE_BIG_ENDIAN,
 114};
 115
 116static void ref405ep_fpga_reset (void *opaque)
 117{
 118    ref405ep_fpga_t *fpga;
 119
 120    fpga = opaque;
 121    fpga->reg0 = 0x00;
 122    fpga->reg1 = 0x0F;
 123}
 124
 125static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base)
 126{
 127    ref405ep_fpga_t *fpga;
 128    MemoryRegion *fpga_memory = g_new(MemoryRegion, 1);
 129
 130    fpga = g_malloc0(sizeof(ref405ep_fpga_t));
 131    memory_region_init_io(fpga_memory, NULL, &ref405ep_fpga_ops, fpga,
 132                          "fpga", 0x00000100);
 133    memory_region_add_subregion(sysmem, base, fpga_memory);
 134    qemu_register_reset(&ref405ep_fpga_reset, fpga);
 135}
 136
 137static void ref405ep_init(MachineState *machine)
 138{
 139    ram_addr_t ram_size = machine->ram_size;
 140    const char *kernel_filename = machine->kernel_filename;
 141    const char *kernel_cmdline = machine->kernel_cmdline;
 142    const char *initrd_filename = machine->initrd_filename;
 143    char *filename;
 144    ppc4xx_bd_info_t bd;
 145    CPUPPCState *env;
 146    qemu_irq *pic;
 147    MemoryRegion *bios;
 148    MemoryRegion *sram = g_new(MemoryRegion, 1);
 149    ram_addr_t bdloc;
 150    MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
 151    hwaddr ram_bases[2], ram_sizes[2];
 152    target_ulong sram_size;
 153    long bios_size;
 154    //int phy_addr = 0;
 155    //static int phy_addr = 1;
 156    target_ulong kernel_base, initrd_base;
 157    long kernel_size, initrd_size;
 158    int linux_boot;
 159    int len;
 160    DriveInfo *dinfo;
 161    MemoryRegion *sysmem = get_system_memory();
 162
 163    /* XXX: fix this */
 164    memory_region_allocate_system_memory(&ram_memories[0], NULL, "ef405ep.ram",
 165                                         0x08000000);
 166    ram_bases[0] = 0;
 167    ram_sizes[0] = 0x08000000;
 168    memory_region_init(&ram_memories[1], NULL, "ef405ep.ram1", 0);
 169    ram_bases[1] = 0x00000000;
 170    ram_sizes[1] = 0x00000000;
 171    ram_size = 128 * MiB;
 172    env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
 173                        33333333, &pic, kernel_filename == NULL ? 0 : 1);
 174    /* allocate SRAM */
 175    sram_size = 512 * KiB;
 176    memory_region_init_ram(sram, NULL, "ef405ep.sram", sram_size,
 177                           &error_fatal);
 178    memory_region_add_subregion(sysmem, 0xFFF00000, sram);
 179    /* allocate and load BIOS */
 180#ifdef USE_FLASH_BIOS
 181    dinfo = drive_get(IF_PFLASH, 0, 0);
 182    if (dinfo) {
 183        bios_size = 8 * MiB;
 184        pflash_cfi02_register((uint32_t)(-bios_size),
 185                              "ef405ep.bios", bios_size,
 186                              dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
 187                              64 * KiB, 1,
 188                              2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
 189                              1);
 190    } else
 191#endif
 192    {
 193        bios = g_new(MemoryRegion, 1);
 194        memory_region_init_ram(bios, NULL, "ef405ep.bios", BIOS_SIZE,
 195                               &error_fatal);
 196
 197        if (bios_name == NULL)
 198            bios_name = BIOS_FILENAME;
 199        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
 200        if (filename) {
 201            bios_size = load_image_size(filename,
 202                                        memory_region_get_ram_ptr(bios),
 203                                        BIOS_SIZE);
 204            g_free(filename);
 205            if (bios_size < 0) {
 206                error_report("Could not load PowerPC BIOS '%s'", bios_name);
 207                exit(1);
 208            }
 209            bios_size = (bios_size + 0xfff) & ~0xfff;
 210            memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
 211        } else if (!qtest_enabled() || kernel_filename != NULL) {
 212            error_report("Could not load PowerPC BIOS '%s'", bios_name);
 213            exit(1);
 214        } else {
 215            /* Avoid an uninitialized variable warning */
 216            bios_size = -1;
 217        }
 218        memory_region_set_readonly(bios, true);
 219    }
 220    /* Register FPGA */
 221    ref405ep_fpga_init(sysmem, 0xF0300000);
 222    /* Register NVRAM */
 223    m48t59_init(NULL, 0xF0000000, 0, 8192, 1968, 8);
 224    /* Load kernel */
 225    linux_boot = (kernel_filename != NULL);
 226    if (linux_boot) {
 227        memset(&bd, 0, sizeof(bd));
 228        bd.bi_memstart = 0x00000000;
 229        bd.bi_memsize = ram_size;
 230        bd.bi_flashstart = -bios_size;
 231        bd.bi_flashsize = -bios_size;
 232        bd.bi_flashoffset = 0;
 233        bd.bi_sramstart = 0xFFF00000;
 234        bd.bi_sramsize = sram_size;
 235        bd.bi_bootflags = 0;
 236        bd.bi_intfreq = 133333333;
 237        bd.bi_busfreq = 33333333;
 238        bd.bi_baudrate = 115200;
 239        bd.bi_s_version[0] = 'Q';
 240        bd.bi_s_version[1] = 'M';
 241        bd.bi_s_version[2] = 'U';
 242        bd.bi_s_version[3] = '\0';
 243        bd.bi_r_version[0] = 'Q';
 244        bd.bi_r_version[1] = 'E';
 245        bd.bi_r_version[2] = 'M';
 246        bd.bi_r_version[3] = 'U';
 247        bd.bi_r_version[4] = '\0';
 248        bd.bi_procfreq = 133333333;
 249        bd.bi_plb_busfreq = 33333333;
 250        bd.bi_pci_busfreq = 33333333;
 251        bd.bi_opbfreq = 33333333;
 252        bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001);
 253        env->gpr[3] = bdloc;
 254        kernel_base = KERNEL_LOAD_ADDR;
 255        /* now we can load the kernel */
 256        kernel_size = load_image_targphys(kernel_filename, kernel_base,
 257                                          ram_size - kernel_base);
 258        if (kernel_size < 0) {
 259            error_report("could not load kernel '%s'", kernel_filename);
 260            exit(1);
 261        }
 262        printf("Load kernel size %ld at " TARGET_FMT_lx,
 263               kernel_size, kernel_base);
 264        /* load initrd */
 265        if (initrd_filename) {
 266            initrd_base = INITRD_LOAD_ADDR;
 267            initrd_size = load_image_targphys(initrd_filename, initrd_base,
 268                                              ram_size - initrd_base);
 269            if (initrd_size < 0) {
 270                error_report("could not load initial ram disk '%s'",
 271                             initrd_filename);
 272                exit(1);
 273            }
 274        } else {
 275            initrd_base = 0;
 276            initrd_size = 0;
 277        }
 278        env->gpr[4] = initrd_base;
 279        env->gpr[5] = initrd_size;
 280        if (kernel_cmdline != NULL) {
 281            len = strlen(kernel_cmdline);
 282            bdloc -= ((len + 255) & ~255);
 283            cpu_physical_memory_write(bdloc, kernel_cmdline, len + 1);
 284            env->gpr[6] = bdloc;
 285            env->gpr[7] = bdloc + len;
 286        } else {
 287            env->gpr[6] = 0;
 288            env->gpr[7] = 0;
 289        }
 290        env->nip = KERNEL_LOAD_ADDR;
 291    } else {
 292        kernel_base = 0;
 293        kernel_size = 0;
 294        initrd_base = 0;
 295        initrd_size = 0;
 296        bdloc = 0;
 297    }
 298}
 299
 300static void ref405ep_class_init(ObjectClass *oc, void *data)
 301{
 302    MachineClass *mc = MACHINE_CLASS(oc);
 303
 304    mc->desc = "ref405ep";
 305    mc->init = ref405ep_init;
 306}
 307
 308static const TypeInfo ref405ep_type = {
 309    .name = MACHINE_TYPE_NAME("ref405ep"),
 310    .parent = TYPE_MACHINE,
 311    .class_init = ref405ep_class_init,
 312};
 313
 314/*****************************************************************************/
 315/* AMCC Taihu evaluation board */
 316/* - PowerPC 405EP processor
 317 * - SDRAM               128 MB at 0x00000000
 318 * - Boot flash          2 MB   at 0xFFE00000
 319 * - Application flash   32 MB  at 0xFC000000
 320 * - 2 serial ports
 321 * - 2 ethernet PHY
 322 * - 1 USB 1.1 device    0x50000000
 323 * - 1 LCD display       0x50100000
 324 * - 1 CPLD              0x50100000
 325 * - 1 I2C EEPROM
 326 * - 1 I2C thermal sensor
 327 * - a set of LEDs
 328 * - bit-bang SPI port using GPIOs
 329 * - 1 EBC interface connector 0 0x50200000
 330 * - 1 cardbus controller + expansion slot.
 331 * - 1 PCI expansion slot.
 332 */
 333typedef struct taihu_cpld_t taihu_cpld_t;
 334struct taihu_cpld_t {
 335    uint8_t reg0;
 336    uint8_t reg1;
 337};
 338
 339static uint64_t taihu_cpld_read(void *opaque, hwaddr addr, unsigned size)
 340{
 341    taihu_cpld_t *cpld;
 342    uint32_t ret;
 343
 344    cpld = opaque;
 345    switch (addr) {
 346    case 0x0:
 347        ret = cpld->reg0;
 348        break;
 349    case 0x1:
 350        ret = cpld->reg1;
 351        break;
 352    default:
 353        ret = 0;
 354        break;
 355    }
 356
 357    return ret;
 358}
 359
 360static void taihu_cpld_write(void *opaque, hwaddr addr,
 361                             uint64_t value, unsigned size)
 362{
 363    taihu_cpld_t *cpld;
 364
 365    cpld = opaque;
 366    switch (addr) {
 367    case 0x0:
 368        /* Read only */
 369        break;
 370    case 0x1:
 371        cpld->reg1 = value;
 372        break;
 373    default:
 374        break;
 375    }
 376}
 377
 378static const MemoryRegionOps taihu_cpld_ops = {
 379    .read = taihu_cpld_read,
 380    .write = taihu_cpld_write,
 381    .impl = {
 382        .min_access_size = 1,
 383        .max_access_size = 1,
 384    },
 385    .endianness = DEVICE_NATIVE_ENDIAN,
 386};
 387
 388static void taihu_cpld_reset (void *opaque)
 389{
 390    taihu_cpld_t *cpld;
 391
 392    cpld = opaque;
 393    cpld->reg0 = 0x01;
 394    cpld->reg1 = 0x80;
 395}
 396
 397static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base)
 398{
 399    taihu_cpld_t *cpld;
 400    MemoryRegion *cpld_memory = g_new(MemoryRegion, 1);
 401
 402    cpld = g_malloc0(sizeof(taihu_cpld_t));
 403    memory_region_init_io(cpld_memory, NULL, &taihu_cpld_ops, cpld, "cpld", 0x100);
 404    memory_region_add_subregion(sysmem, base, cpld_memory);
 405    qemu_register_reset(&taihu_cpld_reset, cpld);
 406}
 407
 408static void taihu_405ep_init(MachineState *machine)
 409{
 410    ram_addr_t ram_size = machine->ram_size;
 411    const char *kernel_filename = machine->kernel_filename;
 412    const char *initrd_filename = machine->initrd_filename;
 413    char *filename;
 414    qemu_irq *pic;
 415    MemoryRegion *sysmem = get_system_memory();
 416    MemoryRegion *bios;
 417    MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
 418    MemoryRegion *ram = g_malloc0(sizeof(*ram));
 419    hwaddr ram_bases[2], ram_sizes[2];
 420    long bios_size;
 421    target_ulong kernel_base, initrd_base;
 422    long kernel_size, initrd_size;
 423    int linux_boot;
 424    int fl_idx;
 425    DriveInfo *dinfo;
 426
 427    /* RAM is soldered to the board so the size cannot be changed */
 428    ram_size = 0x08000000;
 429    memory_region_allocate_system_memory(ram, NULL, "taihu_405ep.ram",
 430                                         ram_size);
 431
 432    ram_bases[0] = 0;
 433    ram_sizes[0] = 0x04000000;
 434    memory_region_init_alias(&ram_memories[0], NULL,
 435                             "taihu_405ep.ram-0", ram, ram_bases[0],
 436                             ram_sizes[0]);
 437    ram_bases[1] = 0x04000000;
 438    ram_sizes[1] = 0x04000000;
 439    memory_region_init_alias(&ram_memories[1], NULL,
 440                             "taihu_405ep.ram-1", ram, ram_bases[1],
 441                             ram_sizes[1]);
 442    ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
 443                  33333333, &pic, kernel_filename == NULL ? 0 : 1);
 444    /* allocate and load BIOS */
 445    fl_idx = 0;
 446#if defined(USE_FLASH_BIOS)
 447    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
 448    if (dinfo) {
 449        bios_size = 2 * MiB;
 450        pflash_cfi02_register(0xFFE00000,
 451                              "taihu_405ep.bios", bios_size,
 452                              dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
 453                              64 * KiB, 1,
 454                              4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
 455                              1);
 456        fl_idx++;
 457    } else
 458#endif
 459    {
 460        if (bios_name == NULL)
 461            bios_name = BIOS_FILENAME;
 462        bios = g_new(MemoryRegion, 1);
 463        memory_region_init_ram(bios, NULL, "taihu_405ep.bios", BIOS_SIZE,
 464                               &error_fatal);
 465        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
 466        if (filename) {
 467            bios_size = load_image_size(filename,
 468                                        memory_region_get_ram_ptr(bios),
 469                                        BIOS_SIZE);
 470            g_free(filename);
 471            if (bios_size < 0) {
 472                error_report("Could not load PowerPC BIOS '%s'", bios_name);
 473                exit(1);
 474            }
 475            bios_size = (bios_size + 0xfff) & ~0xfff;
 476            memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
 477        } else if (!qtest_enabled()) {
 478            error_report("Could not load PowerPC BIOS '%s'", bios_name);
 479            exit(1);
 480        }
 481        memory_region_set_readonly(bios, true);
 482    }
 483    /* Register Linux flash */
 484    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
 485    if (dinfo) {
 486        bios_size = 32 * MiB;
 487        pflash_cfi02_register(0xfc000000, "taihu_405ep.flash", bios_size,
 488                              dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
 489                              64 * KiB, 1,
 490                              4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
 491                              1);
 492        fl_idx++;
 493    }
 494    /* Register CLPD & LCD display */
 495    taihu_cpld_init(sysmem, 0x50100000);
 496    /* Load kernel */
 497    linux_boot = (kernel_filename != NULL);
 498    if (linux_boot) {
 499        kernel_base = KERNEL_LOAD_ADDR;
 500        /* now we can load the kernel */
 501        kernel_size = load_image_targphys(kernel_filename, kernel_base,
 502                                          ram_size - kernel_base);
 503        if (kernel_size < 0) {
 504            error_report("could not load kernel '%s'", kernel_filename);
 505            exit(1);
 506        }
 507        /* load initrd */
 508        if (initrd_filename) {
 509            initrd_base = INITRD_LOAD_ADDR;
 510            initrd_size = load_image_targphys(initrd_filename, initrd_base,
 511                                              ram_size - initrd_base);
 512            if (initrd_size < 0) {
 513                error_report("could not load initial ram disk '%s'",
 514                             initrd_filename);
 515                exit(1);
 516            }
 517        } else {
 518            initrd_base = 0;
 519            initrd_size = 0;
 520        }
 521    } else {
 522        kernel_base = 0;
 523        kernel_size = 0;
 524        initrd_base = 0;
 525        initrd_size = 0;
 526    }
 527}
 528
 529static void taihu_class_init(ObjectClass *oc, void *data)
 530{
 531    MachineClass *mc = MACHINE_CLASS(oc);
 532
 533    mc->desc = "taihu";
 534    mc->init = taihu_405ep_init;
 535}
 536
 537static const TypeInfo taihu_type = {
 538    .name = MACHINE_TYPE_NAME("taihu"),
 539    .parent = TYPE_MACHINE,
 540    .class_init = taihu_class_init,
 541};
 542
 543static void ppc405_machine_init(void)
 544{
 545    type_register_static(&ref405ep_type);
 546    type_register_static(&taihu_type);
 547}
 548
 549type_init(ppc405_machine_init)
 550