mpc8xxx.c (5651B)
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.1 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" 30OBJECT_DECLARE_SIMPLE_TYPE(MPC8XXXGPIOState, MPC8XXX_GPIO) 31 32struct MPC8XXXGPIOState { 33 SysBusDevice parent_obj; 34 35 MemoryRegion iomem; 36 qemu_irq irq; 37 qemu_irq out[32]; 38 39 uint32_t dir; 40 uint32_t odr; 41 uint32_t dat; 42 uint32_t ier; 43 uint32_t imr; 44 uint32_t icr; 45}; 46 47static const VMStateDescription vmstate_mpc8xxx_gpio = { 48 .name = "mpc8xxx_gpio", 49 .version_id = 1, 50 .minimum_version_id = 1, 51 .fields = (VMStateField[]) { 52 VMSTATE_UINT32(dir, MPC8XXXGPIOState), 53 VMSTATE_UINT32(odr, MPC8XXXGPIOState), 54 VMSTATE_UINT32(dat, MPC8XXXGPIOState), 55 VMSTATE_UINT32(ier, MPC8XXXGPIOState), 56 VMSTATE_UINT32(imr, MPC8XXXGPIOState), 57 VMSTATE_UINT32(icr, MPC8XXXGPIOState), 58 VMSTATE_END_OF_LIST() 59 } 60}; 61 62static void mpc8xxx_gpio_update(MPC8XXXGPIOState *s) 63{ 64 qemu_set_irq(s->irq, !!(s->ier & s->imr)); 65} 66 67static uint64_t mpc8xxx_gpio_read(void *opaque, hwaddr offset, 68 unsigned size) 69{ 70 MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque; 71 72 if (size != 4) { 73 /* All registers are 32bit */ 74 return 0; 75 } 76 77 switch (offset) { 78 case 0x0: /* Direction */ 79 return s->dir; 80 case 0x4: /* Open Drain */ 81 return s->odr; 82 case 0x8: /* Data */ 83 return s->dat; 84 case 0xC: /* Interrupt Event */ 85 return s->ier; 86 case 0x10: /* Interrupt Mask */ 87 return s->imr; 88 case 0x14: /* Interrupt Control */ 89 return s->icr; 90 default: 91 return 0; 92 } 93} 94 95static void mpc8xxx_write_data(MPC8XXXGPIOState *s, uint32_t new_data) 96{ 97 uint32_t old_data = s->dat; 98 uint32_t diff = old_data ^ new_data; 99 int i; 100 101 for (i = 0; i < 32; i++) { 102 uint32_t mask = 0x80000000 >> i; 103 if (!(diff & mask)) { 104 continue; 105 } 106 107 if (s->dir & mask) { 108 /* Output */ 109 qemu_set_irq(s->out[i], (new_data & mask) != 0); 110 } 111 } 112 113 s->dat = new_data; 114} 115 116static void mpc8xxx_gpio_write(void *opaque, hwaddr offset, 117 uint64_t value, unsigned size) 118{ 119 MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque; 120 121 if (size != 4) { 122 /* All registers are 32bit */ 123 return; 124 } 125 126 switch (offset) { 127 case 0x0: /* Direction */ 128 s->dir = value; 129 break; 130 case 0x4: /* Open Drain */ 131 s->odr = value; 132 break; 133 case 0x8: /* Data */ 134 mpc8xxx_write_data(s, value); 135 break; 136 case 0xC: /* Interrupt Event */ 137 s->ier &= ~value; 138 break; 139 case 0x10: /* Interrupt Mask */ 140 s->imr = value; 141 break; 142 case 0x14: /* Interrupt Control */ 143 s->icr = value; 144 break; 145 } 146 147 mpc8xxx_gpio_update(s); 148} 149 150static void mpc8xxx_gpio_reset(DeviceState *dev) 151{ 152 MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev); 153 154 s->dir = 0; 155 s->odr = 0; 156 s->dat = 0; 157 s->ier = 0; 158 s->imr = 0; 159 s->icr = 0; 160} 161 162static void mpc8xxx_gpio_set_irq(void * opaque, int irq, int level) 163{ 164 MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque; 165 uint32_t mask; 166 167 mask = 0x80000000 >> irq; 168 if ((s->dir & mask) == 0) { 169 uint32_t old_value = s->dat & mask; 170 171 s->dat &= ~mask; 172 if (level) 173 s->dat |= mask; 174 175 if (!(s->icr & irq) || (old_value && !level)) { 176 s->ier |= mask; 177 } 178 179 mpc8xxx_gpio_update(s); 180 } 181} 182 183static const MemoryRegionOps mpc8xxx_gpio_ops = { 184 .read = mpc8xxx_gpio_read, 185 .write = mpc8xxx_gpio_write, 186 .endianness = DEVICE_BIG_ENDIAN, 187}; 188 189static void mpc8xxx_gpio_initfn(Object *obj) 190{ 191 DeviceState *dev = DEVICE(obj); 192 MPC8XXXGPIOState *s = MPC8XXX_GPIO(obj); 193 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 194 195 memory_region_init_io(&s->iomem, obj, &mpc8xxx_gpio_ops, 196 s, "mpc8xxx_gpio", 0x1000); 197 sysbus_init_mmio(sbd, &s->iomem); 198 sysbus_init_irq(sbd, &s->irq); 199 qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32); 200 qdev_init_gpio_out(dev, s->out, 32); 201} 202 203static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data) 204{ 205 DeviceClass *dc = DEVICE_CLASS(klass); 206 207 dc->vmsd = &vmstate_mpc8xxx_gpio; 208 dc->reset = mpc8xxx_gpio_reset; 209} 210 211static const TypeInfo mpc8xxx_gpio_info = { 212 .name = TYPE_MPC8XXX_GPIO, 213 .parent = TYPE_SYS_BUS_DEVICE, 214 .instance_size = sizeof(MPC8XXXGPIOState), 215 .instance_init = mpc8xxx_gpio_initfn, 216 .class_init = mpc8xxx_gpio_class_init, 217}; 218 219static void mpc8xxx_gpio_register_types(void) 220{ 221 type_register_static(&mpc8xxx_gpio_info); 222} 223 224type_init(mpc8xxx_gpio_register_types)