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.
13 /* S3C2410 : A B C D E F G H = 8
15 #define S3C_IO_BANKS 8
17 struct s3c_gpio_state_s
{ /* Modelled as an interrupt controller */
19 target_phys_addr_t base
;
42 static inline void s3c_gpio_extint(struct s3c_gpio_state_s
*s
, int irq
)
44 if (s
->eintmask
& (1 << irq
))
46 s
->eintpend
|= (1 << irq
) & 0x00fffff0;
49 qemu_irq_raise(s
->pic
[S3C_PIC_EINT0
+ irq
]);
52 qemu_irq_raise(s
->pic
[S3C_PIC_EINT4
]);
55 qemu_irq_raise(s
->pic
[S3C_PIC_EINT8
]);
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;
66 if (bank
> 0 && ((s
->bank
[bank
].con
>> (2 * line
)) & 3) == 0) {
68 s
->bank
[bank
].dat
|= 1 << line
;
70 s
->bank
[bank
].dat
&= ~(1 << line
);
73 /* External interrupts */
74 if (((s
->bank
[bank
].con
>> (2 * line
)) & 3) == 2) {
82 e
= (line
> 15) ? 2 : 1;
88 if (!((s
->bank
[bank
].dat
>> line
) & 1))
89 switch ((s
->extint
[e
] >> (line
* 4)) & 7) {
92 s3c_gpio_extint(s
, eint
);
95 s
->bank
[bank
].dat
|= 1 << line
;
97 if ((s
->bank
[bank
].dat
>> line
) & 1)
98 switch ((s
->extint
[e
] >> (line
* 4)) & 7) {
103 s3c_gpio_extint(s
, eint
);
105 s
->bank
[bank
].dat
&= ~(1 << line
);
111 qemu_irq
*s3c_gpio_in_get(struct s3c_gpio_state_s
*s
)
116 void s3c_gpio_out_set(struct s3c_gpio_state_s
*s
, int line
, qemu_irq handler
)
118 int bank
= line
>> 5;
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
)
130 s
->misccr
= 0x00010330 & ~(1 << 16);
131 s
->dclkcon
= 0x00000000;
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;
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
)
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
;
180 if ((addr
>> 4) < S3C_IO_BANKS
) {
207 return s
->eintflt
[0];
209 return s
->eintflt
[1];
214 /* Per bank registers */
216 return s
->bank
[bank
].con
;
218 return s
->bank
[bank
].dat
;
220 return s
->bank
[bank
].up
;
222 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
228 static void s3c_gpio_write(void *opaque
, target_phys_addr_t addr
,
231 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
234 if ((addr
>> 4) < S3C_IO_BANKS
) {
241 s
->pwrstat
&= 7 & ~value
;
244 s
->inform
[0] = value
;
247 s
->inform
[1] = value
;
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;
258 s
->dclkcon
= value
& 0x0ff30ff3;
261 s
->extint
[0] = value
;
264 s
->extint
[1] = value
;
267 s
->extint
[2] = value
;
270 s
->eintflt
[0] = value
;
273 s
->eintflt
[1] = value
;
276 s
->eintmask
= value
& 0x00fffff0;
279 s
->eintpend
&= ~value
;
281 /* Per bank registers */
283 s
->bank
[bank
].con
= value
;
286 diff
= (s
->bank
[bank
].dat
^ value
) & s
->bank
[bank
].mask
;
287 s
->bank
[bank
].dat
= value
;
288 while ((ln
= ffs(diff
))) {
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);
300 s
->bank
[bank
].up
= value
;
303 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
307 static CPUReadMemoryFunc
*s3c_gpio_readfn
[] = {
313 static CPUWriteMemoryFunc
*s3c_gpio_writefn
[] = {
319 static void s3c_gpio_save(QEMUFile
*f
, void *opaque
)
321 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
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
;
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
);
371 struct s3c_gpio_state_s
*s3c_gpio_init(target_phys_addr_t base
, qemu_irq
*pic
, uint32_t cpu_id
)
374 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*)
375 qemu_mallocz(sizeof(struct s3c_gpio_state_s
));
380 s
->in
= qemu_allocate_irqs(s3c_gpio_set
, s
, S3C_GP_MAX
);
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
);