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 "cpu.h"
27#include "hw/cpu/a9mpcore.h"
28#include "hw/irq.h"
29#include "sysemu/blockdev.h"
30#include "sysemu/sysemu.h"
31#include "hw/sysbus.h"
32#include "hw/arm/boot.h"
33#include "hw/loader.h"
34#include "hw/qdev-properties.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
99
100#define EXYNOS4210_PL330_BASE0_ADDR 0x12680000
101#define EXYNOS4210_PL330_BASE1_ADDR 0x12690000
102#define EXYNOS4210_PL330_BASE2_ADDR 0x12850000
103
104static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
105 0x09, 0x00, 0x00, 0x00 };
106
107static uint64_t exynos4210_chipid_and_omr_read(void *opaque, hwaddr offset,
108 unsigned size)
109{
110 assert(offset < sizeof(chipid_and_omr));
111 return chipid_and_omr[offset];
112}
113
114static void exynos4210_chipid_and_omr_write(void *opaque, hwaddr offset,
115 uint64_t value, unsigned size)
116{
117 return;
118}
119
120static const MemoryRegionOps exynos4210_chipid_and_omr_ops = {
121 .read = exynos4210_chipid_and_omr_read,
122 .write = exynos4210_chipid_and_omr_write,
123 .endianness = DEVICE_NATIVE_ENDIAN,
124 .impl = {
125 .max_access_size = 1,
126 }
127};
128
129void exynos4210_write_secondary(ARMCPU *cpu,
130 const struct arm_boot_info *info)
131{
132 int n;
133 uint32_t smpboot[] = {
134 0xe59f3034,
135 0xe59f2034,
136 0xe59f0034,
137 0xe3a01001,
138 0xe5821000,
139 0xe5831000,
140 0xe3a010ff,
141 0xe5821004,
142 0xe5831004,
143 0xf57ff04f,
144 0xe320f003,
145 0xe5901000,
146 0xe1110001,
147 0x0afffffb,
148 0xe12fff11,
149 EXYNOS4210_EXT_GIC_CPU_BASE_ADDR,
150 0,
151 0
152 };
153 smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
154 smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
155 for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
156 smpboot[n] = tswap32(smpboot[n]);
157 }
158 rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
159 info->smp_loader_start);
160}
161
162static uint64_t exynos4210_calc_affinity(int cpu)
163{
164
165 return (0x9 << ARM_AFF1_SHIFT) | cpu;
166}
167
168static DeviceState *pl330_create(uint32_t base, qemu_or_irq *orgate,
169 qemu_irq irq, int nreq, int nevents, int width)
170{
171 SysBusDevice *busdev;
172 DeviceState *dev;
173 int i;
174
175 dev = qdev_new("pl330");
176 qdev_prop_set_uint8(dev, "num_events", nevents);
177 qdev_prop_set_uint8(dev, "num_chnls", 8);
178 qdev_prop_set_uint8(dev, "num_periph_req", nreq);
179
180 qdev_prop_set_uint8(dev, "wr_cap", 4);
181 qdev_prop_set_uint8(dev, "wr_q_dep", 8);
182 qdev_prop_set_uint8(dev, "rd_cap", 4);
183 qdev_prop_set_uint8(dev, "rd_q_dep", 8);
184 qdev_prop_set_uint8(dev, "data_width", width);
185 qdev_prop_set_uint16(dev, "data_buffer_dep", width);
186 busdev = SYS_BUS_DEVICE(dev);
187 sysbus_realize_and_unref(busdev, &error_fatal);
188 sysbus_mmio_map(busdev, 0, base);
189
190 object_property_set_int(OBJECT(orgate), "num-lines", nevents + 1,
191 &error_abort);
192 qdev_realize(DEVICE(orgate), NULL, &error_abort);
193
194 for (i = 0; i < nevents + 1; i++) {
195 sysbus_connect_irq(busdev, i, qdev_get_gpio_in(DEVICE(orgate), i));
196 }
197 qdev_connect_gpio_out(DEVICE(orgate), 0, irq);
198 return dev;
199}
200
201static void exynos4210_realize(DeviceState *socdev, Error **errp)
202{
203 Exynos4210State *s = EXYNOS4210_SOC(socdev);
204 MemoryRegion *system_mem = get_system_memory();
205 qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
206 SysBusDevice *busdev;
207 DeviceState *dev, *uart[4], *pl330[3];
208 int i, n;
209
210 for (n = 0; n < EXYNOS4210_NCPUS; n++) {
211 Object *cpuobj = object_new(ARM_CPU_TYPE_NAME("cortex-a9"));
212
213
214
215
216 if (object_property_find(cpuobj, "has_el3")) {
217 object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
218 }
219
220 s->cpu[n] = ARM_CPU(cpuobj);
221 object_property_set_int(cpuobj, "mp-affinity",
222 exynos4210_calc_affinity(n), &error_abort);
223 object_property_set_int(cpuobj, "reset-cbar",
224 EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
225 &error_abort);
226 qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
227 }
228
229
230
231 s->irq_table = exynos4210_init_irq(&s->irqs);
232
233
234 for (i = 0; i < EXYNOS4210_NCPUS; i++) {
235 dev = qdev_new("exynos4210.irq_gate");
236 qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
237 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
238
239 for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
240 gate_irq[i][n] = qdev_get_gpio_in(dev, n);
241 }
242 busdev = SYS_BUS_DEVICE(dev);
243
244
245 sysbus_connect_irq(busdev, 0,
246 qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ));
247 }
248
249
250 dev = qdev_new(TYPE_A9MPCORE_PRIV);
251 qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
252 busdev = SYS_BUS_DEVICE(dev);
253 sysbus_realize_and_unref(busdev, &error_fatal);
254 sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
255 for (n = 0; n < EXYNOS4210_NCPUS; n++) {
256 sysbus_connect_irq(busdev, n, gate_irq[n][0]);
257 }
258 for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
259 s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
260 }
261
262
263 sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL);
264
265
266 dev = qdev_new("exynos4210.gic");
267 qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
268 busdev = SYS_BUS_DEVICE(dev);
269 sysbus_realize_and_unref(busdev, &error_fatal);
270
271 sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR);
272
273 sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
274 for (n = 0; n < EXYNOS4210_NCPUS; n++) {
275 sysbus_connect_irq(busdev, n, gate_irq[n][1]);
276 }
277 for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
278 s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
279 }
280
281
282 dev = qdev_new("exynos4210.combiner");
283 busdev = SYS_BUS_DEVICE(dev);
284 sysbus_realize_and_unref(busdev, &error_fatal);
285 for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
286 sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]);
287 }
288 exynos4210_combiner_get_gpioin(&s->irqs, dev, 0);
289 sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR);
290
291
292 dev = qdev_new("exynos4210.combiner");
293 qdev_prop_set_uint32(dev, "external", 1);
294 busdev = SYS_BUS_DEVICE(dev);
295 sysbus_realize_and_unref(busdev, &error_fatal);
296 for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
297 sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]);
298 }
299 exynos4210_combiner_get_gpioin(&s->irqs, dev, 1);
300 sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR);
301
302
303 exynos4210_init_board_irqs(&s->irqs);
304
305
306
307
308 memory_region_init_io(&s->chipid_mem, OBJECT(socdev),
309 &exynos4210_chipid_and_omr_ops, NULL,
310 "exynos4210.chipid", sizeof(chipid_and_omr));
311 memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR,
312 &s->chipid_mem);
313
314
315 memory_region_init_rom(&s->irom_mem, OBJECT(socdev), "exynos4210.irom",
316 EXYNOS4210_IROM_SIZE, &error_fatal);
317 memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
318 &s->irom_mem);
319
320 memory_region_init_alias(&s->irom_alias_mem, OBJECT(socdev),
321 "exynos4210.irom_alias", &s->irom_mem, 0,
322 EXYNOS4210_IROM_SIZE);
323 memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR,
324 &s->irom_alias_mem);
325
326
327 memory_region_init_ram(&s->iram_mem, NULL, "exynos4210.iram",
328 EXYNOS4210_IRAM_SIZE, &error_fatal);
329 memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
330 &s->iram_mem);
331
332
333
334
335
336 sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
337
338 sysbus_create_simple("exynos4210.clk", EXYNOS4210_CLK_BASE_ADDR, NULL);
339 sysbus_create_simple("exynos4210.rng", EXYNOS4210_RNG_BASE_ADDR, NULL);
340
341
342 sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
343 s->irq_table[exynos4210_get_irq(22, 0)],
344 s->irq_table[exynos4210_get_irq(22, 1)],
345 s->irq_table[exynos4210_get_irq(22, 2)],
346 s->irq_table[exynos4210_get_irq(22, 3)],
347 s->irq_table[exynos4210_get_irq(22, 4)],
348 NULL);
349
350 sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR,
351 s->irq_table[exynos4210_get_irq(23, 0)],
352 s->irq_table[exynos4210_get_irq(23, 1)],
353 NULL);
354
355
356 dev = qdev_new("exynos4210.mct");
357 busdev = SYS_BUS_DEVICE(dev);
358 sysbus_realize_and_unref(busdev, &error_fatal);
359 for (n = 0; n < 4; n++) {
360
361 sysbus_connect_irq(busdev, n,
362 s->irq_table[exynos4210_get_irq(1, 4 + n)]);
363 }
364
365 sysbus_connect_irq(busdev, 4,
366 s->irq_table[exynos4210_get_irq(51, 0)]);
367 sysbus_connect_irq(busdev, 5,
368 s->irq_table[exynos4210_get_irq(35, 3)]);
369 sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR);
370
371
372 for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) {
373 uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n;
374 qemu_irq i2c_irq;
375
376 if (n < 8) {
377 i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)];
378 } else {
379 i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)];
380 }
381
382 dev = qdev_new("exynos4210.i2c");
383 busdev = SYS_BUS_DEVICE(dev);
384 sysbus_realize_and_unref(busdev, &error_fatal);
385 sysbus_connect_irq(busdev, 0, i2c_irq);
386 sysbus_mmio_map(busdev, 0, addr);
387 s->i2c_if[n] = (I2CBus *)qdev_get_child_bus(dev, "i2c");
388 }
389
390
391
392 uart[0] = exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
393 EXYNOS4210_UART0_FIFO_SIZE, 0, serial_hd(0),
394 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
395
396 uart[1] = exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
397 EXYNOS4210_UART1_FIFO_SIZE, 1, serial_hd(1),
398 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
399
400 uart[2] = exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
401 EXYNOS4210_UART2_FIFO_SIZE, 2, serial_hd(2),
402 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
403
404 uart[3] = exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
405 EXYNOS4210_UART3_FIFO_SIZE, 3, serial_hd(3),
406 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
407
408
409 for (n = 0; n < EXYNOS4210_SDHCI_NUMBER; n++) {
410 DeviceState *carddev;
411 BlockBackend *blk;
412 DriveInfo *di;
413
414
415
416
417
418
419
420
421
422
423
424
425
426 dev = qdev_new(TYPE_S3C_SDHCI);
427 qdev_prop_set_uint64(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES);
428
429 busdev = SYS_BUS_DEVICE(dev);
430 sysbus_realize_and_unref(busdev, &error_fatal);
431 sysbus_mmio_map(busdev, 0, EXYNOS4210_SDHCI_ADDR(n));
432 sysbus_connect_irq(busdev, 0, s->irq_table[exynos4210_get_irq(29, n)]);
433
434 di = drive_get(IF_SD, 0, n);
435 blk = di ? blk_by_legacy_dinfo(di) : NULL;
436 carddev = qdev_new(TYPE_SD_CARD);
437 qdev_prop_set_drive(carddev, "drive", blk);
438 qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"),
439 &error_fatal);
440 }
441
442
443 sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR,
444 s->irq_table[exynos4210_get_irq(11, 0)],
445 s->irq_table[exynos4210_get_irq(11, 1)],
446 s->irq_table[exynos4210_get_irq(11, 2)],
447 NULL);
448
449 sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR,
450 s->irq_table[exynos4210_get_irq(28, 3)]);
451
452
453 pl330[0] = pl330_create(EXYNOS4210_PL330_BASE0_ADDR,
454 &s->pl330_irq_orgate[0],
455 s->irq_table[exynos4210_get_irq(21, 0)],
456 32, 32, 32);
457 pl330[1] = pl330_create(EXYNOS4210_PL330_BASE1_ADDR,
458 &s->pl330_irq_orgate[1],
459 s->irq_table[exynos4210_get_irq(21, 1)],
460 32, 32, 32);
461 pl330[2] = pl330_create(EXYNOS4210_PL330_BASE2_ADDR,
462 &s->pl330_irq_orgate[2],
463 s->irq_table[exynos4210_get_irq(20, 1)],
464 1, 31, 64);
465
466 sysbus_connect_irq(SYS_BUS_DEVICE(uart[0]), 1,
467 qdev_get_gpio_in(pl330[0], 15));
468 sysbus_connect_irq(SYS_BUS_DEVICE(uart[1]), 1,
469 qdev_get_gpio_in(pl330[1], 15));
470 sysbus_connect_irq(SYS_BUS_DEVICE(uart[2]), 1,
471 qdev_get_gpio_in(pl330[0], 17));
472 sysbus_connect_irq(SYS_BUS_DEVICE(uart[3]), 1,
473 qdev_get_gpio_in(pl330[1], 17));
474}
475
476static void exynos4210_init(Object *obj)
477{
478 Exynos4210State *s = EXYNOS4210_SOC(obj);
479 int i;
480
481 for (i = 0; i < ARRAY_SIZE(s->pl330_irq_orgate); i++) {
482 char *name = g_strdup_printf("pl330-irq-orgate%d", i);
483 qemu_or_irq *orgate = &s->pl330_irq_orgate[i];
484
485 object_initialize_child(obj, name, orgate, TYPE_OR_IRQ);
486 g_free(name);
487 }
488}
489
490static void exynos4210_class_init(ObjectClass *klass, void *data)
491{
492 DeviceClass *dc = DEVICE_CLASS(klass);
493
494 dc->realize = exynos4210_realize;
495}
496
497static const TypeInfo exynos4210_info = {
498 .name = TYPE_EXYNOS4210_SOC,
499 .parent = TYPE_SYS_BUS_DEVICE,
500 .instance_size = sizeof(Exynos4210State),
501 .instance_init = exynos4210_init,
502 .class_init = exynos4210_class_init,
503};
504
505static void exynos4210_register_types(void)
506{
507 type_register_static(&exynos4210_info);
508}
509
510type_init(exynos4210_register_types)
511