1 /*- 2 * Copyright (c) 2006 Benno Rice. 3 * Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD. 4 * All rights reserved. 5 * 6 * Adapted and extended to Marvell SoCs by Semihalf. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_icu.c, rev 1 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/bus.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 #include <sys/rman.h> 40 #include <machine/bus.h> 41 #include <machine/intr.h> 42 43 #include <dev/ofw/ofw_bus.h> 44 #include <dev/ofw/ofw_bus_subr.h> 45 46 #include <arm/mv/mvreg.h> 47 #include <arm/mv/mvvar.h> 48 49 struct mv_ic_softc { 50 struct resource * ic_res[1]; 51 bus_space_tag_t ic_bst; 52 bus_space_handle_t ic_bsh; 53 int ic_high_regs; 54 int ic_error_regs; 55 }; 56 57 static struct resource_spec mv_ic_spec[] = { 58 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 59 { -1, 0 } 60 }; 61 62 static struct mv_ic_softc *mv_ic_sc = NULL; 63 64 static int mv_ic_probe(device_t); 65 static int mv_ic_attach(device_t); 66 67 uint32_t mv_ic_get_cause(void); 68 uint32_t mv_ic_get_mask(void); 69 void mv_ic_set_mask(uint32_t); 70 uint32_t mv_ic_get_cause_hi(void); 71 uint32_t mv_ic_get_mask_hi(void); 72 void mv_ic_set_mask_hi(uint32_t); 73 uint32_t mv_ic_get_cause_error(void); 74 uint32_t mv_ic_get_mask_error(void); 75 void mv_ic_set_mask_error(uint32_t); 76 static void arm_mask_irq_all(void); 77 78 static int 79 mv_ic_probe(device_t dev) 80 { 81 82 if (!ofw_bus_is_compatible(dev, "mrvl,pic")) 83 return (ENXIO); 84 85 device_set_desc(dev, "Marvell Integrated Interrupt Controller"); 86 return (0); 87 } 88 89 static int 90 mv_ic_attach(device_t dev) 91 { 92 struct mv_ic_softc *sc; 93 uint32_t dev_id, rev_id; 94 int error; 95 96 sc = (struct mv_ic_softc *)device_get_softc(dev); 97 98 if (mv_ic_sc != NULL) 99 return (ENXIO); 100 mv_ic_sc = sc; 101 102 soc_id(&dev_id, &rev_id); 103 104 sc->ic_high_regs = 0; 105 sc->ic_error_regs = 0; 106 107 if (dev_id == MV_DEV_88F6281 || dev_id == MV_DEV_MV78100 || 108 dev_id == MV_DEV_MV78100_Z0) 109 sc->ic_high_regs = 1; 110 111 if (dev_id == MV_DEV_MV78100 || dev_id == MV_DEV_MV78100_Z0) 112 sc->ic_error_regs = 1; 113 114 error = bus_alloc_resources(dev, mv_ic_spec, sc->ic_res); 115 if (error) { 116 device_printf(dev, "could not allocate resources\n"); 117 return (ENXIO); 118 } 119 120 sc->ic_bst = rman_get_bustag(sc->ic_res[0]); 121 sc->ic_bsh = rman_get_bushandle(sc->ic_res[0]); 122 123 /* Mask all interrupts */ 124 arm_mask_irq_all(); 125 126 return (0); 127 } 128 129 static device_method_t mv_ic_methods[] = { 130 DEVMETHOD(device_probe, mv_ic_probe), 131 DEVMETHOD(device_attach, mv_ic_attach), 132 { 0, 0 } 133 }; 134 135 static driver_t mv_ic_driver = { 136 "ic", 137 mv_ic_methods, 138 sizeof(struct mv_ic_softc), 139 }; 140 141 static devclass_t mv_ic_devclass; 142 143 DRIVER_MODULE(ic, simplebus, mv_ic_driver, mv_ic_devclass, 0, 0); 144 145 int 146 arm_get_next_irq(int last __unused) 147 { 148 int irq; 149 150 irq = mv_ic_get_cause() & mv_ic_get_mask(); 151 if (irq) 152 return (ffs(irq) - 1); 153 154 if (mv_ic_sc->ic_high_regs) { 155 irq = mv_ic_get_cause_hi() & mv_ic_get_mask_hi(); 156 if (irq) 157 return (ffs(irq) + 31); 158 } 159 160 if (mv_ic_sc->ic_error_regs) { 161 irq = mv_ic_get_cause_error() & mv_ic_get_mask_error(); 162 if (irq) 163 return (ffs(irq) + 63); 164 } 165 166 return (-1); 167 } 168 169 static void 170 arm_mask_irq_all(void) 171 { 172 173 mv_ic_set_mask(0); 174 175 if (mv_ic_sc->ic_high_regs) 176 mv_ic_set_mask_hi(0); 177 178 if (mv_ic_sc->ic_error_regs) 179 mv_ic_set_mask_error(0); 180 } 181 182 void 183 arm_mask_irq(uintptr_t nb) 184 { 185 uint32_t mr; 186 187 if (nb < 32) { 188 mr = mv_ic_get_mask(); 189 mr &= ~(1 << nb); 190 mv_ic_set_mask(mr); 191 192 } else if ((nb < 64) && mv_ic_sc->ic_high_regs) { 193 mr = mv_ic_get_mask_hi(); 194 mr &= ~(1 << (nb - 32)); 195 mv_ic_set_mask_hi(mr); 196 197 } else if ((nb < 96) && mv_ic_sc->ic_error_regs) { 198 mr = mv_ic_get_mask_error(); 199 mr &= ~(1 << (nb - 64)); 200 mv_ic_set_mask_error(mr); 201 } 202 } 203 204 void 205 arm_unmask_irq(uintptr_t nb) 206 { 207 uint32_t mr; 208 209 if (nb < 32) { 210 mr = mv_ic_get_mask(); 211 mr |= (1 << nb); 212 mv_ic_set_mask(mr); 213 214 } else if ((nb < 64) && mv_ic_sc->ic_high_regs) { 215 mr = mv_ic_get_mask_hi(); 216 mr |= (1 << (nb - 32)); 217 mv_ic_set_mask_hi(mr); 218 219 } else if ((nb < 96) && mv_ic_sc->ic_error_regs) { 220 mr = mv_ic_get_mask_error(); 221 mr |= (1 << (nb - 64)); 222 mv_ic_set_mask_error(mr); 223 } 224 } 225 226 void 227 mv_ic_set_mask(uint32_t val) 228 { 229 230 bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh, 231 IRQ_MASK, val); 232 } 233 234 uint32_t 235 mv_ic_get_mask(void) 236 { 237 238 return (bus_space_read_4(mv_ic_sc->ic_bst, 239 mv_ic_sc->ic_bsh, IRQ_MASK)); 240 } 241 242 uint32_t 243 mv_ic_get_cause(void) 244 { 245 246 return (bus_space_read_4(mv_ic_sc->ic_bst, 247 mv_ic_sc->ic_bsh, IRQ_CAUSE)); 248 } 249 250 void 251 mv_ic_set_mask_hi(uint32_t val) 252 { 253 254 bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh, 255 IRQ_MASK_HI, val); 256 } 257 258 uint32_t 259 mv_ic_get_mask_hi(void) 260 { 261 262 return (bus_space_read_4(mv_ic_sc->ic_bst, 263 mv_ic_sc->ic_bsh, IRQ_MASK_HI)); 264 } 265 266 uint32_t 267 mv_ic_get_cause_hi(void) 268 { 269 270 return (bus_space_read_4(mv_ic_sc->ic_bst, 271 mv_ic_sc->ic_bsh, IRQ_CAUSE_HI)); 272 } 273 274 void 275 mv_ic_set_mask_error(uint32_t val) 276 { 277 278 bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh, 279 IRQ_MASK_ERROR, val); 280 } 281 282 uint32_t 283 mv_ic_get_mask_error(void) 284 { 285 286 return (bus_space_read_4(mv_ic_sc->ic_bst, 287 mv_ic_sc->ic_bsh, IRQ_MASK_ERROR)); 288 } 289 290 uint32_t 291 mv_ic_get_cause_error(void) 292 { 293 294 return (bus_space_read_4(mv_ic_sc->ic_bst, 295 mv_ic_sc->ic_bsh, IRQ_CAUSE_ERROR)); 296 } 297