1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "qemu/osdep.h"
25#include "qapi/error.h"
26#include "qemu-common.h"
27#include "qemu/log.h"
28#include "cpu.h"
29#include "hw/cpu/a9mpcore.h"
30#include "hw/boards.h"
31#include "sysemu/sysemu.h"
32#include "hw/sysbus.h"
33#include "hw/arm/arm.h"
34#include "hw/loader.h"
35#include "hw/arm/exynos4210.h"
36#include "hw/sd/sdhci.h"
37#include "hw/usb/hcd-ehci.h"
38
39#define EXYNOS4210_CHIPID_ADDR 0x10000000
40
41
42#define EXYNOS4210_PWM_BASE_ADDR 0x139D0000
43
44
45#define EXYNOS4210_RTC_BASE_ADDR 0x10070000
46
47
48#define EXYNOS4210_MCT_BASE_ADDR 0x10050000
49
50
51#define EXYNOS4210_I2C_SHIFT 0x00010000
52#define EXYNOS4210_I2C_BASE_ADDR 0x13860000
53
54#define EXYNOS4210_I2C_INTG 27
55#define EXYNOS4210_HDMI_INTG 16
56
57
58#define EXYNOS4210_UART0_BASE_ADDR 0x13800000
59#define EXYNOS4210_UART1_BASE_ADDR 0x13810000
60#define EXYNOS4210_UART2_BASE_ADDR 0x13820000
61#define EXYNOS4210_UART3_BASE_ADDR 0x13830000
62#define EXYNOS4210_UART0_FIFO_SIZE 256
63#define EXYNOS4210_UART1_FIFO_SIZE 64
64#define EXYNOS4210_UART2_FIFO_SIZE 16
65#define EXYNOS4210_UART3_FIFO_SIZE 16
66
67#define EXYNOS4210_UART_INT_GRP 26
68
69
70#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR 0x10480000
71#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR 0x10490000
72
73
74#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000
75#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000
76
77
78#define EXYNOS4210_SDHCI_CAPABILITIES 0x05E80080
79#define EXYNOS4210_SDHCI_BASE_ADDR 0x12510000
80#define EXYNOS4210_SDHCI_ADDR(n) (EXYNOS4210_SDHCI_BASE_ADDR + \
81 0x00010000 * (n))
82#define EXYNOS4210_SDHCI_NUMBER 4
83
84
85#define EXYNOS4210_PMU_BASE_ADDR 0x10020000
86
87
88#define EXYNOS4210_CLK_BASE_ADDR 0x10030000
89
90
91#define EXYNOS4210_RNG_BASE_ADDR 0x10830400
92
93
94#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000
95
96
97#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000
98
99static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
100 0x09, 0x00, 0x00, 0x00 };
101
102static uint64_t exynos4210_chipid_and_omr_read(void *opaque, hwaddr offset,
103 unsigned size)
104{
105 assert(offset < sizeof(chipid_and_omr));
106 return chipid_and_omr[offset];
107}
108
109static void exynos4210_chipid_and_omr_write(void *opaque, hwaddr offset,
110 uint64_t value, unsigned size)
111{
112 return;
113}
114
115static const MemoryRegionOps exynos4210_chipid_and_omr_ops = {
116 .read = exynos4210_chipid_and_omr_read,
117 .write = exynos4210_chipid_and_omr_write,
118 .endianness = DEVICE_NATIVE_ENDIAN,
119 .impl = {
120 .max_access_size = 1,
121 }
122};
123
124void exynos4210_write_secondary(ARMCPU *cpu,
125 const struct arm_boot_info *info)
126{
127 int n;
128 uint32_t smpboot[] = {
129 0xe59f3034,
130 0xe59f2034,
131 0xe59f0034,
132 0xe3a01001,
133 0xe5821000,
134 0xe5831000,
135 0xe3a010ff,
136 0xe5821004,
137 0xe5831004,
138 0xf57ff04f,
139 0xe320f003,
140 0xe5901000,
141 0xe1110001,
142 0x0afffffb,
143 0xe12fff11,
144 EXYNOS4210_EXT_GIC_CPU_BASE_ADDR,
145 0,
146 0
147 };
148 smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
149 smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
150 for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
151 smpboot[n] = tswap32(smpboot[n]);
152 }
153 rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
154 info->smp_loader_start);
155}
156
157static uint64_t exynos4210_calc_affinity(int cpu)
158{
159 uint64_t mp_affinity;
160
161
162 mp_affinity = (0x9 << ARM_AFF1_SHIFT) | cpu;
163
164 return mp_affinity;
165}
166
167Exynos4210State *exynos4210_init(MemoryRegion *system_mem)
168{
169 Exynos4210State *s = g_new(Exynos4210State, 1);
170 qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
171 SysBusDevice *busdev;
172 DeviceState *dev;
173 int i, n;
174
175 for (n = 0; n < EXYNOS4210_NCPUS; n++) {
176 Object *cpuobj = object_new(ARM_CPU_TYPE_NAME("cortex-a9"));
177
178
179
180
181 if (object_property_find(cpuobj, "has_el3", NULL)) {
182 object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
183 }
184
185 s->cpu[n] = ARM_CPU(cpuobj);
186 object_property_set_int(cpuobj, exynos4210_calc_affinity(n),
187 "mp-affinity", &error_abort);
188 object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
189 "reset-cbar", &error_abort);
190 object_property_set_bool(cpuobj, true, "realized", &error_fatal);
191 }
192
193
194
195 s->irq_table = exynos4210_init_irq(&s->irqs);
196
197
198 for (i = 0; i < EXYNOS4210_NCPUS; i++) {
199 dev = qdev_create(NULL, "exynos4210.irq_gate");
200 qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
201 qdev_init_nofail(dev);
202
203 for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
204 gate_irq[i][n] = qdev_get_gpio_in(dev, n);
205 }
206 busdev = SYS_BUS_DEVICE(dev);
207
208
209 sysbus_connect_irq(busdev, 0,
210 qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ));
211 }
212
213
214 dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV);
215 qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
216 qdev_init_nofail(dev);
217 busdev = SYS_BUS_DEVICE(dev);
218 sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
219 for (n = 0; n < EXYNOS4210_NCPUS; n++) {
220 sysbus_connect_irq(busdev, n, gate_irq[n][0]);
221 }
222 for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
223 s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
224 }
225
226
227 sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL);
228
229
230 dev = qdev_create(NULL, "exynos4210.gic");
231 qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
232 qdev_init_nofail(dev);
233 busdev = SYS_BUS_DEVICE(dev);
234
235 sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR);
236
237 sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
238 for (n = 0; n < EXYNOS4210_NCPUS; n++) {
239 sysbus_connect_irq(busdev, n, gate_irq[n][1]);
240 }
241 for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
242 s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
243 }
244
245
246 dev = qdev_create(NULL, "exynos4210.combiner");
247 qdev_init_nofail(dev);
248 busdev = SYS_BUS_DEVICE(dev);
249 for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
250 sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]);
251 }
252 exynos4210_combiner_get_gpioin(&s->irqs, dev, 0);
253 sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR);
254
255
256 dev = qdev_create(NULL, "exynos4210.combiner");
257 qdev_prop_set_uint32(dev, "external", 1);
258 qdev_init_nofail(dev);
259 busdev = SYS_BUS_DEVICE(dev);
260 for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
261 sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]);
262 }
263 exynos4210_combiner_get_gpioin(&s->irqs, dev, 1);
264 sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR);
265
266
267 exynos4210_init_board_irqs(&s->irqs);
268
269
270
271
272 memory_region_init_io(&s->chipid_mem, NULL, &exynos4210_chipid_and_omr_ops,
273 NULL, "exynos4210.chipid", sizeof(chipid_and_omr));
274 memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR,
275 &s->chipid_mem);
276
277
278 memory_region_init_ram(&s->irom_mem, NULL, "exynos4210.irom",
279 EXYNOS4210_IROM_SIZE, &error_fatal);
280 memory_region_set_readonly(&s->irom_mem, true);
281 memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
282 &s->irom_mem);
283
284 memory_region_init_alias(&s->irom_alias_mem, NULL, "exynos4210.irom_alias",
285 &s->irom_mem,
286 0,
287 EXYNOS4210_IROM_SIZE);
288 memory_region_set_readonly(&s->irom_alias_mem, true);
289 memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR,
290 &s->irom_alias_mem);
291
292
293 memory_region_init_ram(&s->iram_mem, NULL, "exynos4210.iram",
294 EXYNOS4210_IRAM_SIZE, &error_fatal);
295 memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
296 &s->iram_mem);
297
298
299
300
301
302 sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
303
304 sysbus_create_simple("exynos4210.clk", EXYNOS4210_CLK_BASE_ADDR, NULL);
305 sysbus_create_simple("exynos4210.rng", EXYNOS4210_RNG_BASE_ADDR, NULL);
306
307
308 sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
309 s->irq_table[exynos4210_get_irq(22, 0)],
310 s->irq_table[exynos4210_get_irq(22, 1)],
311 s->irq_table[exynos4210_get_irq(22, 2)],
312 s->irq_table[exynos4210_get_irq(22, 3)],
313 s->irq_table[exynos4210_get_irq(22, 4)],
314 NULL);
315
316 sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR,
317 s->irq_table[exynos4210_get_irq(23, 0)],
318 s->irq_table[exynos4210_get_irq(23, 1)],
319 NULL);
320
321
322 dev = qdev_create(NULL, "exynos4210.mct");
323 qdev_init_nofail(dev);
324 busdev = SYS_BUS_DEVICE(dev);
325 for (n = 0; n < 4; n++) {
326
327 sysbus_connect_irq(busdev, n,
328 s->irq_table[exynos4210_get_irq(1, 4 + n)]);
329 }
330
331 sysbus_connect_irq(busdev, 4,
332 s->irq_table[exynos4210_get_irq(51, 0)]);
333 sysbus_connect_irq(busdev, 5,
334 s->irq_table[exynos4210_get_irq(35, 3)]);
335 sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR);
336
337
338 for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) {
339 uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n;
340 qemu_irq i2c_irq;
341
342 if (n < 8) {
343 i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)];
344 } else {
345 i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)];
346 }
347
348 dev = qdev_create(NULL, "exynos4210.i2c");
349 qdev_init_nofail(dev);
350 busdev = SYS_BUS_DEVICE(dev);
351 sysbus_connect_irq(busdev, 0, i2c_irq);
352 sysbus_mmio_map(busdev, 0, addr);
353 s->i2c_if[n] = (I2CBus *)qdev_get_child_bus(dev, "i2c");
354 }
355
356
357
358 exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
359 EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
360 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
361
362 exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
363 EXYNOS4210_UART1_FIFO_SIZE, 1, NULL,
364 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
365
366 exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
367 EXYNOS4210_UART2_FIFO_SIZE, 2, NULL,
368 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
369
370 exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
371 EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
372 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
373
374
375 for (n = 0; n < EXYNOS4210_SDHCI_NUMBER; n++) {
376 DeviceState *carddev;
377 BlockBackend *blk;
378 DriveInfo *di;
379
380
381
382
383
384
385
386
387
388
389
390
391
392 dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI);
393 qdev_prop_set_uint64(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES);
394 qdev_init_nofail(dev);
395
396 busdev = SYS_BUS_DEVICE(dev);
397 sysbus_mmio_map(busdev, 0, EXYNOS4210_SDHCI_ADDR(n));
398 sysbus_connect_irq(busdev, 0, s->irq_table[exynos4210_get_irq(29, n)]);
399
400 di = drive_get(IF_SD, 0, n);
401 blk = di ? blk_by_legacy_dinfo(di) : NULL;
402 carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
403 qdev_prop_set_drive(carddev, "drive", blk, &error_abort);
404 qdev_init_nofail(carddev);
405 }
406
407
408 sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR,
409 s->irq_table[exynos4210_get_irq(11, 0)],
410 s->irq_table[exynos4210_get_irq(11, 1)],
411 s->irq_table[exynos4210_get_irq(11, 2)],
412 NULL);
413
414 sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR,
415 s->irq_table[exynos4210_get_irq(28, 3)]);
416
417 return s;
418}
419