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