root / hw / omap_gpio.c @ 9e2c1298
History | View | Annotate | Download (20.6 kB)
1 | e5c6b25a | cmchao | /*
|
---|---|---|---|
2 | e5c6b25a | cmchao | * TI OMAP processors GPIO emulation.
|
3 | e5c6b25a | cmchao | *
|
4 | e5c6b25a | cmchao | * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
|
5 | e5c6b25a | cmchao | * Copyright (C) 2007-2009 Nokia Corporation
|
6 | e5c6b25a | cmchao | *
|
7 | e5c6b25a | cmchao | * This program is free software; you can redistribute it and/or
|
8 | e5c6b25a | cmchao | * modify it under the terms of the GNU General Public License as
|
9 | e5c6b25a | cmchao | * published by the Free Software Foundation; either version 2 or
|
10 | e5c6b25a | cmchao | * (at your option) version 3 of the License.
|
11 | e5c6b25a | cmchao | *
|
12 | e5c6b25a | cmchao | * This program is distributed in the hope that it will be useful,
|
13 | e5c6b25a | cmchao | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | e5c6b25a | cmchao | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 | e5c6b25a | cmchao | * GNU General Public License for more details.
|
16 | e5c6b25a | cmchao | *
|
17 | e5c6b25a | cmchao | * You should have received a copy of the GNU General Public License along
|
18 | e5c6b25a | cmchao | * with this program; if not, see <http://www.gnu.org/licenses/>.
|
19 | e5c6b25a | cmchao | */
|
20 | e5c6b25a | cmchao | |
21 | e5c6b25a | cmchao | #include "hw.h" |
22 | e5c6b25a | cmchao | #include "omap.h" |
23 | 77831c20 | Juha Riihimäki | #include "sysbus.h" |
24 | 77831c20 | Juha Riihimäki | |
25 | e5c6b25a | cmchao | struct omap_gpio_s {
|
26 | e5c6b25a | cmchao | qemu_irq irq; |
27 | e5c6b25a | cmchao | qemu_irq handler[16];
|
28 | e5c6b25a | cmchao | |
29 | e5c6b25a | cmchao | uint16_t inputs; |
30 | e5c6b25a | cmchao | uint16_t outputs; |
31 | e5c6b25a | cmchao | uint16_t dir; |
32 | e5c6b25a | cmchao | uint16_t edge; |
33 | e5c6b25a | cmchao | uint16_t mask; |
34 | e5c6b25a | cmchao | uint16_t ints; |
35 | e5c6b25a | cmchao | uint16_t pins; |
36 | e5c6b25a | cmchao | }; |
37 | e5c6b25a | cmchao | |
38 | 77831c20 | Juha Riihimäki | struct omap_gpif_s {
|
39 | 77831c20 | Juha Riihimäki | SysBusDevice busdev; |
40 | 9244b42d | Avi Kivity | MemoryRegion iomem; |
41 | 77831c20 | Juha Riihimäki | int mpu_model;
|
42 | 77831c20 | Juha Riihimäki | void *clk;
|
43 | 77831c20 | Juha Riihimäki | struct omap_gpio_s omap1;
|
44 | 77831c20 | Juha Riihimäki | }; |
45 | 77831c20 | Juha Riihimäki | |
46 | 77831c20 | Juha Riihimäki | /* General-Purpose I/O of OMAP1 */
|
47 | e5c6b25a | cmchao | static void omap_gpio_set(void *opaque, int line, int level) |
48 | e5c6b25a | cmchao | { |
49 | 77831c20 | Juha Riihimäki | struct omap_gpio_s *s = &((struct omap_gpif_s *) opaque)->omap1; |
50 | e5c6b25a | cmchao | uint16_t prev = s->inputs; |
51 | e5c6b25a | cmchao | |
52 | e5c6b25a | cmchao | if (level)
|
53 | e5c6b25a | cmchao | s->inputs |= 1 << line;
|
54 | e5c6b25a | cmchao | else
|
55 | e5c6b25a | cmchao | s->inputs &= ~(1 << line);
|
56 | e5c6b25a | cmchao | |
57 | e5c6b25a | cmchao | if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) &
|
58 | e5c6b25a | cmchao | (1 << line) & s->dir & ~s->mask) {
|
59 | e5c6b25a | cmchao | s->ints |= 1 << line;
|
60 | e5c6b25a | cmchao | qemu_irq_raise(s->irq); |
61 | e5c6b25a | cmchao | } |
62 | e5c6b25a | cmchao | } |
63 | e5c6b25a | cmchao | |
64 | a8170e5e | Avi Kivity | static uint64_t omap_gpio_read(void *opaque, hwaddr addr, |
65 | 9244b42d | Avi Kivity | unsigned size)
|
66 | e5c6b25a | cmchao | { |
67 | e5c6b25a | cmchao | struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; |
68 | e5c6b25a | cmchao | int offset = addr & OMAP_MPUI_REG_MASK;
|
69 | e5c6b25a | cmchao | |
70 | 9244b42d | Avi Kivity | if (size != 2) { |
71 | 9244b42d | Avi Kivity | return omap_badwidth_read16(opaque, addr);
|
72 | 9244b42d | Avi Kivity | } |
73 | 9244b42d | Avi Kivity | |
74 | e5c6b25a | cmchao | switch (offset) {
|
75 | e5c6b25a | cmchao | case 0x00: /* DATA_INPUT */ |
76 | e5c6b25a | cmchao | return s->inputs & s->pins;
|
77 | e5c6b25a | cmchao | |
78 | e5c6b25a | cmchao | case 0x04: /* DATA_OUTPUT */ |
79 | e5c6b25a | cmchao | return s->outputs;
|
80 | e5c6b25a | cmchao | |
81 | e5c6b25a | cmchao | case 0x08: /* DIRECTION_CONTROL */ |
82 | e5c6b25a | cmchao | return s->dir;
|
83 | e5c6b25a | cmchao | |
84 | e5c6b25a | cmchao | case 0x0c: /* INTERRUPT_CONTROL */ |
85 | e5c6b25a | cmchao | return s->edge;
|
86 | e5c6b25a | cmchao | |
87 | e5c6b25a | cmchao | case 0x10: /* INTERRUPT_MASK */ |
88 | e5c6b25a | cmchao | return s->mask;
|
89 | e5c6b25a | cmchao | |
90 | e5c6b25a | cmchao | case 0x14: /* INTERRUPT_STATUS */ |
91 | e5c6b25a | cmchao | return s->ints;
|
92 | e5c6b25a | cmchao | |
93 | e5c6b25a | cmchao | case 0x18: /* PIN_CONTROL (not in OMAP310) */ |
94 | e5c6b25a | cmchao | OMAP_BAD_REG(addr); |
95 | e5c6b25a | cmchao | return s->pins;
|
96 | e5c6b25a | cmchao | } |
97 | e5c6b25a | cmchao | |
98 | e5c6b25a | cmchao | OMAP_BAD_REG(addr); |
99 | e5c6b25a | cmchao | return 0; |
100 | e5c6b25a | cmchao | } |
101 | e5c6b25a | cmchao | |
102 | a8170e5e | Avi Kivity | static void omap_gpio_write(void *opaque, hwaddr addr, |
103 | 9244b42d | Avi Kivity | uint64_t value, unsigned size)
|
104 | e5c6b25a | cmchao | { |
105 | e5c6b25a | cmchao | struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; |
106 | e5c6b25a | cmchao | int offset = addr & OMAP_MPUI_REG_MASK;
|
107 | e5c6b25a | cmchao | uint16_t diff; |
108 | e5c6b25a | cmchao | int ln;
|
109 | e5c6b25a | cmchao | |
110 | 9244b42d | Avi Kivity | if (size != 2) { |
111 | 9244b42d | Avi Kivity | return omap_badwidth_write16(opaque, addr, value);
|
112 | 9244b42d | Avi Kivity | } |
113 | 9244b42d | Avi Kivity | |
114 | e5c6b25a | cmchao | switch (offset) {
|
115 | e5c6b25a | cmchao | case 0x00: /* DATA_INPUT */ |
116 | e5c6b25a | cmchao | OMAP_RO_REG(addr); |
117 | e5c6b25a | cmchao | return;
|
118 | e5c6b25a | cmchao | |
119 | e5c6b25a | cmchao | case 0x04: /* DATA_OUTPUT */ |
120 | e5c6b25a | cmchao | diff = (s->outputs ^ value) & ~s->dir; |
121 | e5c6b25a | cmchao | s->outputs = value; |
122 | e5c6b25a | cmchao | while ((ln = ffs(diff))) {
|
123 | e5c6b25a | cmchao | ln --; |
124 | e5c6b25a | cmchao | if (s->handler[ln])
|
125 | e5c6b25a | cmchao | qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
126 | e5c6b25a | cmchao | diff &= ~(1 << ln);
|
127 | e5c6b25a | cmchao | } |
128 | e5c6b25a | cmchao | break;
|
129 | e5c6b25a | cmchao | |
130 | e5c6b25a | cmchao | case 0x08: /* DIRECTION_CONTROL */ |
131 | e5c6b25a | cmchao | diff = s->outputs & (s->dir ^ value); |
132 | e5c6b25a | cmchao | s->dir = value; |
133 | e5c6b25a | cmchao | |
134 | e5c6b25a | cmchao | value = s->outputs & ~s->dir; |
135 | e5c6b25a | cmchao | while ((ln = ffs(diff))) {
|
136 | e5c6b25a | cmchao | ln --; |
137 | e5c6b25a | cmchao | if (s->handler[ln])
|
138 | e5c6b25a | cmchao | qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
139 | e5c6b25a | cmchao | diff &= ~(1 << ln);
|
140 | e5c6b25a | cmchao | } |
141 | e5c6b25a | cmchao | break;
|
142 | e5c6b25a | cmchao | |
143 | e5c6b25a | cmchao | case 0x0c: /* INTERRUPT_CONTROL */ |
144 | e5c6b25a | cmchao | s->edge = value; |
145 | e5c6b25a | cmchao | break;
|
146 | e5c6b25a | cmchao | |
147 | e5c6b25a | cmchao | case 0x10: /* INTERRUPT_MASK */ |
148 | e5c6b25a | cmchao | s->mask = value; |
149 | e5c6b25a | cmchao | break;
|
150 | e5c6b25a | cmchao | |
151 | e5c6b25a | cmchao | case 0x14: /* INTERRUPT_STATUS */ |
152 | e5c6b25a | cmchao | s->ints &= ~value; |
153 | e5c6b25a | cmchao | if (!s->ints)
|
154 | e5c6b25a | cmchao | qemu_irq_lower(s->irq); |
155 | e5c6b25a | cmchao | break;
|
156 | e5c6b25a | cmchao | |
157 | e5c6b25a | cmchao | case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ |
158 | e5c6b25a | cmchao | OMAP_BAD_REG(addr); |
159 | e5c6b25a | cmchao | s->pins = value; |
160 | e5c6b25a | cmchao | break;
|
161 | e5c6b25a | cmchao | |
162 | e5c6b25a | cmchao | default:
|
163 | e5c6b25a | cmchao | OMAP_BAD_REG(addr); |
164 | e5c6b25a | cmchao | return;
|
165 | e5c6b25a | cmchao | } |
166 | e5c6b25a | cmchao | } |
167 | e5c6b25a | cmchao | |
168 | e5c6b25a | cmchao | /* *Some* sources say the memory region is 32-bit. */
|
169 | 9244b42d | Avi Kivity | static const MemoryRegionOps omap_gpio_ops = { |
170 | 9244b42d | Avi Kivity | .read = omap_gpio_read, |
171 | 9244b42d | Avi Kivity | .write = omap_gpio_write, |
172 | 9244b42d | Avi Kivity | .endianness = DEVICE_NATIVE_ENDIAN, |
173 | e5c6b25a | cmchao | }; |
174 | e5c6b25a | cmchao | |
175 | 77831c20 | Juha Riihimäki | static void omap_gpio_reset(struct omap_gpio_s *s) |
176 | e5c6b25a | cmchao | { |
177 | e5c6b25a | cmchao | s->inputs = 0;
|
178 | e5c6b25a | cmchao | s->outputs = ~0;
|
179 | e5c6b25a | cmchao | s->dir = ~0;
|
180 | e5c6b25a | cmchao | s->edge = ~0;
|
181 | e5c6b25a | cmchao | s->mask = ~0;
|
182 | e5c6b25a | cmchao | s->ints = 0;
|
183 | e5c6b25a | cmchao | s->pins = ~0;
|
184 | e5c6b25a | cmchao | } |
185 | e5c6b25a | cmchao | |
186 | d82310f7 | cmchao | struct omap2_gpio_s {
|
187 | d82310f7 | cmchao | qemu_irq irq[2];
|
188 | d82310f7 | cmchao | qemu_irq wkup; |
189 | 77831c20 | Juha Riihimäki | qemu_irq *handler; |
190 | 9244b42d | Avi Kivity | MemoryRegion iomem; |
191 | d82310f7 | cmchao | |
192 | 77831c20 | Juha Riihimäki | uint8_t revision; |
193 | d82310f7 | cmchao | uint8_t config[2];
|
194 | d82310f7 | cmchao | uint32_t inputs; |
195 | d82310f7 | cmchao | uint32_t outputs; |
196 | d82310f7 | cmchao | uint32_t dir; |
197 | d82310f7 | cmchao | uint32_t level[2];
|
198 | d82310f7 | cmchao | uint32_t edge[2];
|
199 | d82310f7 | cmchao | uint32_t mask[2];
|
200 | d82310f7 | cmchao | uint32_t wumask; |
201 | d82310f7 | cmchao | uint32_t ints[2];
|
202 | d82310f7 | cmchao | uint32_t debounce; |
203 | d82310f7 | cmchao | uint8_t delay; |
204 | d82310f7 | cmchao | }; |
205 | d82310f7 | cmchao | |
206 | 77831c20 | Juha Riihimäki | struct omap2_gpif_s {
|
207 | 77831c20 | Juha Riihimäki | SysBusDevice busdev; |
208 | 9244b42d | Avi Kivity | MemoryRegion iomem; |
209 | 77831c20 | Juha Riihimäki | int mpu_model;
|
210 | 77831c20 | Juha Riihimäki | void *iclk;
|
211 | 77831c20 | Juha Riihimäki | void *fclk[6]; |
212 | 77831c20 | Juha Riihimäki | int modulecount;
|
213 | 77831c20 | Juha Riihimäki | struct omap2_gpio_s *modules;
|
214 | 77831c20 | Juha Riihimäki | qemu_irq *handler; |
215 | 77831c20 | Juha Riihimäki | int autoidle;
|
216 | 77831c20 | Juha Riihimäki | int gpo;
|
217 | 77831c20 | Juha Riihimäki | }; |
218 | 77831c20 | Juha Riihimäki | |
219 | 77831c20 | Juha Riihimäki | /* General-Purpose Interface of OMAP2/3 */
|
220 | d82310f7 | cmchao | static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s, |
221 | 77831c20 | Juha Riihimäki | int line)
|
222 | d82310f7 | cmchao | { |
223 | d82310f7 | cmchao | qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]); |
224 | d82310f7 | cmchao | } |
225 | d82310f7 | cmchao | |
226 | d82310f7 | cmchao | static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line) |
227 | d82310f7 | cmchao | { |
228 | d82310f7 | cmchao | if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */ |
229 | d82310f7 | cmchao | return;
|
230 | d82310f7 | cmchao | if (!(s->config[0] & (3 << 3))) /* Force Idle */ |
231 | d82310f7 | cmchao | return;
|
232 | d82310f7 | cmchao | if (!(s->wumask & (1 << line))) |
233 | d82310f7 | cmchao | return;
|
234 | d82310f7 | cmchao | |
235 | d82310f7 | cmchao | qemu_irq_raise(s->wkup); |
236 | d82310f7 | cmchao | } |
237 | d82310f7 | cmchao | |
238 | d82310f7 | cmchao | static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s, |
239 | d82310f7 | cmchao | uint32_t diff) |
240 | d82310f7 | cmchao | { |
241 | d82310f7 | cmchao | int ln;
|
242 | d82310f7 | cmchao | |
243 | d82310f7 | cmchao | s->outputs ^= diff; |
244 | d82310f7 | cmchao | diff &= ~s->dir; |
245 | d82310f7 | cmchao | while ((ln = ffs(diff))) {
|
246 | d82310f7 | cmchao | ln --; |
247 | d82310f7 | cmchao | qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
|
248 | d82310f7 | cmchao | diff &= ~(1 << ln);
|
249 | d82310f7 | cmchao | } |
250 | d82310f7 | cmchao | } |
251 | d82310f7 | cmchao | |
252 | d82310f7 | cmchao | static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line) |
253 | d82310f7 | cmchao | { |
254 | d82310f7 | cmchao | s->ints[line] |= s->dir & |
255 | d82310f7 | cmchao | ((s->inputs & s->level[1]) | (~s->inputs & s->level[0])); |
256 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, line); |
257 | d82310f7 | cmchao | } |
258 | d82310f7 | cmchao | |
259 | d82310f7 | cmchao | static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line) |
260 | d82310f7 | cmchao | { |
261 | d82310f7 | cmchao | s->ints[0] |= 1 << line; |
262 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 0);
|
263 | d82310f7 | cmchao | s->ints[1] |= 1 << line; |
264 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 1);
|
265 | d82310f7 | cmchao | omap2_gpio_module_wake(s, line); |
266 | d82310f7 | cmchao | } |
267 | d82310f7 | cmchao | |
268 | 77831c20 | Juha Riihimäki | static void omap2_gpio_set(void *opaque, int line, int level) |
269 | d82310f7 | cmchao | { |
270 | 77831c20 | Juha Riihimäki | struct omap2_gpif_s *p = opaque;
|
271 | 77831c20 | Juha Riihimäki | struct omap2_gpio_s *s = &p->modules[line >> 5]; |
272 | d82310f7 | cmchao | |
273 | 77831c20 | Juha Riihimäki | line &= 31;
|
274 | d82310f7 | cmchao | if (level) {
|
275 | d82310f7 | cmchao | if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1])) |
276 | d82310f7 | cmchao | omap2_gpio_module_int(s, line); |
277 | d82310f7 | cmchao | s->inputs |= 1 << line;
|
278 | d82310f7 | cmchao | } else {
|
279 | d82310f7 | cmchao | if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0])) |
280 | d82310f7 | cmchao | omap2_gpio_module_int(s, line); |
281 | d82310f7 | cmchao | s->inputs &= ~(1 << line);
|
282 | d82310f7 | cmchao | } |
283 | d82310f7 | cmchao | } |
284 | d82310f7 | cmchao | |
285 | d82310f7 | cmchao | static void omap2_gpio_module_reset(struct omap2_gpio_s *s) |
286 | d82310f7 | cmchao | { |
287 | d82310f7 | cmchao | s->config[0] = 0; |
288 | d82310f7 | cmchao | s->config[1] = 2; |
289 | d82310f7 | cmchao | s->ints[0] = 0; |
290 | d82310f7 | cmchao | s->ints[1] = 0; |
291 | d82310f7 | cmchao | s->mask[0] = 0; |
292 | d82310f7 | cmchao | s->mask[1] = 0; |
293 | d82310f7 | cmchao | s->wumask = 0;
|
294 | d82310f7 | cmchao | s->dir = ~0;
|
295 | d82310f7 | cmchao | s->level[0] = 0; |
296 | d82310f7 | cmchao | s->level[1] = 0; |
297 | d82310f7 | cmchao | s->edge[0] = 0; |
298 | d82310f7 | cmchao | s->edge[1] = 0; |
299 | d82310f7 | cmchao | s->debounce = 0;
|
300 | d82310f7 | cmchao | s->delay = 0;
|
301 | d82310f7 | cmchao | } |
302 | d82310f7 | cmchao | |
303 | a8170e5e | Avi Kivity | static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr) |
304 | d82310f7 | cmchao | { |
305 | d82310f7 | cmchao | struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; |
306 | d82310f7 | cmchao | |
307 | d82310f7 | cmchao | switch (addr) {
|
308 | d82310f7 | cmchao | case 0x00: /* GPIO_REVISION */ |
309 | 77831c20 | Juha Riihimäki | return s->revision;
|
310 | d82310f7 | cmchao | |
311 | d82310f7 | cmchao | case 0x10: /* GPIO_SYSCONFIG */ |
312 | d82310f7 | cmchao | return s->config[0]; |
313 | d82310f7 | cmchao | |
314 | d82310f7 | cmchao | case 0x14: /* GPIO_SYSSTATUS */ |
315 | d82310f7 | cmchao | return 0x01; |
316 | d82310f7 | cmchao | |
317 | d82310f7 | cmchao | case 0x18: /* GPIO_IRQSTATUS1 */ |
318 | d82310f7 | cmchao | return s->ints[0]; |
319 | d82310f7 | cmchao | |
320 | d82310f7 | cmchao | case 0x1c: /* GPIO_IRQENABLE1 */ |
321 | d82310f7 | cmchao | case 0x60: /* GPIO_CLEARIRQENABLE1 */ |
322 | d82310f7 | cmchao | case 0x64: /* GPIO_SETIRQENABLE1 */ |
323 | d82310f7 | cmchao | return s->mask[0]; |
324 | d82310f7 | cmchao | |
325 | d82310f7 | cmchao | case 0x20: /* GPIO_WAKEUPENABLE */ |
326 | d82310f7 | cmchao | case 0x80: /* GPIO_CLEARWKUENA */ |
327 | d82310f7 | cmchao | case 0x84: /* GPIO_SETWKUENA */ |
328 | d82310f7 | cmchao | return s->wumask;
|
329 | d82310f7 | cmchao | |
330 | d82310f7 | cmchao | case 0x28: /* GPIO_IRQSTATUS2 */ |
331 | d82310f7 | cmchao | return s->ints[1]; |
332 | d82310f7 | cmchao | |
333 | d82310f7 | cmchao | case 0x2c: /* GPIO_IRQENABLE2 */ |
334 | d82310f7 | cmchao | case 0x70: /* GPIO_CLEARIRQENABLE2 */ |
335 | d82310f7 | cmchao | case 0x74: /* GPIO_SETIREQNEABLE2 */ |
336 | d82310f7 | cmchao | return s->mask[1]; |
337 | d82310f7 | cmchao | |
338 | d82310f7 | cmchao | case 0x30: /* GPIO_CTRL */ |
339 | d82310f7 | cmchao | return s->config[1]; |
340 | d82310f7 | cmchao | |
341 | d82310f7 | cmchao | case 0x34: /* GPIO_OE */ |
342 | d82310f7 | cmchao | return s->dir;
|
343 | d82310f7 | cmchao | |
344 | d82310f7 | cmchao | case 0x38: /* GPIO_DATAIN */ |
345 | d82310f7 | cmchao | return s->inputs;
|
346 | d82310f7 | cmchao | |
347 | d82310f7 | cmchao | case 0x3c: /* GPIO_DATAOUT */ |
348 | d82310f7 | cmchao | case 0x90: /* GPIO_CLEARDATAOUT */ |
349 | d82310f7 | cmchao | case 0x94: /* GPIO_SETDATAOUT */ |
350 | d82310f7 | cmchao | return s->outputs;
|
351 | d82310f7 | cmchao | |
352 | d82310f7 | cmchao | case 0x40: /* GPIO_LEVELDETECT0 */ |
353 | d82310f7 | cmchao | return s->level[0]; |
354 | d82310f7 | cmchao | |
355 | d82310f7 | cmchao | case 0x44: /* GPIO_LEVELDETECT1 */ |
356 | d82310f7 | cmchao | return s->level[1]; |
357 | d82310f7 | cmchao | |
358 | d82310f7 | cmchao | case 0x48: /* GPIO_RISINGDETECT */ |
359 | d82310f7 | cmchao | return s->edge[0]; |
360 | d82310f7 | cmchao | |
361 | d82310f7 | cmchao | case 0x4c: /* GPIO_FALLINGDETECT */ |
362 | d82310f7 | cmchao | return s->edge[1]; |
363 | d82310f7 | cmchao | |
364 | d82310f7 | cmchao | case 0x50: /* GPIO_DEBOUNCENABLE */ |
365 | d82310f7 | cmchao | return s->debounce;
|
366 | d82310f7 | cmchao | |
367 | d82310f7 | cmchao | case 0x54: /* GPIO_DEBOUNCINGTIME */ |
368 | d82310f7 | cmchao | return s->delay;
|
369 | d82310f7 | cmchao | } |
370 | d82310f7 | cmchao | |
371 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
372 | d82310f7 | cmchao | return 0; |
373 | d82310f7 | cmchao | } |
374 | d82310f7 | cmchao | |
375 | a8170e5e | Avi Kivity | static void omap2_gpio_module_write(void *opaque, hwaddr addr, |
376 | d82310f7 | cmchao | uint32_t value) |
377 | d82310f7 | cmchao | { |
378 | d82310f7 | cmchao | struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; |
379 | d82310f7 | cmchao | uint32_t diff; |
380 | d82310f7 | cmchao | int ln;
|
381 | d82310f7 | cmchao | |
382 | d82310f7 | cmchao | switch (addr) {
|
383 | d82310f7 | cmchao | case 0x00: /* GPIO_REVISION */ |
384 | d82310f7 | cmchao | case 0x14: /* GPIO_SYSSTATUS */ |
385 | d82310f7 | cmchao | case 0x38: /* GPIO_DATAIN */ |
386 | d82310f7 | cmchao | OMAP_RO_REG(addr); |
387 | d82310f7 | cmchao | break;
|
388 | d82310f7 | cmchao | |
389 | d82310f7 | cmchao | case 0x10: /* GPIO_SYSCONFIG */ |
390 | d82310f7 | cmchao | if (((value >> 3) & 3) == 3) |
391 | d82310f7 | cmchao | fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__);
|
392 | d82310f7 | cmchao | if (value & 2) |
393 | d82310f7 | cmchao | omap2_gpio_module_reset(s); |
394 | d82310f7 | cmchao | s->config[0] = value & 0x1d; |
395 | d82310f7 | cmchao | break;
|
396 | d82310f7 | cmchao | |
397 | d82310f7 | cmchao | case 0x18: /* GPIO_IRQSTATUS1 */ |
398 | d82310f7 | cmchao | if (s->ints[0] & value) { |
399 | d82310f7 | cmchao | s->ints[0] &= ~value;
|
400 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 0);
|
401 | d82310f7 | cmchao | } |
402 | d82310f7 | cmchao | break;
|
403 | d82310f7 | cmchao | |
404 | d82310f7 | cmchao | case 0x1c: /* GPIO_IRQENABLE1 */ |
405 | d82310f7 | cmchao | s->mask[0] = value;
|
406 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 0);
|
407 | d82310f7 | cmchao | break;
|
408 | d82310f7 | cmchao | |
409 | d82310f7 | cmchao | case 0x20: /* GPIO_WAKEUPENABLE */ |
410 | d82310f7 | cmchao | s->wumask = value; |
411 | d82310f7 | cmchao | break;
|
412 | d82310f7 | cmchao | |
413 | d82310f7 | cmchao | case 0x28: /* GPIO_IRQSTATUS2 */ |
414 | d82310f7 | cmchao | if (s->ints[1] & value) { |
415 | d82310f7 | cmchao | s->ints[1] &= ~value;
|
416 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 1);
|
417 | d82310f7 | cmchao | } |
418 | d82310f7 | cmchao | break;
|
419 | d82310f7 | cmchao | |
420 | d82310f7 | cmchao | case 0x2c: /* GPIO_IRQENABLE2 */ |
421 | d82310f7 | cmchao | s->mask[1] = value;
|
422 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 1);
|
423 | d82310f7 | cmchao | break;
|
424 | d82310f7 | cmchao | |
425 | d82310f7 | cmchao | case 0x30: /* GPIO_CTRL */ |
426 | d82310f7 | cmchao | s->config[1] = value & 7; |
427 | d82310f7 | cmchao | break;
|
428 | d82310f7 | cmchao | |
429 | d82310f7 | cmchao | case 0x34: /* GPIO_OE */ |
430 | d82310f7 | cmchao | diff = s->outputs & (s->dir ^ value); |
431 | d82310f7 | cmchao | s->dir = value; |
432 | d82310f7 | cmchao | |
433 | d82310f7 | cmchao | value = s->outputs & ~s->dir; |
434 | d82310f7 | cmchao | while ((ln = ffs(diff))) {
|
435 | d82310f7 | cmchao | diff &= ~(1 <<-- ln);
|
436 | d82310f7 | cmchao | qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
437 | d82310f7 | cmchao | } |
438 | d82310f7 | cmchao | |
439 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 0);
|
440 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 1);
|
441 | d82310f7 | cmchao | break;
|
442 | d82310f7 | cmchao | |
443 | d82310f7 | cmchao | case 0x3c: /* GPIO_DATAOUT */ |
444 | d82310f7 | cmchao | omap2_gpio_module_out_update(s, s->outputs ^ value); |
445 | d82310f7 | cmchao | break;
|
446 | d82310f7 | cmchao | |
447 | d82310f7 | cmchao | case 0x40: /* GPIO_LEVELDETECT0 */ |
448 | d82310f7 | cmchao | s->level[0] = value;
|
449 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 0);
|
450 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 1);
|
451 | d82310f7 | cmchao | break;
|
452 | d82310f7 | cmchao | |
453 | d82310f7 | cmchao | case 0x44: /* GPIO_LEVELDETECT1 */ |
454 | d82310f7 | cmchao | s->level[1] = value;
|
455 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 0);
|
456 | d82310f7 | cmchao | omap2_gpio_module_level_update(s, 1);
|
457 | d82310f7 | cmchao | break;
|
458 | d82310f7 | cmchao | |
459 | d82310f7 | cmchao | case 0x48: /* GPIO_RISINGDETECT */ |
460 | d82310f7 | cmchao | s->edge[0] = value;
|
461 | d82310f7 | cmchao | break;
|
462 | d82310f7 | cmchao | |
463 | d82310f7 | cmchao | case 0x4c: /* GPIO_FALLINGDETECT */ |
464 | d82310f7 | cmchao | s->edge[1] = value;
|
465 | d82310f7 | cmchao | break;
|
466 | d82310f7 | cmchao | |
467 | d82310f7 | cmchao | case 0x50: /* GPIO_DEBOUNCENABLE */ |
468 | d82310f7 | cmchao | s->debounce = value; |
469 | d82310f7 | cmchao | break;
|
470 | d82310f7 | cmchao | |
471 | d82310f7 | cmchao | case 0x54: /* GPIO_DEBOUNCINGTIME */ |
472 | d82310f7 | cmchao | s->delay = value; |
473 | d82310f7 | cmchao | break;
|
474 | d82310f7 | cmchao | |
475 | d82310f7 | cmchao | case 0x60: /* GPIO_CLEARIRQENABLE1 */ |
476 | d82310f7 | cmchao | s->mask[0] &= ~value;
|
477 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 0);
|
478 | d82310f7 | cmchao | break;
|
479 | d82310f7 | cmchao | |
480 | d82310f7 | cmchao | case 0x64: /* GPIO_SETIRQENABLE1 */ |
481 | d82310f7 | cmchao | s->mask[0] |= value;
|
482 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 0);
|
483 | d82310f7 | cmchao | break;
|
484 | d82310f7 | cmchao | |
485 | d82310f7 | cmchao | case 0x70: /* GPIO_CLEARIRQENABLE2 */ |
486 | d82310f7 | cmchao | s->mask[1] &= ~value;
|
487 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 1);
|
488 | d82310f7 | cmchao | break;
|
489 | d82310f7 | cmchao | |
490 | d82310f7 | cmchao | case 0x74: /* GPIO_SETIREQNEABLE2 */ |
491 | d82310f7 | cmchao | s->mask[1] |= value;
|
492 | d82310f7 | cmchao | omap2_gpio_module_int_update(s, 1);
|
493 | d82310f7 | cmchao | break;
|
494 | d82310f7 | cmchao | |
495 | d82310f7 | cmchao | case 0x80: /* GPIO_CLEARWKUENA */ |
496 | d82310f7 | cmchao | s->wumask &= ~value; |
497 | d82310f7 | cmchao | break;
|
498 | d82310f7 | cmchao | |
499 | d82310f7 | cmchao | case 0x84: /* GPIO_SETWKUENA */ |
500 | d82310f7 | cmchao | s->wumask |= value; |
501 | d82310f7 | cmchao | break;
|
502 | d82310f7 | cmchao | |
503 | d82310f7 | cmchao | case 0x90: /* GPIO_CLEARDATAOUT */ |
504 | d82310f7 | cmchao | omap2_gpio_module_out_update(s, s->outputs & value); |
505 | d82310f7 | cmchao | break;
|
506 | d82310f7 | cmchao | |
507 | d82310f7 | cmchao | case 0x94: /* GPIO_SETDATAOUT */ |
508 | d82310f7 | cmchao | omap2_gpio_module_out_update(s, ~s->outputs & value); |
509 | d82310f7 | cmchao | break;
|
510 | d82310f7 | cmchao | |
511 | d82310f7 | cmchao | default:
|
512 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
513 | d82310f7 | cmchao | return;
|
514 | d82310f7 | cmchao | } |
515 | d82310f7 | cmchao | } |
516 | d82310f7 | cmchao | |
517 | a8170e5e | Avi Kivity | static uint32_t omap2_gpio_module_readp(void *opaque, hwaddr addr) |
518 | d82310f7 | cmchao | { |
519 | e1556ad5 | Peter Maydell | return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3); |
520 | d82310f7 | cmchao | } |
521 | d82310f7 | cmchao | |
522 | a8170e5e | Avi Kivity | static void omap2_gpio_module_writep(void *opaque, hwaddr addr, |
523 | d82310f7 | cmchao | uint32_t value) |
524 | d82310f7 | cmchao | { |
525 | d82310f7 | cmchao | uint32_t cur = 0;
|
526 | d82310f7 | cmchao | uint32_t mask = 0xffff;
|
527 | d82310f7 | cmchao | |
528 | d82310f7 | cmchao | switch (addr & ~3) { |
529 | d82310f7 | cmchao | case 0x00: /* GPIO_REVISION */ |
530 | d82310f7 | cmchao | case 0x14: /* GPIO_SYSSTATUS */ |
531 | d82310f7 | cmchao | case 0x38: /* GPIO_DATAIN */ |
532 | d82310f7 | cmchao | OMAP_RO_REG(addr); |
533 | d82310f7 | cmchao | break;
|
534 | d82310f7 | cmchao | |
535 | d82310f7 | cmchao | case 0x10: /* GPIO_SYSCONFIG */ |
536 | d82310f7 | cmchao | case 0x1c: /* GPIO_IRQENABLE1 */ |
537 | d82310f7 | cmchao | case 0x20: /* GPIO_WAKEUPENABLE */ |
538 | d82310f7 | cmchao | case 0x2c: /* GPIO_IRQENABLE2 */ |
539 | d82310f7 | cmchao | case 0x30: /* GPIO_CTRL */ |
540 | d82310f7 | cmchao | case 0x34: /* GPIO_OE */ |
541 | d82310f7 | cmchao | case 0x3c: /* GPIO_DATAOUT */ |
542 | d82310f7 | cmchao | case 0x40: /* GPIO_LEVELDETECT0 */ |
543 | d82310f7 | cmchao | case 0x44: /* GPIO_LEVELDETECT1 */ |
544 | d82310f7 | cmchao | case 0x48: /* GPIO_RISINGDETECT */ |
545 | d82310f7 | cmchao | case 0x4c: /* GPIO_FALLINGDETECT */ |
546 | d82310f7 | cmchao | case 0x50: /* GPIO_DEBOUNCENABLE */ |
547 | d82310f7 | cmchao | case 0x54: /* GPIO_DEBOUNCINGTIME */ |
548 | d82310f7 | cmchao | cur = omap2_gpio_module_read(opaque, addr & ~3) &
|
549 | d82310f7 | cmchao | ~(mask << ((addr & 3) << 3)); |
550 | d82310f7 | cmchao | |
551 | d82310f7 | cmchao | /* Fall through. */
|
552 | d82310f7 | cmchao | case 0x18: /* GPIO_IRQSTATUS1 */ |
553 | d82310f7 | cmchao | case 0x28: /* GPIO_IRQSTATUS2 */ |
554 | d82310f7 | cmchao | case 0x60: /* GPIO_CLEARIRQENABLE1 */ |
555 | d82310f7 | cmchao | case 0x64: /* GPIO_SETIRQENABLE1 */ |
556 | d82310f7 | cmchao | case 0x70: /* GPIO_CLEARIRQENABLE2 */ |
557 | d82310f7 | cmchao | case 0x74: /* GPIO_SETIREQNEABLE2 */ |
558 | d82310f7 | cmchao | case 0x80: /* GPIO_CLEARWKUENA */ |
559 | d82310f7 | cmchao | case 0x84: /* GPIO_SETWKUENA */ |
560 | d82310f7 | cmchao | case 0x90: /* GPIO_CLEARDATAOUT */ |
561 | d82310f7 | cmchao | case 0x94: /* GPIO_SETDATAOUT */ |
562 | d82310f7 | cmchao | value <<= (addr & 3) << 3; |
563 | d82310f7 | cmchao | omap2_gpio_module_write(opaque, addr, cur | value); |
564 | d82310f7 | cmchao | break;
|
565 | d82310f7 | cmchao | |
566 | d82310f7 | cmchao | default:
|
567 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
568 | d82310f7 | cmchao | return;
|
569 | d82310f7 | cmchao | } |
570 | d82310f7 | cmchao | } |
571 | d82310f7 | cmchao | |
572 | 9244b42d | Avi Kivity | static const MemoryRegionOps omap2_gpio_module_ops = { |
573 | 9244b42d | Avi Kivity | .old_mmio = { |
574 | 9244b42d | Avi Kivity | .read = { |
575 | 9244b42d | Avi Kivity | omap2_gpio_module_readp, |
576 | 9244b42d | Avi Kivity | omap2_gpio_module_readp, |
577 | 9244b42d | Avi Kivity | omap2_gpio_module_read, |
578 | 9244b42d | Avi Kivity | }, |
579 | 9244b42d | Avi Kivity | .write = { |
580 | 9244b42d | Avi Kivity | omap2_gpio_module_writep, |
581 | 9244b42d | Avi Kivity | omap2_gpio_module_writep, |
582 | 9244b42d | Avi Kivity | omap2_gpio_module_write, |
583 | 9244b42d | Avi Kivity | }, |
584 | 9244b42d | Avi Kivity | }, |
585 | 9244b42d | Avi Kivity | .endianness = DEVICE_NATIVE_ENDIAN, |
586 | d82310f7 | cmchao | }; |
587 | d82310f7 | cmchao | |
588 | 77831c20 | Juha Riihimäki | static void omap_gpif_reset(DeviceState *dev) |
589 | d82310f7 | cmchao | { |
590 | 77831c20 | Juha Riihimäki | struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, |
591 | 77831c20 | Juha Riihimäki | sysbus_from_qdev(dev)); |
592 | 77831c20 | Juha Riihimäki | omap_gpio_reset(&s->omap1); |
593 | d82310f7 | cmchao | } |
594 | d82310f7 | cmchao | |
595 | 77831c20 | Juha Riihimäki | static void omap2_gpif_reset(DeviceState *dev) |
596 | d82310f7 | cmchao | { |
597 | d82310f7 | cmchao | int i;
|
598 | 77831c20 | Juha Riihimäki | struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, |
599 | 77831c20 | Juha Riihimäki | sysbus_from_qdev(dev)); |
600 | 77831c20 | Juha Riihimäki | for (i = 0; i < s->modulecount; i++) { |
601 | 77831c20 | Juha Riihimäki | omap2_gpio_module_reset(&s->modules[i]); |
602 | 77831c20 | Juha Riihimäki | } |
603 | d82310f7 | cmchao | s->autoidle = 0;
|
604 | d82310f7 | cmchao | s->gpo = 0;
|
605 | d82310f7 | cmchao | } |
606 | d82310f7 | cmchao | |
607 | a8170e5e | Avi Kivity | static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, |
608 | 9244b42d | Avi Kivity | unsigned size)
|
609 | d82310f7 | cmchao | { |
610 | 77831c20 | Juha Riihimäki | struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque; |
611 | d82310f7 | cmchao | |
612 | d82310f7 | cmchao | switch (addr) {
|
613 | d82310f7 | cmchao | case 0x00: /* IPGENERICOCPSPL_REVISION */ |
614 | d82310f7 | cmchao | return 0x18; |
615 | d82310f7 | cmchao | |
616 | d82310f7 | cmchao | case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ |
617 | d82310f7 | cmchao | return s->autoidle;
|
618 | d82310f7 | cmchao | |
619 | d82310f7 | cmchao | case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ |
620 | d82310f7 | cmchao | return 0x01; |
621 | d82310f7 | cmchao | |
622 | d82310f7 | cmchao | case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ |
623 | d82310f7 | cmchao | return 0x00; |
624 | d82310f7 | cmchao | |
625 | d82310f7 | cmchao | case 0x40: /* IPGENERICOCPSPL_GPO */ |
626 | d82310f7 | cmchao | return s->gpo;
|
627 | d82310f7 | cmchao | |
628 | d82310f7 | cmchao | case 0x50: /* IPGENERICOCPSPL_GPI */ |
629 | d82310f7 | cmchao | return 0x00; |
630 | d82310f7 | cmchao | } |
631 | d82310f7 | cmchao | |
632 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
633 | d82310f7 | cmchao | return 0; |
634 | d82310f7 | cmchao | } |
635 | d82310f7 | cmchao | |
636 | a8170e5e | Avi Kivity | static void omap2_gpif_top_write(void *opaque, hwaddr addr, |
637 | 9244b42d | Avi Kivity | uint64_t value, unsigned size)
|
638 | d82310f7 | cmchao | { |
639 | 77831c20 | Juha Riihimäki | struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque; |
640 | d82310f7 | cmchao | |
641 | d82310f7 | cmchao | switch (addr) {
|
642 | d82310f7 | cmchao | case 0x00: /* IPGENERICOCPSPL_REVISION */ |
643 | d82310f7 | cmchao | case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ |
644 | d82310f7 | cmchao | case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ |
645 | d82310f7 | cmchao | case 0x50: /* IPGENERICOCPSPL_GPI */ |
646 | d82310f7 | cmchao | OMAP_RO_REG(addr); |
647 | d82310f7 | cmchao | break;
|
648 | d82310f7 | cmchao | |
649 | d82310f7 | cmchao | case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ |
650 | d82310f7 | cmchao | if (value & (1 << 1)) /* SOFTRESET */ |
651 | 77831c20 | Juha Riihimäki | omap2_gpif_reset(&s->busdev.qdev); |
652 | d82310f7 | cmchao | s->autoidle = value & 1;
|
653 | d82310f7 | cmchao | break;
|
654 | d82310f7 | cmchao | |
655 | d82310f7 | cmchao | case 0x40: /* IPGENERICOCPSPL_GPO */ |
656 | d82310f7 | cmchao | s->gpo = value & 1;
|
657 | d82310f7 | cmchao | break;
|
658 | d82310f7 | cmchao | |
659 | d82310f7 | cmchao | default:
|
660 | d82310f7 | cmchao | OMAP_BAD_REG(addr); |
661 | d82310f7 | cmchao | return;
|
662 | d82310f7 | cmchao | } |
663 | d82310f7 | cmchao | } |
664 | d82310f7 | cmchao | |
665 | 9244b42d | Avi Kivity | static const MemoryRegionOps omap2_gpif_top_ops = { |
666 | 9244b42d | Avi Kivity | .read = omap2_gpif_top_read, |
667 | 9244b42d | Avi Kivity | .write = omap2_gpif_top_write, |
668 | 9244b42d | Avi Kivity | .endianness = DEVICE_NATIVE_ENDIAN, |
669 | d82310f7 | cmchao | }; |
670 | d82310f7 | cmchao | |
671 | 77831c20 | Juha Riihimäki | static int omap_gpio_init(SysBusDevice *dev) |
672 | d82310f7 | cmchao | { |
673 | 77831c20 | Juha Riihimäki | struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, dev); |
674 | 77831c20 | Juha Riihimäki | if (!s->clk) {
|
675 | 77831c20 | Juha Riihimäki | hw_error("omap-gpio: clk not connected\n");
|
676 | 77831c20 | Juha Riihimäki | } |
677 | 77831c20 | Juha Riihimäki | qdev_init_gpio_in(&dev->qdev, omap_gpio_set, 16);
|
678 | 77831c20 | Juha Riihimäki | qdev_init_gpio_out(&dev->qdev, s->omap1.handler, 16);
|
679 | 77831c20 | Juha Riihimäki | sysbus_init_irq(dev, &s->omap1.irq); |
680 | 9244b42d | Avi Kivity | memory_region_init_io(&s->iomem, &omap_gpio_ops, &s->omap1, |
681 | 9244b42d | Avi Kivity | "omap.gpio", 0x1000); |
682 | 750ecd44 | Avi Kivity | sysbus_init_mmio(dev, &s->iomem); |
683 | 77831c20 | Juha Riihimäki | return 0; |
684 | 77831c20 | Juha Riihimäki | } |
685 | d82310f7 | cmchao | |
686 | 77831c20 | Juha Riihimäki | static int omap2_gpio_init(SysBusDevice *dev) |
687 | 77831c20 | Juha Riihimäki | { |
688 | 77831c20 | Juha Riihimäki | int i;
|
689 | 77831c20 | Juha Riihimäki | struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, dev); |
690 | 77831c20 | Juha Riihimäki | if (!s->iclk) {
|
691 | 77831c20 | Juha Riihimäki | hw_error("omap2-gpio: iclk not connected\n");
|
692 | 77831c20 | Juha Riihimäki | } |
693 | 77831c20 | Juha Riihimäki | if (s->mpu_model < omap3430) {
|
694 | 77831c20 | Juha Riihimäki | s->modulecount = (s->mpu_model < omap2430) ? 4 : 5; |
695 | 9244b42d | Avi Kivity | memory_region_init_io(&s->iomem, &omap2_gpif_top_ops, s, |
696 | 9244b42d | Avi Kivity | "omap2.gpio", 0x1000); |
697 | 750ecd44 | Avi Kivity | sysbus_init_mmio(dev, &s->iomem); |
698 | 77831c20 | Juha Riihimäki | } else {
|
699 | 77831c20 | Juha Riihimäki | s->modulecount = 6;
|
700 | 77831c20 | Juha Riihimäki | } |
701 | 7267c094 | Anthony Liguori | s->modules = g_malloc0(s->modulecount * sizeof(struct omap2_gpio_s)); |
702 | 7267c094 | Anthony Liguori | s->handler = g_malloc0(s->modulecount * 32 * sizeof(qemu_irq)); |
703 | 77831c20 | Juha Riihimäki | qdev_init_gpio_in(&dev->qdev, omap2_gpio_set, s->modulecount * 32);
|
704 | 77831c20 | Juha Riihimäki | qdev_init_gpio_out(&dev->qdev, s->handler, s->modulecount * 32);
|
705 | 77831c20 | Juha Riihimäki | for (i = 0; i < s->modulecount; i++) { |
706 | 77831c20 | Juha Riihimäki | struct omap2_gpio_s *m = &s->modules[i];
|
707 | 77831c20 | Juha Riihimäki | if (!s->fclk[i]) {
|
708 | 77831c20 | Juha Riihimäki | hw_error("omap2-gpio: fclk%d not connected\n", i);
|
709 | 77831c20 | Juha Riihimäki | } |
710 | 77831c20 | Juha Riihimäki | m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25; |
711 | 77831c20 | Juha Riihimäki | m->handler = &s->handler[i * 32];
|
712 | 77831c20 | Juha Riihimäki | sysbus_init_irq(dev, &m->irq[0]); /* mpu irq */ |
713 | 77831c20 | Juha Riihimäki | sysbus_init_irq(dev, &m->irq[1]); /* dsp irq */ |
714 | 77831c20 | Juha Riihimäki | sysbus_init_irq(dev, &m->wkup); |
715 | 9244b42d | Avi Kivity | memory_region_init_io(&m->iomem, &omap2_gpio_module_ops, m, |
716 | 9244b42d | Avi Kivity | "omap.gpio-module", 0x1000); |
717 | 750ecd44 | Avi Kivity | sysbus_init_mmio(dev, &m->iomem); |
718 | 77831c20 | Juha Riihimäki | } |
719 | 77831c20 | Juha Riihimäki | return 0; |
720 | 77831c20 | Juha Riihimäki | } |
721 | d82310f7 | cmchao | |
722 | 77831c20 | Juha Riihimäki | /* Using qdev pointer properties for the clocks is not ideal.
|
723 | 77831c20 | Juha Riihimäki | * qdev should support a generic means of defining a 'port' with
|
724 | 77831c20 | Juha Riihimäki | * an arbitrary interface for connecting two devices. Then we
|
725 | 77831c20 | Juha Riihimäki | * could reframe the omap clock API in terms of clock ports,
|
726 | 77831c20 | Juha Riihimäki | * and get some type safety. For now the best qdev provides is
|
727 | 77831c20 | Juha Riihimäki | * passing an arbitrary pointer.
|
728 | 77831c20 | Juha Riihimäki | * (It's not possible to pass in the string which is the clock
|
729 | 77831c20 | Juha Riihimäki | * name, because this device does not have the necessary information
|
730 | 77831c20 | Juha Riihimäki | * (ie the struct omap_mpu_state_s*) to do the clockname to pointer
|
731 | 77831c20 | Juha Riihimäki | * translation.)
|
732 | 77831c20 | Juha Riihimäki | */
|
733 | d82310f7 | cmchao | |
734 | 999e12bb | Anthony Liguori | static Property omap_gpio_properties[] = {
|
735 | 999e12bb | Anthony Liguori | DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0), |
736 | 999e12bb | Anthony Liguori | DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk), |
737 | 999e12bb | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
738 | 77831c20 | Juha Riihimäki | }; |
739 | d82310f7 | cmchao | |
740 | 999e12bb | Anthony Liguori | static void omap_gpio_class_init(ObjectClass *klass, void *data) |
741 | 999e12bb | Anthony Liguori | { |
742 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
743 | 999e12bb | Anthony Liguori | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
744 | 999e12bb | Anthony Liguori | |
745 | 999e12bb | Anthony Liguori | k->init = omap_gpio_init; |
746 | 39bffca2 | Anthony Liguori | dc->reset = omap_gpif_reset; |
747 | 39bffca2 | Anthony Liguori | dc->props = omap_gpio_properties; |
748 | 999e12bb | Anthony Liguori | } |
749 | 999e12bb | Anthony Liguori | |
750 | 39bffca2 | Anthony Liguori | static TypeInfo omap_gpio_info = {
|
751 | 39bffca2 | Anthony Liguori | .name = "omap-gpio",
|
752 | 39bffca2 | Anthony Liguori | .parent = TYPE_SYS_BUS_DEVICE, |
753 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(struct omap_gpif_s), |
754 | 39bffca2 | Anthony Liguori | .class_init = omap_gpio_class_init, |
755 | 999e12bb | Anthony Liguori | }; |
756 | 999e12bb | Anthony Liguori | |
757 | 999e12bb | Anthony Liguori | static Property omap2_gpio_properties[] = {
|
758 | 999e12bb | Anthony Liguori | DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0), |
759 | 999e12bb | Anthony Liguori | DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk), |
760 | 999e12bb | Anthony Liguori | DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]), |
761 | 999e12bb | Anthony Liguori | DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]), |
762 | 999e12bb | Anthony Liguori | DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]), |
763 | 999e12bb | Anthony Liguori | DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]), |
764 | 999e12bb | Anthony Liguori | DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]), |
765 | 999e12bb | Anthony Liguori | DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]), |
766 | 999e12bb | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
767 | 999e12bb | Anthony Liguori | }; |
768 | 999e12bb | Anthony Liguori | |
769 | 999e12bb | Anthony Liguori | static void omap2_gpio_class_init(ObjectClass *klass, void *data) |
770 | 999e12bb | Anthony Liguori | { |
771 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
772 | 999e12bb | Anthony Liguori | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
773 | 999e12bb | Anthony Liguori | |
774 | 999e12bb | Anthony Liguori | k->init = omap2_gpio_init; |
775 | 39bffca2 | Anthony Liguori | dc->reset = omap2_gpif_reset; |
776 | 39bffca2 | Anthony Liguori | dc->props = omap2_gpio_properties; |
777 | 999e12bb | Anthony Liguori | } |
778 | 999e12bb | Anthony Liguori | |
779 | 39bffca2 | Anthony Liguori | static TypeInfo omap2_gpio_info = {
|
780 | 39bffca2 | Anthony Liguori | .name = "omap2-gpio",
|
781 | 39bffca2 | Anthony Liguori | .parent = TYPE_SYS_BUS_DEVICE, |
782 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(struct omap2_gpif_s), |
783 | 39bffca2 | Anthony Liguori | .class_init = omap2_gpio_class_init, |
784 | 77831c20 | Juha Riihimäki | }; |
785 | d82310f7 | cmchao | |
786 | 83f7d43a | Andreas Färber | static void omap_gpio_register_types(void) |
787 | d82310f7 | cmchao | { |
788 | 39bffca2 | Anthony Liguori | type_register_static(&omap_gpio_info); |
789 | 39bffca2 | Anthony Liguori | type_register_static(&omap2_gpio_info); |
790 | d82310f7 | cmchao | } |
791 | d82310f7 | cmchao | |
792 | 83f7d43a | Andreas Färber | type_init(omap_gpio_register_types) |