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 "exec/address-spaces.h"
  20#include "hw/arm/npcm7xx.h"
  21#include "hw/core/cpu.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#include "sysemu/sysemu.h"
  31
  32#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7
  33#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff
  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    /* TODO: Add additional i2c devices. */
 226}
 227
 228static void quanta_gsj_fan_init(NPCM7xxMachine *machine, NPCM7xxState *soc)
 229{
 230    SplitIRQ *splitter = machine->fan_splitter;
 231    static const int fan_counts[] = {2, 2, 2, 0, 0, 0, 0, 0};
 232
 233    npcm7xx_init_pwm_splitter(machine, soc, fan_counts);
 234    npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x00, 0);
 235    npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x01, 1);
 236    npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x02, 0);
 237    npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x03, 1);
 238    npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x04, 0);
 239    npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x05, 1);
 240}
 241
 242static void npcm750_evb_init(MachineState *machine)
 243{
 244    NPCM7xxState *soc;
 245
 246    soc = npcm7xx_create_soc(machine, NPCM750_EVB_POWER_ON_STRAPS);
 247    npcm7xx_connect_dram(soc, machine->ram);
 248    qdev_realize(DEVICE(soc), NULL, &error_fatal);
 249
 250    npcm7xx_load_bootrom(machine, soc);
 251    npcm7xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0));
 252    npcm750_evb_i2c_init(soc);
 253    npcm750_evb_fan_init(NPCM7XX_MACHINE(machine), soc);
 254    npcm7xx_load_kernel(machine, soc);
 255}
 256
 257static void quanta_gsj_init(MachineState *machine)
 258{
 259    NPCM7xxState *soc;
 260
 261    soc = npcm7xx_create_soc(machine, QUANTA_GSJ_POWER_ON_STRAPS);
 262    npcm7xx_connect_dram(soc, machine->ram);
 263    qdev_realize(DEVICE(soc), NULL, &error_fatal);
 264
 265    npcm7xx_load_bootrom(machine, soc);
 266    npcm7xx_connect_flash(&soc->fiu[0], 0, "mx25l25635e",
 267                          drive_get(IF_MTD, 0, 0));
 268    quanta_gsj_i2c_init(soc);
 269    quanta_gsj_fan_init(NPCM7XX_MACHINE(machine), soc);
 270    npcm7xx_load_kernel(machine, soc);
 271}
 272
 273static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type)
 274{
 275    NPCM7xxClass *sc = NPCM7XX_CLASS(object_class_by_name(type));
 276    MachineClass *mc = MACHINE_CLASS(nmc);
 277
 278    nmc->soc_type = type;
 279    mc->default_cpus = mc->min_cpus = mc->max_cpus = sc->num_cpus;
 280}
 281
 282static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
 283{
 284    MachineClass *mc = MACHINE_CLASS(oc);
 285
 286    mc->no_floppy = 1;
 287    mc->no_cdrom = 1;
 288    mc->no_parallel = 1;
 289    mc->default_ram_id = "ram";
 290    mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
 291}
 292
 293/*
 294 * Schematics:
 295 * https://github.com/Nuvoton-Israel/nuvoton-info/blob/master/npcm7xx-poleg/evaluation-board/board_deliverables/NPCM750x_EB_ver.A1.1_COMPLETE.pdf
 296 */
 297static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data)
 298{
 299    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
 300    MachineClass *mc = MACHINE_CLASS(oc);
 301
 302    npcm7xx_set_soc_type(nmc, TYPE_NPCM750);
 303
 304    mc->desc = "Nuvoton NPCM750 Evaluation Board (Cortex A9)";
 305    mc->init = npcm750_evb_init;
 306    mc->default_ram_size = 512 * MiB;
 307};
 308
 309static void gsj_machine_class_init(ObjectClass *oc, void *data)
 310{
 311    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
 312    MachineClass *mc = MACHINE_CLASS(oc);
 313
 314    npcm7xx_set_soc_type(nmc, TYPE_NPCM730);
 315
 316    mc->desc = "Quanta GSJ (Cortex A9)";
 317    mc->init = quanta_gsj_init;
 318    mc->default_ram_size = 512 * MiB;
 319};
 320
 321static const TypeInfo npcm7xx_machine_types[] = {
 322    {
 323        .name           = TYPE_NPCM7XX_MACHINE,
 324        .parent         = TYPE_MACHINE,
 325        .instance_size  = sizeof(NPCM7xxMachine),
 326        .class_size     = sizeof(NPCM7xxMachineClass),
 327        .class_init     = npcm7xx_machine_class_init,
 328        .abstract       = true,
 329    }, {
 330        .name           = MACHINE_TYPE_NAME("npcm750-evb"),
 331        .parent         = TYPE_NPCM7XX_MACHINE,
 332        .class_init     = npcm750_evb_machine_class_init,
 333    }, {
 334        .name           = MACHINE_TYPE_NAME("quanta-gsj"),
 335        .parent         = TYPE_NPCM7XX_MACHINE,
 336        .class_init     = gsj_machine_class_init,
 337    },
 338};
 339
 340DEFINE_TYPES(npcm7xx_machine_types)
 341