1 /* 2 * TI OMAP processors GPIO emulation. 3 * 4 * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org> 5 * Copyright (C) 2007-2009 Nokia Corporation 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 or 10 * (at your option) version 3 of the License. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qemu/log.h" 23 #include "hw/irq.h" 24 #include "hw/qdev-properties.h" 25 #include "hw/arm/omap.h" 26 #include "hw/sysbus.h" 27 #include "qemu/error-report.h" 28 #include "qemu/module.h" 29 #include "qapi/error.h" 30 31 struct omap_gpio_s { 32 qemu_irq irq; 33 qemu_irq handler[16]; 34 35 uint16_t inputs; 36 uint16_t outputs; 37 uint16_t dir; 38 uint16_t edge; 39 uint16_t mask; 40 uint16_t ints; 41 uint16_t pins; 42 }; 43 44 struct Omap1GpioState { 45 SysBusDevice parent_obj; 46 47 MemoryRegion iomem; 48 int mpu_model; 49 void *clk; 50 struct omap_gpio_s omap1; 51 }; 52 53 /* General-Purpose I/O of OMAP1 */ 54 static void omap_gpio_set(void *opaque, int line, int level) 55 { 56 Omap1GpioState *p = opaque; 57 struct omap_gpio_s *s = &p->omap1; 58 uint16_t prev = s->inputs; 59 60 if (level) 61 s->inputs |= 1 << line; 62 else 63 s->inputs &= ~(1 << line); 64 65 if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) & 66 (1 << line) & s->dir & ~s->mask) { 67 s->ints |= 1 << line; 68 qemu_irq_raise(s->irq); 69 } 70 } 71 72 static uint64_t omap_gpio_read(void *opaque, hwaddr addr, 73 unsigned size) 74 { 75 struct omap_gpio_s *s = opaque; 76 int offset = addr & OMAP_MPUI_REG_MASK; 77 78 if (size != 2) { 79 return omap_badwidth_read16(opaque, addr); 80 } 81 82 switch (offset) { 83 case 0x00: /* DATA_INPUT */ 84 return s->inputs & s->pins; 85 86 case 0x04: /* DATA_OUTPUT */ 87 return s->outputs; 88 89 case 0x08: /* DIRECTION_CONTROL */ 90 return s->dir; 91 92 case 0x0c: /* INTERRUPT_CONTROL */ 93 return s->edge; 94 95 case 0x10: /* INTERRUPT_MASK */ 96 return s->mask; 97 98 case 0x14: /* INTERRUPT_STATUS */ 99 return s->ints; 100 101 case 0x18: /* PIN_CONTROL (not in OMAP310) */ 102 OMAP_BAD_REG(addr); 103 return s->pins; 104 } 105 106 OMAP_BAD_REG(addr); 107 return 0; 108 } 109 110 static void omap_gpio_write(void *opaque, hwaddr addr, 111 uint64_t value, unsigned size) 112 { 113 struct omap_gpio_s *s = opaque; 114 int offset = addr & OMAP_MPUI_REG_MASK; 115 uint16_t diff; 116 int ln; 117 118 if (size != 2) { 119 omap_badwidth_write16(opaque, addr, value); 120 return; 121 } 122 123 switch (offset) { 124 case 0x00: /* DATA_INPUT */ 125 OMAP_RO_REG(addr); 126 return; 127 128 case 0x04: /* DATA_OUTPUT */ 129 diff = (s->outputs ^ value) & ~s->dir; 130 s->outputs = value; 131 while ((ln = ctz32(diff)) != 32) { 132 if (s->handler[ln]) 133 qemu_set_irq(s->handler[ln], (value >> ln) & 1); 134 diff &= ~(1 << ln); 135 } 136 break; 137 138 case 0x08: /* DIRECTION_CONTROL */ 139 diff = s->outputs & (s->dir ^ value); 140 s->dir = value; 141 142 value = s->outputs & ~s->dir; 143 while ((ln = ctz32(diff)) != 32) { 144 if (s->handler[ln]) 145 qemu_set_irq(s->handler[ln], (value >> ln) & 1); 146 diff &= ~(1 << ln); 147 } 148 break; 149 150 case 0x0c: /* INTERRUPT_CONTROL */ 151 s->edge = value; 152 break; 153 154 case 0x10: /* INTERRUPT_MASK */ 155 s->mask = value; 156 break; 157 158 case 0x14: /* INTERRUPT_STATUS */ 159 s->ints &= ~value; 160 if (!s->ints) 161 qemu_irq_lower(s->irq); 162 break; 163 164 case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ 165 OMAP_BAD_REG(addr); 166 s->pins = value; 167 break; 168 169 default: 170 OMAP_BAD_REG(addr); 171 return; 172 } 173 } 174 175 /* *Some* sources say the memory region is 32-bit. */ 176 static const MemoryRegionOps omap_gpio_ops = { 177 .read = omap_gpio_read, 178 .write = omap_gpio_write, 179 .endianness = DEVICE_NATIVE_ENDIAN, 180 }; 181 182 static void omap_gpio_reset(struct omap_gpio_s *s) 183 { 184 s->inputs = 0; 185 s->outputs = ~0; 186 s->dir = ~0; 187 s->edge = ~0; 188 s->mask = ~0; 189 s->ints = 0; 190 s->pins = ~0; 191 } 192 193 static void omap_gpif_reset(DeviceState *dev) 194 { 195 Omap1GpioState *s = OMAP1_GPIO(dev); 196 197 omap_gpio_reset(&s->omap1); 198 } 199 200 static void omap_gpio_init(Object *obj) 201 { 202 DeviceState *dev = DEVICE(obj); 203 Omap1GpioState *s = OMAP1_GPIO(obj); 204 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 205 206 qdev_init_gpio_in(dev, omap_gpio_set, 16); 207 qdev_init_gpio_out(dev, s->omap1.handler, 16); 208 sysbus_init_irq(sbd, &s->omap1.irq); 209 memory_region_init_io(&s->iomem, obj, &omap_gpio_ops, &s->omap1, 210 "omap.gpio", 0x1000); 211 sysbus_init_mmio(sbd, &s->iomem); 212 } 213 214 static void omap_gpio_realize(DeviceState *dev, Error **errp) 215 { 216 Omap1GpioState *s = OMAP1_GPIO(dev); 217 218 if (!s->clk) { 219 error_setg(errp, "omap-gpio: clk not connected"); 220 } 221 } 222 223 void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk) 224 { 225 gpio->clk = clk; 226 } 227 228 static Property omap_gpio_properties[] = { 229 DEFINE_PROP_INT32("mpu_model", Omap1GpioState, mpu_model, 0), 230 DEFINE_PROP_END_OF_LIST(), 231 }; 232 233 static void omap_gpio_class_init(ObjectClass *klass, void *data) 234 { 235 DeviceClass *dc = DEVICE_CLASS(klass); 236 237 dc->realize = omap_gpio_realize; 238 device_class_set_legacy_reset(dc, omap_gpif_reset); 239 device_class_set_props(dc, omap_gpio_properties); 240 /* Reason: pointer property "clk" */ 241 dc->user_creatable = false; 242 } 243 244 static const TypeInfo omap_gpio_info = { 245 .name = TYPE_OMAP1_GPIO, 246 .parent = TYPE_SYS_BUS_DEVICE, 247 .instance_size = sizeof(Omap1GpioState), 248 .instance_init = omap_gpio_init, 249 .class_init = omap_gpio_class_init, 250 }; 251 252 static void omap_gpio_register_types(void) 253 { 254 type_register_static(&omap_gpio_info); 255 } 256 257 type_init(omap_gpio_register_types) 258