qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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"
     30 OBJECT_DECLARE_SIMPLE_TYPE(MPC8XXXGPIOState, MPC8XXX_GPIO)
     31 
     32 struct 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 
     47 static 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 
     62 static void mpc8xxx_gpio_update(MPC8XXXGPIOState *s)
     63 {
     64     qemu_set_irq(s->irq, !!(s->ier & s->imr));
     65 }
     66 
     67 static 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 
     95 static 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 
    116 static 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 
    150 static 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 
    162 static 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 
    183 static const MemoryRegionOps mpc8xxx_gpio_ops = {
    184     .read = mpc8xxx_gpio_read,
    185     .write = mpc8xxx_gpio_write,
    186     .endianness = DEVICE_BIG_ENDIAN,
    187 };
    188 
    189 static 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 
    203 static 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 
    211 static 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 
    219 static void mpc8xxx_gpio_register_types(void)
    220 {
    221     type_register_static(&mpc8xxx_gpio_info);
    222 }
    223 
    224 type_init(mpc8xxx_gpio_register_types)