Statistics
| Branch: | Revision:

root / hw / omap_gpio.c @ ff753bb9

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