3 * Samsung S3C24XX GPIO emulation (mostly for E-INT)
5 * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
7 * Copyright 2010, 2013 Stefan Weil
9 * This file is under the terms of the GNU General Public License Version 2.
12 #include "qemu/osdep.h"
15 #include "hw/sysbus.h"
18 #define S3C_GPIO_GPECON 0x40
19 #define S3C_GPIO_GPEDAT 0x44
20 #define S3C_GPIO_GPEUP 0x48
22 #define S3C_GPIO_EINT_MASK 0xA4
23 #define S3C_GPIO_EINT_PEND 0xA8
24 #define S3C_GPIO_GSTATUS0 0xAC
25 #define S3C_GPIO_GSTATUS1 0xB0
26 #define S3C_GPIO_GSTATUS2 0xB4
27 #define S3C_GPIO_GSTATUS3 0xB8
28 #define S3C_GPIO_GSTATUS4 0xBC
30 #define GPRN(r) (r>>2)
31 #define GPR(P) s->gpio_reg[P>>2]
33 #define S3C_GPIO_MAX 0x43
35 /* GPIO controller state */
37 #define TYPE_S3C24XX_GPIO "s3c24xx_gpio"
38 #define S3C24XX_GPIO(obj) \
39 OBJECT_CHECK(S3C24xxGpioState, (obj), TYPE_S3C24XX_GPIO)
41 struct S3C24xxGpioState
{
45 uint32_t gpio_reg
[S3C_GPIO_MAX
];
47 qemu_irq
*eirqs
; /* gpio external interrupts */
49 qemu_irq irqs
[6]; /* cpu irqs to cascade */
53 s3c24xx_gpio_propagate_eint(S3C24xxGpioState
*s
)
57 ints
= GPR(S3C_GPIO_EINT_PEND
) & ~GPR(S3C_GPIO_EINT_MASK
);
59 /* EINT0 - EINT3 are INT0 - INT3 */
60 for (i
=0; i
< 4; ++i
) {
61 qemu_set_irq(s
->irqs
[i
], (ints
& (1<<i
))?1:0);
64 /* EINT4 - EINT7 are INT4 */
65 qemu_set_irq(s
->irqs
[4], (ints
& 0xf0)?1:0);
67 /* EINT8 - EINT23 are INT5 */
68 qemu_set_irq(s
->irqs
[5], (ints
& 0x00ffff00)?1:0);
72 gpio_con_to_mask(uint32_t con
)
77 for (bit
= 0; bit
< 16; bit
++) {
78 if (((con
>> (bit
* 2)) & 0x3) == 0x01) {
87 s3c24xx_gpio_write_f(void *opaque
, hwaddr addr_
, uint64_t value
,
90 S3C24xxGpioState
*s
= opaque
;
91 uint32_t addr
= (addr_
>> 2);
93 assert(addr
< S3C_GPIO_MAX
);
95 assert(!(addr
> 0x3f));
98 if (addr
== (S3C_GPIO_EINT_MASK
>>2)) {
99 value
&= ~0xf; /* cannot mask EINT0-EINT3 */
102 if (addr
== (S3C_GPIO_EINT_PEND
>>2)) {
103 s
->gpio_reg
[addr
] &= ~value
;
105 if (addr
< (0x80/4) && (addr_
& 0xf) == 0x04) {
106 uint32_t mask
= gpio_con_to_mask(s
->gpio_reg
[addr
- 1]);
110 s
->gpio_reg
[addr
] &= ~mask
;
111 s
->gpio_reg
[addr
] |= value
;
113 s
->gpio_reg
[addr
] = value
;
117 if ((addr
== (S3C_GPIO_EINT_MASK
)>>2) ||
118 (addr
== (S3C_GPIO_EINT_PEND
)>>2)) {
119 /* A write to the EINT regs leads us to determine the interrupts to
122 s3c24xx_gpio_propagate_eint(s
);
127 s3c24xx_gpio_read_f(void *opaque
, hwaddr addr_
, unsigned size
)
129 S3C24xxGpioState
*s
= opaque
;
130 uint32_t addr
= (addr_
>> 2);
133 assert(addr
< S3C_GPIO_MAX
);
135 assert(!(addr
> 0x3f));
138 ret
= s
->gpio_reg
[addr
];
140 if (addr
== GPRN(S3C_GPIO_GPEDAT
)) {
141 /* IIC pins are special function pins on GPE14 and GPE15. If GPE is is
142 * in input mode make the IIC lines appear to be pulled high. This is
143 * neccissary because OS i2c drivers use this to ensure the I2C bus is
146 if ((GPR(S3C_GPIO_GPECON
) & (3<<28)) == 0) {
150 if ((GPR(S3C_GPIO_GPECON
) & (3<<30)) == 0) {
158 static const MemoryRegionOps s3c24xx_gpio_ops
= {
159 .read
= s3c24xx_gpio_read_f
,
160 .write
= s3c24xx_gpio_write_f
,
161 .endianness
= DEVICE_NATIVE_ENDIAN
,
163 .min_access_size
= 1,
169 s3c24xx_gpio_irq_handler(void *opaque
, int n
, int level
)
171 S3C24xxGpioState
*s
= opaque
;
174 GPR(S3C_GPIO_EINT_PEND
) |= (1<<n
);
177 s3c24xx_gpio_propagate_eint(s
);
180 static void s3c24xx_gpio_realize(DeviceState
*dev
, Error
**errp
)
182 S3C24xxGpioState
*s
= S3C24XX_GPIO(dev
);
183 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
185 //~ qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
186 //~ sysbus_init_irq(dev, &s->parent_irq);
187 memory_region_init_io(&s
->mmio
, OBJECT(s
), &s3c24xx_gpio_ops
, s
,
188 "s3c24xx-gpio", S3C_GPIO_MAX
* 4);
189 sysbus_init_mmio(sbd
, &s
->mmio
);
191 TODO
: i
/o starting at base_addr
, S3C_GPIO_MAX
* 4 bytes
.
194 /* Set non zero default values. */
195 GPR(0x00) = 0x7fffff;
200 GPR(S3C_GPIO_EINT_MASK
) = 0xfffff0;
201 //~ GPR(S3C_GPIO_GSTATUS1) = cpu_id;
202 GPR(S3C_GPIO_GSTATUS2
) = 1;
203 GPR(S3C_GPIO_GSTATUS3
) = 0;
204 GPR(S3C_GPIO_GSTATUS4
) = 0;
208 s3c24xx_gpio_init(S3CState
*soc
, hwaddr base_addr
, uint32_t cpu_id
)
210 /* Samsung S3C24XX GPIO
212 * The primary operation here is the ID register and IRQs
216 S3C24xxGpioState
*s
= g_new0(S3C24xxGpioState
, 1);
218 /* TODO: Diese Funktion ist veraltet und soll ersetzt werden, s.o. */
220 /* Set non zero default values. */
221 GPR(0x00) = 0x7fffff;
226 GPR(S3C_GPIO_EINT_MASK
) = 0xfffff0;
227 GPR(S3C_GPIO_GSTATUS1
) = cpu_id
;
228 GPR(S3C_GPIO_GSTATUS2
) = 1;
229 GPR(S3C_GPIO_GSTATUS3
) = 0;
230 GPR(S3C_GPIO_GSTATUS4
) = 0;
232 /* obtain first level IRQs for cascade */
233 for (i
= 0; i
<= 5; i
++) {
234 s
->irqs
[i
] = s3c24xx_get_irq(soc
->irq
, i
);
237 /* EINTs 0-23 -- Only 24, not 48 because EINTs are not level */
238 s
->eirqs
= qemu_allocate_irqs(s3c24xx_gpio_irq_handler
, s
, 24);
243 /* get the qemu interrupt from an eirq number */
245 s3c24xx_get_eirq(S3C24xxGpioState
*s
, unsigned einum
)
248 return s
->eirqs
[einum
];
251 static const VMStateDescription s3c24xx_gpio_vmstate
= {
252 .name
= TYPE_S3C24XX_GPIO
,
254 .minimum_version_id
= 1,
255 .minimum_version_id_old
= 1,
256 .fields
= (VMStateField
[]) {
257 VMSTATE_UINT32_ARRAY(gpio_reg
, S3C24xxGpioState
, S3C_GPIO_MAX
),
258 VMSTATE_END_OF_LIST()
262 static Property s3c24xx_gpio_properties
[] = {
263 DEFINE_PROP_END_OF_LIST()
266 static void s3c24xx_gpio_class_init(ObjectClass
*klass
, void *data
)
268 DeviceClass
*dc
= DEVICE_CLASS(klass
);
269 dc
->props
= s3c24xx_gpio_properties
;
270 dc
->realize
= s3c24xx_gpio_realize
;
271 dc
->vmsd
= &s3c24xx_gpio_vmstate
;
274 static const TypeInfo s3c24xx_gpio_info
= {
275 .name
= TYPE_S3C24XX_GPIO
,
276 .parent
= TYPE_SYS_BUS_DEVICE
,
277 .instance_size
= sizeof(S3C24xxGpioState
),
278 .class_init
= s3c24xx_gpio_class_init
281 static void s3c24xx_register_types(void)
283 type_register_static(&s3c24xx_gpio_info
);
286 type_init(s3c24xx_register_types
)