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 object_property_set_link(OBJECT(dev), "memory",
177 OBJECT(get_system_memory()),
178 &error_fatal);
179 qdev_prop_set_uint8(dev, "num_events", nevents);
180 qdev_prop_set_uint8(dev, "num_chnls", 8);
181 qdev_prop_set_uint8(dev, "num_periph_req", nreq);
182
183 qdev_prop_set_uint8(dev, "wr_cap", 4);
184 qdev_prop_set_uint8(dev, "wr_q_dep", 8);
185 qdev_prop_set_uint8(dev, "rd_cap", 4);
186 qdev_prop_set_uint8(dev, "rd_q_dep", 8);
187 qdev_prop_set_uint8(dev, "data_width", width);
188 qdev_prop_set_uint16(dev, "data_buffer_dep", width);
189 busdev = SYS_BUS_DEVICE(dev);
190 sysbus_realize_and_unref(busdev, &error_fatal);
191 sysbus_mmio_map(busdev, 0, base);
192
193 object_property_set_int(OBJECT(orgate), "num-lines", nevents + 1,
194 &error_abort);
195 qdev_realize(DEVICE(orgate), NULL, &error_abort);
196
197 for (i = 0; i < nevents + 1; i++) {
198 sysbus_connect_irq(busdev, i, qdev_get_gpio_in(DEVICE(orgate), i));
199 }
200 qdev_connect_gpio_out(DEVICE(orgate), 0, irq);
201 return dev;
202}
203
204static void exynos4210_realize(DeviceState *socdev, Error **errp)
205{
206 Exynos4210State *s = EXYNOS4210_SOC(socdev);
207 MemoryRegion *system_mem = get_system_memory();
208 qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
209 SysBusDevice *busdev;
210 DeviceState *dev, *uart[4], *pl330[3];
211 int i, n;
212
213 for (n = 0; n < EXYNOS4210_NCPUS; n++) {
214 Object *cpuobj = object_new(ARM_CPU_TYPE_NAME("cortex-a9"));
215
216
217
218
219 if (object_property_find(cpuobj, "has_el3")) {
220 object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
221 }
222
223 s->cpu[n] = ARM_CPU(cpuobj);
224 object_property_set_int(cpuobj, "mp-affinity",
225 exynos4210_calc_affinity(n), &error_abort);
226 object_property_set_int(cpuobj, "reset-cbar",
227 EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
228 &error_abort);
229 qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
230 }
231
232
233
234 s->irq_table = exynos4210_init_irq(&s->irqs);
235
236
237 for (i = 0; i < EXYNOS4210_NCPUS; i++) {
238 dev = qdev_new("exynos4210.irq_gate");
239 qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
240 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
241
242 for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
243 gate_irq[i][n] = qdev_get_gpio_in(dev, n);
244 }
245 busdev = SYS_BUS_DEVICE(dev);
246
247
248 sysbus_connect_irq(busdev, 0,
249 qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ));
250 }
251
252
253 dev = qdev_new(TYPE_A9MPCORE_PRIV);
254 qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
255 busdev = SYS_BUS_DEVICE(dev);
256 sysbus_realize_and_unref(busdev, &error_fatal);
257 sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
258 for (n = 0; n < EXYNOS4210_NCPUS; n++) {
259 sysbus_connect_irq(busdev, n, gate_irq[n][0]);
260 }
261 for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
262 s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
263 }
264
265
266 sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL);
267
268
269 dev = qdev_new("exynos4210.gic");
270 qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
271 busdev = SYS_BUS_DEVICE(dev);
272 sysbus_realize_and_unref(busdev, &error_fatal);
273
274 sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR);
275
276 sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
277 for (n = 0; n < EXYNOS4210_NCPUS; n++) {
278 sysbus_connect_irq(busdev, n, gate_irq[n][1]);
279 }
280 for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
281 s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
282 }
283
284
285 dev = qdev_new("exynos4210.combiner");
286 busdev = SYS_BUS_DEVICE(dev);
287 sysbus_realize_and_unref(busdev, &error_fatal);
288 for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
289 sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]);
290 }
291 exynos4210_combiner_get_gpioin(&s->irqs, dev, 0);
292 sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR);
293
294
295 dev = qdev_new("exynos4210.combiner");
296 qdev_prop_set_uint32(dev, "external", 1);
297 busdev = SYS_BUS_DEVICE(dev);
298 sysbus_realize_and_unref(busdev, &error_fatal);
299 for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
300 sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]);
301 }
302 exynos4210_combiner_get_gpioin(&s->irqs, dev, 1);
303 sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR);
304
305
306 exynos4210_init_board_irqs(&s->irqs);
307
308
309
310
311 memory_region_init_io(&s->chipid_mem, OBJECT(socdev),
312 &exynos4210_chipid_and_omr_ops, NULL,
313 "exynos4210.chipid", sizeof(chipid_and_omr));
314 memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR,
315 &s->chipid_mem);
316
317
318 memory_region_init_rom(&s->irom_mem, OBJECT(socdev), "exynos4210.irom",
319 EXYNOS4210_IROM_SIZE, &error_fatal);
320 memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
321 &s->irom_mem);
322
323 memory_region_init_alias(&s->irom_alias_mem, OBJECT(socdev),
324 "exynos4210.irom_alias", &s->irom_mem, 0,
325 EXYNOS4210_IROM_SIZE);
326 memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR,
327 &s->irom_alias_mem);
328
329
330 memory_region_init_ram(&s->iram_mem, NULL, "exynos4210.iram",
331 EXYNOS4210_IRAM_SIZE, &error_fatal);
332 memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
333 &s->iram_mem);
334
335
336
337
338
339 sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
340
341 sysbus_create_simple("exynos4210.clk", EXYNOS4210_CLK_BASE_ADDR, NULL);
342 sysbus_create_simple("exynos4210.rng", EXYNOS4210_RNG_BASE_ADDR, NULL);
343
344
345 sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
346 s->irq_table[exynos4210_get_irq(22, 0)],
347 s->irq_table[exynos4210_get_irq(22, 1)],
348 s->irq_table[exynos4210_get_irq(22, 2)],
349 s->irq_table[exynos4210_get_irq(22, 3)],
350 s->irq_table[exynos4210_get_irq(22, 4)],
351 NULL);
352
353 sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR,
354 s->irq_table[exynos4210_get_irq(23, 0)],
355 s->irq_table[exynos4210_get_irq(23, 1)],
356 NULL);
357
358
359 dev = qdev_new("exynos4210.mct");
360 busdev = SYS_BUS_DEVICE(dev);
361 sysbus_realize_and_unref(busdev, &error_fatal);
362 for (n = 0; n < 4; n++) {
363
364 sysbus_connect_irq(busdev, n,
365 s->irq_table[exynos4210_get_irq(1, 4 + n)]);
366 }
367
368 sysbus_connect_irq(busdev, 4,
369 s->irq_table[exynos4210_get_irq(51, 0)]);
370 sysbus_connect_irq(busdev, 5,
371 s->irq_table[exynos4210_get_irq(35, 3)]);
372 sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR);
373
374
375 for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) {
376 uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n;
377 qemu_irq i2c_irq;
378
379 if (n < 8) {
380 i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)];
381 } else {
382 i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)];
383 }
384
385 dev = qdev_new("exynos4210.i2c");
386 busdev = SYS_BUS_DEVICE(dev);
387 sysbus_realize_and_unref(busdev, &error_fatal);
388 sysbus_connect_irq(busdev, 0, i2c_irq);
389 sysbus_mmio_map(busdev, 0, addr);
390 s->i2c_if[n] = (I2CBus *)qdev_get_child_bus(dev, "i2c");
391 }
392
393
394
395 uart[0] = exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
396 EXYNOS4210_UART0_FIFO_SIZE, 0, serial_hd(0),
397 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
398
399 uart[1] = exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
400 EXYNOS4210_UART1_FIFO_SIZE, 1, serial_hd(1),
401 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
402
403 uart[2] = exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
404 EXYNOS4210_UART2_FIFO_SIZE, 2, serial_hd(2),
405 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
406
407 uart[3] = exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
408 EXYNOS4210_UART3_FIFO_SIZE, 3, serial_hd(3),
409 s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
410
411
412 for (n = 0; n < EXYNOS4210_SDHCI_NUMBER; n++) {
413 DeviceState *carddev;
414 BlockBackend *blk;
415 DriveInfo *di;
416
417
418
419
420
421
422
423
424
425
426
427
428
429 dev = qdev_new(TYPE_S3C_SDHCI);
430 qdev_prop_set_uint64(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES);
431
432 busdev = SYS_BUS_DEVICE(dev);
433 sysbus_realize_and_unref(busdev, &error_fatal);
434 sysbus_mmio_map(busdev, 0, EXYNOS4210_SDHCI_ADDR(n));
435 sysbus_connect_irq(busdev, 0, s->irq_table[exynos4210_get_irq(29, n)]);
436
437 di = drive_get(IF_SD, 0, n);
438 blk = di ? blk_by_legacy_dinfo(di) : NULL;
439 carddev = qdev_new(TYPE_SD_CARD);
440 qdev_prop_set_drive(carddev, "drive", blk);
441 qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"),
442 &error_fatal);
443 }
444
445
446 sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR,
447 s->irq_table[exynos4210_get_irq(11, 0)],
448 s->irq_table[exynos4210_get_irq(11, 1)],
449 s->irq_table[exynos4210_get_irq(11, 2)],
450 NULL);
451
452 sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR,
453 s->irq_table[exynos4210_get_irq(28, 3)]);
454
455
456 pl330[0] = pl330_create(EXYNOS4210_PL330_BASE0_ADDR,
457 &s->pl330_irq_orgate[0],
458 s->irq_table[exynos4210_get_irq(21, 0)],
459 32, 32, 32);
460 pl330[1] = pl330_create(EXYNOS4210_PL330_BASE1_ADDR,
461 &s->pl330_irq_orgate[1],
462 s->irq_table[exynos4210_get_irq(21, 1)],
463 32, 32, 32);
464 pl330[2] = pl330_create(EXYNOS4210_PL330_BASE2_ADDR,
465 &s->pl330_irq_orgate[2],
466 s->irq_table[exynos4210_get_irq(20, 1)],
467 1, 31, 64);
468
469 sysbus_connect_irq(SYS_BUS_DEVICE(uart[0]), 1,
470 qdev_get_gpio_in(pl330[0], 15));
471 sysbus_connect_irq(SYS_BUS_DEVICE(uart[1]), 1,
472 qdev_get_gpio_in(pl330[1], 15));
473 sysbus_connect_irq(SYS_BUS_DEVICE(uart[2]), 1,
474 qdev_get_gpio_in(pl330[0], 17));
475 sysbus_connect_irq(SYS_BUS_DEVICE(uart[3]), 1,
476 qdev_get_gpio_in(pl330[1], 17));
477}
478
479static void exynos4210_init(Object *obj)
480{
481 Exynos4210State *s = EXYNOS4210_SOC(obj);
482 int i;
483
484 for (i = 0; i < ARRAY_SIZE(s->pl330_irq_orgate); i++) {
485 char *name = g_strdup_printf("pl330-irq-orgate%d", i);
486 qemu_or_irq *orgate = &s->pl330_irq_orgate[i];
487
488 object_initialize_child(obj, name, orgate, TYPE_OR_IRQ);
489 g_free(name);
490 }
491}
492
493static void exynos4210_class_init(ObjectClass *klass, void *data)
494{
495 DeviceClass *dc = DEVICE_CLASS(klass);
496
497 dc->realize = exynos4210_realize;
498}
499
500static const TypeInfo exynos4210_info = {
501 .name = TYPE_EXYNOS4210_SOC,
502 .parent = TYPE_SYS_BUS_DEVICE,
503 .instance_size = sizeof(Exynos4210State),
504 .instance_init = exynos4210_init,
505 .class_init = exynos4210_class_init,
506};
507
508static void exynos4210_register_types(void)
509{
510 type_register_static(&exynos4210_info);
511}
512
513type_init(exynos4210_register_types)
514