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