qemu/hw/arm/fsl-imx25.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
   3 *
   4 * i.MX25 SOC emulation.
   5 *
   6 * Based on hw/arm/xlnx-zynqmp.c
   7 *
   8 * Copyright (C) 2015 Xilinx Inc
   9 * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
  10 *
  11 *  This program is free software; you can redistribute it and/or modify it
  12 *  under the terms of the GNU General Public License as published by the
  13 *  Free Software Foundation; either version 2 of the License, or
  14 *  (at your option) any later version.
  15 *
  16 *  This program is distributed in the hope that it will be useful, but WITHOUT
  17 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  18 *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  19 *  for more details.
  20 *
  21 *  You should have received a copy of the GNU General Public License along
  22 *  with this program; if not, see <http://www.gnu.org/licenses/>.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qapi/error.h"
  27#include "cpu.h"
  28#include "hw/arm/fsl-imx25.h"
  29#include "sysemu/sysemu.h"
  30#include "exec/address-spaces.h"
  31#include "hw/qdev-properties.h"
  32#include "chardev/char.h"
  33
  34#define IMX25_ESDHC_CAPABILITIES     0x07e20000
  35
  36static void fsl_imx25_init(Object *obj)
  37{
  38    FslIMX25State *s = FSL_IMX25(obj);
  39    int i;
  40
  41    object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("arm926"));
  42
  43    object_initialize_child(obj, "avic", &s->avic, TYPE_IMX_AVIC);
  44
  45    object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX25_CCM);
  46
  47    for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
  48        object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_IMX_SERIAL);
  49    }
  50
  51    for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
  52        object_initialize_child(obj, "gpt[*]", &s->gpt[i], TYPE_IMX25_GPT);
  53    }
  54
  55    for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) {
  56        object_initialize_child(obj, "epit[*]", &s->epit[i], TYPE_IMX_EPIT);
  57    }
  58
  59    object_initialize_child(obj, "fec", &s->fec, TYPE_IMX_FEC);
  60
  61    object_initialize_child(obj, "rngc", &s->rngc, TYPE_IMX_RNGC);
  62
  63    for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
  64        object_initialize_child(obj, "i2c[*]", &s->i2c[i], TYPE_IMX_I2C);
  65    }
  66
  67    for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
  68        object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_IMX_GPIO);
  69    }
  70
  71    for (i = 0; i < FSL_IMX25_NUM_ESDHCS; i++) {
  72        object_initialize_child(obj, "sdhc[*]", &s->esdhc[i], TYPE_IMX_USDHC);
  73    }
  74
  75    for (i = 0; i < FSL_IMX25_NUM_USBS; i++) {
  76        object_initialize_child(obj, "usb[*]", &s->usb[i], TYPE_CHIPIDEA);
  77    }
  78
  79    object_initialize_child(obj, "wdt", &s->wdt, TYPE_IMX2_WDT);
  80}
  81
  82static void fsl_imx25_realize(DeviceState *dev, Error **errp)
  83{
  84    FslIMX25State *s = FSL_IMX25(dev);
  85    uint8_t i;
  86    Error *err = NULL;
  87
  88    if (!qdev_realize(DEVICE(&s->cpu), NULL, errp)) {
  89        return;
  90    }
  91
  92    if (!sysbus_realize(SYS_BUS_DEVICE(&s->avic), errp)) {
  93        return;
  94    }
  95    sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX25_AVIC_ADDR);
  96    sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0,
  97                       qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
  98    sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1,
  99                       qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
 100
 101    if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) {
 102        return;
 103    }
 104    sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX25_CCM_ADDR);
 105
 106    /* Initialize all UARTs */
 107    for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
 108        static const struct {
 109            hwaddr addr;
 110            unsigned int irq;
 111        } serial_table[FSL_IMX25_NUM_UARTS] = {
 112            { FSL_IMX25_UART1_ADDR, FSL_IMX25_UART1_IRQ },
 113            { FSL_IMX25_UART2_ADDR, FSL_IMX25_UART2_IRQ },
 114            { FSL_IMX25_UART3_ADDR, FSL_IMX25_UART3_IRQ },
 115            { FSL_IMX25_UART4_ADDR, FSL_IMX25_UART4_IRQ },
 116            { FSL_IMX25_UART5_ADDR, FSL_IMX25_UART5_IRQ }
 117        };
 118
 119        qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i));
 120
 121        if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
 122            return;
 123        }
 124        sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
 125        sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
 126                           qdev_get_gpio_in(DEVICE(&s->avic),
 127                                            serial_table[i].irq));
 128    }
 129
 130    /* Initialize all GPT timers */
 131    for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
 132        static const struct {
 133            hwaddr addr;
 134            unsigned int irq;
 135        } gpt_table[FSL_IMX25_NUM_GPTS] = {
 136            { FSL_IMX25_GPT1_ADDR, FSL_IMX25_GPT1_IRQ },
 137            { FSL_IMX25_GPT2_ADDR, FSL_IMX25_GPT2_IRQ },
 138            { FSL_IMX25_GPT3_ADDR, FSL_IMX25_GPT3_IRQ },
 139            { FSL_IMX25_GPT4_ADDR, FSL_IMX25_GPT4_IRQ }
 140        };
 141
 142        s->gpt[i].ccm = IMX_CCM(&s->ccm);
 143
 144        if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), errp)) {
 145            return;
 146        }
 147        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_table[i].addr);
 148        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
 149                           qdev_get_gpio_in(DEVICE(&s->avic),
 150                                            gpt_table[i].irq));
 151    }
 152
 153    /* Initialize all EPIT timers */
 154    for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) {
 155        static const struct {
 156            hwaddr addr;
 157            unsigned int irq;
 158        } epit_table[FSL_IMX25_NUM_EPITS] = {
 159            { FSL_IMX25_EPIT1_ADDR, FSL_IMX25_EPIT1_IRQ },
 160            { FSL_IMX25_EPIT2_ADDR, FSL_IMX25_EPIT2_IRQ }
 161        };
 162
 163        s->epit[i].ccm = IMX_CCM(&s->ccm);
 164
 165        if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), errp)) {
 166            return;
 167        }
 168        sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
 169        sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
 170                           qdev_get_gpio_in(DEVICE(&s->avic),
 171                                            epit_table[i].irq));
 172    }
 173
 174    object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num, &err);
 175    qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]);
 176
 177    if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), errp)) {
 178        return;
 179    }
 180    sysbus_mmio_map(SYS_BUS_DEVICE(&s->fec), 0, FSL_IMX25_FEC_ADDR);
 181    sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0,
 182                       qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ));
 183
 184    if (!sysbus_realize(SYS_BUS_DEVICE(&s->rngc), errp)) {
 185        return;
 186    }
 187    sysbus_mmio_map(SYS_BUS_DEVICE(&s->rngc), 0, FSL_IMX25_RNGC_ADDR);
 188    sysbus_connect_irq(SYS_BUS_DEVICE(&s->rngc), 0,
 189                       qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_RNGC_IRQ));
 190
 191    /* Initialize all I2C */
 192    for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
 193        static const struct {
 194            hwaddr addr;
 195            unsigned int irq;
 196        } i2c_table[FSL_IMX25_NUM_I2CS] = {
 197            { FSL_IMX25_I2C1_ADDR, FSL_IMX25_I2C1_IRQ },
 198            { FSL_IMX25_I2C2_ADDR, FSL_IMX25_I2C2_IRQ },
 199            { FSL_IMX25_I2C3_ADDR, FSL_IMX25_I2C3_IRQ }
 200        };
 201
 202        if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) {
 203            return;
 204        }
 205        sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
 206        sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
 207                           qdev_get_gpio_in(DEVICE(&s->avic),
 208                                            i2c_table[i].irq));
 209    }
 210
 211    /* Initialize all GPIOs */
 212    for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
 213        static const struct {
 214            hwaddr addr;
 215            unsigned int irq;
 216        } gpio_table[FSL_IMX25_NUM_GPIOS] = {
 217            { FSL_IMX25_GPIO1_ADDR, FSL_IMX25_GPIO1_IRQ },
 218            { FSL_IMX25_GPIO2_ADDR, FSL_IMX25_GPIO2_IRQ },
 219            { FSL_IMX25_GPIO3_ADDR, FSL_IMX25_GPIO3_IRQ },
 220            { FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ }
 221        };
 222
 223        if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) {
 224            return;
 225        }
 226        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
 227        /* Connect GPIO IRQ to PIC */
 228        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
 229                           qdev_get_gpio_in(DEVICE(&s->avic),
 230                                            gpio_table[i].irq));
 231    }
 232
 233    /* Initialize all SDHC */
 234    for (i = 0; i < FSL_IMX25_NUM_ESDHCS; i++) {
 235        static const struct {
 236            hwaddr addr;
 237            unsigned int irq;
 238        } esdhc_table[FSL_IMX25_NUM_ESDHCS] = {
 239            { FSL_IMX25_ESDHC1_ADDR, FSL_IMX25_ESDHC1_IRQ },
 240            { FSL_IMX25_ESDHC2_ADDR, FSL_IMX25_ESDHC2_IRQ },
 241        };
 242
 243        object_property_set_uint(OBJECT(&s->esdhc[i]), "sd-spec-version", 2,
 244                                 &error_abort);
 245        object_property_set_uint(OBJECT(&s->esdhc[i]), "capareg",
 246                                 IMX25_ESDHC_CAPABILITIES, &error_abort);
 247        object_property_set_uint(OBJECT(&s->esdhc[i]), "vendor",
 248                                 SDHCI_VENDOR_IMX, &error_abort);
 249        if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), errp)) {
 250            return;
 251        }
 252        sysbus_mmio_map(SYS_BUS_DEVICE(&s->esdhc[i]), 0, esdhc_table[i].addr);
 253        sysbus_connect_irq(SYS_BUS_DEVICE(&s->esdhc[i]), 0,
 254                           qdev_get_gpio_in(DEVICE(&s->avic),
 255                                            esdhc_table[i].irq));
 256    }
 257
 258    /* USB */
 259    for (i = 0; i < FSL_IMX25_NUM_USBS; i++) {
 260        static const struct {
 261            hwaddr addr;
 262            unsigned int irq;
 263        } usb_table[FSL_IMX25_NUM_USBS] = {
 264            { FSL_IMX25_USB1_ADDR, FSL_IMX25_USB1_IRQ },
 265            { FSL_IMX25_USB2_ADDR, FSL_IMX25_USB2_IRQ },
 266        };
 267
 268        sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), &error_abort);
 269        sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, usb_table[i].addr);
 270        sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i]), 0,
 271                           qdev_get_gpio_in(DEVICE(&s->avic),
 272                                            usb_table[i].irq));
 273    }
 274
 275    /* Watchdog */
 276    object_property_set_bool(OBJECT(&s->wdt), "pretimeout-support", true,
 277                             &error_abort);
 278    sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort);
 279    sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, FSL_IMX25_WDT_ADDR);
 280    sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt), 0,
 281                                      qdev_get_gpio_in(DEVICE(&s->avic),
 282                                                       FSL_IMX25_WDT_IRQ));
 283
 284    /* initialize 2 x 16 KB ROM */
 285    memory_region_init_rom(&s->rom[0], OBJECT(dev), "imx25.rom0",
 286                           FSL_IMX25_ROM0_SIZE, &err);
 287    if (err) {
 288        error_propagate(errp, err);
 289        return;
 290    }
 291    memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
 292                                &s->rom[0]);
 293    memory_region_init_rom(&s->rom[1], OBJECT(dev), "imx25.rom1",
 294                           FSL_IMX25_ROM1_SIZE, &err);
 295    if (err) {
 296        error_propagate(errp, err);
 297        return;
 298    }
 299    memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM1_ADDR,
 300                                &s->rom[1]);
 301
 302    /* initialize internal RAM (128 KB) */
 303    memory_region_init_ram(&s->iram, NULL, "imx25.iram", FSL_IMX25_IRAM_SIZE,
 304                           &err);
 305    if (err) {
 306        error_propagate(errp, err);
 307        return;
 308    }
 309    memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ADDR,
 310                                &s->iram);
 311
 312    /* internal RAM (128 KB) is aliased over 128 MB - 128 KB */
 313    memory_region_init_alias(&s->iram_alias, OBJECT(dev), "imx25.iram_alias",
 314                             &s->iram, 0, FSL_IMX25_IRAM_ALIAS_SIZE);
 315    memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ALIAS_ADDR,
 316                                &s->iram_alias);
 317}
 318
 319static Property fsl_imx25_properties[] = {
 320    DEFINE_PROP_UINT32("fec-phy-num", FslIMX25State, phy_num, 0),
 321    DEFINE_PROP_END_OF_LIST(),
 322};
 323
 324static void fsl_imx25_class_init(ObjectClass *oc, void *data)
 325{
 326    DeviceClass *dc = DEVICE_CLASS(oc);
 327
 328    device_class_set_props(dc, fsl_imx25_properties);
 329    dc->realize = fsl_imx25_realize;
 330    dc->desc = "i.MX25 SOC";
 331    /*
 332     * Reason: uses serial_hds in realize and the imx25 board does not
 333     * support multiple CPUs
 334     */
 335    dc->user_creatable = false;
 336}
 337
 338static const TypeInfo fsl_imx25_type_info = {
 339    .name = TYPE_FSL_IMX25,
 340    .parent = TYPE_DEVICE,
 341    .instance_size = sizeof(FslIMX25State),
 342    .instance_init = fsl_imx25_init,
 343    .class_init = fsl_imx25_class_init,
 344};
 345
 346static void fsl_imx25_register_types(void)
 347{
 348    type_register_static(&fsl_imx25_type_info);
 349}
 350
 351type_init(fsl_imx25_register_types)
 352