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