[S3C] Make s3c aware of 2440s
[qemu/mini2440.git] / hw / s3c24xx_gpio.c
blobc7aa67e5bee29309761f9d1b397aa05bbe8b2ab4
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 addr -= s->base;
179 if ((addr >> 4) < S3C_IO_BANKS) {
180 bank = addr >> 4;
181 addr &= 0xf;
184 switch (addr) {
185 case S3C_GSTATUS0:
186 return 0x0;
187 case S3C_GSTATUS1:
188 return s->cpu_id;
189 case S3C_GSTATUS2:
190 return s->pwrstat;
191 case S3C_GSTATUS3:
192 return s->inform[0];
193 case S3C_GSTATUS4:
194 return s->inform[1];
195 case S3C_MISCCR:
196 return s->misccr;
197 case S3C_DCLKCON:
198 return s->dclkcon;
199 case S3C_EXTINT0:
200 return s->extint[0];
201 case S3C_EXTINT1:
202 return s->extint[1];
203 case S3C_EXTINT2:
204 return s->extint[2];
205 case S3C_EINTFLT2:
206 return s->eintflt[0];
207 case S3C_EINTFLT3:
208 return s->eintflt[1];
209 case S3C_EINTMASK:
210 return s->eintmask;
211 case S3C_EINTPEND:
212 return s->eintpend;
213 /* Per bank registers */
214 case S3C_GPCON:
215 return s->bank[bank].con;
216 case S3C_GPDAT:
217 return s->bank[bank].dat;
218 case S3C_GPUP:
219 return s->bank[bank].up;
220 default:
221 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
222 break;
224 return 0;
227 static void s3c_gpio_write(void *opaque, target_phys_addr_t addr,
228 uint32_t value)
230 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
231 uint32_t diff;
232 int ln, bank = 0;
233 addr -= s->base;
234 if ((addr >> 4) < S3C_IO_BANKS) {
235 bank = addr >> 4;
236 addr &= 0xf;
239 switch (addr) {
240 case S3C_GSTATUS2:
241 s->pwrstat &= 7 & ~value;
242 break;
243 case S3C_GSTATUS3:
244 s->inform[0] = value;
245 break;
246 case S3C_GSTATUS4:
247 s->inform[1] = value;
248 break;
249 case S3C_MISCCR:
250 if (value & (1 << 16)) /* nRSTCON */
251 printf("%s: software reset.\n", __FUNCTION__);
252 if ((value ^ s->misccr) & (1 << 3)) /* USBPAD */
253 printf("%s: now in USB %s mode.\n", __FUNCTION__,
254 (value >> 3) & 1 ? "host" : "slave");
255 s->misccr = value & 0x000f377b;
256 break;
257 case S3C_DCLKCON:
258 s->dclkcon = value & 0x0ff30ff3;
259 break;
260 case S3C_EXTINT0:
261 s->extint[0] = value;
262 break;
263 case S3C_EXTINT1:
264 s->extint[1] = value;
265 break;
266 case S3C_EXTINT2:
267 s->extint[2] = value;
268 break;
269 case S3C_EINTFLT2:
270 s->eintflt[0] = value;
271 break;
272 case S3C_EINTFLT3:
273 s->eintflt[1] = value;
274 break;
275 case S3C_EINTMASK:
276 s->eintmask = value & 0x00fffff0;
277 break;
278 case S3C_EINTPEND:
279 s->eintpend &= ~value;
280 break;
281 /* Per bank registers */
282 case S3C_GPCON:
283 s->bank[bank].con = value;
284 break;
285 case S3C_GPDAT:
286 diff = (s->bank[bank].dat ^ value) & s->bank[bank].mask;
287 s->bank[bank].dat = value;
288 while ((ln = ffs(diff))) {
289 ln --;
290 if (s->bank[bank].handler[ln]) {
291 if (bank && ((s->bank[bank].con >> (2 * ln)) & 3) == 1)
292 qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
293 else if (!bank && ((s->bank[bank].con >> ln) & 1) == 0)
294 qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
296 diff &= ~(1 << ln);
298 break;
299 case S3C_GPUP:
300 s->bank[bank].up = value;
301 break;
302 default:
303 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
307 static CPUReadMemoryFunc *s3c_gpio_readfn[] = {
308 s3c_gpio_read,
309 s3c_gpio_read,
310 s3c_gpio_read,
313 static CPUWriteMemoryFunc *s3c_gpio_writefn[] = {
314 s3c_gpio_write,
315 s3c_gpio_write,
316 s3c_gpio_write,
319 static void s3c_gpio_save(QEMUFile *f, void *opaque)
321 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
322 int i;
323 for (i = 0; i < S3C_IO_BANKS; i ++) {
324 qemu_put_be32s(f, &s->bank[i].con);
325 qemu_put_be32s(f, &s->bank[i].dat);
326 qemu_put_be32s(f, &s->bank[i].up);
327 qemu_put_be32s(f, &s->bank[i].mask);
330 qemu_put_be32s(f, &s->inform[0]);
331 qemu_put_be32s(f, &s->inform[1]);
332 qemu_put_be32s(f, &s->pwrstat);
333 qemu_put_be32s(f, &s->misccr);
334 qemu_put_be32s(f, &s->dclkcon);
335 qemu_put_be32s(f, &s->extint[0]);
336 qemu_put_be32s(f, &s->extint[1]);
337 qemu_put_be32s(f, &s->extint[2]);
338 qemu_put_be32s(f, &s->eintflt[0]);
339 qemu_put_be32s(f, &s->eintflt[1]);
340 qemu_put_be32s(f, &s->eintmask);
341 qemu_put_be32s(f, &s->eintpend);
344 static int s3c_gpio_load(QEMUFile *f, void *opaque, int version_id)
346 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
347 int i;
348 for (i = 0; i < S3C_IO_BANKS; i ++) {
349 qemu_get_be32s(f, &s->bank[i].con);
350 qemu_get_be32s(f, &s->bank[i].dat);
351 qemu_get_be32s(f, &s->bank[i].up);
352 qemu_get_be32s(f, &s->bank[i].mask);
355 qemu_get_be32s(f, &s->inform[0]);
356 qemu_get_be32s(f, &s->inform[1]);
357 qemu_get_be32s(f, &s->pwrstat);
358 qemu_get_be32s(f, &s->misccr);
359 qemu_get_be32s(f, &s->dclkcon);
360 qemu_get_be32s(f, &s->extint[0]);
361 qemu_get_be32s(f, &s->extint[1]);
362 qemu_get_be32s(f, &s->extint[2]);
363 qemu_get_be32s(f, &s->eintflt[0]);
364 qemu_get_be32s(f, &s->eintflt[1]);
365 qemu_get_be32s(f, &s->eintmask);
366 qemu_get_be32s(f, &s->eintpend);
368 return 0;
371 struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, qemu_irq *pic, uint32_t cpu_id)
373 int iomemtype;
374 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *)
375 qemu_mallocz(sizeof(struct s3c_gpio_state_s));
377 s->cpu_id = cpu_id;
378 s->base = base;
379 s->pic = pic;
380 s->in = qemu_allocate_irqs(s3c_gpio_set, s, S3C_GP_MAX);
382 s->bank[0].n = 23;
383 s->bank[1].n = 11;
384 s->bank[2].n = 16;
385 s->bank[3].n = 16;
386 s->bank[4].n = 16;
387 s->bank[5].n = 8;
388 s->bank[6].n = 16;
389 s->bank[7].n = 11;
391 s3c_gpio_reset(s);
393 iomemtype = cpu_register_io_memory(0, s3c_gpio_readfn,
394 s3c_gpio_writefn, s);
395 cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
397 register_savevm("s3c24xx_io", 0, 0, s3c_gpio_save, s3c_gpio_load, s);
399 return s;