2 * Copyright (c) 2018, Impinj, Inc.
4 * i.MX7 SoC definitions
6 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
8 * Based on hw/arm/fsl-imx6.c
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "qemu/osdep.h"
22 #include "qapi/error.h"
23 #include "qemu-common.h"
24 #include "hw/arm/fsl-imx7.h"
25 #include "hw/misc/unimp.h"
26 #include "sysemu/sysemu.h"
27 #include "qemu/error-report.h"
31 static void fsl_imx7_init(Object
*obj
)
33 BusState
*sysbus
= sysbus_get_default();
34 FslIMX7State
*s
= FSL_IMX7(obj
);
38 if (smp_cpus
> FSL_IMX7_NUM_CPUS
) {
39 error_report("%s: Only %d CPUs are supported (%d requested)",
40 TYPE_FSL_IMX7
, FSL_IMX7_NUM_CPUS
, smp_cpus
);
44 for (i
= 0; i
< smp_cpus
; i
++) {
45 object_initialize(&s
->cpu
[i
], sizeof(s
->cpu
[i
]),
46 ARM_CPU_TYPE_NAME("cortex-a7"));
47 snprintf(name
, NAME_SIZE
, "cpu%d", i
);
48 object_property_add_child(obj
, name
, OBJECT(&s
->cpu
[i
]),
55 object_initialize(&s
->a7mpcore
, sizeof(s
->a7mpcore
), TYPE_A15MPCORE_PRIV
);
56 qdev_set_parent_bus(DEVICE(&s
->a7mpcore
), sysbus
);
57 object_property_add_child(obj
, "a7mpcore",
58 OBJECT(&s
->a7mpcore
), &error_fatal
);
63 for (i
= 0; i
< FSL_IMX7_NUM_GPIOS
; i
++) {
64 object_initialize(&s
->gpio
[i
], sizeof(s
->gpio
[i
]),
66 qdev_set_parent_bus(DEVICE(&s
->gpio
[i
]), sysbus
);
67 snprintf(name
, NAME_SIZE
, "gpio%d", i
);
68 object_property_add_child(obj
, name
,
69 OBJECT(&s
->gpio
[i
]), &error_fatal
);
75 for (i
= 0; i
< FSL_IMX7_NUM_GPTS
; i
++) {
76 object_initialize(&s
->gpt
[i
], sizeof(s
->gpt
[i
]), TYPE_IMX7_GPT
);
77 qdev_set_parent_bus(DEVICE(&s
->gpt
[i
]), sysbus
);
78 snprintf(name
, NAME_SIZE
, "gpt%d", i
);
79 object_property_add_child(obj
, name
, OBJECT(&s
->gpt
[i
]),
86 object_initialize(&s
->ccm
, sizeof(s
->ccm
), TYPE_IMX7_CCM
);
87 qdev_set_parent_bus(DEVICE(&s
->ccm
), sysbus
);
88 object_property_add_child(obj
, "ccm", OBJECT(&s
->ccm
), &error_fatal
);
93 object_initialize(&s
->analog
, sizeof(s
->analog
), TYPE_IMX7_ANALOG
);
94 qdev_set_parent_bus(DEVICE(&s
->analog
), sysbus
);
95 object_property_add_child(obj
, "analog", OBJECT(&s
->analog
), &error_fatal
);
100 object_initialize(&s
->gpcv2
, sizeof(s
->gpcv2
), TYPE_IMX_GPCV2
);
101 qdev_set_parent_bus(DEVICE(&s
->gpcv2
), sysbus
);
102 object_property_add_child(obj
, "gpcv2", OBJECT(&s
->gpcv2
), &error_fatal
);
104 for (i
= 0; i
< FSL_IMX7_NUM_ECSPIS
; i
++) {
105 object_initialize(&s
->spi
[i
], sizeof(s
->spi
[i
]), TYPE_IMX_SPI
);
106 qdev_set_parent_bus(DEVICE(&s
->spi
[i
]), sysbus_get_default());
107 snprintf(name
, NAME_SIZE
, "spi%d", i
+ 1);
108 object_property_add_child(obj
, name
, OBJECT(&s
->spi
[i
]), NULL
);
112 for (i
= 0; i
< FSL_IMX7_NUM_I2CS
; i
++) {
113 object_initialize(&s
->i2c
[i
], sizeof(s
->i2c
[i
]), TYPE_IMX_I2C
);
114 qdev_set_parent_bus(DEVICE(&s
->i2c
[i
]), sysbus_get_default());
115 snprintf(name
, NAME_SIZE
, "i2c%d", i
+ 1);
116 object_property_add_child(obj
, name
, OBJECT(&s
->i2c
[i
]), NULL
);
122 for (i
= 0; i
< FSL_IMX7_NUM_UARTS
; i
++) {
123 object_initialize(&s
->uart
[i
], sizeof(s
->uart
[i
]), TYPE_IMX_SERIAL
);
124 qdev_set_parent_bus(DEVICE(&s
->uart
[i
]), sysbus
);
125 snprintf(name
, NAME_SIZE
, "uart%d", i
);
126 object_property_add_child(obj
, name
, OBJECT(&s
->uart
[i
]),
133 for (i
= 0; i
< FSL_IMX7_NUM_ETHS
; i
++) {
134 object_initialize(&s
->eth
[i
], sizeof(s
->eth
[i
]), TYPE_IMX_ENET
);
135 qdev_set_parent_bus(DEVICE(&s
->eth
[i
]), sysbus
);
136 snprintf(name
, NAME_SIZE
, "eth%d", i
);
137 object_property_add_child(obj
, name
, OBJECT(&s
->eth
[i
]),
144 for (i
= 0; i
< FSL_IMX7_NUM_USDHCS
; i
++) {
145 object_initialize(&s
->usdhc
[i
], sizeof(s
->usdhc
[i
]),
147 qdev_set_parent_bus(DEVICE(&s
->usdhc
[i
]), sysbus
);
148 snprintf(name
, NAME_SIZE
, "usdhc%d", i
);
149 object_property_add_child(obj
, name
, OBJECT(&s
->usdhc
[i
]),
156 object_initialize(&s
->snvs
, sizeof(s
->snvs
), TYPE_IMX7_SNVS
);
157 qdev_set_parent_bus(DEVICE(&s
->snvs
), sysbus
);
158 object_property_add_child(obj
, "snvs", OBJECT(&s
->snvs
), &error_fatal
);
163 for (i
= 0; i
< FSL_IMX7_NUM_WDTS
; i
++) {
164 object_initialize(&s
->wdt
[i
], sizeof(s
->wdt
[i
]), TYPE_IMX2_WDT
);
165 qdev_set_parent_bus(DEVICE(&s
->wdt
[i
]), sysbus
);
166 snprintf(name
, NAME_SIZE
, "wdt%d", i
);
167 object_property_add_child(obj
, name
, OBJECT(&s
->wdt
[i
]),
174 object_initialize(&s
->gpr
, sizeof(s
->gpr
), TYPE_IMX7_GPR
);
175 qdev_set_parent_bus(DEVICE(&s
->gpr
), sysbus
);
176 object_property_add_child(obj
, "gpr", OBJECT(&s
->gpr
), &error_fatal
);
178 object_initialize(&s
->pcie
, sizeof(s
->pcie
), TYPE_DESIGNWARE_PCIE_HOST
);
179 qdev_set_parent_bus(DEVICE(&s
->pcie
), sysbus
);
180 object_property_add_child(obj
, "pcie", OBJECT(&s
->pcie
), &error_fatal
);
182 for (i
= 0; i
< FSL_IMX7_NUM_USBS
; i
++) {
183 object_initialize(&s
->usb
[i
],
184 sizeof(s
->usb
[i
]), TYPE_CHIPIDEA
);
185 qdev_set_parent_bus(DEVICE(&s
->usb
[i
]), sysbus
);
186 snprintf(name
, NAME_SIZE
, "usb%d", i
);
187 object_property_add_child(obj
, name
,
188 OBJECT(&s
->usb
[i
]), &error_fatal
);
192 static void fsl_imx7_realize(DeviceState
*dev
, Error
**errp
)
194 FslIMX7State
*s
= FSL_IMX7(dev
);
198 char name
[NAME_SIZE
];
200 for (i
= 0; i
< smp_cpus
; i
++) {
201 o
= OBJECT(&s
->cpu
[i
]);
203 object_property_set_int(o
, QEMU_PSCI_CONDUIT_SMC
,
204 "psci-conduit", &error_abort
);
206 /* On uniprocessor, the CBAR is set to 0 */
208 object_property_set_int(o
, FSL_IMX7_A7MPCORE_ADDR
,
209 "reset-cbar", &error_abort
);
213 /* Secondary CPUs start in PSCI powered-down state */
214 object_property_set_bool(o
, true,
215 "start-powered-off", &error_abort
);
218 object_property_set_bool(o
, true, "realized", &error_abort
);
224 object_property_set_int(OBJECT(&s
->a7mpcore
), smp_cpus
, "num-cpu",
226 object_property_set_int(OBJECT(&s
->a7mpcore
),
227 FSL_IMX7_MAX_IRQ
+ GIC_INTERNAL
,
228 "num-irq", &error_abort
);
230 object_property_set_bool(OBJECT(&s
->a7mpcore
), true, "realized",
232 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->a7mpcore
), 0, FSL_IMX7_A7MPCORE_ADDR
);
234 for (i
= 0; i
< smp_cpus
; i
++) {
235 SysBusDevice
*sbd
= SYS_BUS_DEVICE(&s
->a7mpcore
);
236 DeviceState
*d
= DEVICE(qemu_get_cpu(i
));
238 irq
= qdev_get_gpio_in(d
, ARM_CPU_IRQ
);
239 sysbus_connect_irq(sbd
, i
, irq
);
240 irq
= qdev_get_gpio_in(d
, ARM_CPU_FIQ
);
241 sysbus_connect_irq(sbd
, i
+ smp_cpus
, irq
);
247 create_unimplemented_device("a7mpcore-dap", FSL_IMX7_A7MPCORE_DAP_ADDR
,
253 for (i
= 0; i
< FSL_IMX7_NUM_GPTS
; i
++) {
254 static const hwaddr FSL_IMX7_GPTn_ADDR
[FSL_IMX7_NUM_GPTS
] = {
261 s
->gpt
[i
].ccm
= IMX_CCM(&s
->ccm
);
262 object_property_set_bool(OBJECT(&s
->gpt
[i
]), true, "realized",
264 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->gpt
[i
]), 0, FSL_IMX7_GPTn_ADDR
[i
]);
267 for (i
= 0; i
< FSL_IMX7_NUM_GPIOS
; i
++) {
268 static const hwaddr FSL_IMX7_GPIOn_ADDR
[FSL_IMX7_NUM_GPIOS
] = {
278 object_property_set_bool(OBJECT(&s
->gpio
[i
]), true, "realized",
280 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->gpio
[i
]), 0, FSL_IMX7_GPIOn_ADDR
[i
]);
284 * IOMUXC and IOMUXC_LPSR
286 for (i
= 0; i
< FSL_IMX7_NUM_IOMUXCS
; i
++) {
287 static const hwaddr FSL_IMX7_IOMUXCn_ADDR
[FSL_IMX7_NUM_IOMUXCS
] = {
288 FSL_IMX7_IOMUXC_ADDR
,
289 FSL_IMX7_IOMUXC_LPSR_ADDR
,
292 snprintf(name
, NAME_SIZE
, "iomuxc%d", i
);
293 create_unimplemented_device(name
, FSL_IMX7_IOMUXCn_ADDR
[i
],
294 FSL_IMX7_IOMUXCn_SIZE
);
300 object_property_set_bool(OBJECT(&s
->ccm
), true, "realized", &error_abort
);
301 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->ccm
), 0, FSL_IMX7_CCM_ADDR
);
306 object_property_set_bool(OBJECT(&s
->analog
), true, "realized",
308 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->analog
), 0, FSL_IMX7_ANALOG_ADDR
);
313 object_property_set_bool(OBJECT(&s
->gpcv2
), true,
314 "realized", &error_abort
);
315 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->gpcv2
), 0, FSL_IMX7_GPC_ADDR
);
317 /* Initialize all ECSPI */
318 for (i
= 0; i
< FSL_IMX7_NUM_ECSPIS
; i
++) {
319 static const hwaddr FSL_IMX7_SPIn_ADDR
[FSL_IMX7_NUM_ECSPIS
] = {
320 FSL_IMX7_ECSPI1_ADDR
,
321 FSL_IMX7_ECSPI2_ADDR
,
322 FSL_IMX7_ECSPI3_ADDR
,
323 FSL_IMX7_ECSPI4_ADDR
,
326 static const hwaddr FSL_IMX7_SPIn_IRQ
[FSL_IMX7_NUM_ECSPIS
] = {
333 /* Initialize the SPI */
334 object_property_set_bool(OBJECT(&s
->spi
[i
]), true, "realized",
336 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->spi
[i
]), 0,
337 FSL_IMX7_SPIn_ADDR
[i
]);
338 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->spi
[i
]), 0,
339 qdev_get_gpio_in(DEVICE(&s
->a7mpcore
),
340 FSL_IMX7_SPIn_IRQ
[i
]));
343 for (i
= 0; i
< FSL_IMX7_NUM_I2CS
; i
++) {
344 static const hwaddr FSL_IMX7_I2Cn_ADDR
[FSL_IMX7_NUM_I2CS
] = {
351 static const hwaddr FSL_IMX7_I2Cn_IRQ
[FSL_IMX7_NUM_I2CS
] = {
358 object_property_set_bool(OBJECT(&s
->i2c
[i
]), true, "realized",
360 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->i2c
[i
]), 0, FSL_IMX7_I2Cn_ADDR
[i
]);
362 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->i2c
[i
]), 0,
363 qdev_get_gpio_in(DEVICE(&s
->a7mpcore
),
364 FSL_IMX7_I2Cn_IRQ
[i
]));
370 for (i
= 0; i
< FSL_IMX7_NUM_UARTS
; i
++) {
371 static const hwaddr FSL_IMX7_UARTn_ADDR
[FSL_IMX7_NUM_UARTS
] = {
381 static const int FSL_IMX7_UARTn_IRQ
[FSL_IMX7_NUM_UARTS
] = {
392 if (i
< MAX_SERIAL_PORTS
) {
393 qdev_prop_set_chr(DEVICE(&s
->uart
[i
]), "chardev", serial_hds
[i
]);
396 object_property_set_bool(OBJECT(&s
->uart
[i
]), true, "realized",
399 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->uart
[i
]), 0, FSL_IMX7_UARTn_ADDR
[i
]);
401 irq
= qdev_get_gpio_in(DEVICE(&s
->a7mpcore
), FSL_IMX7_UARTn_IRQ
[i
]);
402 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->uart
[i
]), 0, irq
);
408 for (i
= 0; i
< FSL_IMX7_NUM_ETHS
; i
++) {
409 static const hwaddr FSL_IMX7_ENETn_ADDR
[FSL_IMX7_NUM_ETHS
] = {
414 object_property_set_uint(OBJECT(&s
->eth
[i
]), FSL_IMX7_ETH_NUM_TX_RINGS
,
415 "tx-ring-num", &error_abort
);
416 qdev_set_nic_properties(DEVICE(&s
->eth
[i
]), &nd_table
[i
]);
417 object_property_set_bool(OBJECT(&s
->eth
[i
]), true, "realized",
420 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->eth
[i
]), 0, FSL_IMX7_ENETn_ADDR
[i
]);
422 irq
= qdev_get_gpio_in(DEVICE(&s
->a7mpcore
), FSL_IMX7_ENET_IRQ(i
, 0));
423 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->eth
[i
]), 0, irq
);
424 irq
= qdev_get_gpio_in(DEVICE(&s
->a7mpcore
), FSL_IMX7_ENET_IRQ(i
, 3));
425 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->eth
[i
]), 1, irq
);
431 for (i
= 0; i
< FSL_IMX7_NUM_USDHCS
; i
++) {
432 static const hwaddr FSL_IMX7_USDHCn_ADDR
[FSL_IMX7_NUM_USDHCS
] = {
433 FSL_IMX7_USDHC1_ADDR
,
434 FSL_IMX7_USDHC2_ADDR
,
435 FSL_IMX7_USDHC3_ADDR
,
438 static const int FSL_IMX7_USDHCn_IRQ
[FSL_IMX7_NUM_USDHCS
] = {
444 object_property_set_bool(OBJECT(&s
->usdhc
[i
]), true, "realized",
447 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->usdhc
[i
]), 0,
448 FSL_IMX7_USDHCn_ADDR
[i
]);
450 irq
= qdev_get_gpio_in(DEVICE(&s
->a7mpcore
), FSL_IMX7_USDHCn_IRQ
[i
]);
451 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->usdhc
[i
]), 0, irq
);
457 object_property_set_bool(OBJECT(&s
->snvs
), true, "realized", &error_abort
);
458 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->snvs
), 0, FSL_IMX7_SNVS_ADDR
);
463 create_unimplemented_device("sdma", FSL_IMX7_SRC_ADDR
, FSL_IMX7_SRC_SIZE
);
468 for (i
= 0; i
< FSL_IMX7_NUM_WDTS
; i
++) {
469 static const hwaddr FSL_IMX7_WDOGn_ADDR
[FSL_IMX7_NUM_WDTS
] = {
476 object_property_set_bool(OBJECT(&s
->wdt
[i
]), true, "realized",
479 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->wdt
[i
]), 0, FSL_IMX7_WDOGn_ADDR
[i
]);
485 create_unimplemented_device("sdma", FSL_IMX7_SDMA_ADDR
, FSL_IMX7_SDMA_SIZE
);
488 object_property_set_bool(OBJECT(&s
->gpr
), true, "realized",
490 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->gpr
), 0, FSL_IMX7_GPR_ADDR
);
492 object_property_set_bool(OBJECT(&s
->pcie
), true,
493 "realized", &error_abort
);
494 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->pcie
), 0, FSL_IMX7_PCIE_REG_ADDR
);
496 irq
= qdev_get_gpio_in(DEVICE(&s
->a7mpcore
), FSL_IMX7_PCI_INTA_IRQ
);
497 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->pcie
), 0, irq
);
498 irq
= qdev_get_gpio_in(DEVICE(&s
->a7mpcore
), FSL_IMX7_PCI_INTB_IRQ
);
499 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->pcie
), 1, irq
);
500 irq
= qdev_get_gpio_in(DEVICE(&s
->a7mpcore
), FSL_IMX7_PCI_INTC_IRQ
);
501 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->pcie
), 2, irq
);
502 irq
= qdev_get_gpio_in(DEVICE(&s
->a7mpcore
), FSL_IMX7_PCI_INTD_IRQ
);
503 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->pcie
), 3, irq
);
506 for (i
= 0; i
< FSL_IMX7_NUM_USBS
; i
++) {
507 static const hwaddr FSL_IMX7_USBMISCn_ADDR
[FSL_IMX7_NUM_USBS
] = {
508 FSL_IMX7_USBMISC1_ADDR
,
509 FSL_IMX7_USBMISC2_ADDR
,
510 FSL_IMX7_USBMISC3_ADDR
,
513 static const hwaddr FSL_IMX7_USBn_ADDR
[FSL_IMX7_NUM_USBS
] = {
519 static const hwaddr FSL_IMX7_USBn_IRQ
[FSL_IMX7_NUM_USBS
] = {
525 object_property_set_bool(OBJECT(&s
->usb
[i
]), true, "realized",
527 sysbus_mmio_map(SYS_BUS_DEVICE(&s
->usb
[i
]), 0,
528 FSL_IMX7_USBn_ADDR
[i
]);
530 irq
= qdev_get_gpio_in(DEVICE(&s
->a7mpcore
), FSL_IMX7_USBn_IRQ
[i
]);
531 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->usb
[i
]), 0, irq
);
533 snprintf(name
, NAME_SIZE
, "usbmisc%d", i
);
534 create_unimplemented_device(name
, FSL_IMX7_USBMISCn_ADDR
[i
],
535 FSL_IMX7_USBMISCn_SIZE
);
541 for (i
= 0; i
< FSL_IMX7_NUM_ADCS
; i
++) {
542 static const hwaddr FSL_IMX7_ADCn_ADDR
[FSL_IMX7_NUM_ADCS
] = {
547 snprintf(name
, NAME_SIZE
, "adc%d", i
);
548 create_unimplemented_device(name
, FSL_IMX7_ADCn_ADDR
[i
],
555 create_unimplemented_device("lcdif", FSL_IMX7_LCDIF_ADDR
,
556 FSL_IMX7_LCDIF_SIZE
);
559 static void fsl_imx7_class_init(ObjectClass
*oc
, void *data
)
561 DeviceClass
*dc
= DEVICE_CLASS(oc
);
563 dc
->realize
= fsl_imx7_realize
;
565 /* Reason: Uses serial_hds and nd_table in realize() directly */
566 dc
->user_creatable
= false;
567 dc
->desc
= "i.MX7 SOC";
570 static const TypeInfo fsl_imx7_type_info
= {
571 .name
= TYPE_FSL_IMX7
,
572 .parent
= TYPE_DEVICE
,
573 .instance_size
= sizeof(FslIMX7State
),
574 .instance_init
= fsl_imx7_init
,
575 .class_init
= fsl_imx7_class_init
,
578 static void fsl_imx7_register_types(void)
580 type_register_static(&fsl_imx7_type_info
);
582 type_init(fsl_imx7_register_types
)