xref: /qemu/hw/gpio/mpc8xxx.c (revision 228aa992fc5be408888c423b6a5b30daf18a96cf)
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