3 * Samsung S3C24XX GPIO emulation (mostly for E-INT)
5 * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
7 * Copyright 2010, 2013, 2020 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/irq.h" /* qemu_set_irq */
16 #include "hw/qdev-properties.h" /* DEFINE_PROP_END_OF_LIST */
17 #include "hw/sysbus.h"
18 #include "migration/vmstate.h" /* VMStateDescription */
21 #define S3C_GPIO_GPECON 0x40
22 #define S3C_GPIO_GPEDAT 0x44
23 #define S3C_GPIO_GPEUP 0x48
25 #define S3C_GPIO_EINT_MASK 0xA4
26 #define S3C_GPIO_EINT_PEND 0xA8
27 #define S3C_GPIO_GSTATUS0 0xAC
28 #define S3C_GPIO_GSTATUS1 0xB0
29 #define S3C_GPIO_GSTATUS2 0xB4
30 #define S3C_GPIO_GSTATUS3 0xB8
31 #define S3C_GPIO_GSTATUS4 0xBC
33 #define GPRN(r) (r>>2)
34 #define GPR(P) s->gpio_reg[P>>2]
36 #define S3C_GPIO_MAX 0x43
38 /* GPIO controller state */
40 #define TYPE_S3C24XX_GPIO "s3c24xx_gpio"
41 #define S3C24XX_GPIO(obj) \
42 OBJECT_CHECK(S3C24xxGpioState, (obj), TYPE_S3C24XX_GPIO)
44 struct S3C24xxGpioState
{
48 uint32_t gpio_reg
[S3C_GPIO_MAX
];
50 qemu_irq
*eirqs
; /* gpio external interrupts */
52 qemu_irq irqs
[6]; /* cpu irqs to cascade */
56 s3c24xx_gpio_propagate_eint(S3C24xxGpioState
*s
)
60 ints
= GPR(S3C_GPIO_EINT_PEND
) & ~GPR(S3C_GPIO_EINT_MASK
);
62 /* EINT0 - EINT3 are INT0 - INT3 */
63 for (i
=0; i
< 4; ++i
) {
64 qemu_set_irq(s
->irqs
[i
], (ints
& (1<<i
))?1:0);
67 /* EINT4 - EINT7 are INT4 */
68 qemu_set_irq(s
->irqs
[4], (ints
& 0xf0)?1:0);
70 /* EINT8 - EINT23 are INT5 */
71 qemu_set_irq(s
->irqs
[5], (ints
& 0x00ffff00)?1:0);
75 gpio_con_to_mask(uint32_t con
)
80 for (bit
= 0; bit
< 16; bit
++) {
81 if (((con
>> (bit
* 2)) & 0x3) == 0x01) {
90 s3c24xx_gpio_write_f(void *opaque
, hwaddr addr_
, uint64_t value
,
93 S3C24xxGpioState
*s
= opaque
;
94 uint32_t addr
= (addr_
>> 2);
96 assert(addr
< S3C_GPIO_MAX
);
98 assert(!(addr
> 0x3f));
101 if (addr
== (S3C_GPIO_EINT_MASK
>>2)) {
102 value
&= ~0xf; /* cannot mask EINT0-EINT3 */
105 if (addr
== (S3C_GPIO_EINT_PEND
>>2)) {
106 s
->gpio_reg
[addr
] &= ~value
;
108 if (addr
< (0x80/4) && (addr_
& 0xf) == 0x04) {
109 uint32_t mask
= gpio_con_to_mask(s
->gpio_reg
[addr
- 1]);
113 s
->gpio_reg
[addr
] &= ~mask
;
114 s
->gpio_reg
[addr
] |= value
;
116 s
->gpio_reg
[addr
] = value
;
120 if ((addr
== (S3C_GPIO_EINT_MASK
)>>2) ||
121 (addr
== (S3C_GPIO_EINT_PEND
)>>2)) {
122 /* A write to the EINT regs leads us to determine the interrupts to
125 s3c24xx_gpio_propagate_eint(s
);
130 s3c24xx_gpio_read_f(void *opaque
, hwaddr addr_
, unsigned size
)
132 S3C24xxGpioState
*s
= opaque
;
133 uint32_t addr
= (addr_
>> 2);
136 assert(addr
< S3C_GPIO_MAX
);
138 assert(!(addr
> 0x3f));
141 ret
= s
->gpio_reg
[addr
];
143 if (addr
== GPRN(S3C_GPIO_GPEDAT
)) {
144 /* IIC pins are special function pins on GPE14 and GPE15. If GPE is is
145 * in input mode make the IIC lines appear to be pulled high. This is
146 * neccissary because OS i2c drivers use this to ensure the I2C bus is
149 if ((GPR(S3C_GPIO_GPECON
) & (3<<28)) == 0) {
153 if ((GPR(S3C_GPIO_GPECON
) & (3<<30)) == 0) {
161 static const MemoryRegionOps s3c24xx_gpio_ops
= {
162 .read
= s3c24xx_gpio_read_f
,
163 .write
= s3c24xx_gpio_write_f
,
164 .endianness
= DEVICE_NATIVE_ENDIAN
,
166 .min_access_size
= 1,
172 s3c24xx_gpio_irq_handler(void *opaque
, int n
, int level
)
174 S3C24xxGpioState
*s
= opaque
;
177 GPR(S3C_GPIO_EINT_PEND
) |= (1<<n
);
180 s3c24xx_gpio_propagate_eint(s
);
183 static void s3c24xx_gpio_realize(DeviceState
*dev
, Error
**errp
)
185 S3C24xxGpioState
*s
= S3C24XX_GPIO(dev
);
186 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
188 //~ qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
189 //~ sysbus_init_irq(dev, &s->parent_irq);
190 memory_region_init_io(&s
->mmio
, OBJECT(s
), &s3c24xx_gpio_ops
, s
,
191 "s3c24xx-gpio", S3C_GPIO_MAX
* 4);
192 sysbus_init_mmio(sbd
, &s
->mmio
);
194 TODO
: i
/o starting at base_addr
, S3C_GPIO_MAX
* 4 bytes
.
197 /* Set non zero default values. */
198 GPR(0x00) = 0x7fffff;
203 GPR(S3C_GPIO_EINT_MASK
) = 0xfffff0;
204 //~ GPR(S3C_GPIO_GSTATUS1) = cpu_id;
205 GPR(S3C_GPIO_GSTATUS2
) = 1;
206 GPR(S3C_GPIO_GSTATUS3
) = 0;
207 GPR(S3C_GPIO_GSTATUS4
) = 0;
211 s3c24xx_gpio_init(S3CState
*soc
, hwaddr base_addr
, uint32_t cpu_id
)
213 /* Samsung S3C24XX GPIO
215 * The primary operation here is the ID register and IRQs
219 S3C24xxGpioState
*s
= g_new0(S3C24xxGpioState
, 1);
221 /* TODO: Diese Funktion ist veraltet und soll ersetzt werden, s.o. */
223 /* Set non zero default values. */
224 GPR(0x00) = 0x7fffff;
229 GPR(S3C_GPIO_EINT_MASK
) = 0xfffff0;
230 GPR(S3C_GPIO_GSTATUS1
) = cpu_id
;
231 GPR(S3C_GPIO_GSTATUS2
) = 1;
232 GPR(S3C_GPIO_GSTATUS3
) = 0;
233 GPR(S3C_GPIO_GSTATUS4
) = 0;
235 /* obtain first level IRQs for cascade */
236 for (i
= 0; i
<= 5; i
++) {
237 s
->irqs
[i
] = s3c24xx_get_irq(soc
->irq
, i
);
240 /* EINTs 0-23 -- Only 24, not 48 because EINTs are not level */
241 s
->eirqs
= qemu_allocate_irqs(s3c24xx_gpio_irq_handler
, s
, 24);
246 /* get the qemu interrupt from an eirq number */
248 s3c24xx_get_eirq(S3C24xxGpioState
*s
, unsigned einum
)
251 return s
->eirqs
[einum
];
254 static const VMStateDescription s3c24xx_gpio_vmstate
= {
255 .name
= TYPE_S3C24XX_GPIO
,
257 .minimum_version_id
= 1,
258 .minimum_version_id_old
= 1,
259 .fields
= (VMStateField
[]) {
260 VMSTATE_UINT32_ARRAY(gpio_reg
, S3C24xxGpioState
, S3C_GPIO_MAX
),
261 VMSTATE_END_OF_LIST()
265 static Property s3c24xx_gpio_properties
[] = {
266 DEFINE_PROP_END_OF_LIST()
269 static void s3c24xx_gpio_class_init(ObjectClass
*klass
, void *data
)
271 DeviceClass
*dc
= DEVICE_CLASS(klass
);
272 dc
->props
= s3c24xx_gpio_properties
;
273 dc
->realize
= s3c24xx_gpio_realize
;
274 dc
->vmsd
= &s3c24xx_gpio_vmstate
;
277 static const TypeInfo s3c24xx_gpio_info
= {
278 .name
= TYPE_S3C24XX_GPIO
,
279 .parent
= TYPE_SYS_BUS_DEVICE
,
280 .instance_size
= sizeof(S3C24xxGpioState
),
281 .class_init
= s3c24xx_gpio_class_init
284 static void s3c24xx_register_types(void)
286 type_register_static(&s3c24xx_gpio_info
);
289 type_init(s3c24xx_register_types
)