[NAND] Added readraw() to read underlying data storage
[qemu/mini2440.git] / hw / s3c24xx_gpio.c
blob0c67dba8f41fa7d1cbaeea9d1b09d98c9150c94b
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 /* S3C2410 : A B C D E F G H = 8
14 * S3C2440 : J = 1 */
15 #define S3C_IO_BANKS 8
17 struct s3c_gpio_state_s { /* Modelled as an interrupt controller */
18 uint32_t cpu_id;
19 target_phys_addr_t base;
20 qemu_irq *pic;
21 qemu_irq *in;
23 struct {
24 int n;
25 uint32_t con;
26 uint32_t dat;
27 uint32_t up;
28 uint32_t mask;
29 qemu_irq handler[32];
30 } bank[S3C_IO_BANKS];
32 uint32_t inform[2];
33 uint32_t pwrstat;
34 uint32_t misccr;
35 uint32_t dclkcon;
36 uint32_t extint[3];
37 uint32_t eintflt[2];
38 uint32_t eintmask;
39 uint32_t eintpend;
42 static inline void s3c_gpio_extint(struct s3c_gpio_state_s *s, int irq)
44 if (s->eintmask & (1 << irq))
45 return;
46 s->eintpend |= (1 << irq) & 0x00fffff0;
47 switch (irq) {
48 case 0 ... 3:
49 qemu_irq_raise(s->pic[S3C_PIC_EINT0 + irq]);
50 break;
51 case 4 ... 7:
52 qemu_irq_raise(s->pic[S3C_PIC_EINT4]);
53 break;
54 case 8 ... 23:
55 qemu_irq_raise(s->pic[S3C_PIC_EINT8]);
56 break;
60 static void s3c_gpio_set(void *opaque, int line, int level)
62 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
63 int e, eint, bank = line >> 5;
64 line &= 0x1f;
65 /* Input ports */
66 if (bank > 0 && ((s->bank[bank].con >> (2 * line)) & 3) == 0) {
67 if (level)
68 s->bank[bank].dat |= 1 << line;
69 else
70 s->bank[bank].dat &= ~(1 << line);
71 return;
73 /* External interrupts */
74 if (((s->bank[bank].con >> (2 * line)) & 3) == 2) {
75 switch (bank) {
76 case 5: /* GPF */
77 eint = line;
78 e = 0;
79 break;
80 case 6: /* GPG */
81 eint = line + 8;
82 e = (line > 15) ? 2 : 1;
83 break;
84 default:
85 return;
87 if (level) {
88 if (!((s->bank[bank].dat >> line) & 1))
89 switch ((s->extint[e] >> (line * 4)) & 7) {
90 case 1:
91 case 4 ... 7:
92 s3c_gpio_extint(s, eint);
93 break;
95 s->bank[bank].dat |= 1 << line;
96 } else {
97 if ((s->bank[bank].dat >> line) & 1)
98 switch ((s->extint[e] >> (line * 4)) & 7) {
99 case 1:
100 case 4 ... 5:
101 break;
102 default:
103 s3c_gpio_extint(s, eint);
105 s->bank[bank].dat &= ~(1 << line);
107 return;
111 qemu_irq *s3c_gpio_in_get(struct s3c_gpio_state_s *s)
113 return s->in;
116 void s3c_gpio_out_set(struct s3c_gpio_state_s *s, int line, qemu_irq handler)
118 int bank = line >> 5;
119 line &= 0x1f;
120 if (bank >= S3C_IO_BANKS || line >= s->bank[bank].n)
121 cpu_abort(cpu_single_env, "%s: No I/O port %i\n", __FUNCTION__, line);
122 s->bank[bank].handler[line] = handler;
125 void s3c_gpio_reset(struct s3c_gpio_state_s *s)
127 int i;
128 s->inform[0] = 0;
129 s->inform[1] = 0;
130 s->misccr = 0x00010330 & ~(1 << 16);
131 s->dclkcon = 0x00000000;
132 s->extint[0] = 0;
133 s->extint[1] = 0;
134 s->extint[2] = 0;
135 s->eintflt[0] = 0;
136 s->eintflt[1] = 0;
137 s->eintmask = 0x00fffff0;
138 s->eintpend = 0x00000000;
140 for (i = 0; i < S3C_IO_BANKS; i ++) {
141 s->bank[i].mask = (1 << s->bank[i].n) - 1;
142 s->bank[i].con = 0;
143 s->bank[i].dat = 0;
144 s->bank[i].up = 0;
146 s->bank[0].con = 0x07ffffff;
147 s->bank[3].up = 0x0000f000;
148 s->bank[6].up = 0x0000f800;
151 void s3c_gpio_setpwrstat(struct s3c_gpio_state_s *s, int stat)
153 s->pwrstat = stat;
156 #define S3C_GPCON 0x00 /* Configuration register */
157 #define S3C_GPDAT 0x04 /* Data register */
158 #define S3C_GPUP 0x08 /* Pull-up register */
159 #define S3C_MISCCR 0x80 /* Miscellaneous Control register */
160 #define S3C_DCLKCON 0x84 /* DCLK0/1 Control register */
161 #define S3C_EXTINT0 0x88 /* External Interrupt Control register 0 */
162 #define S3C_EXTINT1 0x8c /* External Interrupt Control register 1 */
163 #define S3C_EXTINT2 0x90 /* External Interrupt Control register 2 */
164 #define S3C_EINTFLT0 0x94 /* External Interrupt Filter register 0 */
165 #define S3C_EINTFLT1 0x98 /* External Interrupt Filter register 1 */
166 #define S3C_EINTFLT2 0x9c /* External Interrupt Filter register 2 */
167 #define S3C_EINTFLT3 0xa0 /* External Interrupt Filter register 3 */
168 #define S3C_EINTMASK 0xa4 /* External Interrupt Mask register */
169 #define S3C_EINTPEND 0xa8 /* External Interrupt Pending register */
170 #define S3C_GSTATUS0 0xac /* External Pin Status register */
171 #define S3C_GSTATUS1 0xb0 /* Chip ID register */
172 #define S3C_GSTATUS2 0xb4 /* Reset Status register */
173 #define S3C_GSTATUS3 0xb8 /* Inform register */
174 #define S3C_GSTATUS4 0xbc /* Inform register */
176 static uint32_t s3c_gpio_read(void *opaque, target_phys_addr_t addr)
178 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
179 int bank = 0;
180 if ((addr >> 4) < S3C_IO_BANKS) {
181 bank = addr >> 4;
182 addr &= 0xf;
185 switch (addr) {
186 case S3C_GSTATUS0:
187 return 0x0;
188 case S3C_GSTATUS1:
189 return s->cpu_id;
190 case S3C_GSTATUS2:
191 return s->pwrstat;
192 case S3C_GSTATUS3:
193 return s->inform[0];
194 case S3C_GSTATUS4:
195 return s->inform[1];
196 case S3C_MISCCR:
197 return s->misccr;
198 case S3C_DCLKCON:
199 return s->dclkcon;
200 case S3C_EXTINT0:
201 return s->extint[0];
202 case S3C_EXTINT1:
203 return s->extint[1];
204 case S3C_EXTINT2:
205 return s->extint[2];
206 case S3C_EINTFLT2:
207 return s->eintflt[0];
208 case S3C_EINTFLT3:
209 return s->eintflt[1];
210 case S3C_EINTMASK:
211 return s->eintmask;
212 case S3C_EINTPEND:
213 return s->eintpend;
214 /* Per bank registers */
215 case S3C_GPCON:
216 return s->bank[bank].con;
217 case S3C_GPDAT:
218 return s->bank[bank].dat;
219 case S3C_GPUP:
220 return s->bank[bank].up;
221 default:
222 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
223 break;
225 return 0;
228 static void s3c_gpio_write(void *opaque, target_phys_addr_t addr,
229 uint32_t value)
231 struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
232 uint32_t diff;
233 int ln, bank = 0;
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;