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 #define S3C_IO_BANKS 8
15 struct s3c_gpio_state_s
{ /* Modelled as an interrupt controller */
17 target_phys_addr_t base
;
40 static inline void s3c_gpio_extint(struct s3c_gpio_state_s
*s
, int irq
)
42 if (s
->eintmask
& (1 << irq
))
44 s
->eintpend
|= (1 << irq
) & 0x00fffff0;
47 qemu_irq_raise(s
->pic
[S3C_PIC_EINT0
+ irq
]);
50 qemu_irq_raise(s
->pic
[S3C_PIC_EINT4
]);
53 qemu_irq_raise(s
->pic
[S3C_PIC_EINT8
]);
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;
64 if (bank
> 0 && ((s
->bank
[bank
].con
>> (2 * line
)) & 3) == 0) {
66 s
->bank
[bank
].dat
|= 1 << line
;
68 s
->bank
[bank
].dat
&= ~(1 << line
);
71 /* External interrupts */
72 if (((s
->bank
[bank
].con
>> (2 * line
)) & 3) == 2) {
80 e
= (line
> 15) ? 2 : 1;
86 if (!((s
->bank
[bank
].dat
>> line
) & 1))
87 switch ((s
->extint
[e
] >> (line
* 4)) & 7) {
90 s3c_gpio_extint(s
, eint
);
93 s
->bank
[bank
].dat
|= 1 << line
;
95 if ((s
->bank
[bank
].dat
>> line
) & 1)
96 switch ((s
->extint
[e
] >> (line
* 4)) & 7) {
101 s3c_gpio_extint(s
, eint
);
103 s
->bank
[bank
].dat
&= ~(1 << line
);
109 qemu_irq
*s3c_gpio_in_get(struct s3c_gpio_state_s
*s
)
114 void s3c_gpio_out_set(struct s3c_gpio_state_s
*s
, int line
, qemu_irq handler
)
116 int bank
= line
>> 5;
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
)
128 s
->misccr
= 0x00010330 & ~(1 << 16);
129 s
->dclkcon
= 0x00000000;
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;
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
)
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
;
179 if ((addr
>> 4) < S3C_IO_BANKS
) {
206 return s
->eintflt
[0];
208 return s
->eintflt
[1];
213 /* Per bank registers */
215 return s
->bank
[bank
].con
;
217 return s
->bank
[bank
].dat
;
219 return s
->bank
[bank
].up
;
221 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
227 static void s3c_gpio_write(void *opaque
, target_phys_addr_t addr
,
230 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
);