Merge remote-tracking branch 'qemu/master'
[qemu/ar7.git] / hw / arm / s3c24xx_gpio.c
blobed4f9402c707265eb73366899f185c332ba7c636
1 /* hw/s3c24xx_gpio.c
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"
13 #include "cpu.h"
14 #include "hw/hw.h"
15 #include "hw/sysbus.h"
16 #include "s3c24xx.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 {
42 SysBusDevice busdev;
43 MemoryRegion mmio;
45 uint32_t gpio_reg[S3C_GPIO_MAX];
47 qemu_irq *eirqs; /* gpio external interrupts */
49 qemu_irq irqs[6]; /* cpu irqs to cascade */
52 static void
53 s3c24xx_gpio_propagate_eint(S3C24xxGpioState *s)
55 uint32_t ints, i;
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);
71 static uint32_t
72 gpio_con_to_mask(uint32_t con)
74 uint32_t mask = 0x0;
75 int bit;
77 for (bit = 0; bit < 16; bit++) {
78 if (((con >> (bit * 2)) & 0x3) == 0x01) {
79 mask |= 1 << bit;
83 return mask;
86 static void
87 s3c24xx_gpio_write_f(void *opaque, hwaddr addr_, uint64_t value,
88 unsigned size)
90 S3C24xxGpioState *s = opaque;
91 uint32_t addr = (addr_ >> 2);
93 assert(addr < S3C_GPIO_MAX);
95 assert(!(addr > 0x3f));
96 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;
104 } else {
105 if (addr < (0x80/4) && (addr_ & 0xf) == 0x04) {
106 uint32_t mask = gpio_con_to_mask(s->gpio_reg[addr - 1]);
108 value &= mask;
110 s->gpio_reg[addr] &= ~mask;
111 s->gpio_reg[addr] |= value;
112 } else {
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
120 * propagate
122 s3c24xx_gpio_propagate_eint(s);
126 static uint64_t
127 s3c24xx_gpio_read_f(void *opaque, hwaddr addr_, unsigned size)
129 S3C24xxGpioState *s = opaque;
130 uint32_t addr = (addr_ >> 2);
131 uint32_t ret;
133 assert(addr < S3C_GPIO_MAX);
135 assert(!(addr > 0x3f));
136 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
144 * clear.
146 if ((GPR(S3C_GPIO_GPECON) & (3<<28)) == 0) {
147 ret |= 1 << 14;
150 if ((GPR(S3C_GPIO_GPECON) & (3<<30)) == 0) {
151 ret |= 1 << 15;
155 return ret;
158 static const MemoryRegionOps s3c24xx_gpio_ops = {
159 .read = s3c24xx_gpio_read_f,
160 .write = s3c24xx_gpio_write_f,
161 .endianness = DEVICE_NATIVE_ENDIAN,
162 .valid = {
163 .min_access_size = 1,
164 .max_access_size = 4
168 static void
169 s3c24xx_gpio_irq_handler(void *opaque, int n, int level)
171 S3C24xxGpioState *s = opaque;
173 if (level) {
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);
190 #if 0
191 TODO: i/o starting at base_addr, S3C_GPIO_MAX * 4 bytes.
192 #endif
194 /* Set non zero default values. */
195 GPR(0x00) = 0x7fffff;
196 GPR(0x34) = 0xfefc;
197 GPR(0x38) = 0xf000;
198 GPR(0x68) = 0xf800;
199 GPR(0x80) = 0x10330;
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;
207 S3C24xxGpioState *
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
214 int i;
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;
222 GPR(0x34) = 0xfefc;
223 GPR(0x38) = 0xf000;
224 GPR(0x68) = 0xf800;
225 GPR(0x80) = 0x10330;
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);
240 return s;
243 /* get the qemu interrupt from an eirq number */
244 qemu_irq
245 s3c24xx_get_eirq(S3C24xxGpioState *s, unsigned einum)
247 assert(einum < 24);
248 return s->eirqs[einum];
251 static const VMStateDescription s3c24xx_gpio_vmstate = {
252 .name = TYPE_S3C24XX_GPIO,
253 .version_id = 1,
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)