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