1 | /* |
2 | * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net> |
3 | * |
4 | * i.MX31 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 "cpu.h" |
25 | #include "hw/arm/fsl-imx31.h" |
26 | #include "sysemu/sysemu.h" |
27 | #include "exec/address-spaces.h" |
28 | #include "hw/qdev-properties.h" |
29 | #include "chardev/char.h" |
30 | |
31 | static void fsl_imx31_init(Object *obj) |
32 | { |
33 | FslIMX31State *s = FSL_IMX31(obj); |
34 | int i; |
35 | |
36 | object_initialize_child(obj, "cpu" , &s->cpu, sizeof(s->cpu), |
37 | ARM_CPU_TYPE_NAME("arm1136" ), |
38 | &error_abort, NULL); |
39 | |
40 | sysbus_init_child_obj(obj, "avic" , &s->avic, sizeof(s->avic), |
41 | TYPE_IMX_AVIC); |
42 | |
43 | sysbus_init_child_obj(obj, "ccm" , &s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM); |
44 | |
45 | for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) { |
46 | sysbus_init_child_obj(obj, "uart[*]" , &s->uart[i], sizeof(s->uart[i]), |
47 | TYPE_IMX_SERIAL); |
48 | } |
49 | |
50 | sysbus_init_child_obj(obj, "gpt" , &s->gpt, sizeof(s->gpt), TYPE_IMX31_GPT); |
51 | |
52 | for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) { |
53 | sysbus_init_child_obj(obj, "epit[*]" , &s->epit[i], sizeof(s->epit[i]), |
54 | TYPE_IMX_EPIT); |
55 | } |
56 | |
57 | for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) { |
58 | sysbus_init_child_obj(obj, "i2c[*]" , &s->i2c[i], sizeof(s->i2c[i]), |
59 | TYPE_IMX_I2C); |
60 | } |
61 | |
62 | for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) { |
63 | sysbus_init_child_obj(obj, "gpio[*]" , &s->gpio[i], sizeof(s->gpio[i]), |
64 | TYPE_IMX_GPIO); |
65 | } |
66 | } |
67 | |
68 | static void fsl_imx31_realize(DeviceState *dev, Error **errp) |
69 | { |
70 | FslIMX31State *s = FSL_IMX31(dev); |
71 | uint16_t i; |
72 | Error *err = NULL; |
73 | |
74 | object_property_set_bool(OBJECT(&s->cpu), true, "realized" , &err); |
75 | if (err) { |
76 | error_propagate(errp, err); |
77 | return; |
78 | } |
79 | |
80 | object_property_set_bool(OBJECT(&s->avic), true, "realized" , &err); |
81 | if (err) { |
82 | error_propagate(errp, err); |
83 | return; |
84 | } |
85 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX31_AVIC_ADDR); |
86 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0, |
87 | qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ)); |
88 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, |
89 | qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); |
90 | |
91 | object_property_set_bool(OBJECT(&s->ccm), true, "realized" , &err); |
92 | if (err) { |
93 | error_propagate(errp, err); |
94 | return; |
95 | } |
96 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX31_CCM_ADDR); |
97 | |
98 | /* Initialize all UARTS */ |
99 | for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) { |
100 | static const struct { |
101 | hwaddr addr; |
102 | unsigned int irq; |
103 | } serial_table[FSL_IMX31_NUM_UARTS] = { |
104 | { FSL_IMX31_UART1_ADDR, FSL_IMX31_UART1_IRQ }, |
105 | { FSL_IMX31_UART2_ADDR, FSL_IMX31_UART2_IRQ }, |
106 | }; |
107 | |
108 | qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev" , serial_hd(i)); |
109 | |
110 | object_property_set_bool(OBJECT(&s->uart[i]), true, "realized" , &err); |
111 | if (err) { |
112 | error_propagate(errp, err); |
113 | return; |
114 | } |
115 | |
116 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr); |
117 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, |
118 | qdev_get_gpio_in(DEVICE(&s->avic), |
119 | serial_table[i].irq)); |
120 | } |
121 | |
122 | s->gpt.ccm = IMX_CCM(&s->ccm); |
123 | |
124 | object_property_set_bool(OBJECT(&s->gpt), true, "realized" , &err); |
125 | if (err) { |
126 | error_propagate(errp, err); |
127 | return; |
128 | } |
129 | |
130 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX31_GPT_ADDR); |
131 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0, |
132 | qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX31_GPT_IRQ)); |
133 | |
134 | /* Initialize all EPIT timers */ |
135 | for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) { |
136 | static const struct { |
137 | hwaddr addr; |
138 | unsigned int irq; |
139 | } epit_table[FSL_IMX31_NUM_EPITS] = { |
140 | { FSL_IMX31_EPIT1_ADDR, FSL_IMX31_EPIT1_IRQ }, |
141 | { FSL_IMX31_EPIT2_ADDR, FSL_IMX31_EPIT2_IRQ }, |
142 | }; |
143 | |
144 | s->epit[i].ccm = IMX_CCM(&s->ccm); |
145 | |
146 | object_property_set_bool(OBJECT(&s->epit[i]), true, "realized" , &err); |
147 | if (err) { |
148 | error_propagate(errp, err); |
149 | return; |
150 | } |
151 | |
152 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr); |
153 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0, |
154 | qdev_get_gpio_in(DEVICE(&s->avic), |
155 | epit_table[i].irq)); |
156 | } |
157 | |
158 | /* Initialize all I2C */ |
159 | for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) { |
160 | static const struct { |
161 | hwaddr addr; |
162 | unsigned int irq; |
163 | } i2c_table[FSL_IMX31_NUM_I2CS] = { |
164 | { FSL_IMX31_I2C1_ADDR, FSL_IMX31_I2C1_IRQ }, |
165 | { FSL_IMX31_I2C2_ADDR, FSL_IMX31_I2C2_IRQ }, |
166 | { FSL_IMX31_I2C3_ADDR, FSL_IMX31_I2C3_IRQ } |
167 | }; |
168 | |
169 | /* Initialize the I2C */ |
170 | object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized" , &err); |
171 | if (err) { |
172 | error_propagate(errp, err); |
173 | return; |
174 | } |
175 | /* Map I2C memory */ |
176 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr); |
177 | /* Connect I2C IRQ to PIC */ |
178 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, |
179 | qdev_get_gpio_in(DEVICE(&s->avic), |
180 | i2c_table[i].irq)); |
181 | } |
182 | |
183 | /* Initialize all GPIOs */ |
184 | for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) { |
185 | static const struct { |
186 | hwaddr addr; |
187 | unsigned int irq; |
188 | } gpio_table[FSL_IMX31_NUM_GPIOS] = { |
189 | { FSL_IMX31_GPIO1_ADDR, FSL_IMX31_GPIO1_IRQ }, |
190 | { FSL_IMX31_GPIO2_ADDR, FSL_IMX31_GPIO2_IRQ }, |
191 | { FSL_IMX31_GPIO3_ADDR, FSL_IMX31_GPIO3_IRQ } |
192 | }; |
193 | |
194 | object_property_set_bool(OBJECT(&s->gpio[i]), false, "has-edge-sel" , |
195 | &error_abort); |
196 | object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized" , &err); |
197 | if (err) { |
198 | error_propagate(errp, err); |
199 | return; |
200 | } |
201 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); |
202 | /* Connect GPIO IRQ to PIC */ |
203 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0, |
204 | qdev_get_gpio_in(DEVICE(&s->avic), |
205 | gpio_table[i].irq)); |
206 | } |
207 | |
208 | /* On a real system, the first 16k is a `secure boot rom' */ |
209 | memory_region_init_rom(&s->secure_rom, NULL, "imx31.secure_rom" , |
210 | FSL_IMX31_SECURE_ROM_SIZE, &err); |
211 | if (err) { |
212 | error_propagate(errp, err); |
213 | return; |
214 | } |
215 | memory_region_add_subregion(get_system_memory(), FSL_IMX31_SECURE_ROM_ADDR, |
216 | &s->secure_rom); |
217 | |
218 | /* There is also a 16k ROM */ |
219 | memory_region_init_rom(&s->rom, NULL, "imx31.rom" , |
220 | FSL_IMX31_ROM_SIZE, &err); |
221 | if (err) { |
222 | error_propagate(errp, err); |
223 | return; |
224 | } |
225 | memory_region_add_subregion(get_system_memory(), FSL_IMX31_ROM_ADDR, |
226 | &s->rom); |
227 | |
228 | /* initialize internal RAM (16 KB) */ |
229 | memory_region_init_ram(&s->iram, NULL, "imx31.iram" , FSL_IMX31_IRAM_SIZE, |
230 | &err); |
231 | if (err) { |
232 | error_propagate(errp, err); |
233 | return; |
234 | } |
235 | memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ADDR, |
236 | &s->iram); |
237 | |
238 | /* internal RAM (16 KB) is aliased over 256 MB - 16 KB */ |
239 | memory_region_init_alias(&s->iram_alias, NULL, "imx31.iram_alias" , |
240 | &s->iram, 0, FSL_IMX31_IRAM_ALIAS_SIZE); |
241 | memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ALIAS_ADDR, |
242 | &s->iram_alias); |
243 | } |
244 | |
245 | static void fsl_imx31_class_init(ObjectClass *oc, void *data) |
246 | { |
247 | DeviceClass *dc = DEVICE_CLASS(oc); |
248 | |
249 | dc->realize = fsl_imx31_realize; |
250 | dc->desc = "i.MX31 SOC" ; |
251 | /* |
252 | * Reason: uses serial_hds in realize and the kzm board does not |
253 | * support multiple CPUs |
254 | */ |
255 | dc->user_creatable = false; |
256 | } |
257 | |
258 | static const TypeInfo fsl_imx31_type_info = { |
259 | .name = TYPE_FSL_IMX31, |
260 | .parent = TYPE_DEVICE, |
261 | .instance_size = sizeof(FslIMX31State), |
262 | .instance_init = fsl_imx31_init, |
263 | .class_init = fsl_imx31_class_init, |
264 | }; |
265 | |
266 | static void fsl_imx31_register_types(void) |
267 | { |
268 | type_register_static(&fsl_imx31_type_info); |
269 | } |
270 | |
271 | type_init(fsl_imx31_register_types) |
272 | |