qemu/hw/arm/aspeed.c
<<
>>
Prefs
   1/*
   2 * OpenPOWER Palmetto BMC
   3 *
   4 * Andrew Jeffery <andrew@aj.id.au>
   5 *
   6 * Copyright 2016 IBM Corp.
   7 *
   8 * This code is licensed under the GPL version 2 or later.  See
   9 * the COPYING file in the top-level directory.
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "qapi/error.h"
  14#include "qemu-common.h"
  15#include "cpu.h"
  16#include "exec/address-spaces.h"
  17#include "hw/arm/arm.h"
  18#include "hw/arm/aspeed_soc.h"
  19#include "hw/boards.h"
  20#include "hw/i2c/smbus.h"
  21#include "qemu/log.h"
  22#include "sysemu/block-backend.h"
  23#include "hw/loader.h"
  24#include "qemu/error-report.h"
  25
  26static struct arm_boot_info aspeed_board_binfo = {
  27    .board_id = -1, /* device-tree-only board */
  28    .nb_cpus = 1,
  29};
  30
  31typedef struct AspeedBoardState {
  32    AspeedSoCState soc;
  33    MemoryRegion ram;
  34} AspeedBoardState;
  35
  36typedef struct AspeedBoardConfig {
  37    const char *soc_name;
  38    uint32_t hw_strap1;
  39    const char *fmc_model;
  40    const char *spi_model;
  41    uint32_t num_cs;
  42    void (*i2c_init)(AspeedBoardState *bmc);
  43} AspeedBoardConfig;
  44
  45enum {
  46    PALMETTO_BMC,
  47    AST2500_EVB,
  48    ROMULUS_BMC,
  49    WITHERSPOON_BMC,
  50};
  51
  52/* Palmetto hardware value: 0x120CE416 */
  53#define PALMETTO_BMC_HW_STRAP1 (                                        \
  54        SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) |               \
  55        SCU_AST2400_HW_STRAP_DRAM_CONFIG(2 /* DDR3 with CL=6, CWL=5 */) | \
  56        SCU_AST2400_HW_STRAP_ACPI_DIS |                                 \
  57        SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(AST2400_CLK_48M_IN) |       \
  58        SCU_HW_STRAP_VGA_CLASS_CODE |                                   \
  59        SCU_HW_STRAP_LPC_RESET_PIN |                                    \
  60        SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_M_S_EN) |                \
  61        SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(AST2400_CPU_AHB_RATIO_2_1) | \
  62        SCU_HW_STRAP_SPI_WIDTH |                                        \
  63        SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) |                       \
  64        SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT))
  65
  66/* AST2500 evb hardware value: 0xF100C2E6 */
  67#define AST2500_EVB_HW_STRAP1 ((                                        \
  68        AST2500_HW_STRAP1_DEFAULTS |                                    \
  69        SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE |                     \
  70        SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE |                        \
  71        SCU_AST2500_HW_STRAP_UART_DEBUG |                               \
  72        SCU_AST2500_HW_STRAP_DDR4_ENABLE |                              \
  73        SCU_HW_STRAP_MAC1_RGMII |                                       \
  74        SCU_HW_STRAP_MAC0_RGMII) &                                      \
  75        ~SCU_HW_STRAP_2ND_BOOT_WDT)
  76
  77/* Romulus hardware value: 0xF10AD206 */
  78#define ROMULUS_BMC_HW_STRAP1 (                                         \
  79        AST2500_HW_STRAP1_DEFAULTS |                                    \
  80        SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE |                     \
  81        SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE |                        \
  82        SCU_AST2500_HW_STRAP_UART_DEBUG |                               \
  83        SCU_AST2500_HW_STRAP_DDR4_ENABLE |                              \
  84        SCU_AST2500_HW_STRAP_ACPI_ENABLE |                              \
  85        SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
  86
  87/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
  88#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
  89
  90static void palmetto_bmc_i2c_init(AspeedBoardState *bmc);
  91static void ast2500_evb_i2c_init(AspeedBoardState *bmc);
  92static void romulus_bmc_i2c_init(AspeedBoardState *bmc);
  93static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc);
  94
  95static const AspeedBoardConfig aspeed_boards[] = {
  96    [PALMETTO_BMC] = {
  97        .soc_name  = "ast2400-a1",
  98        .hw_strap1 = PALMETTO_BMC_HW_STRAP1,
  99        .fmc_model = "n25q256a",
 100        .spi_model = "mx25l25635e",
 101        .num_cs    = 1,
 102        .i2c_init  = palmetto_bmc_i2c_init,
 103    },
 104    [AST2500_EVB]  = {
 105        .soc_name  = "ast2500-a1",
 106        .hw_strap1 = AST2500_EVB_HW_STRAP1,
 107        .fmc_model = "n25q256a",
 108        .spi_model = "mx25l25635e",
 109        .num_cs    = 1,
 110        .i2c_init  = ast2500_evb_i2c_init,
 111    },
 112    [ROMULUS_BMC]  = {
 113        .soc_name  = "ast2500-a1",
 114        .hw_strap1 = ROMULUS_BMC_HW_STRAP1,
 115        .fmc_model = "n25q256a",
 116        .spi_model = "mx66l1g45g",
 117        .num_cs    = 2,
 118        .i2c_init  = romulus_bmc_i2c_init,
 119    },
 120    [WITHERSPOON_BMC]  = {
 121        .soc_name  = "ast2500-a1",
 122        .hw_strap1 = WITHERSPOON_BMC_HW_STRAP1,
 123        .fmc_model = "mx25l25635e",
 124        .spi_model = "mx66l1g45g",
 125        .num_cs    = 2,
 126        .i2c_init  = witherspoon_bmc_i2c_init,
 127    },
 128};
 129
 130#define FIRMWARE_ADDR 0x0
 131
 132static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size,
 133                           Error **errp)
 134{
 135    BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
 136    uint8_t *storage;
 137    int64_t size;
 138
 139    /* The block backend size should have already been 'validated' by
 140     * the creation of the m25p80 object.
 141     */
 142    size = blk_getlength(blk);
 143    if (size <= 0) {
 144        error_setg(errp, "failed to get flash size");
 145        return;
 146    }
 147
 148    if (rom_size > size) {
 149        rom_size = size;
 150    }
 151
 152    storage = g_new0(uint8_t, rom_size);
 153    if (blk_pread(blk, 0, storage, rom_size) < 0) {
 154        error_setg(errp, "failed to read the initial flash content");
 155        return;
 156    }
 157
 158    rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr);
 159    g_free(storage);
 160}
 161
 162static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
 163                                      Error **errp)
 164{
 165    int i ;
 166
 167    for (i = 0; i < s->num_cs; ++i) {
 168        AspeedSMCFlash *fl = &s->flashes[i];
 169        DriveInfo *dinfo = drive_get_next(IF_MTD);
 170        qemu_irq cs_line;
 171
 172        fl->flash = ssi_create_slave_no_init(s->spi, flashtype);
 173        if (dinfo) {
 174            qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo),
 175                                errp);
 176        }
 177        qdev_init_nofail(fl->flash);
 178
 179        cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
 180        sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line);
 181    }
 182}
 183
 184static void aspeed_board_init(MachineState *machine,
 185                              const AspeedBoardConfig *cfg)
 186{
 187    AspeedBoardState *bmc;
 188    AspeedSoCClass *sc;
 189    DriveInfo *drive0 = drive_get(IF_MTD, 0, 0);
 190
 191    bmc = g_new0(AspeedBoardState, 1);
 192    object_initialize(&bmc->soc, (sizeof(bmc->soc)), cfg->soc_name);
 193    object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc),
 194                              &error_abort);
 195
 196    sc = ASPEED_SOC_GET_CLASS(&bmc->soc);
 197
 198    object_property_set_uint(OBJECT(&bmc->soc), ram_size, "ram-size",
 199                             &error_abort);
 200    object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1",
 201                            &error_abort);
 202    object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs",
 203                            &error_abort);
 204    if (machine->kernel_filename) {
 205        /*
 206         * When booting with a -kernel command line there is no u-boot
 207         * that runs to unlock the SCU. In this case set the default to
 208         * be unlocked as the kernel expects
 209         */
 210        object_property_set_int(OBJECT(&bmc->soc), ASPEED_SCU_PROT_KEY,
 211                                "hw-prot-key", &error_abort);
 212    }
 213    object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
 214                             &error_abort);
 215
 216    /*
 217     * Allocate RAM after the memory controller has checked the size
 218     * was valid. If not, a default value is used.
 219     */
 220    ram_size = object_property_get_uint(OBJECT(&bmc->soc), "ram-size",
 221                                        &error_abort);
 222
 223    memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
 224    memory_region_add_subregion(get_system_memory(), sc->info->sdram_base,
 225                                &bmc->ram);
 226    object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
 227                                   &error_abort);
 228
 229    aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort);
 230    aspeed_board_init_flashes(&bmc->soc.spi[0], cfg->spi_model, &error_abort);
 231
 232    /* Install first FMC flash content as a boot rom. */
 233    if (drive0) {
 234        AspeedSMCFlash *fl = &bmc->soc.fmc.flashes[0];
 235        MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
 236
 237        /*
 238         * create a ROM region using the default mapping window size of
 239         * the flash module. The window size is 64MB for the AST2400
 240         * SoC and 128MB for the AST2500 SoC, which is twice as big as
 241         * needed by the flash modules of the Aspeed machines.
 242         */
 243        memory_region_init_rom(boot_rom, OBJECT(bmc), "aspeed.boot_rom",
 244                               fl->size, &error_abort);
 245        memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR,
 246                                    boot_rom);
 247        write_boot_rom(drive0, FIRMWARE_ADDR, fl->size, &error_abort);
 248    }
 249
 250    aspeed_board_binfo.kernel_filename = machine->kernel_filename;
 251    aspeed_board_binfo.initrd_filename = machine->initrd_filename;
 252    aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
 253    aspeed_board_binfo.ram_size = ram_size;
 254    aspeed_board_binfo.loader_start = sc->info->sdram_base;
 255
 256    if (cfg->i2c_init) {
 257        cfg->i2c_init(bmc);
 258    }
 259
 260    arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo);
 261}
 262
 263static void palmetto_bmc_i2c_init(AspeedBoardState *bmc)
 264{
 265    AspeedSoCState *soc = &bmc->soc;
 266    DeviceState *dev;
 267    uint8_t *eeprom_buf = g_malloc0(32 * 1024);
 268
 269    /* The palmetto platform expects a ds3231 RTC but a ds1338 is
 270     * enough to provide basic RTC features. Alarms will be missing */
 271    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), "ds1338", 0x68);
 272
 273    smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), 0x50,
 274                          eeprom_buf);
 275
 276    /* add a TMP423 temperature sensor */
 277    dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2),
 278                           "tmp423", 0x4c);
 279    object_property_set_int(OBJECT(dev), 31000, "temperature0", &error_abort);
 280    object_property_set_int(OBJECT(dev), 28000, "temperature1", &error_abort);
 281    object_property_set_int(OBJECT(dev), 20000, "temperature2", &error_abort);
 282    object_property_set_int(OBJECT(dev), 110000, "temperature3", &error_abort);
 283}
 284
 285static void palmetto_bmc_init(MachineState *machine)
 286{
 287    aspeed_board_init(machine, &aspeed_boards[PALMETTO_BMC]);
 288}
 289
 290static void palmetto_bmc_class_init(ObjectClass *oc, void *data)
 291{
 292    MachineClass *mc = MACHINE_CLASS(oc);
 293
 294    mc->desc = "OpenPOWER Palmetto BMC (ARM926EJ-S)";
 295    mc->init = palmetto_bmc_init;
 296    mc->max_cpus = 1;
 297    mc->no_sdcard = 1;
 298    mc->no_floppy = 1;
 299    mc->no_cdrom = 1;
 300    mc->no_parallel = 1;
 301}
 302
 303static const TypeInfo palmetto_bmc_type = {
 304    .name = MACHINE_TYPE_NAME("palmetto-bmc"),
 305    .parent = TYPE_MACHINE,
 306    .class_init = palmetto_bmc_class_init,
 307};
 308
 309static void ast2500_evb_i2c_init(AspeedBoardState *bmc)
 310{
 311    AspeedSoCState *soc = &bmc->soc;
 312    uint8_t *eeprom_buf = g_malloc0(8 * 1024);
 313
 314    smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), 0x50,
 315                          eeprom_buf);
 316
 317    /* The AST2500 EVB expects a LM75 but a TMP105 is compatible */
 318    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "tmp105", 0x4d);
 319
 320    /* The AST2500 EVB does not have an RTC. Let's pretend that one is
 321     * plugged on the I2C bus header */
 322    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
 323}
 324
 325static void ast2500_evb_init(MachineState *machine)
 326{
 327    aspeed_board_init(machine, &aspeed_boards[AST2500_EVB]);
 328}
 329
 330static void ast2500_evb_class_init(ObjectClass *oc, void *data)
 331{
 332    MachineClass *mc = MACHINE_CLASS(oc);
 333
 334    mc->desc = "Aspeed AST2500 EVB (ARM1176)";
 335    mc->init = ast2500_evb_init;
 336    mc->max_cpus = 1;
 337    mc->no_sdcard = 1;
 338    mc->no_floppy = 1;
 339    mc->no_cdrom = 1;
 340    mc->no_parallel = 1;
 341}
 342
 343static const TypeInfo ast2500_evb_type = {
 344    .name = MACHINE_TYPE_NAME("ast2500-evb"),
 345    .parent = TYPE_MACHINE,
 346    .class_init = ast2500_evb_class_init,
 347};
 348
 349static void romulus_bmc_i2c_init(AspeedBoardState *bmc)
 350{
 351    AspeedSoCState *soc = &bmc->soc;
 352
 353    /* The romulus board expects Epson RX8900 I2C RTC but a ds1338 is
 354     * good enough */
 355    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
 356}
 357
 358static void romulus_bmc_init(MachineState *machine)
 359{
 360    aspeed_board_init(machine, &aspeed_boards[ROMULUS_BMC]);
 361}
 362
 363static void romulus_bmc_class_init(ObjectClass *oc, void *data)
 364{
 365    MachineClass *mc = MACHINE_CLASS(oc);
 366
 367    mc->desc = "OpenPOWER Romulus BMC (ARM1176)";
 368    mc->init = romulus_bmc_init;
 369    mc->max_cpus = 1;
 370    mc->no_sdcard = 1;
 371    mc->no_floppy = 1;
 372    mc->no_cdrom = 1;
 373    mc->no_parallel = 1;
 374}
 375
 376static const TypeInfo romulus_bmc_type = {
 377    .name = MACHINE_TYPE_NAME("romulus-bmc"),
 378    .parent = TYPE_MACHINE,
 379    .class_init = romulus_bmc_class_init,
 380};
 381
 382static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc)
 383{
 384    AspeedSoCState *soc = &bmc->soc;
 385    uint8_t *eeprom_buf = g_malloc0(8 * 1024);
 386
 387    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), "pca9552", 0x60);
 388
 389    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "tmp423", 0x4c);
 390    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 5), "tmp423", 0x4c);
 391
 392    /* The Witherspoon expects a TMP275 but a TMP105 is compatible */
 393    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "tmp105", 0x4a);
 394
 395    /* The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is
 396     * good enough */
 397    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
 398
 399    smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), 0x51,
 400                          eeprom_buf);
 401    i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "pca9552",
 402                     0x60);
 403}
 404
 405static void witherspoon_bmc_init(MachineState *machine)
 406{
 407    aspeed_board_init(machine, &aspeed_boards[WITHERSPOON_BMC]);
 408}
 409
 410static void witherspoon_bmc_class_init(ObjectClass *oc, void *data)
 411{
 412    MachineClass *mc = MACHINE_CLASS(oc);
 413
 414    mc->desc = "OpenPOWER Witherspoon BMC (ARM1176)";
 415    mc->init = witherspoon_bmc_init;
 416    mc->max_cpus = 1;
 417    mc->no_sdcard = 1;
 418    mc->no_floppy = 1;
 419    mc->no_cdrom = 1;
 420    mc->no_parallel = 1;
 421}
 422
 423static const TypeInfo witherspoon_bmc_type = {
 424    .name = MACHINE_TYPE_NAME("witherspoon-bmc"),
 425    .parent = TYPE_MACHINE,
 426    .class_init = witherspoon_bmc_class_init,
 427};
 428
 429static void aspeed_machine_init(void)
 430{
 431    type_register_static(&palmetto_bmc_type);
 432    type_register_static(&ast2500_evb_type);
 433    type_register_static(&romulus_bmc_type);
 434    type_register_static(&witherspoon_bmc_type);
 435}
 436
 437type_init(aspeed_machine_init)
 438