1 | /* |
2 | * QEMU model of the Canon DIGIC SoC. |
3 | * |
4 | * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com> |
5 | * |
6 | * This model is based on reverse engineering efforts |
7 | * made by CHDK (http://chdk.wikia.com) and |
8 | * Magic Lantern (http://www.magiclantern.fm) projects |
9 | * contributors. |
10 | * |
11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or |
14 | * (at your option) any later version. |
15 | * |
16 | * This program is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU General Public License for more details. |
20 | * |
21 | */ |
22 | |
23 | #include "qemu/osdep.h" |
24 | #include "qapi/error.h" |
25 | #include "qemu/module.h" |
26 | #include "hw/arm/digic.h" |
27 | #include "hw/qdev-properties.h" |
28 | #include "sysemu/sysemu.h" |
29 | |
30 | #define DIGIC4_TIMER_BASE(n) (0xc0210000 + (n) * 0x100) |
31 | |
32 | #define DIGIC_UART_BASE 0xc0800000 |
33 | |
34 | static void digic_init(Object *obj) |
35 | { |
36 | DigicState *s = DIGIC(obj); |
37 | int i; |
38 | |
39 | object_initialize_child(obj, "cpu" , &s->cpu, sizeof(s->cpu), |
40 | ARM_CPU_TYPE_NAME("arm946" ), |
41 | &error_abort, NULL); |
42 | |
43 | for (i = 0; i < DIGIC4_NB_TIMERS; i++) { |
44 | #define DIGIC_TIMER_NAME_MLEN 11 |
45 | char name[DIGIC_TIMER_NAME_MLEN]; |
46 | |
47 | snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]" , i); |
48 | sysbus_init_child_obj(obj, name, &s->timer[i], sizeof(s->timer[i]), |
49 | TYPE_DIGIC_TIMER); |
50 | } |
51 | |
52 | sysbus_init_child_obj(obj, "uart" , &s->uart, sizeof(s->uart), |
53 | TYPE_DIGIC_UART); |
54 | } |
55 | |
56 | static void digic_realize(DeviceState *dev, Error **errp) |
57 | { |
58 | DigicState *s = DIGIC(dev); |
59 | Error *err = NULL; |
60 | SysBusDevice *sbd; |
61 | int i; |
62 | |
63 | object_property_set_bool(OBJECT(&s->cpu), true, "reset-hivecs" , &err); |
64 | if (err != NULL) { |
65 | error_propagate(errp, err); |
66 | return; |
67 | } |
68 | |
69 | object_property_set_bool(OBJECT(&s->cpu), true, "realized" , &err); |
70 | if (err != NULL) { |
71 | error_propagate(errp, err); |
72 | return; |
73 | } |
74 | |
75 | for (i = 0; i < DIGIC4_NB_TIMERS; i++) { |
76 | object_property_set_bool(OBJECT(&s->timer[i]), true, "realized" , &err); |
77 | if (err != NULL) { |
78 | error_propagate(errp, err); |
79 | return; |
80 | } |
81 | |
82 | sbd = SYS_BUS_DEVICE(&s->timer[i]); |
83 | sysbus_mmio_map(sbd, 0, DIGIC4_TIMER_BASE(i)); |
84 | } |
85 | |
86 | qdev_prop_set_chr(DEVICE(&s->uart), "chardev" , serial_hd(0)); |
87 | object_property_set_bool(OBJECT(&s->uart), true, "realized" , &err); |
88 | if (err != NULL) { |
89 | error_propagate(errp, err); |
90 | return; |
91 | } |
92 | |
93 | sbd = SYS_BUS_DEVICE(&s->uart); |
94 | sysbus_mmio_map(sbd, 0, DIGIC_UART_BASE); |
95 | } |
96 | |
97 | static void digic_class_init(ObjectClass *oc, void *data) |
98 | { |
99 | DeviceClass *dc = DEVICE_CLASS(oc); |
100 | |
101 | dc->realize = digic_realize; |
102 | /* Reason: Uses serial_hds in the realize function --> not usable twice */ |
103 | dc->user_creatable = false; |
104 | } |
105 | |
106 | static const TypeInfo digic_type_info = { |
107 | .name = TYPE_DIGIC, |
108 | .parent = TYPE_DEVICE, |
109 | .instance_size = sizeof(DigicState), |
110 | .instance_init = digic_init, |
111 | .class_init = digic_class_init, |
112 | }; |
113 | |
114 | static void digic_register_types(void) |
115 | { |
116 | type_register_static(&digic_type_info); |
117 | } |
118 | |
119 | type_init(digic_register_types) |
120 | |