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