MINI2440: General update
[qemu/mini2440.git] / hw / s3c24xx_gpio.c
blob3ac41aa797211339bd0a9c8f44abdbdf2cc8cf0c
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_set_dat(struct s3c_gpio_state_s *s, int gpio, int level)
128 int bank = gpio >> 5, bit = gpio & 0x1f;
129 s->bank[bank].dat = (s->bank[bank].dat & ~(1 << bit)) | (level ? (1 << bit) : 0);
132 void s3c_gpio_reset(struct s3c_gpio_state_s *s)
134 int i;
135 s->inform[0] = 0;
136 s->inform[1] = 0;
137 s->misccr = 0x00010330 & ~(1 << 16);
138 s->dclkcon = 0x00000000;
139 s->extint[0] = 0;
140 s->extint[1] = 0;
141 s->extint[2] = 0;
142 s->eintflt[0] = 0;
143 s->eintflt[1] = 0;
144 s->eintmask = 0x00fffff0;
145 s->eintpend = 0x00000000;
147 for (i = 0; i < S3C_IO_BANKS; i ++) {
148 s->bank[i].mask = (1 << s->bank[i].n) - 1;
149 s->bank[i].con = 0;
150 s->bank[i].dat = 0;
151 s->bank[i].up = 0;
153 s->bank[0].con = 0x07ffffff;
154 s->bank[3].up = 0x0000f000;
155 s->bank[6].up = 0x0000f800;
158 void s3c_gpio_setpwrstat(struct s3c_gpio_state_s *s, int stat)
160 s->pwrstat = stat;
163 #define S3C_GPCON 0x00 /* Configuration register */
164 #define S3C_GPDAT 0x04 /* Data register */
165 #define S3C_GPUP 0x08 /* Pull-up register */
166 #define S3C_MISCCR 0x80 /* Miscellaneous Control register */
167 #define S3C_DCLKCON 0x84 /* DCLK0/1 Control register */
168 #define S3C_EXTINT0 0x88 /* External Interrupt Control register 0 */
169 #define S3C_EXTINT1 0x8c /* External Interrupt Control register 1 */
170 #define S3C_EXTINT2 0x90 /* External Interrupt Control register 2 */
171 #define S3C_EINTFLT0 0x94 /* External Interrupt Filter register 0 */
172 #define S3C_EINTFLT1 0x98 /* External Interrupt Filter register 1 */
173 #define S3C_EINTFLT2 0x9c /* External Interrupt Filter register 2 */
174 #define S3C_EINTFLT3 0xa0 /* External Interrupt Filter register 3 */
175 #define S3C_EINTMASK 0xa4 /* External Interrupt Mask register */
176 #define S3C_EINTPEND 0xa8 /* External Interrupt Pending register */
177 #define S3C_GSTATUS0 0xac /* External Pin Status register */
178 #define S3C_GSTATUS1 0xb0 /* Chip ID register */
179 #define S3C_GSTATUS2 0xb4 /* Reset Status register */
180 #define S3C_GSTATUS3 0xb8 /* Inform register */
181 #define S3C_GSTATUS4 0xbc /* Inform register */
183 static uint32_t s3c_gpio_read(void *opaque, target_phys_addr_t addr)
185 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
186 int bank = 0;
187 if ((addr >> 4) < S3C_IO_BANKS) {
188 bank = addr >> 4;
189 addr &= 0xf;
192 switch (addr) {
193 case S3C_GSTATUS0:
194 return 0x0;
195 case S3C_GSTATUS1:
196 return s->cpu_id;
197 case S3C_GSTATUS2:
198 return s->pwrstat;
199 case S3C_GSTATUS3:
200 return s->inform[0];
201 case S3C_GSTATUS4:
202 return s->inform[1];
203 case S3C_MISCCR:
204 return s->misccr;
205 case S3C_DCLKCON:
206 return s->dclkcon;
207 case S3C_EXTINT0:
208 return s->extint[0];
209 case S3C_EXTINT1:
210 return s->extint[1];
211 case S3C_EXTINT2:
212 return s->extint[2];
213 case S3C_EINTFLT2:
214 return s->eintflt[0];
215 case S3C_EINTFLT3:
216 return s->eintflt[1];
217 case S3C_EINTMASK:
218 return s->eintmask;
219 case S3C_EINTPEND:
220 return s->eintpend;
221 /* Per bank registers */
222 case S3C_GPCON:
223 return s->bank[bank].con;
224 case S3C_GPDAT:
225 /* printf("%s: read port '%c' = %08x\n", __FUNCTION__, 'A' + bank, s->bank[bank].dat); */
226 return s->bank[bank].dat;
227 case S3C_GPUP:
228 return s->bank[bank].up;
229 default:
230 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
231 break;
233 return 0;
236 static void s3c_gpio_write(void *opaque, target_phys_addr_t addr,
237 uint32_t value)
239 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
240 uint32_t diff;
241 int ln, bank = 0;
242 if ((addr >> 4) < S3C_IO_BANKS) {
243 bank = addr >> 4;
244 addr &= 0xf;
247 switch (addr) {
248 case S3C_GSTATUS2:
249 s->pwrstat &= 7 & ~value;
250 break;
251 case S3C_GSTATUS3:
252 s->inform[0] = value;
253 break;
254 case S3C_GSTATUS4:
255 s->inform[1] = value;
256 break;
257 case S3C_MISCCR:
258 if (value & (1 << 16)) /* nRSTCON */
259 printf("%s: software reset.\n", __FUNCTION__);
260 if ((value ^ s->misccr) & (1 << 3)) /* USBPAD */
261 printf("%s: now in USB %s mode.\n", __FUNCTION__,
262 (value >> 3) & 1 ? "host" : "slave");
263 s->misccr = value & 0x000f377b;
264 break;
265 case S3C_DCLKCON:
266 s->dclkcon = value & 0x0ff30ff3;
267 break;
268 case S3C_EXTINT0:
269 s->extint[0] = value;
270 break;
271 case S3C_EXTINT1:
272 s->extint[1] = value;
273 break;
274 case S3C_EXTINT2:
275 s->extint[2] = value;
276 break;
277 case S3C_EINTFLT2:
278 s->eintflt[0] = value;
279 break;
280 case S3C_EINTFLT3:
281 s->eintflt[1] = value;
282 break;
283 case S3C_EINTMASK:
284 s->eintmask = value & 0x00fffff0;
285 break;
286 case S3C_EINTPEND:
287 s->eintpend &= ~value;
288 break;
289 /* Per bank registers */
290 case S3C_GPCON:
291 s->bank[bank].con = value;
292 break;
293 case S3C_GPDAT:
294 diff = (s->bank[bank].dat ^ value) & s->bank[bank].mask;
295 s->bank[bank].dat = value;
296 /* printf("%s: write port '%c' = %08x\n", __FUNCTION__, 'A' + bank, s->bank[bank].dat); */
297 while ((ln = ffs(diff))) {
298 ln --;
299 if (s->bank[bank].handler[ln]) {
300 if (bank && ((s->bank[bank].con >> (2 * ln)) & 3) == 1)
301 qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
302 else if (!bank && ((s->bank[bank].con >> ln) & 1) == 0)
303 qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
305 diff &= ~(1 << ln);
307 break;
308 case S3C_GPUP:
309 s->bank[bank].up = value;
310 break;
311 default:
312 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
316 static CPUReadMemoryFunc *s3c_gpio_readfn[] = {
317 s3c_gpio_read,
318 s3c_gpio_read,
319 s3c_gpio_read,
322 static CPUWriteMemoryFunc *s3c_gpio_writefn[] = {
323 s3c_gpio_write,
324 s3c_gpio_write,
325 s3c_gpio_write,
328 static void s3c_gpio_save(QEMUFile *f, void *opaque)
330 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
331 int i;
332 for (i = 0; i < S3C_IO_BANKS; i ++) {
333 qemu_put_be32s(f, &s->bank[i].con);
334 qemu_put_be32s(f, &s->bank[i].dat);
335 qemu_put_be32s(f, &s->bank[i].up);
336 qemu_put_be32s(f, &s->bank[i].mask);
339 qemu_put_be32s(f, &s->inform[0]);
340 qemu_put_be32s(f, &s->inform[1]);
341 qemu_put_be32s(f, &s->pwrstat);
342 qemu_put_be32s(f, &s->misccr);
343 qemu_put_be32s(f, &s->dclkcon);
344 qemu_put_be32s(f, &s->extint[0]);
345 qemu_put_be32s(f, &s->extint[1]);
346 qemu_put_be32s(f, &s->extint[2]);
347 qemu_put_be32s(f, &s->eintflt[0]);
348 qemu_put_be32s(f, &s->eintflt[1]);
349 qemu_put_be32s(f, &s->eintmask);
350 qemu_put_be32s(f, &s->eintpend);
353 static int s3c_gpio_load(QEMUFile *f, void *opaque, int version_id)
355 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
356 int i;
357 for (i = 0; i < S3C_IO_BANKS; i ++) {
358 qemu_get_be32s(f, &s->bank[i].con);
359 qemu_get_be32s(f, &s->bank[i].dat);
360 qemu_get_be32s(f, &s->bank[i].up);
361 qemu_get_be32s(f, &s->bank[i].mask);
364 qemu_get_be32s(f, &s->inform[0]);
365 qemu_get_be32s(f, &s->inform[1]);
366 qemu_get_be32s(f, &s->pwrstat);
367 qemu_get_be32s(f, &s->misccr);
368 qemu_get_be32s(f, &s->dclkcon);
369 qemu_get_be32s(f, &s->extint[0]);
370 qemu_get_be32s(f, &s->extint[1]);
371 qemu_get_be32s(f, &s->extint[2]);
372 qemu_get_be32s(f, &s->eintflt[0]);
373 qemu_get_be32s(f, &s->eintflt[1]);
374 qemu_get_be32s(f, &s->eintmask);
375 qemu_get_be32s(f, &s->eintpend);
377 return 0;
380 struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, qemu_irq *pic, uint32_t cpu_id)
382 int iomemtype;
383 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *)
384 qemu_mallocz(sizeof(struct s3c_gpio_state_s));
386 s->cpu_id = cpu_id;
387 s->base = base;
388 s->pic = pic;
389 s->in = qemu_allocate_irqs(s3c_gpio_set, s, S3C_GP_MAX);
391 s->bank[0].n = 23;
392 s->bank[1].n = 11;
393 s->bank[2].n = 16;
394 s->bank[3].n = 16;
395 s->bank[4].n = 16;
396 s->bank[5].n = 8;
397 s->bank[6].n = 16;
398 s->bank[7].n = 11;
400 s3c_gpio_reset(s);
402 iomemtype = cpu_register_io_memory(0, s3c_gpio_readfn,
403 s3c_gpio_writefn, s);
404 cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
406 register_savevm("s3c24xx_io", 0, 0, s3c_gpio_save, s3c_gpio_load, s);
408 return s;