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
34static void fsl_imx25_init(Object *obj)
35{
36 FslIMX25State *s = FSL_IMX25(obj);
37 int i;
38
39 object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu),
40 ARM_CPU_TYPE_NAME("arm926"),
41 &error_abort, NULL);
42
43 sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic),
44 TYPE_IMX_AVIC);
45
46 sysbus_init_child_obj(obj, "ccm", &s->ccm, sizeof(s->ccm), TYPE_IMX25_CCM);
47
48 for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
49 sysbus_init_child_obj(obj, "uart[*]", &s->uart[i], sizeof(s->uart[i]),
50 TYPE_IMX_SERIAL);
51 }
52
53 for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
54 sysbus_init_child_obj(obj, "gpt[*]", &s->gpt[i], sizeof(s->gpt[i]),
55 TYPE_IMX25_GPT);
56 }
57
58 for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) {
59 sysbus_init_child_obj(obj, "epit[*]", &s->epit[i], sizeof(s->epit[i]),
60 TYPE_IMX_EPIT);
61 }
62
63 sysbus_init_child_obj(obj, "fec", &s->fec, sizeof(s->fec), TYPE_IMX_FEC);
64
65 for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
66 sysbus_init_child_obj(obj, "i2c[*]", &s->i2c[i], sizeof(s->i2c[i]),
67 TYPE_IMX_I2C);
68 }
69
70 for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
71 sysbus_init_child_obj(obj, "gpio[*]", &s->gpio[i], sizeof(s->gpio[i]),
72 TYPE_IMX_GPIO);
73 }
74}
75
76static void fsl_imx25_realize(DeviceState *dev, Error **errp)
77{
78 FslIMX25State *s = FSL_IMX25(dev);
79 uint8_t i;
80 Error *err = NULL;
81
82 object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
83 if (err) {
84 error_propagate(errp, err);
85 return;
86 }
87
88 object_property_set_bool(OBJECT(&s->avic), true, "realized", &err);
89 if (err) {
90 error_propagate(errp, err);
91 return;
92 }
93 sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX25_AVIC_ADDR);
94 sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0,
95 qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
96 sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1,
97 qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
98
99 object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err);
100 if (err) {
101 error_propagate(errp, err);
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 object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
122 if (err) {
123 error_propagate(errp, err);
124 return;
125 }
126 sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
127 sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
128 qdev_get_gpio_in(DEVICE(&s->avic),
129 serial_table[i].irq));
130 }
131
132 /* Initialize all GPT timers */
133 for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
134 static const struct {
135 hwaddr addr;
136 unsigned int irq;
137 } gpt_table[FSL_IMX25_NUM_GPTS] = {
138 { FSL_IMX25_GPT1_ADDR, FSL_IMX25_GPT1_IRQ },
139 { FSL_IMX25_GPT2_ADDR, FSL_IMX25_GPT2_IRQ },
140 { FSL_IMX25_GPT3_ADDR, FSL_IMX25_GPT3_IRQ },
141 { FSL_IMX25_GPT4_ADDR, FSL_IMX25_GPT4_IRQ }
142 };
143
144 s->gpt[i].ccm = IMX_CCM(&s->ccm);
145
146 object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", &err);
147 if (err) {
148 error_propagate(errp, err);
149 return;
150 }
151 sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_table[i].addr);
152 sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
153 qdev_get_gpio_in(DEVICE(&s->avic),
154 gpt_table[i].irq));
155 }
156
157 /* Initialize all EPIT timers */
158 for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) {
159 static const struct {
160 hwaddr addr;
161 unsigned int irq;
162 } epit_table[FSL_IMX25_NUM_EPITS] = {
163 { FSL_IMX25_EPIT1_ADDR, FSL_IMX25_EPIT1_IRQ },
164 { FSL_IMX25_EPIT2_ADDR, FSL_IMX25_EPIT2_IRQ }
165 };
166
167 s->epit[i].ccm = IMX_CCM(&s->ccm);
168
169 object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
170 if (err) {
171 error_propagate(errp, err);
172 return;
173 }
174 sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
175 sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
176 qdev_get_gpio_in(DEVICE(&s->avic),
177 epit_table[i].irq));
178 }
179
180 qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]);
181
182 object_property_set_bool(OBJECT(&s->fec), true, "realized", &err);
183 if (err) {
184 error_propagate(errp, err);
185 return;
186 }
187 sysbus_mmio_map(SYS_BUS_DEVICE(&s->fec), 0, FSL_IMX25_FEC_ADDR);
188 sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0,
189 qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ));
190
191
192 /* Initialize all I2C */
193 for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
194 static const struct {
195 hwaddr addr;
196 unsigned int irq;
197 } i2c_table[FSL_IMX25_NUM_I2CS] = {
198 { FSL_IMX25_I2C1_ADDR, FSL_IMX25_I2C1_IRQ },
199 { FSL_IMX25_I2C2_ADDR, FSL_IMX25_I2C2_IRQ },
200 { FSL_IMX25_I2C3_ADDR, FSL_IMX25_I2C3_IRQ }
201 };
202
203 object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
204 if (err) {
205 error_propagate(errp, err);
206 return;
207 }
208 sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
209 sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
210 qdev_get_gpio_in(DEVICE(&s->avic),
211 i2c_table[i].irq));
212 }
213
214 /* Initialize all GPIOs */
215 for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
216 static const struct {
217 hwaddr addr;
218 unsigned int irq;
219 } gpio_table[FSL_IMX25_NUM_GPIOS] = {
220 { FSL_IMX25_GPIO1_ADDR, FSL_IMX25_GPIO1_IRQ },
221 { FSL_IMX25_GPIO2_ADDR, FSL_IMX25_GPIO2_IRQ },
222 { FSL_IMX25_GPIO3_ADDR, FSL_IMX25_GPIO3_IRQ },
223 { FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ }
224 };
225
226 object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
227 if (err) {
228 error_propagate(errp, err);
229 return;
230 }
231 sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
232 /* Connect GPIO IRQ to PIC */
233 sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
234 qdev_get_gpio_in(DEVICE(&s->avic),
235 gpio_table[i].irq));
236 }
237
238 /* initialize 2 x 16 KB ROM */
239 memory_region_init_rom(&s->rom[0], NULL,
240 "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
241 if (err) {
242 error_propagate(errp, err);
243 return;
244 }
245 memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
246 &s->rom[0]);
247 memory_region_init_rom(&s->rom[1], NULL,
248 "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
249 if (err) {
250 error_propagate(errp, err);
251 return;
252 }
253 memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM1_ADDR,
254 &s->rom[1]);
255
256 /* initialize internal RAM (128 KB) */
257 memory_region_init_ram(&s->iram, NULL, "imx25.iram", FSL_IMX25_IRAM_SIZE,
258 &err);
259 if (err) {
260 error_propagate(errp, err);
261 return;
262 }
263 memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ADDR,
264 &s->iram);
265
266 /* internal RAM (128 KB) is aliased over 128 MB - 128 KB */
267 memory_region_init_alias(&s->iram_alias, NULL, "imx25.iram_alias",
268 &s->iram, 0, FSL_IMX25_IRAM_ALIAS_SIZE);
269 memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ALIAS_ADDR,
270 &s->iram_alias);
271}
272
273static void fsl_imx25_class_init(ObjectClass *oc, void *data)
274{
275 DeviceClass *dc = DEVICE_CLASS(oc);
276
277 dc->realize = fsl_imx25_realize;
278 dc->desc = "i.MX25 SOC";
279 /*
280 * Reason: uses serial_hds in realize and the imx25 board does not
281 * support multiple CPUs
282 */
283 dc->user_creatable = false;
284}
285
286static const TypeInfo fsl_imx25_type_info = {
287 .name = TYPE_FSL_IMX25,
288 .parent = TYPE_DEVICE,
289 .instance_size = sizeof(FslIMX25State),
290 .instance_init = fsl_imx25_init,
291 .class_init = fsl_imx25_class_init,
292};
293
294static void fsl_imx25_register_types(void)
295{
296 type_register_static(&fsl_imx25_type_info);
297}
298
299type_init(fsl_imx25_register_types)
300