1e28bee8eSPaolo Bonzini /*
2e28bee8eSPaolo Bonzini * PXA270-based Intel Mainstone platforms.
3e28bee8eSPaolo Bonzini * FPGA driver
4e28bee8eSPaolo Bonzini *
5e28bee8eSPaolo Bonzini * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
6e28bee8eSPaolo Bonzini * <akuster@mvista.com>
7e28bee8eSPaolo Bonzini *
8e28bee8eSPaolo Bonzini * This code is licensed under the GNU GPL v2.
9e28bee8eSPaolo Bonzini *
10e28bee8eSPaolo Bonzini * Contributions after 2012-01-13 are licensed under the terms of the
11e28bee8eSPaolo Bonzini * GNU GPL, version 2 or (at your option) any later version.
12e28bee8eSPaolo Bonzini */
130b8fa32fSMarkus Armbruster
140d1c9782SPeter Maydell #include "qemu/osdep.h"
1564552b6bSMarkus Armbruster #include "hw/irq.h"
16e28bee8eSPaolo Bonzini #include "hw/sysbus.h"
17d6454270SMarkus Armbruster #include "migration/vmstate.h"
180b8fa32fSMarkus Armbruster #include "qemu/module.h"
19db1015e9SEduardo Habkost #include "qom/object.h"
20e28bee8eSPaolo Bonzini
21e28bee8eSPaolo Bonzini /* Mainstone FPGA for extern irqs */
22e28bee8eSPaolo Bonzini #define FPGA_GPIO_PIN 0
23e28bee8eSPaolo Bonzini #define MST_NUM_IRQS 16
24e28bee8eSPaolo Bonzini #define MST_LEDDAT1 0x10
25e28bee8eSPaolo Bonzini #define MST_LEDDAT2 0x14
26e28bee8eSPaolo Bonzini #define MST_LEDCTRL 0x40
27e28bee8eSPaolo Bonzini #define MST_GPSWR 0x60
28e28bee8eSPaolo Bonzini #define MST_MSCWR1 0x80
29e28bee8eSPaolo Bonzini #define MST_MSCWR2 0x84
30e28bee8eSPaolo Bonzini #define MST_MSCWR3 0x88
31e28bee8eSPaolo Bonzini #define MST_MSCRD 0x90
32e28bee8eSPaolo Bonzini #define MST_INTMSKENA 0xc0
33e28bee8eSPaolo Bonzini #define MST_INTSETCLR 0xd0
34e28bee8eSPaolo Bonzini #define MST_PCMCIA0 0xe0
35e28bee8eSPaolo Bonzini #define MST_PCMCIA1 0xe4
36e28bee8eSPaolo Bonzini
37e28bee8eSPaolo Bonzini #define MST_PCMCIAx_READY (1 << 10)
38e28bee8eSPaolo Bonzini #define MST_PCMCIAx_nCD (1 << 5)
39e28bee8eSPaolo Bonzini
40e28bee8eSPaolo Bonzini #define MST_PCMCIA_CD0_IRQ 9
41e28bee8eSPaolo Bonzini #define MST_PCMCIA_CD1_IRQ 13
42e28bee8eSPaolo Bonzini
435c0e12f5SAndreas Färber #define TYPE_MAINSTONE_FPGA "mainstone-fpga"
448063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(mst_irq_state, MAINSTONE_FPGA)
455c0e12f5SAndreas Färber
46db1015e9SEduardo Habkost struct mst_irq_state {
475c0e12f5SAndreas Färber SysBusDevice parent_obj;
485c0e12f5SAndreas Färber
49e28bee8eSPaolo Bonzini MemoryRegion iomem;
50e28bee8eSPaolo Bonzini
51e28bee8eSPaolo Bonzini qemu_irq parent;
52e28bee8eSPaolo Bonzini
53e28bee8eSPaolo Bonzini uint32_t prev_level;
54e28bee8eSPaolo Bonzini uint32_t leddat1;
55e28bee8eSPaolo Bonzini uint32_t leddat2;
56e28bee8eSPaolo Bonzini uint32_t ledctrl;
57e28bee8eSPaolo Bonzini uint32_t gpswr;
58e28bee8eSPaolo Bonzini uint32_t mscwr1;
59e28bee8eSPaolo Bonzini uint32_t mscwr2;
60e28bee8eSPaolo Bonzini uint32_t mscwr3;
61e28bee8eSPaolo Bonzini uint32_t mscrd;
62e28bee8eSPaolo Bonzini uint32_t intmskena;
63e28bee8eSPaolo Bonzini uint32_t intsetclr;
64e28bee8eSPaolo Bonzini uint32_t pcmcia0;
65e28bee8eSPaolo Bonzini uint32_t pcmcia1;
66db1015e9SEduardo Habkost };
67e28bee8eSPaolo Bonzini
68e28bee8eSPaolo Bonzini static void
mst_fpga_set_irq(void * opaque,int irq,int level)69e28bee8eSPaolo Bonzini mst_fpga_set_irq(void *opaque, int irq, int level)
70e28bee8eSPaolo Bonzini {
71e28bee8eSPaolo Bonzini mst_irq_state *s = (mst_irq_state *)opaque;
72e28bee8eSPaolo Bonzini uint32_t oldint = s->intsetclr & s->intmskena;
73e28bee8eSPaolo Bonzini
74e28bee8eSPaolo Bonzini if (level)
75e28bee8eSPaolo Bonzini s->prev_level |= 1u << irq;
76e28bee8eSPaolo Bonzini else
77e28bee8eSPaolo Bonzini s->prev_level &= ~(1u << irq);
78e28bee8eSPaolo Bonzini
79e28bee8eSPaolo Bonzini switch(irq) {
80e28bee8eSPaolo Bonzini case MST_PCMCIA_CD0_IRQ:
81e28bee8eSPaolo Bonzini if (level)
82e28bee8eSPaolo Bonzini s->pcmcia0 &= ~MST_PCMCIAx_nCD;
83e28bee8eSPaolo Bonzini else
84e28bee8eSPaolo Bonzini s->pcmcia0 |= MST_PCMCIAx_nCD;
85e28bee8eSPaolo Bonzini break;
86e28bee8eSPaolo Bonzini case MST_PCMCIA_CD1_IRQ:
87e28bee8eSPaolo Bonzini if (level)
88e28bee8eSPaolo Bonzini s->pcmcia1 &= ~MST_PCMCIAx_nCD;
89e28bee8eSPaolo Bonzini else
90e28bee8eSPaolo Bonzini s->pcmcia1 |= MST_PCMCIAx_nCD;
91e28bee8eSPaolo Bonzini break;
92e28bee8eSPaolo Bonzini }
93e28bee8eSPaolo Bonzini
94e28bee8eSPaolo Bonzini if ((s->intmskena & (1u << irq)) && level)
95e28bee8eSPaolo Bonzini s->intsetclr |= 1u << irq;
96e28bee8eSPaolo Bonzini
97e28bee8eSPaolo Bonzini if (oldint != (s->intsetclr & s->intmskena))
98e28bee8eSPaolo Bonzini qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
99e28bee8eSPaolo Bonzini }
100e28bee8eSPaolo Bonzini
101e28bee8eSPaolo Bonzini
102e28bee8eSPaolo Bonzini static uint64_t
mst_fpga_readb(void * opaque,hwaddr addr,unsigned size)103e28bee8eSPaolo Bonzini mst_fpga_readb(void *opaque, hwaddr addr, unsigned size)
104e28bee8eSPaolo Bonzini {
105e28bee8eSPaolo Bonzini mst_irq_state *s = (mst_irq_state *) opaque;
106e28bee8eSPaolo Bonzini
107e28bee8eSPaolo Bonzini switch (addr) {
108e28bee8eSPaolo Bonzini case MST_LEDDAT1:
109e28bee8eSPaolo Bonzini return s->leddat1;
110e28bee8eSPaolo Bonzini case MST_LEDDAT2:
111e28bee8eSPaolo Bonzini return s->leddat2;
112e28bee8eSPaolo Bonzini case MST_LEDCTRL:
113e28bee8eSPaolo Bonzini return s->ledctrl;
114e28bee8eSPaolo Bonzini case MST_GPSWR:
115e28bee8eSPaolo Bonzini return s->gpswr;
116e28bee8eSPaolo Bonzini case MST_MSCWR1:
117e28bee8eSPaolo Bonzini return s->mscwr1;
118e28bee8eSPaolo Bonzini case MST_MSCWR2:
119e28bee8eSPaolo Bonzini return s->mscwr2;
120e28bee8eSPaolo Bonzini case MST_MSCWR3:
121e28bee8eSPaolo Bonzini return s->mscwr3;
122e28bee8eSPaolo Bonzini case MST_MSCRD:
123e28bee8eSPaolo Bonzini return s->mscrd;
124e28bee8eSPaolo Bonzini case MST_INTMSKENA:
125e28bee8eSPaolo Bonzini return s->intmskena;
126e28bee8eSPaolo Bonzini case MST_INTSETCLR:
127e28bee8eSPaolo Bonzini return s->intsetclr;
128e28bee8eSPaolo Bonzini case MST_PCMCIA0:
129e28bee8eSPaolo Bonzini return s->pcmcia0;
130e28bee8eSPaolo Bonzini case MST_PCMCIA1:
131e28bee8eSPaolo Bonzini return s->pcmcia1;
132e28bee8eSPaolo Bonzini default:
133e28bee8eSPaolo Bonzini printf("Mainstone - mst_fpga_readb: Bad register offset "
134883f2c59SPhilippe Mathieu-Daudé "0x" HWADDR_FMT_plx "\n", addr);
135e28bee8eSPaolo Bonzini }
136e28bee8eSPaolo Bonzini return 0;
137e28bee8eSPaolo Bonzini }
138e28bee8eSPaolo Bonzini
139e28bee8eSPaolo Bonzini static void
mst_fpga_writeb(void * opaque,hwaddr addr,uint64_t value,unsigned size)140e28bee8eSPaolo Bonzini mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
141e28bee8eSPaolo Bonzini unsigned size)
142e28bee8eSPaolo Bonzini {
143e28bee8eSPaolo Bonzini mst_irq_state *s = (mst_irq_state *) opaque;
144e28bee8eSPaolo Bonzini value &= 0xffffffff;
145e28bee8eSPaolo Bonzini
146e28bee8eSPaolo Bonzini switch (addr) {
147e28bee8eSPaolo Bonzini case MST_LEDDAT1:
148e28bee8eSPaolo Bonzini s->leddat1 = value;
149e28bee8eSPaolo Bonzini break;
150e28bee8eSPaolo Bonzini case MST_LEDDAT2:
151e28bee8eSPaolo Bonzini s->leddat2 = value;
152e28bee8eSPaolo Bonzini break;
153e28bee8eSPaolo Bonzini case MST_LEDCTRL:
154e28bee8eSPaolo Bonzini s->ledctrl = value;
155e28bee8eSPaolo Bonzini break;
156e28bee8eSPaolo Bonzini case MST_GPSWR:
157e28bee8eSPaolo Bonzini s->gpswr = value;
158e28bee8eSPaolo Bonzini break;
159e28bee8eSPaolo Bonzini case MST_MSCWR1:
160e28bee8eSPaolo Bonzini s->mscwr1 = value;
161e28bee8eSPaolo Bonzini break;
162e28bee8eSPaolo Bonzini case MST_MSCWR2:
163e28bee8eSPaolo Bonzini s->mscwr2 = value;
164e28bee8eSPaolo Bonzini break;
165e28bee8eSPaolo Bonzini case MST_MSCWR3:
166e28bee8eSPaolo Bonzini s->mscwr3 = value;
167e28bee8eSPaolo Bonzini break;
168e28bee8eSPaolo Bonzini case MST_MSCRD:
169e28bee8eSPaolo Bonzini s->mscrd = value;
170e28bee8eSPaolo Bonzini break;
171e28bee8eSPaolo Bonzini case MST_INTMSKENA: /* Mask interrupt */
172e28bee8eSPaolo Bonzini s->intmskena = (value & 0xFEEFF);
173e28bee8eSPaolo Bonzini qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
174e28bee8eSPaolo Bonzini break;
175e28bee8eSPaolo Bonzini case MST_INTSETCLR: /* clear or set interrupt */
176e28bee8eSPaolo Bonzini s->intsetclr = (value & 0xFEEFF);
177e28bee8eSPaolo Bonzini qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
178e28bee8eSPaolo Bonzini break;
179e28bee8eSPaolo Bonzini /* For PCMCIAx allow the to change only power and reset */
180e28bee8eSPaolo Bonzini case MST_PCMCIA0:
181e28bee8eSPaolo Bonzini s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f);
182e28bee8eSPaolo Bonzini break;
183e28bee8eSPaolo Bonzini case MST_PCMCIA1:
184e28bee8eSPaolo Bonzini s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f);
185e28bee8eSPaolo Bonzini break;
186e28bee8eSPaolo Bonzini default:
187e28bee8eSPaolo Bonzini printf("Mainstone - mst_fpga_writeb: Bad register offset "
188883f2c59SPhilippe Mathieu-Daudé "0x" HWADDR_FMT_plx "\n", addr);
189e28bee8eSPaolo Bonzini }
190e28bee8eSPaolo Bonzini }
191e28bee8eSPaolo Bonzini
192e28bee8eSPaolo Bonzini static const MemoryRegionOps mst_fpga_ops = {
193e28bee8eSPaolo Bonzini .read = mst_fpga_readb,
194e28bee8eSPaolo Bonzini .write = mst_fpga_writeb,
195e28bee8eSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
196e28bee8eSPaolo Bonzini };
197e28bee8eSPaolo Bonzini
mst_fpga_post_load(void * opaque,int version_id)198e28bee8eSPaolo Bonzini static int mst_fpga_post_load(void *opaque, int version_id)
199e28bee8eSPaolo Bonzini {
200e28bee8eSPaolo Bonzini mst_irq_state *s = (mst_irq_state *) opaque;
201e28bee8eSPaolo Bonzini
202e28bee8eSPaolo Bonzini qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
203e28bee8eSPaolo Bonzini return 0;
204e28bee8eSPaolo Bonzini }
205e28bee8eSPaolo Bonzini
mst_fpga_init(Object * obj)206e2d4f17eSxiaoqiang zhao static void mst_fpga_init(Object *obj)
207e28bee8eSPaolo Bonzini {
208e2d4f17eSxiaoqiang zhao DeviceState *dev = DEVICE(obj);
209e2d4f17eSxiaoqiang zhao mst_irq_state *s = MAINSTONE_FPGA(obj);
210e2d4f17eSxiaoqiang zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
211e28bee8eSPaolo Bonzini
212e28bee8eSPaolo Bonzini s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
213e28bee8eSPaolo Bonzini s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
214e28bee8eSPaolo Bonzini
2155c0e12f5SAndreas Färber sysbus_init_irq(sbd, &s->parent);
216e28bee8eSPaolo Bonzini
217e28bee8eSPaolo Bonzini /* alloc the external 16 irqs */
2185c0e12f5SAndreas Färber qdev_init_gpio_in(dev, mst_fpga_set_irq, MST_NUM_IRQS);
219e28bee8eSPaolo Bonzini
220e2d4f17eSxiaoqiang zhao memory_region_init_io(&s->iomem, obj, &mst_fpga_ops, s,
221e28bee8eSPaolo Bonzini "fpga", 0x00100000);
2225c0e12f5SAndreas Färber sysbus_init_mmio(sbd, &s->iomem);
223e28bee8eSPaolo Bonzini }
224e28bee8eSPaolo Bonzini
225cfa52e09SPhilippe Mathieu-Daudé static const VMStateDescription vmstate_mst_fpga_regs = {
226e28bee8eSPaolo Bonzini .name = "mainstone_fpga",
227e28bee8eSPaolo Bonzini .version_id = 0,
228e28bee8eSPaolo Bonzini .minimum_version_id = 0,
229e28bee8eSPaolo Bonzini .post_load = mst_fpga_post_load,
230*e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
231e28bee8eSPaolo Bonzini VMSTATE_UINT32(prev_level, mst_irq_state),
232e28bee8eSPaolo Bonzini VMSTATE_UINT32(leddat1, mst_irq_state),
233e28bee8eSPaolo Bonzini VMSTATE_UINT32(leddat2, mst_irq_state),
234e28bee8eSPaolo Bonzini VMSTATE_UINT32(ledctrl, mst_irq_state),
235e28bee8eSPaolo Bonzini VMSTATE_UINT32(gpswr, mst_irq_state),
236e28bee8eSPaolo Bonzini VMSTATE_UINT32(mscwr1, mst_irq_state),
237e28bee8eSPaolo Bonzini VMSTATE_UINT32(mscwr2, mst_irq_state),
238e28bee8eSPaolo Bonzini VMSTATE_UINT32(mscwr3, mst_irq_state),
239e28bee8eSPaolo Bonzini VMSTATE_UINT32(mscrd, mst_irq_state),
240e28bee8eSPaolo Bonzini VMSTATE_UINT32(intmskena, mst_irq_state),
241e28bee8eSPaolo Bonzini VMSTATE_UINT32(intsetclr, mst_irq_state),
242e28bee8eSPaolo Bonzini VMSTATE_UINT32(pcmcia0, mst_irq_state),
243e28bee8eSPaolo Bonzini VMSTATE_UINT32(pcmcia1, mst_irq_state),
244e28bee8eSPaolo Bonzini VMSTATE_END_OF_LIST(),
245e28bee8eSPaolo Bonzini },
246e28bee8eSPaolo Bonzini };
247e28bee8eSPaolo Bonzini
mst_fpga_class_init(ObjectClass * klass,void * data)248e28bee8eSPaolo Bonzini static void mst_fpga_class_init(ObjectClass *klass, void *data)
249e28bee8eSPaolo Bonzini {
250e28bee8eSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
251e28bee8eSPaolo Bonzini
252e28bee8eSPaolo Bonzini dc->desc = "Mainstone II FPGA";
253e28bee8eSPaolo Bonzini dc->vmsd = &vmstate_mst_fpga_regs;
254e28bee8eSPaolo Bonzini }
255e28bee8eSPaolo Bonzini
256e28bee8eSPaolo Bonzini static const TypeInfo mst_fpga_info = {
2575c0e12f5SAndreas Färber .name = TYPE_MAINSTONE_FPGA,
258e28bee8eSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
259e28bee8eSPaolo Bonzini .instance_size = sizeof(mst_irq_state),
260e2d4f17eSxiaoqiang zhao .instance_init = mst_fpga_init,
261e28bee8eSPaolo Bonzini .class_init = mst_fpga_class_init,
262e28bee8eSPaolo Bonzini };
263e28bee8eSPaolo Bonzini
mst_fpga_register_types(void)264e28bee8eSPaolo Bonzini static void mst_fpga_register_types(void)
265e28bee8eSPaolo Bonzini {
266e28bee8eSPaolo Bonzini type_register_static(&mst_fpga_info);
267e28bee8eSPaolo Bonzini }
268e28bee8eSPaolo Bonzini
269e28bee8eSPaolo Bonzini type_init(mst_fpga_register_types)
270