1 | /* |
2 | * GPIO device simulation in PKUnity SoC |
3 | * |
4 | * Copyright (C) 2010-2012 Guan Xuetao |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation, or any later version. |
9 | * See the COPYING file in the top-level directory. |
10 | */ |
11 | |
12 | #include "qemu/osdep.h" |
13 | #include "hw/sysbus.h" |
14 | |
15 | #undef DEBUG_PUV3 |
16 | #include "hw/unicore32/puv3.h" |
17 | #include "qemu/module.h" |
18 | |
19 | #define TYPE_PUV3_GPIO "puv3_gpio" |
20 | #define PUV3_GPIO(obj) OBJECT_CHECK(PUV3GPIOState, (obj), TYPE_PUV3_GPIO) |
21 | |
22 | typedef struct PUV3GPIOState { |
23 | SysBusDevice parent_obj; |
24 | |
25 | MemoryRegion iomem; |
26 | qemu_irq irq[9]; |
27 | |
28 | uint32_t reg_GPLR; |
29 | uint32_t reg_GPDR; |
30 | uint32_t reg_GPIR; |
31 | } PUV3GPIOState; |
32 | |
33 | static uint64_t puv3_gpio_read(void *opaque, hwaddr offset, |
34 | unsigned size) |
35 | { |
36 | PUV3GPIOState *s = opaque; |
37 | uint32_t ret = 0; |
38 | |
39 | switch (offset) { |
40 | case 0x00: |
41 | ret = s->reg_GPLR; |
42 | break; |
43 | case 0x04: |
44 | ret = s->reg_GPDR; |
45 | break; |
46 | case 0x20: |
47 | ret = s->reg_GPIR; |
48 | break; |
49 | default: |
50 | DPRINTF("Bad offset 0x%x\n" , offset); |
51 | } |
52 | DPRINTF("offset 0x%x, value 0x%x\n" , offset, ret); |
53 | |
54 | return ret; |
55 | } |
56 | |
57 | static void puv3_gpio_write(void *opaque, hwaddr offset, |
58 | uint64_t value, unsigned size) |
59 | { |
60 | PUV3GPIOState *s = opaque; |
61 | |
62 | DPRINTF("offset 0x%x, value 0x%x\n" , offset, value); |
63 | switch (offset) { |
64 | case 0x04: |
65 | s->reg_GPDR = value; |
66 | break; |
67 | case 0x08: |
68 | if (s->reg_GPDR & value) { |
69 | s->reg_GPLR |= value; |
70 | } else { |
71 | DPRINTF("Write gpio input port error!" ); |
72 | } |
73 | break; |
74 | case 0x0c: |
75 | if (s->reg_GPDR & value) { |
76 | s->reg_GPLR &= ~value; |
77 | } else { |
78 | DPRINTF("Write gpio input port error!" ); |
79 | } |
80 | break; |
81 | case 0x10: /* GRER */ |
82 | case 0x14: /* GFER */ |
83 | case 0x18: /* GEDR */ |
84 | break; |
85 | case 0x20: /* GPIR */ |
86 | s->reg_GPIR = value; |
87 | break; |
88 | default: |
89 | DPRINTF("Bad offset 0x%x\n" , offset); |
90 | } |
91 | } |
92 | |
93 | static const MemoryRegionOps puv3_gpio_ops = { |
94 | .read = puv3_gpio_read, |
95 | .write = puv3_gpio_write, |
96 | .impl = { |
97 | .min_access_size = 4, |
98 | .max_access_size = 4, |
99 | }, |
100 | .endianness = DEVICE_NATIVE_ENDIAN, |
101 | }; |
102 | |
103 | static void puv3_gpio_realize(DeviceState *dev, Error **errp) |
104 | { |
105 | PUV3GPIOState *s = PUV3_GPIO(dev); |
106 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); |
107 | |
108 | s->reg_GPLR = 0; |
109 | s->reg_GPDR = 0; |
110 | |
111 | /* FIXME: these irqs not handled yet */ |
112 | sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW0]); |
113 | sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW1]); |
114 | sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW2]); |
115 | sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW3]); |
116 | sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW4]); |
117 | sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW5]); |
118 | sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW6]); |
119 | sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW7]); |
120 | sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOHIGH]); |
121 | |
122 | memory_region_init_io(&s->iomem, OBJECT(s), &puv3_gpio_ops, s, "puv3_gpio" , |
123 | PUV3_REGS_OFFSET); |
124 | sysbus_init_mmio(sbd, &s->iomem); |
125 | } |
126 | |
127 | static void puv3_gpio_class_init(ObjectClass *klass, void *data) |
128 | { |
129 | DeviceClass *dc = DEVICE_CLASS(klass); |
130 | |
131 | dc->realize = puv3_gpio_realize; |
132 | } |
133 | |
134 | static const TypeInfo puv3_gpio_info = { |
135 | .name = TYPE_PUV3_GPIO, |
136 | .parent = TYPE_SYS_BUS_DEVICE, |
137 | .instance_size = sizeof(PUV3GPIOState), |
138 | .class_init = puv3_gpio_class_init, |
139 | }; |
140 | |
141 | static void puv3_gpio_register_type(void) |
142 | { |
143 | type_register_static(&puv3_gpio_info); |
144 | } |
145 | |
146 | type_init(puv3_gpio_register_type) |
147 | |