qemu/hw/arm/npcm7xx_boards.c
<<
>>
Prefs
   1/*
   2 * Machine definitions for boards featuring an NPCM7xx SoC.
   3 *
   4 * Copyright 2020 Google LLC
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License as published by the
   8 * Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14 * for more details.
  15 */
  16
  17#include "qemu/osdep.h"
  18
  19#include "hw/arm/npcm7xx.h"
  20#include "hw/core/cpu.h"
  21#include "hw/i2c/i2c_mux_pca954x.h"
  22#include "hw/i2c/smbus_eeprom.h"
  23#include "hw/loader.h"
  24#include "hw/qdev-core.h"
  25#include "hw/qdev-properties.h"
  26#include "qapi/error.h"
  27#include "qemu-common.h"
  28#include "qemu/datadir.h"
  29#include "qemu/units.h"
  30
  31#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7
  32#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff
  33#define QUANTA_GBS_POWER_ON_STRAPS 0x000017ff
  34
  35static const char npcm7xx_default_bootrom[] = "npcm7xx_bootrom.bin";
  36
  37static void npcm7xx_load_bootrom(MachineState *machine, NPCM7xxState *soc)
  38{
  39    const char *bios_name = machine->firmware ?: npcm7xx_default_bootrom;
  40    g_autofree char *filename = NULL;
  41    int ret;
  42
  43    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
  44    if (!filename) {
  45        error_report("Could not find ROM image '%s'", bios_name);
  46        if (!machine->kernel_filename) {
  47            /* We can't boot without a bootrom or a kernel image. */
  48            exit(1);
  49        }
  50        return;
  51    }
  52    ret = load_image_mr(filename, &soc->irom);
  53    if (ret < 0) {
  54        error_report("Failed to load ROM image '%s'", filename);
  55        exit(1);
  56    }
  57}
  58
  59static void npcm7xx_connect_flash(NPCM7xxFIUState *fiu, int cs_no,
  60                                  const char *flash_type, DriveInfo *dinfo)
  61{
  62    DeviceState *flash;
  63    qemu_irq flash_cs;
  64
  65    flash = qdev_new(flash_type);
  66    if (dinfo) {
  67        qdev_prop_set_drive(flash, "drive", blk_by_legacy_dinfo(dinfo));
  68    }
  69    qdev_realize_and_unref(flash, BUS(fiu->spi), &error_fatal);
  70
  71    flash_cs = qdev_get_gpio_in_named(flash, SSI_GPIO_CS, 0);
  72    qdev_connect_gpio_out_named(DEVICE(fiu), "cs", cs_no, flash_cs);
  73}
  74
  75static void npcm7xx_connect_dram(NPCM7xxState *soc, MemoryRegion *dram)
  76{
  77    memory_region_add_subregion(get_system_memory(), NPCM7XX_DRAM_BA, dram);
  78
  79    object_property_set_link(OBJECT(soc), "dram-mr", OBJECT(dram),
  80                             &error_abort);
  81}
  82
  83static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
  84                                        uint32_t hw_straps)
  85{
  86    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
  87    MachineClass *mc = MACHINE_CLASS(nmc);
  88    Object *obj;
  89
  90    if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
  91        error_report("This board can only be used with %s",
  92                     mc->default_cpu_type);
  93        exit(1);
  94    }
  95
  96    obj = object_new_with_props(nmc->soc_type, OBJECT(machine), "soc",
  97                                &error_abort, NULL);
  98    object_property_set_uint(obj, "power-on-straps", hw_straps, &error_abort);
  99
 100    return NPCM7XX(obj);
 101}
 102
 103static I2CBus *npcm7xx_i2c_get_bus(NPCM7xxState *soc, uint32_t num)
 104{
 105    g_assert(num < ARRAY_SIZE(soc->smbus));
 106    return I2C_BUS(qdev_get_child_bus(DEVICE(&soc->smbus[num]), "i2c-bus"));
 107}
 108
 109static void at24c_eeprom_init(NPCM7xxState *soc, int bus, uint8_t addr,
 110                              uint32_t rsize)
 111{
 112    I2CBus *i2c_bus = npcm7xx_i2c_get_bus(soc, bus);
 113    I2CSlave *i2c_dev = i2c_slave_new("at24c-eeprom", addr);
 114    DeviceState *dev = DEVICE(i2c_dev);
 115
 116    qdev_prop_set_uint32(dev, "rom-size", rsize);
 117    i2c_slave_realize_and_unref(i2c_dev, i2c_bus, &error_abort);
 118}
 119
 120static void npcm7xx_init_pwm_splitter(NPCM7xxMachine *machine,
 121                                      NPCM7xxState *soc, const int *fan_counts)
 122{
 123    SplitIRQ *splitters = machine->fan_splitter;
 124
 125    /*
 126     * PWM 0~3 belong to module 0 output 0~3.
 127     * PWM 4~7 belong to module 1 output 0~3.
 128     */
 129    for (int i = 0; i < NPCM7XX_NR_PWM_MODULES; ++i) {
 130        for (int j = 0; j < NPCM7XX_PWM_PER_MODULE; ++j) {
 131            int splitter_no = i * NPCM7XX_PWM_PER_MODULE + j;
 132            DeviceState *splitter;
 133
 134            if (fan_counts[splitter_no] < 1) {
 135                continue;
 136            }
 137            object_initialize_child(OBJECT(machine), "fan-splitter[*]",
 138                                    &splitters[splitter_no], TYPE_SPLIT_IRQ);
 139            splitter = DEVICE(&splitters[splitter_no]);
 140            qdev_prop_set_uint16(splitter, "num-lines",
 141                                 fan_counts[splitter_no]);
 142            qdev_realize(splitter, NULL, &error_abort);
 143            qdev_connect_gpio_out_named(DEVICE(&soc->pwm[i]), "duty-gpio-out",
 144                                        j, qdev_get_gpio_in(splitter, 0));
 145        }
 146    }
 147}
 148
 149static void npcm7xx_connect_pwm_fan(NPCM7xxState *soc, SplitIRQ *splitter,
 150                                    int fan_no, int output_no)
 151{
 152    DeviceState *fan;
 153    int fan_input;
 154    qemu_irq fan_duty_gpio;
 155
 156    g_assert(fan_no >= 0 && fan_no <= NPCM7XX_MFT_MAX_FAN_INPUT);
 157    /*
 158     * Fan 0~1 belong to module 0 input 0~1.
 159     * Fan 2~3 belong to module 1 input 0~1.
 160     * ...
 161     * Fan 14~15 belong to module 7 input 0~1.
 162     * Fan 16~17 belong to module 0 input 2~3.
 163     * Fan 18~19 belong to module 1 input 2~3.
 164     */
 165    if (fan_no < 16) {
 166        fan = DEVICE(&soc->mft[fan_no / 2]);
 167        fan_input = fan_no % 2;
 168    } else {
 169        fan = DEVICE(&soc->mft[(fan_no - 16) / 2]);
 170        fan_input = fan_no % 2 + 2;
 171    }
 172
 173    /* Connect the Fan to PWM module */
 174    fan_duty_gpio = qdev_get_gpio_in_named(fan, "duty", fan_input);
 175    qdev_connect_gpio_out(DEVICE(splitter), output_no, fan_duty_gpio);
 176}
 177
 178static void npcm750_evb_i2c_init(NPCM7xxState *soc)
 179{
 180    /* lm75 temperature sensor on SVB, tmp105 is compatible */
 181    i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 0), "tmp105", 0x48);
 182    /* lm75 temperature sensor on EB, tmp105 is compatible */
 183    i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 1), "tmp105", 0x48);
 184    /* tmp100 temperature sensor on EB, tmp105 is compatible */
 185    i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 2), "tmp105", 0x48);
 186    /* tmp100 temperature sensor on SVB, tmp105 is compatible */
 187    i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 6), "tmp105", 0x48);
 188}
 189
 190static void npcm750_evb_fan_init(NPCM7xxMachine *machine, NPCM7xxState *soc)
 191{
 192    SplitIRQ *splitter = machine->fan_splitter;
 193    static const int fan_counts[] = {2, 2, 2, 2, 2, 2, 2, 2};
 194
 195    npcm7xx_init_pwm_splitter(machine, soc, fan_counts);
 196    npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x00, 0);
 197    npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x01, 1);
 198    npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x02, 0);
 199    npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x03, 1);
 200    npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x04, 0);
 201    npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x05, 1);
 202    npcm7xx_connect_pwm_fan(soc, &splitter[3], 0x06, 0);
 203    npcm7xx_connect_pwm_fan(soc, &splitter[3], 0x07, 1);
 204    npcm7xx_connect_pwm_fan(soc, &splitter[4], 0x08, 0);
 205    npcm7xx_connect_pwm_fan(soc, &splitter[4], 0x09, 1);
 206    npcm7xx_connect_pwm_fan(soc, &splitter[5], 0x0a, 0);
 207    npcm7xx_connect_pwm_fan(soc, &splitter[5], 0x0b, 1);
 208    npcm7xx_connect_pwm_fan(soc, &splitter[6], 0x0c, 0);
 209    npcm7xx_connect_pwm_fan(soc, &splitter[6], 0x0d, 1);
 210    npcm7xx_connect_pwm_fan(soc, &splitter[7], 0x0e, 0);
 211    npcm7xx_connect_pwm_fan(soc, &splitter[7], 0x0f, 1);
 212}
 213
 214static void quanta_gsj_i2c_init(NPCM7xxState *soc)
 215{
 216    /* GSJ machine have 4 max31725 temperature sensors, tmp105 is compatible. */
 217    i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 1), "tmp105", 0x5c);
 218    i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 2), "tmp105", 0x5c);
 219    i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 3), "tmp105", 0x5c);
 220    i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 4), "tmp105", 0x5c);
 221
 222    at24c_eeprom_init(soc, 9, 0x55, 8192);
 223    at24c_eeprom_init(soc, 10, 0x55, 8192);
 224
 225    /*
 226     * i2c-11:
 227     * - power-brick@36: delta,dps800
 228     * - hotswap@15: ti,lm5066i
 229     */
 230
 231    /*
 232     * i2c-12:
 233     * - ucd90160@6b
 234     */
 235
 236    i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 15), "pca9548", 0x75);
 237}
 238
 239static void quanta_gsj_fan_init(NPCM7xxMachine *machine, NPCM7xxState *soc)
 240{
 241    SplitIRQ *splitter = machine->fan_splitter;
 242    static const int fan_counts[] = {2, 2, 2, 0, 0, 0, 0, 0};
 243
 244    npcm7xx_init_pwm_splitter(machine, soc, fan_counts);
 245    npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x00, 0);
 246    npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x01, 1);
 247    npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x02, 0);
 248    npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x03, 1);
 249    npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x04, 0);
 250    npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x05, 1);
 251}
 252
 253static void quanta_gbs_i2c_init(NPCM7xxState *soc)
 254{
 255    /*
 256     * i2c-0:
 257     *     pca9546@71
 258     *
 259     * i2c-1:
 260     *     pca9535@24
 261     *     pca9535@20
 262     *     pca9535@21
 263     *     pca9535@22
 264     *     pca9535@23
 265     *     pca9535@25
 266     *     pca9535@26
 267     *
 268     * i2c-2:
 269     *     sbtsi@4c
 270     *
 271     * i2c-5:
 272     *     atmel,24c64@50 mb_fru
 273     *     pca9546@71
 274     *         - channel 0: max31725@54
 275     *         - channel 1: max31725@55
 276     *         - channel 2: max31725@5d
 277     *                      atmel,24c64@51 fan_fru
 278     *         - channel 3: atmel,24c64@52 hsbp_fru
 279     *
 280     * i2c-6:
 281     *     pca9545@73
 282     *
 283     * i2c-7:
 284     *     pca9545@72
 285     *
 286     * i2c-8:
 287     *     adi,adm1272@10
 288     *
 289     * i2c-9:
 290     *     pca9546@71
 291     *         - channel 0: isil,isl68137@60
 292     *         - channel 1: isil,isl68137@61
 293     *         - channel 2: isil,isl68137@63
 294     *         - channel 3: isil,isl68137@45
 295     *
 296     * i2c-10:
 297     *     pca9545@71
 298     *
 299     * i2c-11:
 300     *     pca9545@76
 301     *
 302     * i2c-12:
 303     *     maxim,max34451@4e
 304     *     isil,isl68137@5d
 305     *     isil,isl68137@5e
 306     *
 307     * i2c-14:
 308     *     pca9545@70
 309     */
 310}
 311
 312static void npcm750_evb_init(MachineState *machine)
 313{
 314    NPCM7xxState *soc;
 315
 316    soc = npcm7xx_create_soc(machine, NPCM750_EVB_POWER_ON_STRAPS);
 317    npcm7xx_connect_dram(soc, machine->ram);
 318    qdev_realize(DEVICE(soc), NULL, &error_fatal);
 319
 320    npcm7xx_load_bootrom(machine, soc);
 321    npcm7xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0));
 322    npcm750_evb_i2c_init(soc);
 323    npcm750_evb_fan_init(NPCM7XX_MACHINE(machine), soc);
 324    npcm7xx_load_kernel(machine, soc);
 325}
 326
 327static void quanta_gsj_init(MachineState *machine)
 328{
 329    NPCM7xxState *soc;
 330
 331    soc = npcm7xx_create_soc(machine, QUANTA_GSJ_POWER_ON_STRAPS);
 332    npcm7xx_connect_dram(soc, machine->ram);
 333    qdev_realize(DEVICE(soc), NULL, &error_fatal);
 334
 335    npcm7xx_load_bootrom(machine, soc);
 336    npcm7xx_connect_flash(&soc->fiu[0], 0, "mx25l25635e",
 337                          drive_get(IF_MTD, 0, 0));
 338    quanta_gsj_i2c_init(soc);
 339    quanta_gsj_fan_init(NPCM7XX_MACHINE(machine), soc);
 340    npcm7xx_load_kernel(machine, soc);
 341}
 342
 343static void quanta_gbs_init(MachineState *machine)
 344{
 345    NPCM7xxState *soc;
 346
 347    soc = npcm7xx_create_soc(machine, QUANTA_GBS_POWER_ON_STRAPS);
 348    npcm7xx_connect_dram(soc, machine->ram);
 349    qdev_realize(DEVICE(soc), NULL, &error_fatal);
 350
 351    npcm7xx_load_bootrom(machine, soc);
 352
 353    npcm7xx_connect_flash(&soc->fiu[0], 0, "mx66u51235f",
 354                          drive_get(IF_MTD, 0, 0));
 355
 356    quanta_gbs_i2c_init(soc);
 357    npcm7xx_load_kernel(machine, soc);
 358}
 359
 360static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type)
 361{
 362    NPCM7xxClass *sc = NPCM7XX_CLASS(object_class_by_name(type));
 363    MachineClass *mc = MACHINE_CLASS(nmc);
 364
 365    nmc->soc_type = type;
 366    mc->default_cpus = mc->min_cpus = mc->max_cpus = sc->num_cpus;
 367}
 368
 369static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
 370{
 371    MachineClass *mc = MACHINE_CLASS(oc);
 372
 373    mc->no_floppy = 1;
 374    mc->no_cdrom = 1;
 375    mc->no_parallel = 1;
 376    mc->default_ram_id = "ram";
 377    mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
 378}
 379
 380/*
 381 * Schematics:
 382 * https://github.com/Nuvoton-Israel/nuvoton-info/blob/master/npcm7xx-poleg/evaluation-board/board_deliverables/NPCM750x_EB_ver.A1.1_COMPLETE.pdf
 383 */
 384static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data)
 385{
 386    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
 387    MachineClass *mc = MACHINE_CLASS(oc);
 388
 389    npcm7xx_set_soc_type(nmc, TYPE_NPCM750);
 390
 391    mc->desc = "Nuvoton NPCM750 Evaluation Board (Cortex-A9)";
 392    mc->init = npcm750_evb_init;
 393    mc->default_ram_size = 512 * MiB;
 394};
 395
 396static void gsj_machine_class_init(ObjectClass *oc, void *data)
 397{
 398    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
 399    MachineClass *mc = MACHINE_CLASS(oc);
 400
 401    npcm7xx_set_soc_type(nmc, TYPE_NPCM730);
 402
 403    mc->desc = "Quanta GSJ (Cortex-A9)";
 404    mc->init = quanta_gsj_init;
 405    mc->default_ram_size = 512 * MiB;
 406};
 407
 408static void gbs_bmc_machine_class_init(ObjectClass *oc, void *data)
 409{
 410    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
 411    MachineClass *mc = MACHINE_CLASS(oc);
 412
 413    npcm7xx_set_soc_type(nmc, TYPE_NPCM730);
 414
 415    mc->desc = "Quanta GBS (Cortex-A9)";
 416    mc->init = quanta_gbs_init;
 417    mc->default_ram_size = 1 * GiB;
 418}
 419
 420static const TypeInfo npcm7xx_machine_types[] = {
 421    {
 422        .name           = TYPE_NPCM7XX_MACHINE,
 423        .parent         = TYPE_MACHINE,
 424        .instance_size  = sizeof(NPCM7xxMachine),
 425        .class_size     = sizeof(NPCM7xxMachineClass),
 426        .class_init     = npcm7xx_machine_class_init,
 427        .abstract       = true,
 428    }, {
 429        .name           = MACHINE_TYPE_NAME("npcm750-evb"),
 430        .parent         = TYPE_NPCM7XX_MACHINE,
 431        .class_init     = npcm750_evb_machine_class_init,
 432    }, {
 433        .name           = MACHINE_TYPE_NAME("quanta-gsj"),
 434        .parent         = TYPE_NPCM7XX_MACHINE,
 435        .class_init     = gsj_machine_class_init,
 436    }, {
 437        .name           = MACHINE_TYPE_NAME("quanta-gbs-bmc"),
 438        .parent         = TYPE_NPCM7XX_MACHINE,
 439        .class_init     = gbs_bmc_machine_class_init,
 440    },
 441};
 442
 443DEFINE_TYPES(npcm7xx_machine_types)
 444