[S3C/DM9000] Removed base addresses substractions
[qemu/mini2440.git] / hw / s3c24xx_gpio.c
blob33337c8f59a5b184f6ced5709a26c4e539221c1a
1 /*
2 * Samsung S3C24xx series I/O ports.
4 * Copyright (c) 2007 OpenMoko, Inc.
5 * Author: Andrzej Zaborowski <andrew@openedhand.com>
7 * This code is licenced under the GNU GPL v2.
8 */
10 #include "s3c.h"
11 #include "hw.h"
13 #define S3C_IO_BANKS 8
15 struct s3c_gpio_state_s { /* Modelled as an interrupt controller */
16 uint32_t cpu_id;
17 target_phys_addr_t base;
18 qemu_irq *pic;
19 qemu_irq *in;
21 struct {
22 int n;
23 uint32_t con;
24 uint32_t dat;
25 uint32_t up;
26 uint32_t mask;
27 qemu_irq handler[32];
28 } bank[S3C_IO_BANKS];
30 uint32_t inform[2];
31 uint32_t pwrstat;
32 uint32_t misccr;
33 uint32_t dclkcon;
34 uint32_t extint[3];
35 uint32_t eintflt[2];
36 uint32_t eintmask;
37 uint32_t eintpend;
40 static inline void s3c_gpio_extint(struct s3c_gpio_state_s *s, int irq)
42 if (s->eintmask & (1 << irq))
43 return;
44 s->eintpend |= (1 << irq) & 0x00fffff0;
45 switch (irq) {
46 case 0 ... 3:
47 qemu_irq_raise(s->pic[S3C_PIC_EINT0 + irq]);
48 break;
49 case 4 ... 7:
50 qemu_irq_raise(s->pic[S3C_PIC_EINT4]);
51 break;
52 case 8 ... 23:
53 qemu_irq_raise(s->pic[S3C_PIC_EINT8]);
54 break;
58 static void s3c_gpio_set(void *opaque, int line, int level)
60 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
61 int e, eint, bank = line >> 5;
62 line &= 0x1f;
63 /* Input ports */
64 if (bank > 0 && ((s->bank[bank].con >> (2 * line)) & 3) == 0) {
65 if (level)
66 s->bank[bank].dat |= 1 << line;
67 else
68 s->bank[bank].dat &= ~(1 << line);
69 return;
71 /* External interrupts */
72 if (((s->bank[bank].con >> (2 * line)) & 3) == 2) {
73 switch (bank) {
74 case 5: /* GPF */
75 eint = line;
76 e = 0;
77 break;
78 case 6: /* GPG */
79 eint = line + 8;
80 e = (line > 15) ? 2 : 1;
81 break;
82 default:
83 return;
85 if (level) {
86 if (!((s->bank[bank].dat >> line) & 1))
87 switch ((s->extint[e] >> (line * 4)) & 7) {
88 case 1:
89 case 4 ... 7:
90 s3c_gpio_extint(s, eint);
91 break;
93 s->bank[bank].dat |= 1 << line;
94 } else {
95 if ((s->bank[bank].dat >> line) & 1)
96 switch ((s->extint[e] >> (line * 4)) & 7) {
97 case 1:
98 case 4 ... 5:
99 break;
100 default:
101 s3c_gpio_extint(s, eint);
103 s->bank[bank].dat &= ~(1 << line);
105 return;
109 qemu_irq *s3c_gpio_in_get(struct s3c_gpio_state_s *s)
111 return s->in;
114 void s3c_gpio_out_set(struct s3c_gpio_state_s *s, int line, qemu_irq handler)
116 int bank = line >> 5;
117 line &= 0x1f;
118 if (bank >= S3C_IO_BANKS || line >= s->bank[bank].n)
119 cpu_abort(cpu_single_env, "%s: No I/O port %i\n", __FUNCTION__, line);
120 s->bank[bank].handler[line] = handler;
123 void s3c_gpio_reset(struct s3c_gpio_state_s *s)
125 int i;
126 s->inform[0] = 0;
127 s->inform[1] = 0;
128 s->misccr = 0x00010330 & ~(1 << 16);
129 s->dclkcon = 0x00000000;
130 s->extint[0] = 0;
131 s->extint[1] = 0;
132 s->extint[2] = 0;
133 s->eintflt[0] = 0;
134 s->eintflt[1] = 0;
135 s->eintmask = 0x00fffff0;
136 s->eintpend = 0x00000000;
138 for (i = 0; i < S3C_IO_BANKS; i ++) {
139 s->bank[i].mask = (1 << s->bank[i].n) - 1;
140 s->bank[i].con = 0;
141 s->bank[i].dat = 0;
142 s->bank[i].up = 0;
144 s->bank[0].con = 0x07ffffff;
145 s->bank[3].up = 0x0000f000;
146 s->bank[6].up = 0x0000f800;
149 void s3c_gpio_setpwrstat(struct s3c_gpio_state_s *s, int stat)
151 s->pwrstat = stat;
154 #define S3C_GPCON 0x00 /* Configuration register */
155 #define S3C_GPDAT 0x04 /* Data register */
156 #define S3C_GPUP 0x08 /* Pull-up register */
157 #define S3C_MISCCR 0x80 /* Miscellaneous Control register */
158 #define S3C_DCLKCON 0x84 /* DCLK0/1 Control register */
159 #define S3C_EXTINT0 0x88 /* External Interrupt Control register 0 */
160 #define S3C_EXTINT1 0x8c /* External Interrupt Control register 1 */
161 #define S3C_EXTINT2 0x90 /* External Interrupt Control register 2 */
162 #define S3C_EINTFLT0 0x94 /* External Interrupt Filter register 0 */
163 #define S3C_EINTFLT1 0x98 /* External Interrupt Filter register 1 */
164 #define S3C_EINTFLT2 0x9c /* External Interrupt Filter register 2 */
165 #define S3C_EINTFLT3 0xa0 /* External Interrupt Filter register 3 */
166 #define S3C_EINTMASK 0xa4 /* External Interrupt Mask register */
167 #define S3C_EINTPEND 0xa8 /* External Interrupt Pending register */
168 #define S3C_GSTATUS0 0xac /* External Pin Status register */
169 #define S3C_GSTATUS1 0xb0 /* Chip ID register */
170 #define S3C_GSTATUS2 0xb4 /* Reset Status register */
171 #define S3C_GSTATUS3 0xb8 /* Inform register */
172 #define S3C_GSTATUS4 0xbc /* Inform register */
174 static uint32_t s3c_gpio_read(void *opaque, target_phys_addr_t addr)
176 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
177 int bank = 0;
178 if ((addr >> 4) < S3C_IO_BANKS) {
179 bank = addr >> 4;
180 addr &= 0xf;
183 switch (addr) {
184 case S3C_GSTATUS0:
185 return 0x0;
186 case S3C_GSTATUS1:
187 return s->cpu_id;
188 case S3C_GSTATUS2:
189 return s->pwrstat;
190 case S3C_GSTATUS3:
191 return s->inform[0];
192 case S3C_GSTATUS4:
193 return s->inform[1];
194 case S3C_MISCCR:
195 return s->misccr;
196 case S3C_DCLKCON:
197 return s->dclkcon;
198 case S3C_EXTINT0:
199 return s->extint[0];
200 case S3C_EXTINT1:
201 return s->extint[1];
202 case S3C_EXTINT2:
203 return s->extint[2];
204 case S3C_EINTFLT2:
205 return s->eintflt[0];
206 case S3C_EINTFLT3:
207 return s->eintflt[1];
208 case S3C_EINTMASK:
209 return s->eintmask;
210 case S3C_EINTPEND:
211 return s->eintpend;
212 /* Per bank registers */
213 case S3C_GPCON:
214 return s->bank[bank].con;
215 case S3C_GPDAT:
216 return s->bank[bank].dat;
217 case S3C_GPUP:
218 return s->bank[bank].up;
219 default:
220 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
221 break;
223 return 0;
226 static void s3c_gpio_write(void *opaque, target_phys_addr_t addr,
227 uint32_t value)
229 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
230 uint32_t diff;
231 int ln, bank = 0;
232 if ((addr >> 4) < S3C_IO_BANKS) {
233 bank = addr >> 4;
234 addr &= 0xf;
237 switch (addr) {
238 case S3C_GSTATUS2:
239 s->pwrstat &= 7 & ~value;
240 break;
241 case S3C_GSTATUS3:
242 s->inform[0] = value;
243 break;
244 case S3C_GSTATUS4:
245 s->inform[1] = value;
246 break;
247 case S3C_MISCCR:
248 if (value & (1 << 16)) /* nRSTCON */
249 printf("%s: software reset.\n", __FUNCTION__);
250 if ((value ^ s->misccr) & (1 << 3)) /* USBPAD */
251 printf("%s: now in USB %s mode.\n", __FUNCTION__,
252 (value >> 3) & 1 ? "host" : "slave");
253 s->misccr = value & 0x000f377b;
254 break;
255 case S3C_DCLKCON:
256 s->dclkcon = value & 0x0ff30ff3;
257 break;
258 case S3C_EXTINT0:
259 s->extint[0] = value;
260 break;
261 case S3C_EXTINT1:
262 s->extint[1] = value;
263 break;
264 case S3C_EXTINT2:
265 s->extint[2] = value;
266 break;
267 case S3C_EINTFLT2:
268 s->eintflt[0] = value;
269 break;
270 case S3C_EINTFLT3:
271 s->eintflt[1] = value;
272 break;
273 case S3C_EINTMASK:
274 s->eintmask = value & 0x00fffff0;
275 break;
276 case S3C_EINTPEND:
277 s->eintpend &= ~value;
278 break;
279 /* Per bank registers */
280 case S3C_GPCON:
281 s->bank[bank].con = value;
282 break;
283 case S3C_GPDAT:
284 diff = (s->bank[bank].dat ^ value) & s->bank[bank].mask;
285 s->bank[bank].dat = value;
286 while ((ln = ffs(diff))) {
287 ln --;
288 if (s->bank[bank].handler[ln]) {
289 if (bank && ((s->bank[bank].con >> (2 * ln)) & 3) == 1)
290 qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
291 else if (!bank && ((s->bank[bank].con >> ln) & 1) == 0)
292 qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
294 diff &= ~(1 << ln);
296 break;
297 case S3C_GPUP:
298 s->bank[bank].up = value;
299 break;
300 default:
301 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
305 static CPUReadMemoryFunc *s3c_gpio_readfn[] = {
306 s3c_gpio_read,
307 s3c_gpio_read,
308 s3c_gpio_read,
311 static CPUWriteMemoryFunc *s3c_gpio_writefn[] = {
312 s3c_gpio_write,
313 s3c_gpio_write,
314 s3c_gpio_write,
317 static void s3c_gpio_save(QEMUFile *f, void *opaque)
319 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
320 int i;
321 for (i = 0; i < S3C_IO_BANKS; i ++) {
322 qemu_put_be32s(f, &s->bank[i].con);
323 qemu_put_be32s(f, &s->bank[i].dat);
324 qemu_put_be32s(f, &s->bank[i].up);
325 qemu_put_be32s(f, &s->bank[i].mask);
328 qemu_put_be32s(f, &s->inform[0]);
329 qemu_put_be32s(f, &s->inform[1]);
330 qemu_put_be32s(f, &s->pwrstat);
331 qemu_put_be32s(f, &s->misccr);
332 qemu_put_be32s(f, &s->dclkcon);
333 qemu_put_be32s(f, &s->extint[0]);
334 qemu_put_be32s(f, &s->extint[1]);
335 qemu_put_be32s(f, &s->extint[2]);
336 qemu_put_be32s(f, &s->eintflt[0]);
337 qemu_put_be32s(f, &s->eintflt[1]);
338 qemu_put_be32s(f, &s->eintmask);
339 qemu_put_be32s(f, &s->eintpend);
342 static int s3c_gpio_load(QEMUFile *f, void *opaque, int version_id)
344 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
345 int i;
346 for (i = 0; i < S3C_IO_BANKS; i ++) {
347 qemu_get_be32s(f, &s->bank[i].con);
348 qemu_get_be32s(f, &s->bank[i].dat);
349 qemu_get_be32s(f, &s->bank[i].up);
350 qemu_get_be32s(f, &s->bank[i].mask);
353 qemu_get_be32s(f, &s->inform[0]);
354 qemu_get_be32s(f, &s->inform[1]);
355 qemu_get_be32s(f, &s->pwrstat);
356 qemu_get_be32s(f, &s->misccr);
357 qemu_get_be32s(f, &s->dclkcon);
358 qemu_get_be32s(f, &s->extint[0]);
359 qemu_get_be32s(f, &s->extint[1]);
360 qemu_get_be32s(f, &s->extint[2]);
361 qemu_get_be32s(f, &s->eintflt[0]);
362 qemu_get_be32s(f, &s->eintflt[1]);
363 qemu_get_be32s(f, &s->eintmask);
364 qemu_get_be32s(f, &s->eintpend);
366 return 0;
369 struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, qemu_irq *pic, uint32_t cpu_id)
371 int iomemtype;
372 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *)
373 qemu_mallocz(sizeof(struct s3c_gpio_state_s));
375 s->cpu_id = cpu_id;
376 s->base = base;
377 s->pic = pic;
378 s->in = qemu_allocate_irqs(s3c_gpio_set, s, S3C_GP_MAX);
380 s->bank[0].n = 23;
381 s->bank[1].n = 11;
382 s->bank[2].n = 16;
383 s->bank[3].n = 16;
384 s->bank[4].n = 16;
385 s->bank[5].n = 8;
386 s->bank[6].n = 16;
387 s->bank[7].n = 11;
389 s3c_gpio_reset(s);
391 iomemtype = cpu_register_io_memory(0, s3c_gpio_readfn,
392 s3c_gpio_writefn, s);
393 cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
395 register_savevm("s3c24xx_io", 0, 0, s3c_gpio_save, s3c_gpio_load, s);
397 return s;