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
;
178 if ((addr
>> 4) < S3C_IO_BANKS
) {
205 return s
->eintflt
[0];
207 return s
->eintflt
[1];
212 /* Per bank registers */
214 return s
->bank
[bank
].con
;
216 return s
->bank
[bank
].dat
;
218 return s
->bank
[bank
].up
;
220 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
226 static void s3c_gpio_write(void *opaque
, target_phys_addr_t addr
,
229 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
232 if ((addr
>> 4) < S3C_IO_BANKS
) {
239 s
->pwrstat
&= 7 & ~value
;
242 s
->inform
[0] = value
;
245 s
->inform
[1] = value
;
248 if (value
& (1 << 16)) /* nRSTCON */
249 printf("%s: software reset.\n", __FUNCTION__
);
250 if ((value
^ s
->misccr
) & (1 << 3)) /* USBPAD */
251 printf("%s: now in USB %s mode.\n", __FUNCTION__
,
252 (value
>> 3) & 1 ? "host" : "slave");
253 s
->misccr
= value
& 0x000f377b;
256 s
->dclkcon
= value
& 0x0ff30ff3;
259 s
->extint
[0] = value
;
262 s
->extint
[1] = value
;
265 s
->extint
[2] = value
;
268 s
->eintflt
[0] = value
;
271 s
->eintflt
[1] = value
;
274 s
->eintmask
= value
& 0x00fffff0;
277 s
->eintpend
&= ~value
;
279 /* Per bank registers */
281 s
->bank
[bank
].con
= value
;
284 diff
= (s
->bank
[bank
].dat
^ value
) & s
->bank
[bank
].mask
;
285 s
->bank
[bank
].dat
= value
;
286 while ((ln
= ffs(diff
))) {
288 if (s
->bank
[bank
].handler
[ln
]) {
289 if (bank
&& ((s
->bank
[bank
].con
>> (2 * ln
)) & 3) == 1)
290 qemu_set_irq(s
->bank
[bank
].handler
[ln
], (value
>> ln
) & 1);
291 else if (!bank
&& ((s
->bank
[bank
].con
>> ln
) & 1) == 0)
292 qemu_set_irq(s
->bank
[bank
].handler
[ln
], (value
>> ln
) & 1);
298 s
->bank
[bank
].up
= value
;
301 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
305 static CPUReadMemoryFunc
*s3c_gpio_readfn
[] = {
311 static CPUWriteMemoryFunc
*s3c_gpio_writefn
[] = {
317 static void s3c_gpio_save(QEMUFile
*f
, void *opaque
)
319 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
321 for (i
= 0; i
< S3C_IO_BANKS
; i
++) {
322 qemu_put_be32s(f
, &s
->bank
[i
].con
);
323 qemu_put_be32s(f
, &s
->bank
[i
].dat
);
324 qemu_put_be32s(f
, &s
->bank
[i
].up
);
325 qemu_put_be32s(f
, &s
->bank
[i
].mask
);
328 qemu_put_be32s(f
, &s
->inform
[0]);
329 qemu_put_be32s(f
, &s
->inform
[1]);
330 qemu_put_be32s(f
, &s
->pwrstat
);
331 qemu_put_be32s(f
, &s
->misccr
);
332 qemu_put_be32s(f
, &s
->dclkcon
);
333 qemu_put_be32s(f
, &s
->extint
[0]);
334 qemu_put_be32s(f
, &s
->extint
[1]);
335 qemu_put_be32s(f
, &s
->extint
[2]);
336 qemu_put_be32s(f
, &s
->eintflt
[0]);
337 qemu_put_be32s(f
, &s
->eintflt
[1]);
338 qemu_put_be32s(f
, &s
->eintmask
);
339 qemu_put_be32s(f
, &s
->eintpend
);
342 static int s3c_gpio_load(QEMUFile
*f
, void *opaque
, int version_id
)
344 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
346 for (i
= 0; i
< S3C_IO_BANKS
; i
++) {
347 qemu_get_be32s(f
, &s
->bank
[i
].con
);
348 qemu_get_be32s(f
, &s
->bank
[i
].dat
);
349 qemu_get_be32s(f
, &s
->bank
[i
].up
);
350 qemu_get_be32s(f
, &s
->bank
[i
].mask
);
353 qemu_get_be32s(f
, &s
->inform
[0]);
354 qemu_get_be32s(f
, &s
->inform
[1]);
355 qemu_get_be32s(f
, &s
->pwrstat
);
356 qemu_get_be32s(f
, &s
->misccr
);
357 qemu_get_be32s(f
, &s
->dclkcon
);
358 qemu_get_be32s(f
, &s
->extint
[0]);
359 qemu_get_be32s(f
, &s
->extint
[1]);
360 qemu_get_be32s(f
, &s
->extint
[2]);
361 qemu_get_be32s(f
, &s
->eintflt
[0]);
362 qemu_get_be32s(f
, &s
->eintflt
[1]);
363 qemu_get_be32s(f
, &s
->eintmask
);
364 qemu_get_be32s(f
, &s
->eintpend
);
369 struct s3c_gpio_state_s
*s3c_gpio_init(target_phys_addr_t base
, qemu_irq
*pic
, uint32_t cpu_id
)
372 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*)
373 qemu_mallocz(sizeof(struct s3c_gpio_state_s
));
378 s
->in
= qemu_allocate_irqs(s3c_gpio_set
, s
, S3C_GP_MAX
);
391 iomemtype
= cpu_register_io_memory(0, s3c_gpio_readfn
,
392 s3c_gpio_writefn
, s
);
393 cpu_register_physical_memory(s
->base
, 0xffffff, iomemtype
);
395 register_savevm("s3c24xx_io", 0, 0, s3c_gpio_save
, s3c_gpio_load
, s
);