1 /* 2 * GPIO Controller for a lot of Freescale SoCs 3 * 4 * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved. 5 * 6 * Author: Alexander Graf, <agraf@suse.de> 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #include "qemu/osdep.h" 23 #include "hw/irq.h" 24 #include "hw/sysbus.h" 25 #include "migration/vmstate.h" 26 #include "qemu/module.h" 27 #include "qom/object.h" 28 29 #define TYPE_MPC8XXX_GPIO "mpc8xxx_gpio" 30 typedef struct MPC8XXXGPIOState MPC8XXXGPIOState; 31 DECLARE_INSTANCE_CHECKER(MPC8XXXGPIOState, MPC8XXX_GPIO, 32 TYPE_MPC8XXX_GPIO) 33 34 struct MPC8XXXGPIOState { 35 SysBusDevice parent_obj; 36 37 MemoryRegion iomem; 38 qemu_irq irq; 39 qemu_irq out[32]; 40 41 uint32_t dir; 42 uint32_t odr; 43 uint32_t dat; 44 uint32_t ier; 45 uint32_t imr; 46 uint32_t icr; 47 }; 48 49 static const VMStateDescription vmstate_mpc8xxx_gpio = { 50 .name = "mpc8xxx_gpio", 51 .version_id = 1, 52 .minimum_version_id = 1, 53 .fields = (VMStateField[]) { 54 VMSTATE_UINT32(dir, MPC8XXXGPIOState), 55 VMSTATE_UINT32(odr, MPC8XXXGPIOState), 56 VMSTATE_UINT32(dat, MPC8XXXGPIOState), 57 VMSTATE_UINT32(ier, MPC8XXXGPIOState), 58 VMSTATE_UINT32(imr, MPC8XXXGPIOState), 59 VMSTATE_UINT32(icr, MPC8XXXGPIOState), 60 VMSTATE_END_OF_LIST() 61 } 62 }; 63 64 static void mpc8xxx_gpio_update(MPC8XXXGPIOState *s) 65 { 66 qemu_set_irq(s->irq, !!(s->ier & s->imr)); 67 } 68 69 static uint64_t mpc8xxx_gpio_read(void *opaque, hwaddr offset, 70 unsigned size) 71 { 72 MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque; 73 74 if (size != 4) { 75 /* All registers are 32bit */ 76 return 0; 77 } 78 79 switch (offset) { 80 case 0x0: /* Direction */ 81 return s->dir; 82 case 0x4: /* Open Drain */ 83 return s->odr; 84 case 0x8: /* Data */ 85 return s->dat; 86 case 0xC: /* Interrupt Event */ 87 return s->ier; 88 case 0x10: /* Interrupt Mask */ 89 return s->imr; 90 case 0x14: /* Interrupt Control */ 91 return s->icr; 92 default: 93 return 0; 94 } 95 } 96 97 static void mpc8xxx_write_data(MPC8XXXGPIOState *s, uint32_t new_data) 98 { 99 uint32_t old_data = s->dat; 100 uint32_t diff = old_data ^ new_data; 101 int i; 102 103 for (i = 0; i < 32; i++) { 104 uint32_t mask = 0x80000000 >> i; 105 if (!(diff & mask)) { 106 continue; 107 } 108 109 if (s->dir & mask) { 110 /* Output */ 111 qemu_set_irq(s->out[i], (new_data & mask) != 0); 112 } 113 } 114 115 s->dat = new_data; 116 } 117 118 static void mpc8xxx_gpio_write(void *opaque, hwaddr offset, 119 uint64_t value, unsigned size) 120 { 121 MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque; 122 123 if (size != 4) { 124 /* All registers are 32bit */ 125 return; 126 } 127 128 switch (offset) { 129 case 0x0: /* Direction */ 130 s->dir = value; 131 break; 132 case 0x4: /* Open Drain */ 133 s->odr = value; 134 break; 135 case 0x8: /* Data */ 136 mpc8xxx_write_data(s, value); 137 break; 138 case 0xC: /* Interrupt Event */ 139 s->ier &= ~value; 140 break; 141 case 0x10: /* Interrupt Mask */ 142 s->imr = value; 143 break; 144 case 0x14: /* Interrupt Control */ 145 s->icr = value; 146 break; 147 } 148 149 mpc8xxx_gpio_update(s); 150 } 151 152 static void mpc8xxx_gpio_reset(DeviceState *dev) 153 { 154 MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev); 155 156 s->dir = 0; 157 s->odr = 0; 158 s->dat = 0; 159 s->ier = 0; 160 s->imr = 0; 161 s->icr = 0; 162 } 163 164 static void mpc8xxx_gpio_set_irq(void * opaque, int irq, int level) 165 { 166 MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque; 167 uint32_t mask; 168 169 mask = 0x80000000 >> irq; 170 if ((s->dir & mask) == 0) { 171 uint32_t old_value = s->dat & mask; 172 173 s->dat &= ~mask; 174 if (level) 175 s->dat |= mask; 176 177 if (!(s->icr & irq) || (old_value && !level)) { 178 s->ier |= mask; 179 } 180 181 mpc8xxx_gpio_update(s); 182 } 183 } 184 185 static const MemoryRegionOps mpc8xxx_gpio_ops = { 186 .read = mpc8xxx_gpio_read, 187 .write = mpc8xxx_gpio_write, 188 .endianness = DEVICE_BIG_ENDIAN, 189 }; 190 191 static void mpc8xxx_gpio_initfn(Object *obj) 192 { 193 DeviceState *dev = DEVICE(obj); 194 MPC8XXXGPIOState *s = MPC8XXX_GPIO(obj); 195 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 196 197 memory_region_init_io(&s->iomem, obj, &mpc8xxx_gpio_ops, 198 s, "mpc8xxx_gpio", 0x1000); 199 sysbus_init_mmio(sbd, &s->iomem); 200 sysbus_init_irq(sbd, &s->irq); 201 qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32); 202 qdev_init_gpio_out(dev, s->out, 32); 203 } 204 205 static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data) 206 { 207 DeviceClass *dc = DEVICE_CLASS(klass); 208 209 dc->vmsd = &vmstate_mpc8xxx_gpio; 210 dc->reset = mpc8xxx_gpio_reset; 211 } 212 213 static const TypeInfo mpc8xxx_gpio_info = { 214 .name = TYPE_MPC8XXX_GPIO, 215 .parent = TYPE_SYS_BUS_DEVICE, 216 .instance_size = sizeof(MPC8XXXGPIOState), 217 .instance_init = mpc8xxx_gpio_initfn, 218 .class_init = mpc8xxx_gpio_class_init, 219 }; 220 221 static void mpc8xxx_gpio_register_types(void) 222 { 223 type_register_static(&mpc8xxx_gpio_info); 224 } 225 226 type_init(mpc8xxx_gpio_register_types) 227