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 "qemu-common.h"
  25#include "hw/arm/fsl-imx6.h"
  26#include "sysemu/sysemu.h"
  27#include "chardev/char.h"
  28#include "qemu/error-report.h"
  29
  30#define NAME_SIZE 20
  31
  32static void fsl_imx6_init(Object *obj)
  33{
  34    FslIMX6State *s = FSL_IMX6(obj);
  35    char name[NAME_SIZE];
  36    int i;
  37
  38    if (smp_cpus > FSL_IMX6_NUM_CPUS) {
  39        error_report("%s: Only %d CPUs are supported (%d requested)",
  40                     TYPE_FSL_IMX6, FSL_IMX6_NUM_CPUS, smp_cpus);
  41        exit(1);
  42    }
  43
  44    for (i = 0; i < smp_cpus; i++) {
  45        object_initialize(&s->cpu[i], sizeof(s->cpu[i]),
  46                          "cortex-a9-" TYPE_ARM_CPU);
  47        snprintf(name, NAME_SIZE, "cpu%d", i);
  48        object_property_add_child(obj, name, OBJECT(&s->cpu[i]), NULL);
  49    }
  50
  51    object_initialize(&s->a9mpcore, sizeof(s->a9mpcore), TYPE_A9MPCORE_PRIV);
  52    qdev_set_parent_bus(DEVICE(&s->a9mpcore), sysbus_get_default());
  53    object_property_add_child(obj, "a9mpcore", OBJECT(&s->a9mpcore), NULL);
  54
  55    object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX6_CCM);
  56    qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
  57    object_property_add_child(obj, "ccm", OBJECT(&s->ccm), NULL);
  58
  59    object_initialize(&s->src, sizeof(s->src), TYPE_IMX6_SRC);
  60    qdev_set_parent_bus(DEVICE(&s->src), sysbus_get_default());
  61    object_property_add_child(obj, "src", OBJECT(&s->src), NULL);
  62
  63    for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) {
  64        object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL);
  65        qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
  66        snprintf(name, NAME_SIZE, "uart%d", i + 1);
  67        object_property_add_child(obj, name, OBJECT(&s->uart[i]), NULL);
  68    }
  69
  70    object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX6_GPT);
  71    qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
  72    object_property_add_child(obj, "gpt", OBJECT(&s->gpt), NULL);
  73
  74    for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) {
  75        object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT);
  76        qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default());
  77        snprintf(name, NAME_SIZE, "epit%d", i + 1);
  78        object_property_add_child(obj, name, OBJECT(&s->epit[i]), NULL);
  79    }
  80
  81    for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) {
  82        object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C);
  83        qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default());
  84        snprintf(name, NAME_SIZE, "i2c%d", i + 1);
  85        object_property_add_child(obj, name, OBJECT(&s->i2c[i]), NULL);
  86    }
  87
  88    for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) {
  89        object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO);
  90        qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default());
  91        snprintf(name, NAME_SIZE, "gpio%d", i + 1);
  92        object_property_add_child(obj, name, OBJECT(&s->gpio[i]), NULL);
  93    }
  94
  95    for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) {
  96        object_initialize(&s->esdhc[i], sizeof(s->esdhc[i]), TYPE_SYSBUS_SDHCI);
  97        qdev_set_parent_bus(DEVICE(&s->esdhc[i]), sysbus_get_default());
  98        snprintf(name, NAME_SIZE, "sdhc%d", i + 1);
  99        object_property_add_child(obj, name, OBJECT(&s->esdhc[i]), NULL);
 100    }
 101
 102    for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) {
 103        object_initialize(&s->spi[i], sizeof(s->spi[i]), TYPE_IMX_SPI);
 104        qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
 105        snprintf(name, NAME_SIZE, "spi%d", i + 1);
 106        object_property_add_child(obj, name, OBJECT(&s->spi[i]), NULL);
 107    }
 108
 109    object_initialize(&s->eth, sizeof(s->eth), TYPE_IMX_ENET);
 110    qdev_set_parent_bus(DEVICE(&s->eth), sysbus_get_default());
 111    object_property_add_child(obj, "eth", OBJECT(&s->eth), NULL);
 112}
 113
 114static void fsl_imx6_realize(DeviceState *dev, Error **errp)
 115{
 116    FslIMX6State *s = FSL_IMX6(dev);
 117    uint16_t i;
 118    Error *err = NULL;
 119
 120    for (i = 0; i < smp_cpus; i++) {
 121
 122        /* On uniprocessor, the CBAR is set to 0 */
 123        if (smp_cpus > 1) {
 124            object_property_set_int(OBJECT(&s->cpu[i]), FSL_IMX6_A9MPCORE_ADDR,
 125                                    "reset-cbar", &error_abort);
 126        }
 127
 128        /* All CPU but CPU 0 start in power off mode */
 129        if (i) {
 130            object_property_set_bool(OBJECT(&s->cpu[i]), true,
 131                                     "start-powered-off", &error_abort);
 132        }
 133
 134        object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
 135        if (err) {
 136            error_propagate(errp, err);
 137            return;
 138        }
 139    }
 140
 141    object_property_set_int(OBJECT(&s->a9mpcore), smp_cpus, "num-cpu",
 142                            &error_abort);
 143
 144    object_property_set_int(OBJECT(&s->a9mpcore),
 145                            FSL_IMX6_MAX_IRQ + GIC_INTERNAL, "num-irq",
 146                            &error_abort);
 147
 148    object_property_set_bool(OBJECT(&s->a9mpcore), true, "realized", &err);
 149    if (err) {
 150        error_propagate(errp, err);
 151        return;
 152    }
 153    sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, FSL_IMX6_A9MPCORE_ADDR);
 154
 155    for (i = 0; i < smp_cpus; i++) {
 156        sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i,
 157                           qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
 158        sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + smp_cpus,
 159                           qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ));
 160    }
 161
 162    object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err);
 163    if (err) {
 164        error_propagate(errp, err);
 165        return;
 166    }
 167    sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX6_CCM_ADDR);
 168
 169    object_property_set_bool(OBJECT(&s->src), true, "realized", &err);
 170    if (err) {
 171        error_propagate(errp, err);
 172        return;
 173    }
 174    sysbus_mmio_map(SYS_BUS_DEVICE(&s->src), 0, FSL_IMX6_SRC_ADDR);
 175
 176    /* Initialize all UARTs */
 177    for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) {
 178        static const struct {
 179            hwaddr addr;
 180            unsigned int irq;
 181        } serial_table[FSL_IMX6_NUM_UARTS] = {
 182            { FSL_IMX6_UART1_ADDR, FSL_IMX6_UART1_IRQ },
 183            { FSL_IMX6_UART2_ADDR, FSL_IMX6_UART2_IRQ },
 184            { FSL_IMX6_UART3_ADDR, FSL_IMX6_UART3_IRQ },
 185            { FSL_IMX6_UART4_ADDR, FSL_IMX6_UART4_IRQ },
 186            { FSL_IMX6_UART5_ADDR, FSL_IMX6_UART5_IRQ },
 187        };
 188
 189        if (i < MAX_SERIAL_PORTS) {
 190            Chardev *chr;
 191
 192            chr = serial_hds[i];
 193
 194            if (!chr) {
 195                char *label = g_strdup_printf("imx6.uart%d", i + 1);
 196                chr = qemu_chr_new(label, "null");
 197                g_free(label);
 198                serial_hds[i] = chr;
 199            }
 200
 201            qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
 202        }
 203
 204        object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
 205        if (err) {
 206            error_propagate(errp, err);
 207            return;
 208        }
 209
 210        sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
 211        sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
 212                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 213                                            serial_table[i].irq));
 214    }
 215
 216    s->gpt.ccm = IMX_CCM(&s->ccm);
 217
 218    object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err);
 219    if (err) {
 220        error_propagate(errp, err);
 221        return;
 222    }
 223
 224    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX6_GPT_ADDR);
 225    sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0,
 226                       qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 227                                        FSL_IMX6_GPT_IRQ));
 228
 229    /* Initialize all EPIT timers */
 230    for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) {
 231        static const struct {
 232            hwaddr addr;
 233            unsigned int irq;
 234        } epit_table[FSL_IMX6_NUM_EPITS] = {
 235            { FSL_IMX6_EPIT1_ADDR, FSL_IMX6_EPIT1_IRQ },
 236            { FSL_IMX6_EPIT2_ADDR, FSL_IMX6_EPIT2_IRQ },
 237        };
 238
 239        s->epit[i].ccm = IMX_CCM(&s->ccm);
 240
 241        object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
 242        if (err) {
 243            error_propagate(errp, err);
 244            return;
 245        }
 246
 247        sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
 248        sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
 249                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 250                                            epit_table[i].irq));
 251    }
 252
 253    /* Initialize all I2C */
 254    for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) {
 255        static const struct {
 256            hwaddr addr;
 257            unsigned int irq;
 258        } i2c_table[FSL_IMX6_NUM_I2CS] = {
 259            { FSL_IMX6_I2C1_ADDR, FSL_IMX6_I2C1_IRQ },
 260            { FSL_IMX6_I2C2_ADDR, FSL_IMX6_I2C2_IRQ },
 261            { FSL_IMX6_I2C3_ADDR, FSL_IMX6_I2C3_IRQ }
 262        };
 263
 264        object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
 265        if (err) {
 266            error_propagate(errp, err);
 267            return;
 268        }
 269
 270        sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
 271        sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
 272                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 273                                            i2c_table[i].irq));
 274    }
 275
 276    /* Initialize all GPIOs */
 277    for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) {
 278        static const struct {
 279            hwaddr addr;
 280            unsigned int irq_low;
 281            unsigned int irq_high;
 282        } gpio_table[FSL_IMX6_NUM_GPIOS] = {
 283            {
 284                FSL_IMX6_GPIO1_ADDR,
 285                FSL_IMX6_GPIO1_LOW_IRQ,
 286                FSL_IMX6_GPIO1_HIGH_IRQ
 287            },
 288            {
 289                FSL_IMX6_GPIO2_ADDR,
 290                FSL_IMX6_GPIO2_LOW_IRQ,
 291                FSL_IMX6_GPIO2_HIGH_IRQ
 292            },
 293            {
 294                FSL_IMX6_GPIO3_ADDR,
 295                FSL_IMX6_GPIO3_LOW_IRQ,
 296                FSL_IMX6_GPIO3_HIGH_IRQ
 297            },
 298            {
 299                FSL_IMX6_GPIO4_ADDR,
 300                FSL_IMX6_GPIO4_LOW_IRQ,
 301                FSL_IMX6_GPIO4_HIGH_IRQ
 302            },
 303            {
 304                FSL_IMX6_GPIO5_ADDR,
 305                FSL_IMX6_GPIO5_LOW_IRQ,
 306                FSL_IMX6_GPIO5_HIGH_IRQ
 307            },
 308            {
 309                FSL_IMX6_GPIO6_ADDR,
 310                FSL_IMX6_GPIO6_LOW_IRQ,
 311                FSL_IMX6_GPIO6_HIGH_IRQ
 312            },
 313            {
 314                FSL_IMX6_GPIO7_ADDR,
 315                FSL_IMX6_GPIO7_LOW_IRQ,
 316                FSL_IMX6_GPIO7_HIGH_IRQ
 317            },
 318        };
 319
 320        object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-edge-sel",
 321                                 &error_abort);
 322        object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-upper-pin-irq",
 323                                 &error_abort);
 324        object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
 325        if (err) {
 326            error_propagate(errp, err);
 327            return;
 328        }
 329
 330        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
 331        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
 332                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 333                                            gpio_table[i].irq_low));
 334        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
 335                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 336                                            gpio_table[i].irq_high));
 337    }
 338
 339    /* Initialize all SDHC */
 340    for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) {
 341        static const struct {
 342            hwaddr addr;
 343            unsigned int irq;
 344        } esdhc_table[FSL_IMX6_NUM_ESDHCS] = {
 345            { FSL_IMX6_uSDHC1_ADDR, FSL_IMX6_uSDHC1_IRQ },
 346            { FSL_IMX6_uSDHC2_ADDR, FSL_IMX6_uSDHC2_IRQ },
 347            { FSL_IMX6_uSDHC3_ADDR, FSL_IMX6_uSDHC3_IRQ },
 348            { FSL_IMX6_uSDHC4_ADDR, FSL_IMX6_uSDHC4_IRQ },
 349        };
 350
 351        object_property_set_bool(OBJECT(&s->esdhc[i]), true, "realized", &err);
 352        if (err) {
 353            error_propagate(errp, err);
 354            return;
 355        }
 356        sysbus_mmio_map(SYS_BUS_DEVICE(&s->esdhc[i]), 0, esdhc_table[i].addr);
 357        sysbus_connect_irq(SYS_BUS_DEVICE(&s->esdhc[i]), 0,
 358                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 359                                            esdhc_table[i].irq));
 360    }
 361
 362    /* Initialize all ECSPI */
 363    for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) {
 364        static const struct {
 365            hwaddr addr;
 366            unsigned int irq;
 367        } spi_table[FSL_IMX6_NUM_ECSPIS] = {
 368            { FSL_IMX6_eCSPI1_ADDR, FSL_IMX6_ECSPI1_IRQ },
 369            { FSL_IMX6_eCSPI2_ADDR, FSL_IMX6_ECSPI2_IRQ },
 370            { FSL_IMX6_eCSPI3_ADDR, FSL_IMX6_ECSPI3_IRQ },
 371            { FSL_IMX6_eCSPI4_ADDR, FSL_IMX6_ECSPI4_IRQ },
 372            { FSL_IMX6_eCSPI5_ADDR, FSL_IMX6_ECSPI5_IRQ },
 373        };
 374
 375        /* Initialize the SPI */
 376        object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
 377        if (err) {
 378            error_propagate(errp, err);
 379            return;
 380        }
 381
 382        sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
 383        sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
 384                           qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 385                                            spi_table[i].irq));
 386    }
 387
 388    object_property_set_bool(OBJECT(&s->eth), true, "realized", &err);
 389    if (err) {
 390        error_propagate(errp, err);
 391        return;
 392    }
 393    sysbus_mmio_map(SYS_BUS_DEVICE(&s->eth), 0, FSL_IMX6_ENET_ADDR);
 394    sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 0,
 395                       qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 396                                        FSL_IMX6_ENET_MAC_IRQ));
 397    sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 1,
 398                       qdev_get_gpio_in(DEVICE(&s->a9mpcore),
 399                                        FSL_IMX6_ENET_MAC_1588_IRQ));
 400
 401    /* ROM memory */
 402    memory_region_init_rom(&s->rom, NULL, "imx6.rom",
 403                           FSL_IMX6_ROM_SIZE, &err);
 404    if (err) {
 405        error_propagate(errp, err);
 406        return;
 407    }
 408    memory_region_add_subregion(get_system_memory(), FSL_IMX6_ROM_ADDR,
 409                                &s->rom);
 410
 411    /* CAAM memory */
 412    memory_region_init_rom(&s->caam, NULL, "imx6.caam",
 413                           FSL_IMX6_CAAM_MEM_SIZE, &err);
 414    if (err) {
 415        error_propagate(errp, err);
 416        return;
 417    }
 418    memory_region_add_subregion(get_system_memory(), FSL_IMX6_CAAM_MEM_ADDR,
 419                                &s->caam);
 420
 421    /* OCRAM memory */
 422    memory_region_init_ram(&s->ocram, NULL, "imx6.ocram", FSL_IMX6_OCRAM_SIZE,
 423                           &err);
 424    if (err) {
 425        error_propagate(errp, err);
 426        return;
 427    }
 428    memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ADDR,
 429                                &s->ocram);
 430
 431    /* internal OCRAM (256 KB) is aliased over 1 MB */
 432    memory_region_init_alias(&s->ocram_alias, NULL, "imx6.ocram_alias",
 433                             &s->ocram, 0, FSL_IMX6_OCRAM_ALIAS_SIZE);
 434    memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ALIAS_ADDR,
 435                                &s->ocram_alias);
 436}
 437
 438static void fsl_imx6_class_init(ObjectClass *oc, void *data)
 439{
 440    DeviceClass *dc = DEVICE_CLASS(oc);
 441
 442    dc->realize = fsl_imx6_realize;
 443
 444    dc->desc = "i.MX6 SOC";
 445}
 446
 447static const TypeInfo fsl_imx6_type_info = {
 448    .name = TYPE_FSL_IMX6,
 449    .parent = TYPE_DEVICE,
 450    .instance_size = sizeof(FslIMX6State),
 451    .instance_init = fsl_imx6_init,
 452    .class_init = fsl_imx6_class_init,
 453};
 454
 455static void fsl_imx6_register_types(void)
 456{
 457    type_register_static(&fsl_imx6_type_info);
 458}
 459
 460type_init(fsl_imx6_register_types)
 461