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.
14 /* S3C2410 : A B C D E F G H = 8
16 #define S3C_IO_BANKS 8
18 struct s3c_gpio_state_s
{ /* Modelled as an interrupt controller */
20 target_phys_addr_t base
;
43 static inline void s3c_gpio_extint(struct s3c_gpio_state_s
*s
, int irq
)
45 if (s
->eintmask
& (1 << irq
))
47 s
->eintpend
|= (1 << irq
) & 0x00fffff0;
50 qemu_irq_raise(s
->pic
[S3C_PIC_EINT0
+ irq
]);
53 qemu_irq_raise(s
->pic
[S3C_PIC_EINT4
]);
56 qemu_irq_raise(s
->pic
[S3C_PIC_EINT8
]);
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;
67 if (bank
> 0 && ((s
->bank
[bank
].con
>> (2 * line
)) & 3) == 0) {
69 s
->bank
[bank
].dat
|= 1 << line
;
71 s
->bank
[bank
].dat
&= ~(1 << line
);
74 /* External interrupts */
75 if (((s
->bank
[bank
].con
>> (2 * line
)) & 3) == 2) {
83 e
= (line
> 15) ? 2 : 1;
89 if (!((s
->bank
[bank
].dat
>> line
) & 1))
90 switch ((s
->extint
[e
] >> (line
* 4)) & 7) {
93 s3c_gpio_extint(s
, eint
);
96 s
->bank
[bank
].dat
|= 1 << line
;
98 if ((s
->bank
[bank
].dat
>> line
) & 1)
99 switch ((s
->extint
[e
] >> (line
* 4)) & 7) {
104 s3c_gpio_extint(s
, eint
);
106 s
->bank
[bank
].dat
&= ~(1 << line
);
112 qemu_irq
*s3c_gpio_in_get(struct s3c_gpio_state_s
*s
)
117 void s3c_gpio_out_set(struct s3c_gpio_state_s
*s
, int line
, qemu_irq handler
)
119 int bank
= line
>> 5;
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_reset(struct s3c_gpio_state_s
*s
)
131 s
->misccr
= 0x00010330 & ~(1 << 16);
132 s
->dclkcon
= 0x00000000;
138 s
->eintmask
= 0x00fffff0;
139 s
->eintpend
= 0x00000000;
141 for (i
= 0; i
< S3C_IO_BANKS
; i
++) {
142 s
->bank
[i
].mask
= (1 << s
->bank
[i
].n
) - 1;
147 s
->bank
[0].con
= 0x07ffffff;
148 s
->bank
[3].up
= 0x0000f000;
149 s
->bank
[6].up
= 0x0000f800;
152 void s3c_gpio_setpwrstat(struct s3c_gpio_state_s
*s
, int stat
)
157 #define S3C_GPCON 0x00 /* Configuration register */
158 #define S3C_GPDAT 0x04 /* Data register */
159 #define S3C_GPUP 0x08 /* Pull-up register */
160 #define S3C_MISCCR 0x80 /* Miscellaneous Control register */
161 #define S3C_DCLKCON 0x84 /* DCLK0/1 Control register */
162 #define S3C_EXTINT0 0x88 /* External Interrupt Control register 0 */
163 #define S3C_EXTINT1 0x8c /* External Interrupt Control register 1 */
164 #define S3C_EXTINT2 0x90 /* External Interrupt Control register 2 */
165 #define S3C_EINTFLT0 0x94 /* External Interrupt Filter register 0 */
166 #define S3C_EINTFLT1 0x98 /* External Interrupt Filter register 1 */
167 #define S3C_EINTFLT2 0x9c /* External Interrupt Filter register 2 */
168 #define S3C_EINTFLT3 0xa0 /* External Interrupt Filter register 3 */
169 #define S3C_EINTMASK 0xa4 /* External Interrupt Mask register */
170 #define S3C_EINTPEND 0xa8 /* External Interrupt Pending register */
171 #define S3C_GSTATUS0 0xac /* External Pin Status register */
172 #define S3C_GSTATUS1 0xb0 /* Chip ID register */
173 #define S3C_GSTATUS2 0xb4 /* Reset Status register */
174 #define S3C_GSTATUS3 0xb8 /* Inform register */
175 #define S3C_GSTATUS4 0xbc /* Inform register */
177 static uint32_t s3c_gpio_read(void *opaque
, target_phys_addr_t addr
)
179 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
181 if ((addr
>> 4) < S3C_IO_BANKS
) {
208 return s
->eintflt
[0];
210 return s
->eintflt
[1];
215 /* Per bank registers */
217 return s
->bank
[bank
].con
;
219 return s
->bank
[bank
].dat
;
221 return s
->bank
[bank
].up
;
223 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
229 static void s3c_gpio_write(void *opaque
, target_phys_addr_t addr
,
232 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
235 if ((addr
>> 4) < S3C_IO_BANKS
) {
242 s
->pwrstat
&= 7 & ~value
;
245 s
->inform
[0] = value
;
248 s
->inform
[1] = value
;
251 if (value
& (1 << 16)) /* nRSTCON */
252 printf("%s: software reset.\n", __FUNCTION__
);
253 if ((value
^ s
->misccr
) & (1 << 3)) /* USBPAD */
254 printf("%s: now in USB %s mode.\n", __FUNCTION__
,
255 (value
>> 3) & 1 ? "host" : "slave");
256 s
->misccr
= value
& 0x000f377b;
259 s
->dclkcon
= value
& 0x0ff30ff3;
262 s
->extint
[0] = value
;
265 s
->extint
[1] = value
;
268 s
->extint
[2] = value
;
271 s
->eintflt
[0] = value
;
274 s
->eintflt
[1] = value
;
277 s
->eintmask
= value
& 0x00fffff0;
280 s
->eintpend
&= ~value
;
282 /* Per bank registers */
284 s
->bank
[bank
].con
= value
;
287 diff
= (s
->bank
[bank
].dat
^ value
) & s
->bank
[bank
].mask
;
288 s
->bank
[bank
].dat
= value
;
289 while ((ln
= ffs(diff
))) {
291 if (s
->bank
[bank
].handler
[ln
]) {
292 if (bank
&& ((s
->bank
[bank
].con
>> (2 * ln
)) & 3) == 1)
293 qemu_set_irq(s
->bank
[bank
].handler
[ln
], (value
>> ln
) & 1);
294 else if (!bank
&& ((s
->bank
[bank
].con
>> ln
) & 1) == 0)
295 qemu_set_irq(s
->bank
[bank
].handler
[ln
], (value
>> ln
) & 1);
301 s
->bank
[bank
].up
= value
;
304 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
308 static CPUReadMemoryFunc
*s3c_gpio_readfn
[] = {
314 static CPUWriteMemoryFunc
*s3c_gpio_writefn
[] = {
320 static void s3c_gpio_save(QEMUFile
*f
, void *opaque
)
322 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
324 for (i
= 0; i
< S3C_IO_BANKS
; i
++) {
325 qemu_put_be32s(f
, &s
->bank
[i
].con
);
326 qemu_put_be32s(f
, &s
->bank
[i
].dat
);
327 qemu_put_be32s(f
, &s
->bank
[i
].up
);
328 qemu_put_be32s(f
, &s
->bank
[i
].mask
);
331 qemu_put_be32s(f
, &s
->inform
[0]);
332 qemu_put_be32s(f
, &s
->inform
[1]);
333 qemu_put_be32s(f
, &s
->pwrstat
);
334 qemu_put_be32s(f
, &s
->misccr
);
335 qemu_put_be32s(f
, &s
->dclkcon
);
336 qemu_put_be32s(f
, &s
->extint
[0]);
337 qemu_put_be32s(f
, &s
->extint
[1]);
338 qemu_put_be32s(f
, &s
->extint
[2]);
339 qemu_put_be32s(f
, &s
->eintflt
[0]);
340 qemu_put_be32s(f
, &s
->eintflt
[1]);
341 qemu_put_be32s(f
, &s
->eintmask
);
342 qemu_put_be32s(f
, &s
->eintpend
);
345 static int s3c_gpio_load(QEMUFile
*f
, void *opaque
, int version_id
)
347 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
349 for (i
= 0; i
< S3C_IO_BANKS
; i
++) {
350 qemu_get_be32s(f
, &s
->bank
[i
].con
);
351 qemu_get_be32s(f
, &s
->bank
[i
].dat
);
352 qemu_get_be32s(f
, &s
->bank
[i
].up
);
353 qemu_get_be32s(f
, &s
->bank
[i
].mask
);
356 qemu_get_be32s(f
, &s
->inform
[0]);
357 qemu_get_be32s(f
, &s
->inform
[1]);
358 qemu_get_be32s(f
, &s
->pwrstat
);
359 qemu_get_be32s(f
, &s
->misccr
);
360 qemu_get_be32s(f
, &s
->dclkcon
);
361 qemu_get_be32s(f
, &s
->extint
[0]);
362 qemu_get_be32s(f
, &s
->extint
[1]);
363 qemu_get_be32s(f
, &s
->extint
[2]);
364 qemu_get_be32s(f
, &s
->eintflt
[0]);
365 qemu_get_be32s(f
, &s
->eintflt
[1]);
366 qemu_get_be32s(f
, &s
->eintmask
);
367 qemu_get_be32s(f
, &s
->eintpend
);
372 struct s3c_gpio_state_s
*s3c_gpio_init(target_phys_addr_t base
, qemu_irq
*pic
, uint32_t cpu_id
)
375 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*)
376 qemu_mallocz(sizeof(struct s3c_gpio_state_s
));
381 s
->in
= qemu_allocate_irqs(s3c_gpio_set
, s
, S3C_GP_MAX
);
394 iomemtype
= cpu_register_io_memory(0, s3c_gpio_readfn
,
395 s3c_gpio_writefn
, s
);
396 cpu_register_physical_memory(s
->base
, 0xffffff, iomemtype
);
398 register_savevm("s3c24xx_io", 0, 0, s3c_gpio_save
, s3c_gpio_load
, s
);