qemu/hw/arm/fsl-imx6.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
   3 *
   4 * i.MX6 SOC emulation.
   5 *
   6 * Based on hw/arm/fsl-imx31.c
   7 *
   8 *  This program is free software; you can redistribute it and/or modify it
   9 *  under the terms of the GNU General Public License as published by the
  10 *  Free Software Foundation; either version 2 of the License, or
  11 *  (at your option) any later version.
  12 *
  13 *  This program is distributed in the hope that it will be useful, but WITHOUT
  14 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15 *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  16 *  for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License along
  19 *  with this program; if not, see <http://www.gnu.org/licenses/>.
  20 */
  21
  22#include "qemu/osdep.h"
  23#include "qapi/error.h"
  24#include "hw/arm/fsl-imx6.h"
  25#include "hw/boards.h"
  26#include "sysemu/sysemu.h"
  27#include "chardev/char.h"
  28#include "qemu/error-report.h"
  29#include "qemu/module.h"
  30
  31#define IMX6_ESDHC_CAPABILITIES     0x057834b4
  32
  33#define NAME_SIZE 20
  34
  35static void fsl_imx6_init(Object *obj)
  36{
  37    MachineState *ms = MACHINE(qdev_get_machine());
  38    FslIMX6State *s = FSL_IMX6(obj);
  39    char name[NAME_SIZE];
  40    int i;
  41
  42    for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX6_NUM_CPUS); i++) {
  43        snprintf(name, NAME_SIZE, "cpu%d", i);
  44        object_initialize_child(obj, name, &s->cpu[i], sizeof(s->cpu[i]),
  45                                "cortex-a9-" TYPE_ARM_CPU, &error_abort, NULL);
  46    }
  47
  48    sysbus_init_child_obj(obj, "a9mpcore", &s->a9mpcore, sizeof(s->a9mpcore),
  49                          TYPE_A9MPCORE_PRIV);
  50
  51    sysbus_init_child_obj(obj, "ccm", &s->ccm, sizeof(s->ccm), TYPE_IMX6_CCM);
  52
  53    sysbus_init_child_obj(obj, "src", &s->src, sizeof(s->src), TYPE_IMX6_SRC);
  54
  55    for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) {
  56        snprintf(name, NAME_SIZE, "uart%d", i + 1);
  57        sysbus_init_child_obj(obj, name, &s->uart[i], sizeof(s->uart[i]),
  58                              TYPE_IMX_SERIAL);
  59    }
  60
  61    sysbus_init_child_obj(obj, "gpt", &s->gpt, sizeof(s->gpt), TYPE_IMX6_GPT);
  62
  63    for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) {
  64        snprintf(name, NAME_SIZE, "epit%d", i + 1);
  65        sysbus_init_child_obj(obj, name, &s->epit[i], sizeof(s->epit[i]),
  66                              TYPE_IMX_EPIT);
  67    }
  68
  69    for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) {
  70        snprintf(name, NAME_SIZE, "i2c%d", i + 1);
  71        sysbus_init_child_obj(obj, name, &s->i2c[i], sizeof(s->i2c[i]),
  72                              TYPE_IMX_I2C);
  73    }
  74
  75    for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) {
  76        snprintf(name, NAME_SIZE, "gpio%d", i + 1);
  77        sysbus_init_child_obj(obj, name, &s->gpio[i], sizeof(s->gpio[i]),
  78                              TYPE_IMX_GPIO);
  79    }
  80
  81    for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) {
  82        snprintf(name, NAME_SIZE, "sdhc%d", i + 1);
  83        sysbus_init_child_obj(obj, name, &s->esdhc[i], sizeof(s->esdhc[i]),
  84                              TYPE_IMX_USDHC);
  85    }
  86
  87    for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) {
  88        snprintf(name, NAME_SIZE, "spi%d", i + 1);
  89        sysbus_init_child_obj(obj, name, &s->spi[i], sizeof(s->spi[i]),
  90                              TYPE_IMX_SPI);
  91    }
  92
  93    sysbus_init_child_obj(obj, "eth", &s->eth, sizeof(s->eth), TYPE_IMX_ENET);
  94}
  95
  96static void fsl_imx6_realize(DeviceState *dev, Error **errp)
  97{
  98    MachineState *ms = MACHINE(qdev_get_machine());
  99    FslIMX6State *s = FSL_IMX6(dev);
 100    uint16_t i;
 101    Error *err = NULL;
 102    unsigned int smp_cpus = ms->smp.cpus;
 103
 104    if (smp_cpus > FSL_IMX6_NUM_CPUS) {
 105        error_setg(errp, "%s: Only %d CPUs are supported (%d requested)",
 106                   TYPE_FSL_IMX6, FSL_IMX6_NUM_CPUS, smp_cpus);
 107        return;
 108    }
 109
 110    for (i = 0; i < smp_cpus; i++) {
 111
 112        /* On uniprocessor, the CBAR is set to 0 */
 113        if (smp_cpus > 1) {
 114            object_property_set_int(OBJECT(&s->cpu[i]), FSL_IMX6_A9MPCORE_ADDR,
 115                                    "reset-cbar", &error_abort);
 116        }
 117
 118        /* All CPU but CPU 0 start in power off mode */
 119        if (i) {
 120            object_property_set_bool(OBJECT(&s->cpu[i]), true,
 121                                     "start-powered-off", &error_abort);
 122        }
 123
 124        object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
 125        if (err) {
 126            error_propagate(errp, err);
 127            return;
 128        }
 129    }
 130
 131    object_property_set_int(OBJECT(&s->a9mpcore), smp_cpus, "num-cpu",
 132                            &error_abort);
 133
 134    object_property_set_int(OBJECT(&s->a9mpcore),
 135                            FSL_IMX6_MAX_IRQ + GIC_INTERNAL, "num-irq",
 136                            &error_abort);
 137
 138    object_property_set_bool(OBJECT(&s->a9mpcore), true, "realized", &err);
 139    if (err) {
 140        error_propagate(errp, err);
 141        return;
 142    }
 143    sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, FSL_IMX6_A9MPCORE_ADDR);
 144
 145    for (i = 0; i < smp_cpus; i++) {
 146        sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i,
 147                           qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
 148        sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + smp_cpus,
 149                           qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ));
 150    }
 151
 152    object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err);
 153    if (err) {
 154        error_propagate(errp, err);
 155        return;
 156    }
 157    sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX6_CCM_ADDR);
 158
 159    object_property_set_bool(OBJECT(&s->src), true, "realized", &err);
 160    if (err) {
 161        error_propagate(errp, err);
 162        return;
 163    }
 164    sysbus_mmio_map(SYS_BUS_DEVICE(&s->src), 0, FSL_IMX6_SRC_ADDR);
 165
 166    /* Initialize all UARTs */
 167    for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) {
 168        static const struct {
 169            hwaddr addr;
 170            unsigned int irq;
 171        } serial_table[FSL_IMX6_NUM_UARTS] = {
 172            { FSL_IMX6_UART1_ADDR, FSL_IMX6_UART1_IRQ },
 173            { FSL_IMX6_UART2_ADDR, FSL_IMX6_UART2_IRQ },
 174            { FSL_IMX6_UART3_ADDR, FSL_IMX6_UART3_IRQ },
 175            { FSL_IMX6_UART4_ADDR, FSL_IMX6_UART4_IRQ },
 176            { FSL_IMX6_UART5_ADDR, FSL_IMX6_UART5_IRQ },
 177        };
 178
 179        qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i));
 180
 181        object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
 182        if (err) {
 183            error_propagate(errp, err);
 184            return;
 185        }
 186
 187        sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
 188        sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
 189                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 190                                            serial_table[i].irq));
 191    }
 192
 193    s->gpt.ccm = IMX_CCM(&s->ccm);
 194
 195    object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err);
 196    if (err) {
 197        error_propagate(errp, err);
 198        return;
 199    }
 200
 201    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX6_GPT_ADDR);
 202    sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0,
 203                       qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 204                                        FSL_IMX6_GPT_IRQ));
 205
 206    /* Initialize all EPIT timers */
 207    for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) {
 208        static const struct {
 209            hwaddr addr;
 210            unsigned int irq;
 211        } epit_table[FSL_IMX6_NUM_EPITS] = {
 212            { FSL_IMX6_EPIT1_ADDR, FSL_IMX6_EPIT1_IRQ },
 213            { FSL_IMX6_EPIT2_ADDR, FSL_IMX6_EPIT2_IRQ },
 214        };
 215
 216        s->epit[i].ccm = IMX_CCM(&s->ccm);
 217
 218        object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
 219        if (err) {
 220            error_propagate(errp, err);
 221            return;
 222        }
 223
 224        sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
 225        sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
 226                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 227                                            epit_table[i].irq));
 228    }
 229
 230    /* Initialize all I2C */
 231    for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) {
 232        static const struct {
 233            hwaddr addr;
 234            unsigned int irq;
 235        } i2c_table[FSL_IMX6_NUM_I2CS] = {
 236            { FSL_IMX6_I2C1_ADDR, FSL_IMX6_I2C1_IRQ },
 237            { FSL_IMX6_I2C2_ADDR, FSL_IMX6_I2C2_IRQ },
 238            { FSL_IMX6_I2C3_ADDR, FSL_IMX6_I2C3_IRQ }
 239        };
 240
 241        object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
 242        if (err) {
 243            error_propagate(errp, err);
 244            return;
 245        }
 246
 247        sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
 248        sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
 249                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 250                                            i2c_table[i].irq));
 251    }
 252
 253    /* Initialize all GPIOs */
 254    for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) {
 255        static const struct {
 256            hwaddr addr;
 257            unsigned int irq_low;
 258            unsigned int irq_high;
 259        } gpio_table[FSL_IMX6_NUM_GPIOS] = {
 260            {
 261                FSL_IMX6_GPIO1_ADDR,
 262                FSL_IMX6_GPIO1_LOW_IRQ,
 263                FSL_IMX6_GPIO1_HIGH_IRQ
 264            },
 265            {
 266                FSL_IMX6_GPIO2_ADDR,
 267                FSL_IMX6_GPIO2_LOW_IRQ,
 268                FSL_IMX6_GPIO2_HIGH_IRQ
 269            },
 270            {
 271                FSL_IMX6_GPIO3_ADDR,
 272                FSL_IMX6_GPIO3_LOW_IRQ,
 273                FSL_IMX6_GPIO3_HIGH_IRQ
 274            },
 275            {
 276                FSL_IMX6_GPIO4_ADDR,
 277                FSL_IMX6_GPIO4_LOW_IRQ,
 278                FSL_IMX6_GPIO4_HIGH_IRQ
 279            },
 280            {
 281                FSL_IMX6_GPIO5_ADDR,
 282                FSL_IMX6_GPIO5_LOW_IRQ,
 283                FSL_IMX6_GPIO5_HIGH_IRQ
 284            },
 285            {
 286                FSL_IMX6_GPIO6_ADDR,
 287                FSL_IMX6_GPIO6_LOW_IRQ,
 288                FSL_IMX6_GPIO6_HIGH_IRQ
 289            },
 290            {
 291                FSL_IMX6_GPIO7_ADDR,
 292                FSL_IMX6_GPIO7_LOW_IRQ,
 293                FSL_IMX6_GPIO7_HIGH_IRQ
 294            },
 295        };
 296
 297        object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-edge-sel",
 298                                 &error_abort);
 299        object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-upper-pin-irq",
 300                                 &error_abort);
 301        object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
 302        if (err) {
 303            error_propagate(errp, err);
 304            return;
 305        }
 306
 307        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
 308        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
 309                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 310                                            gpio_table[i].irq_low));
 311        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
 312                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 313                                            gpio_table[i].irq_high));
 314    }
 315
 316    /* Initialize all SDHC */
 317    for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) {
 318        static const struct {
 319            hwaddr addr;
 320            unsigned int irq;
 321        } esdhc_table[FSL_IMX6_NUM_ESDHCS] = {
 322            { FSL_IMX6_uSDHC1_ADDR, FSL_IMX6_uSDHC1_IRQ },
 323            { FSL_IMX6_uSDHC2_ADDR, FSL_IMX6_uSDHC2_IRQ },
 324            { FSL_IMX6_uSDHC3_ADDR, FSL_IMX6_uSDHC3_IRQ },
 325            { FSL_IMX6_uSDHC4_ADDR, FSL_IMX6_uSDHC4_IRQ },
 326        };
 327
 328        /* UHS-I SDIO3.0 SDR104 1.8V ADMA */
 329        object_property_set_uint(OBJECT(&s->esdhc[i]), 3, "sd-spec-version",
 330                                 &err);
 331        object_property_set_uint(OBJECT(&s->esdhc[i]), IMX6_ESDHC_CAPABILITIES,
 332                                 "capareg", &err);
 333        object_property_set_bool(OBJECT(&s->esdhc[i]), true, "realized", &err);
 334        if (err) {
 335            error_propagate(errp, err);
 336            return;
 337        }
 338        sysbus_mmio_map(SYS_BUS_DEVICE(&s->esdhc[i]), 0, esdhc_table[i].addr);
 339        sysbus_connect_irq(SYS_BUS_DEVICE(&s->esdhc[i]), 0,
 340                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 341                                            esdhc_table[i].irq));
 342    }
 343
 344    /* Initialize all ECSPI */
 345    for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) {
 346        static const struct {
 347            hwaddr addr;
 348            unsigned int irq;
 349        } spi_table[FSL_IMX6_NUM_ECSPIS] = {
 350            { FSL_IMX6_eCSPI1_ADDR, FSL_IMX6_ECSPI1_IRQ },
 351            { FSL_IMX6_eCSPI2_ADDR, FSL_IMX6_ECSPI2_IRQ },
 352            { FSL_IMX6_eCSPI3_ADDR, FSL_IMX6_ECSPI3_IRQ },
 353            { FSL_IMX6_eCSPI4_ADDR, FSL_IMX6_ECSPI4_IRQ },
 354            { FSL_IMX6_eCSPI5_ADDR, FSL_IMX6_ECSPI5_IRQ },
 355        };
 356
 357        /* Initialize the SPI */
 358        object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
 359        if (err) {
 360            error_propagate(errp, err);
 361            return;
 362        }
 363
 364        sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
 365        sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
 366                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 367                                            spi_table[i].irq));
 368    }
 369
 370    qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]);
 371    object_property_set_bool(OBJECT(&s->eth), true, "realized", &err);
 372    if (err) {
 373        error_propagate(errp, err);
 374        return;
 375    }
 376    sysbus_mmio_map(SYS_BUS_DEVICE(&s->eth), 0, FSL_IMX6_ENET_ADDR);
 377    sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 0,
 378                       qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 379                                        FSL_IMX6_ENET_MAC_IRQ));
 380    sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 1,
 381                       qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 382                                        FSL_IMX6_ENET_MAC_1588_IRQ));
 383
 384    /* ROM memory */
 385    memory_region_init_rom(&s->rom, NULL, "imx6.rom",
 386                           FSL_IMX6_ROM_SIZE, &err);
 387    if (err) {
 388        error_propagate(errp, err);
 389        return;
 390    }
 391    memory_region_add_subregion(get_system_memory(), FSL_IMX6_ROM_ADDR,
 392                                &s->rom);
 393
 394    /* CAAM memory */
 395    memory_region_init_rom(&s->caam, NULL, "imx6.caam",
 396                           FSL_IMX6_CAAM_MEM_SIZE, &err);
 397    if (err) {
 398        error_propagate(errp, err);
 399        return;
 400    }
 401    memory_region_add_subregion(get_system_memory(), FSL_IMX6_CAAM_MEM_ADDR,
 402                                &s->caam);
 403
 404    /* OCRAM memory */
 405    memory_region_init_ram(&s->ocram, NULL, "imx6.ocram", FSL_IMX6_OCRAM_SIZE,
 406                           &err);
 407    if (err) {
 408        error_propagate(errp, err);
 409        return;
 410    }
 411    memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ADDR,
 412                                &s->ocram);
 413
 414    /* internal OCRAM (256 KB) is aliased over 1 MB */
 415    memory_region_init_alias(&s->ocram_alias, NULL, "imx6.ocram_alias",
 416                             &s->ocram, 0, FSL_IMX6_OCRAM_ALIAS_SIZE);
 417    memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ALIAS_ADDR,
 418                                &s->ocram_alias);
 419}
 420
 421static void fsl_imx6_class_init(ObjectClass *oc, void *data)
 422{
 423    DeviceClass *dc = DEVICE_CLASS(oc);
 424
 425    dc->realize = fsl_imx6_realize;
 426    dc->desc = "i.MX6 SOC";
 427    /* Reason: Uses serial_hd() in the realize() function */
 428    dc->user_creatable = false;
 429}
 430
 431static const TypeInfo fsl_imx6_type_info = {
 432    .name = TYPE_FSL_IMX6,
 433    .parent = TYPE_DEVICE,
 434    .instance_size = sizeof(FslIMX6State),
 435    .instance_init = fsl_imx6_init,
 436    .class_init = fsl_imx6_class_init,
 437};
 438
 439static void fsl_imx6_register_types(void)
 440{
 441    type_register_static(&fsl_imx6_type_info);
 442}
 443
 444type_init(fsl_imx6_register_types)
 445