xref: /openbmc/qemu/hw/arm/fsl-imx6.c (revision 0bdb12c7)
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 "sysemu/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              CharDriverState *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", 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      vmstate_register_ram_global(&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  
445      /*
446       * Reason: creates an ARM CPU, thus use after free(), see
447       * arm_cpu_class_init()
448       */
449      dc->cannot_destroy_with_object_finalize_yet = true;
450      dc->desc = "i.MX6 SOC";
451  }
452  
453  static const TypeInfo fsl_imx6_type_info = {
454      .name = TYPE_FSL_IMX6,
455      .parent = TYPE_DEVICE,
456      .instance_size = sizeof(FslIMX6State),
457      .instance_init = fsl_imx6_init,
458      .class_init = fsl_imx6_class_init,
459  };
460  
461  static void fsl_imx6_register_types(void)
462  {
463      type_register_static(&fsl_imx6_type_info);
464  }
465  
466  type_init(fsl_imx6_register_types)
467