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_set_dat(struct s3c_gpio_state_s
*s
, int gpio
, int level
)
128 int bank
= gpio
>> 5, bit
= gpio
& 0x1f;
129 s
->bank
[bank
].dat
= (s
->bank
[bank
].dat
& ~(1 << bit
)) | (level
? (1 << bit
) : 0);
132 void s3c_gpio_reset(struct s3c_gpio_state_s
*s
)
137 s
->misccr
= 0x00010330 & ~(1 << 16);
138 s
->dclkcon
= 0x00000000;
144 s
->eintmask
= 0x00fffff0;
145 s
->eintpend
= 0x00000000;
147 for (i
= 0; i
< S3C_IO_BANKS
; i
++) {
148 s
->bank
[i
].mask
= (1 << s
->bank
[i
].n
) - 1;
153 s
->bank
[0].con
= 0x07ffffff;
154 s
->bank
[3].up
= 0x0000f000;
155 s
->bank
[6].up
= 0x0000f800;
158 void s3c_gpio_setpwrstat(struct s3c_gpio_state_s
*s
, int stat
)
163 #define S3C_GPCON 0x00 /* Configuration register */
164 #define S3C_GPDAT 0x04 /* Data register */
165 #define S3C_GPUP 0x08 /* Pull-up register */
166 #define S3C_MISCCR 0x80 /* Miscellaneous Control register */
167 #define S3C_DCLKCON 0x84 /* DCLK0/1 Control register */
168 #define S3C_EXTINT0 0x88 /* External Interrupt Control register 0 */
169 #define S3C_EXTINT1 0x8c /* External Interrupt Control register 1 */
170 #define S3C_EXTINT2 0x90 /* External Interrupt Control register 2 */
171 #define S3C_EINTFLT0 0x94 /* External Interrupt Filter register 0 */
172 #define S3C_EINTFLT1 0x98 /* External Interrupt Filter register 1 */
173 #define S3C_EINTFLT2 0x9c /* External Interrupt Filter register 2 */
174 #define S3C_EINTFLT3 0xa0 /* External Interrupt Filter register 3 */
175 #define S3C_EINTMASK 0xa4 /* External Interrupt Mask register */
176 #define S3C_EINTPEND 0xa8 /* External Interrupt Pending register */
177 #define S3C_GSTATUS0 0xac /* External Pin Status register */
178 #define S3C_GSTATUS1 0xb0 /* Chip ID register */
179 #define S3C_GSTATUS2 0xb4 /* Reset Status register */
180 #define S3C_GSTATUS3 0xb8 /* Inform register */
181 #define S3C_GSTATUS4 0xbc /* Inform register */
183 static uint32_t s3c_gpio_read(void *opaque
, target_phys_addr_t addr
)
185 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
187 if ((addr
>> 4) < S3C_IO_BANKS
) {
214 return s
->eintflt
[0];
216 return s
->eintflt
[1];
221 /* Per bank registers */
223 return s
->bank
[bank
].con
;
225 /* printf("%s: read port '%c' = %08x\n", __FUNCTION__, 'A' + bank, s->bank[bank].dat); */
226 return s
->bank
[bank
].dat
;
228 return s
->bank
[bank
].up
;
230 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
236 static void s3c_gpio_write(void *opaque
, target_phys_addr_t addr
,
239 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
242 if ((addr
>> 4) < S3C_IO_BANKS
) {
249 s
->pwrstat
&= 7 & ~value
;
252 s
->inform
[0] = value
;
255 s
->inform
[1] = value
;
258 if (value
& (1 << 16)) /* nRSTCON */
259 printf("%s: software reset.\n", __FUNCTION__
);
260 if ((value
^ s
->misccr
) & (1 << 3)) /* USBPAD */
261 printf("%s: now in USB %s mode.\n", __FUNCTION__
,
262 (value
>> 3) & 1 ? "host" : "slave");
263 s
->misccr
= value
& 0x000f377b;
266 s
->dclkcon
= value
& 0x0ff30ff3;
269 s
->extint
[0] = value
;
272 s
->extint
[1] = value
;
275 s
->extint
[2] = value
;
278 s
->eintflt
[0] = value
;
281 s
->eintflt
[1] = value
;
284 s
->eintmask
= value
& 0x00fffff0;
287 s
->eintpend
&= ~value
;
289 /* Per bank registers */
291 s
->bank
[bank
].con
= value
;
294 diff
= (s
->bank
[bank
].dat
^ value
) & s
->bank
[bank
].mask
;
295 s
->bank
[bank
].dat
= value
;
296 /* printf("%s: write port '%c' = %08x\n", __FUNCTION__, 'A' + bank, s->bank[bank].dat); */
297 while ((ln
= ffs(diff
))) {
299 if (s
->bank
[bank
].handler
[ln
]) {
300 if (bank
&& ((s
->bank
[bank
].con
>> (2 * ln
)) & 3) == 1)
301 qemu_set_irq(s
->bank
[bank
].handler
[ln
], (value
>> ln
) & 1);
302 else if (!bank
&& ((s
->bank
[bank
].con
>> ln
) & 1) == 0)
303 qemu_set_irq(s
->bank
[bank
].handler
[ln
], (value
>> ln
) & 1);
309 s
->bank
[bank
].up
= value
;
312 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
316 static CPUReadMemoryFunc
*s3c_gpio_readfn
[] = {
322 static CPUWriteMemoryFunc
*s3c_gpio_writefn
[] = {
328 static void s3c_gpio_save(QEMUFile
*f
, void *opaque
)
330 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
332 for (i
= 0; i
< S3C_IO_BANKS
; i
++) {
333 qemu_put_be32s(f
, &s
->bank
[i
].con
);
334 qemu_put_be32s(f
, &s
->bank
[i
].dat
);
335 qemu_put_be32s(f
, &s
->bank
[i
].up
);
336 qemu_put_be32s(f
, &s
->bank
[i
].mask
);
339 qemu_put_be32s(f
, &s
->inform
[0]);
340 qemu_put_be32s(f
, &s
->inform
[1]);
341 qemu_put_be32s(f
, &s
->pwrstat
);
342 qemu_put_be32s(f
, &s
->misccr
);
343 qemu_put_be32s(f
, &s
->dclkcon
);
344 qemu_put_be32s(f
, &s
->extint
[0]);
345 qemu_put_be32s(f
, &s
->extint
[1]);
346 qemu_put_be32s(f
, &s
->extint
[2]);
347 qemu_put_be32s(f
, &s
->eintflt
[0]);
348 qemu_put_be32s(f
, &s
->eintflt
[1]);
349 qemu_put_be32s(f
, &s
->eintmask
);
350 qemu_put_be32s(f
, &s
->eintpend
);
353 static int s3c_gpio_load(QEMUFile
*f
, void *opaque
, int version_id
)
355 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*) opaque
;
357 for (i
= 0; i
< S3C_IO_BANKS
; i
++) {
358 qemu_get_be32s(f
, &s
->bank
[i
].con
);
359 qemu_get_be32s(f
, &s
->bank
[i
].dat
);
360 qemu_get_be32s(f
, &s
->bank
[i
].up
);
361 qemu_get_be32s(f
, &s
->bank
[i
].mask
);
364 qemu_get_be32s(f
, &s
->inform
[0]);
365 qemu_get_be32s(f
, &s
->inform
[1]);
366 qemu_get_be32s(f
, &s
->pwrstat
);
367 qemu_get_be32s(f
, &s
->misccr
);
368 qemu_get_be32s(f
, &s
->dclkcon
);
369 qemu_get_be32s(f
, &s
->extint
[0]);
370 qemu_get_be32s(f
, &s
->extint
[1]);
371 qemu_get_be32s(f
, &s
->extint
[2]);
372 qemu_get_be32s(f
, &s
->eintflt
[0]);
373 qemu_get_be32s(f
, &s
->eintflt
[1]);
374 qemu_get_be32s(f
, &s
->eintmask
);
375 qemu_get_be32s(f
, &s
->eintpend
);
380 struct s3c_gpio_state_s
*s3c_gpio_init(target_phys_addr_t base
, qemu_irq
*pic
, uint32_t cpu_id
)
383 struct s3c_gpio_state_s
*s
= (struct s3c_gpio_state_s
*)
384 qemu_mallocz(sizeof(struct s3c_gpio_state_s
));
389 s
->in
= qemu_allocate_irqs(s3c_gpio_set
, s
, S3C_GP_MAX
);
402 iomemtype
= cpu_register_io_memory(0, s3c_gpio_readfn
,
403 s3c_gpio_writefn
, s
);
404 cpu_register_physical_memory(s
->base
, 0xffffff, iomemtype
);
406 register_savevm("s3c24xx_io", 0, 0, s3c_gpio_save
, s3c_gpio_load
, s
);