[MISC] Updated maintainer
[qemu/mini2440.git] / hw / s3c24xx_gpio.c
blobba88cdf04497887211f2e83f4b6863bf9e9e68d7
1 /*
2 * Samsung S3C24xx series I/O ports.
4 * Copyright (c) 2007 OpenMoko, Inc.
5 * Author: Andrzej Zaborowski <andrew@openedhand.com>
6 * With: Michel Pollet <buserror@gmail.com>
8 * This code is licenced under the GNU GPL v2.
9 */
11 #include "s3c.h"
12 #include "hw.h"
14 /* S3C2410 : A B C D E F G H = 8
15 * S3C2440 : J = 1 */
16 #define S3C_IO_BANKS 8
18 struct s3c_gpio_state_s { /* Modelled as an interrupt controller */
19 uint32_t cpu_id;
20 target_phys_addr_t base;
21 qemu_irq *pic;
22 qemu_irq *in;
24 struct {
25 int n;
26 uint32_t con;
27 uint32_t dat;
28 uint32_t up;
29 uint32_t mask;
30 qemu_irq handler[32];
31 } bank[S3C_IO_BANKS];
33 uint32_t inform[2];
34 uint32_t pwrstat;
35 uint32_t misccr;
36 uint32_t dclkcon;
37 uint32_t extint[3];
38 uint32_t eintflt[2];
39 uint32_t eintmask;
40 uint32_t eintpend;
43 static inline void s3c_gpio_extint(struct s3c_gpio_state_s *s, int irq)
45 if (s->eintmask & (1 << irq))
46 return;
47 s->eintpend |= (1 << irq) & 0x00fffff0;
48 switch (irq) {
49 case 0 ... 3:
50 qemu_irq_raise(s->pic[S3C_PIC_EINT0 + irq]);
51 break;
52 case 4 ... 7:
53 qemu_irq_raise(s->pic[S3C_PIC_EINT4]);
54 break;
55 case 8 ... 23:
56 qemu_irq_raise(s->pic[S3C_PIC_EINT8]);
57 break;
61 static void s3c_gpio_set(void *opaque, int line, int level)
63 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
64 int e, eint, bank = line >> 5;
65 line &= 0x1f;
66 /* Input ports */
67 if (bank > 0 && ((s->bank[bank].con >> (2 * line)) & 3) == 0) {
68 if (level)
69 s->bank[bank].dat |= 1 << line;
70 else
71 s->bank[bank].dat &= ~(1 << line);
72 return;
74 /* External interrupts */
75 if (((s->bank[bank].con >> (2 * line)) & 3) == 2) {
76 switch (bank) {
77 case 5: /* GPF */
78 eint = line;
79 e = 0;
80 break;
81 case 6: /* GPG */
82 eint = line + 8;
83 e = (line > 15) ? 2 : 1;
84 break;
85 default:
86 return;
88 if (level) {
89 if (!((s->bank[bank].dat >> line) & 1))
90 switch ((s->extint[e] >> (line * 4)) & 7) {
91 case 1:
92 case 4 ... 7:
93 s3c_gpio_extint(s, eint);
94 break;
96 s->bank[bank].dat |= 1 << line;
97 } else {
98 if ((s->bank[bank].dat >> line) & 1)
99 switch ((s->extint[e] >> (line * 4)) & 7) {
100 case 1:
101 case 4 ... 5:
102 break;
103 default:
104 s3c_gpio_extint(s, eint);
106 s->bank[bank].dat &= ~(1 << line);
108 return;
112 qemu_irq *s3c_gpio_in_get(struct s3c_gpio_state_s *s)
114 return s->in;
117 void s3c_gpio_out_set(struct s3c_gpio_state_s *s, int line, qemu_irq handler)
119 int bank = line >> 5;
120 line &= 0x1f;
121 if (bank >= S3C_IO_BANKS || line >= s->bank[bank].n)
122 cpu_abort(cpu_single_env, "%s: No I/O port %i\n", __FUNCTION__, line);
123 s->bank[bank].handler[line] = handler;
126 void s3c_gpio_reset(struct s3c_gpio_state_s *s)
128 int i;
129 s->inform[0] = 0;
130 s->inform[1] = 0;
131 s->misccr = 0x00010330 & ~(1 << 16);
132 s->dclkcon = 0x00000000;
133 s->extint[0] = 0;
134 s->extint[1] = 0;
135 s->extint[2] = 0;
136 s->eintflt[0] = 0;
137 s->eintflt[1] = 0;
138 s->eintmask = 0x00fffff0;
139 s->eintpend = 0x00000000;
141 for (i = 0; i < S3C_IO_BANKS; i ++) {
142 s->bank[i].mask = (1 << s->bank[i].n) - 1;
143 s->bank[i].con = 0;
144 s->bank[i].dat = 0;
145 s->bank[i].up = 0;
147 s->bank[0].con = 0x07ffffff;
148 s->bank[3].up = 0x0000f000;
149 s->bank[6].up = 0x0000f800;
152 void s3c_gpio_setpwrstat(struct s3c_gpio_state_s *s, int stat)
154 s->pwrstat = stat;
157 #define S3C_GPCON 0x00 /* Configuration register */
158 #define S3C_GPDAT 0x04 /* Data register */
159 #define S3C_GPUP 0x08 /* Pull-up register */
160 #define S3C_MISCCR 0x80 /* Miscellaneous Control register */
161 #define S3C_DCLKCON 0x84 /* DCLK0/1 Control register */
162 #define S3C_EXTINT0 0x88 /* External Interrupt Control register 0 */
163 #define S3C_EXTINT1 0x8c /* External Interrupt Control register 1 */
164 #define S3C_EXTINT2 0x90 /* External Interrupt Control register 2 */
165 #define S3C_EINTFLT0 0x94 /* External Interrupt Filter register 0 */
166 #define S3C_EINTFLT1 0x98 /* External Interrupt Filter register 1 */
167 #define S3C_EINTFLT2 0x9c /* External Interrupt Filter register 2 */
168 #define S3C_EINTFLT3 0xa0 /* External Interrupt Filter register 3 */
169 #define S3C_EINTMASK 0xa4 /* External Interrupt Mask register */
170 #define S3C_EINTPEND 0xa8 /* External Interrupt Pending register */
171 #define S3C_GSTATUS0 0xac /* External Pin Status register */
172 #define S3C_GSTATUS1 0xb0 /* Chip ID register */
173 #define S3C_GSTATUS2 0xb4 /* Reset Status register */
174 #define S3C_GSTATUS3 0xb8 /* Inform register */
175 #define S3C_GSTATUS4 0xbc /* Inform register */
177 static uint32_t s3c_gpio_read(void *opaque, target_phys_addr_t addr)
179 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
180 int bank = 0;
181 if ((addr >> 4) < S3C_IO_BANKS) {
182 bank = addr >> 4;
183 addr &= 0xf;
186 switch (addr) {
187 case S3C_GSTATUS0:
188 return 0x0;
189 case S3C_GSTATUS1:
190 return s->cpu_id;
191 case S3C_GSTATUS2:
192 return s->pwrstat;
193 case S3C_GSTATUS3:
194 return s->inform[0];
195 case S3C_GSTATUS4:
196 return s->inform[1];
197 case S3C_MISCCR:
198 return s->misccr;
199 case S3C_DCLKCON:
200 return s->dclkcon;
201 case S3C_EXTINT0:
202 return s->extint[0];
203 case S3C_EXTINT1:
204 return s->extint[1];
205 case S3C_EXTINT2:
206 return s->extint[2];
207 case S3C_EINTFLT2:
208 return s->eintflt[0];
209 case S3C_EINTFLT3:
210 return s->eintflt[1];
211 case S3C_EINTMASK:
212 return s->eintmask;
213 case S3C_EINTPEND:
214 return s->eintpend;
215 /* Per bank registers */
216 case S3C_GPCON:
217 return s->bank[bank].con;
218 case S3C_GPDAT:
219 return s->bank[bank].dat;
220 case S3C_GPUP:
221 return s->bank[bank].up;
222 default:
223 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
224 break;
226 return 0;
229 static void s3c_gpio_write(void *opaque, target_phys_addr_t addr,
230 uint32_t value)
232 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
233 uint32_t diff;
234 int ln, bank = 0;
235 if ((addr >> 4) < S3C_IO_BANKS) {
236 bank = addr >> 4;
237 addr &= 0xf;
240 switch (addr) {
241 case S3C_GSTATUS2:
242 s->pwrstat &= 7 & ~value;
243 break;
244 case S3C_GSTATUS3:
245 s->inform[0] = value;
246 break;
247 case S3C_GSTATUS4:
248 s->inform[1] = value;
249 break;
250 case S3C_MISCCR:
251 if (value & (1 << 16)) /* nRSTCON */
252 printf("%s: software reset.\n", __FUNCTION__);
253 if ((value ^ s->misccr) & (1 << 3)) /* USBPAD */
254 printf("%s: now in USB %s mode.\n", __FUNCTION__,
255 (value >> 3) & 1 ? "host" : "slave");
256 s->misccr = value & 0x000f377b;
257 break;
258 case S3C_DCLKCON:
259 s->dclkcon = value & 0x0ff30ff3;
260 break;
261 case S3C_EXTINT0:
262 s->extint[0] = value;
263 break;
264 case S3C_EXTINT1:
265 s->extint[1] = value;
266 break;
267 case S3C_EXTINT2:
268 s->extint[2] = value;
269 break;
270 case S3C_EINTFLT2:
271 s->eintflt[0] = value;
272 break;
273 case S3C_EINTFLT3:
274 s->eintflt[1] = value;
275 break;
276 case S3C_EINTMASK:
277 s->eintmask = value & 0x00fffff0;
278 break;
279 case S3C_EINTPEND:
280 s->eintpend &= ~value;
281 break;
282 /* Per bank registers */
283 case S3C_GPCON:
284 s->bank[bank].con = value;
285 break;
286 case S3C_GPDAT:
287 diff = (s->bank[bank].dat ^ value) & s->bank[bank].mask;
288 s->bank[bank].dat = value;
289 while ((ln = ffs(diff))) {
290 ln --;
291 if (s->bank[bank].handler[ln]) {
292 if (bank && ((s->bank[bank].con >> (2 * ln)) & 3) == 1)
293 qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
294 else if (!bank && ((s->bank[bank].con >> ln) & 1) == 0)
295 qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
297 diff &= ~(1 << ln);
299 break;
300 case S3C_GPUP:
301 s->bank[bank].up = value;
302 break;
303 default:
304 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
308 static CPUReadMemoryFunc *s3c_gpio_readfn[] = {
309 s3c_gpio_read,
310 s3c_gpio_read,
311 s3c_gpio_read,
314 static CPUWriteMemoryFunc *s3c_gpio_writefn[] = {
315 s3c_gpio_write,
316 s3c_gpio_write,
317 s3c_gpio_write,
320 static void s3c_gpio_save(QEMUFile *f, void *opaque)
322 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
323 int i;
324 for (i = 0; i < S3C_IO_BANKS; i ++) {
325 qemu_put_be32s(f, &s->bank[i].con);
326 qemu_put_be32s(f, &s->bank[i].dat);
327 qemu_put_be32s(f, &s->bank[i].up);
328 qemu_put_be32s(f, &s->bank[i].mask);
331 qemu_put_be32s(f, &s->inform[0]);
332 qemu_put_be32s(f, &s->inform[1]);
333 qemu_put_be32s(f, &s->pwrstat);
334 qemu_put_be32s(f, &s->misccr);
335 qemu_put_be32s(f, &s->dclkcon);
336 qemu_put_be32s(f, &s->extint[0]);
337 qemu_put_be32s(f, &s->extint[1]);
338 qemu_put_be32s(f, &s->extint[2]);
339 qemu_put_be32s(f, &s->eintflt[0]);
340 qemu_put_be32s(f, &s->eintflt[1]);
341 qemu_put_be32s(f, &s->eintmask);
342 qemu_put_be32s(f, &s->eintpend);
345 static int s3c_gpio_load(QEMUFile *f, void *opaque, int version_id)
347 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
348 int i;
349 for (i = 0; i < S3C_IO_BANKS; i ++) {
350 qemu_get_be32s(f, &s->bank[i].con);
351 qemu_get_be32s(f, &s->bank[i].dat);
352 qemu_get_be32s(f, &s->bank[i].up);
353 qemu_get_be32s(f, &s->bank[i].mask);
356 qemu_get_be32s(f, &s->inform[0]);
357 qemu_get_be32s(f, &s->inform[1]);
358 qemu_get_be32s(f, &s->pwrstat);
359 qemu_get_be32s(f, &s->misccr);
360 qemu_get_be32s(f, &s->dclkcon);
361 qemu_get_be32s(f, &s->extint[0]);
362 qemu_get_be32s(f, &s->extint[1]);
363 qemu_get_be32s(f, &s->extint[2]);
364 qemu_get_be32s(f, &s->eintflt[0]);
365 qemu_get_be32s(f, &s->eintflt[1]);
366 qemu_get_be32s(f, &s->eintmask);
367 qemu_get_be32s(f, &s->eintpend);
369 return 0;
372 struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, qemu_irq *pic, uint32_t cpu_id)
374 int iomemtype;
375 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *)
376 qemu_mallocz(sizeof(struct s3c_gpio_state_s));
378 s->cpu_id = cpu_id;
379 s->base = base;
380 s->pic = pic;
381 s->in = qemu_allocate_irqs(s3c_gpio_set, s, S3C_GP_MAX);
383 s->bank[0].n = 23;
384 s->bank[1].n = 11;
385 s->bank[2].n = 16;
386 s->bank[3].n = 16;
387 s->bank[4].n = 16;
388 s->bank[5].n = 8;
389 s->bank[6].n = 16;
390 s->bank[7].n = 11;
392 s3c_gpio_reset(s);
394 iomemtype = cpu_register_io_memory(0, s3c_gpio_readfn,
395 s3c_gpio_writefn, s);
396 cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
398 register_savevm("s3c24xx_io", 0, 0, s3c_gpio_save, s3c_gpio_load, s);
400 return s;