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