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 32 static 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 114 static 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 qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); 389 object_property_set_bool(OBJECT(&s->eth), true, "realized", &err); 390 if (err) { 391 error_propagate(errp, err); 392 return; 393 } 394 sysbus_mmio_map(SYS_BUS_DEVICE(&s->eth), 0, FSL_IMX6_ENET_ADDR); 395 sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 0, 396 qdev_get_gpio_in(DEVICE(&s->a9mpcore), 397 FSL_IMX6_ENET_MAC_IRQ)); 398 sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 1, 399 qdev_get_gpio_in(DEVICE(&s->a9mpcore), 400 FSL_IMX6_ENET_MAC_1588_IRQ)); 401 402 /* ROM memory */ 403 memory_region_init_rom(&s->rom, NULL, "imx6.rom", 404 FSL_IMX6_ROM_SIZE, &err); 405 if (err) { 406 error_propagate(errp, err); 407 return; 408 } 409 memory_region_add_subregion(get_system_memory(), FSL_IMX6_ROM_ADDR, 410 &s->rom); 411 412 /* CAAM memory */ 413 memory_region_init_rom(&s->caam, NULL, "imx6.caam", 414 FSL_IMX6_CAAM_MEM_SIZE, &err); 415 if (err) { 416 error_propagate(errp, err); 417 return; 418 } 419 memory_region_add_subregion(get_system_memory(), FSL_IMX6_CAAM_MEM_ADDR, 420 &s->caam); 421 422 /* OCRAM memory */ 423 memory_region_init_ram(&s->ocram, NULL, "imx6.ocram", FSL_IMX6_OCRAM_SIZE, 424 &err); 425 if (err) { 426 error_propagate(errp, err); 427 return; 428 } 429 memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ADDR, 430 &s->ocram); 431 432 /* internal OCRAM (256 KB) is aliased over 1 MB */ 433 memory_region_init_alias(&s->ocram_alias, NULL, "imx6.ocram_alias", 434 &s->ocram, 0, FSL_IMX6_OCRAM_ALIAS_SIZE); 435 memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ALIAS_ADDR, 436 &s->ocram_alias); 437 } 438 439 static void fsl_imx6_class_init(ObjectClass *oc, void *data) 440 { 441 DeviceClass *dc = DEVICE_CLASS(oc); 442 443 dc->realize = fsl_imx6_realize; 444 dc->desc = "i.MX6 SOC"; 445 /* Reason: Uses serial_hds[] in the realize() function */ 446 dc->user_creatable = false; 447 } 448 449 static const TypeInfo fsl_imx6_type_info = { 450 .name = TYPE_FSL_IMX6, 451 .parent = TYPE_DEVICE, 452 .instance_size = sizeof(FslIMX6State), 453 .instance_init = fsl_imx6_init, 454 .class_init = fsl_imx6_class_init, 455 }; 456 457 static void fsl_imx6_register_types(void) 458 { 459 type_register_static(&fsl_imx6_type_info); 460 } 461 462 type_init(fsl_imx6_register_types) 463