1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018 Rubicon Communications, LLC (Netgate) 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/bus.h> 31 32 #include <sys/bitset.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/rman.h> 36 #include <sys/lock.h> 37 #include <sys/mutex.h> 38 39 #include <machine/bus.h> 40 #include <machine/resource.h> 41 #include <machine/intr.h> 42 43 #include <dev/fdt/simplebus.h> 44 45 #include <dev/ofw/ofw_bus.h> 46 #include <dev/ofw/ofw_bus_subr.h> 47 48 #include <arm/arm/gic_common.h> 49 50 #include <dt-bindings/interrupt-controller/irq.h> 51 52 #include "msi_if.h" 53 #include "pic_if.h" 54 55 #define MV_AP806_GICP_MAX_NIRQS 207 56 57 MALLOC_DECLARE(M_GICP); 58 MALLOC_DEFINE(M_GICP, "gicp", "Marvell gicp driver"); 59 60 struct mv_ap806_gicp_softc { 61 device_t dev; 62 device_t parent; 63 struct resource *res; 64 65 ssize_t spi_ranges_cnt; 66 uint32_t *spi_ranges; 67 struct intr_map_data_fdt *parent_map_data; 68 69 ssize_t msi_bitmap_size; /* Nr of bits in the bitmap. */ 70 BITSET_DEFINE_VAR() *msi_bitmap; 71 }; 72 73 static struct ofw_compat_data compat_data[] = { 74 {"marvell,ap806-gicp", 1}, 75 {NULL, 0} 76 }; 77 78 #define RD4(sc, reg) bus_read_4((sc)->res, (reg)) 79 #define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 80 81 static msi_alloc_msi_t mv_ap806_gicp_alloc_msi; 82 static msi_release_msi_t mv_ap806_gicp_release_msi; 83 static msi_map_msi_t mv_ap806_gicp_map_msi; 84 85 static int 86 mv_ap806_gicp_probe(device_t dev) 87 { 88 89 if (!ofw_bus_status_okay(dev)) 90 return (ENXIO); 91 92 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 93 return (ENXIO); 94 95 device_set_desc(dev, "Marvell GICP"); 96 return (BUS_PROBE_DEFAULT); 97 } 98 99 static int 100 mv_ap806_gicp_attach(device_t dev) 101 { 102 struct mv_ap806_gicp_softc *sc; 103 phandle_t node, xref, intr_parent; 104 int i, rid; 105 106 sc = device_get_softc(dev); 107 sc->dev = dev; 108 node = ofw_bus_get_node(dev); 109 110 /* Look for our parent */ 111 if ((intr_parent = ofw_bus_find_iparent(node)) == 0) { 112 device_printf(dev, 113 "Cannot find our parent interrupt controller\n"); 114 return (ENXIO); 115 } 116 if ((sc->parent = OF_device_from_xref(intr_parent)) == NULL) { 117 device_printf(dev, 118 "cannot find parent interrupt controller device\n"); 119 return (ENXIO); 120 } 121 122 rid = 0; 123 sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 124 if (sc->res == NULL) { 125 device_printf(dev, "cannot allocate resources for device\n"); 126 return (ENXIO); 127 } 128 129 sc->spi_ranges_cnt = OF_getencprop_alloc_multi(node, "marvell,spi-ranges", 130 sizeof(*sc->spi_ranges), (void **)&sc->spi_ranges); 131 132 sc->msi_bitmap_size = 0; 133 for (i = 0; i < sc->spi_ranges_cnt; i += 2) 134 sc->msi_bitmap_size += sc->spi_ranges[i + 1]; 135 136 /* 137 * Create a bitmap of all MSIs that we have. 138 * Each has a correspoding SPI in the GIC. 139 * It will be used to dynamically allocate IRQs when requested. 140 */ 141 sc->msi_bitmap = BITSET_ALLOC(sc->msi_bitmap_size, M_GICP, M_WAITOK); 142 BIT_FILL(sc->msi_bitmap_size, sc->msi_bitmap); /* 1 - available, 0 - used. */ 143 144 xref = OF_xref_from_node(node); 145 if (intr_pic_register(dev, xref) == NULL) { 146 device_printf(dev, "Cannot register GICP\n"); 147 return (ENXIO); 148 } 149 /* Allocate GIC compatible mapping entry (3 cells) */ 150 sc->parent_map_data = (struct intr_map_data_fdt *)intr_alloc_map_data( 151 INTR_MAP_DATA_FDT, sizeof(struct intr_map_data_fdt) + 152 + 3 * sizeof(phandle_t), M_WAITOK | M_ZERO); 153 OF_device_register_xref(xref, dev); 154 155 return (0); 156 } 157 158 static int 159 mv_ap806_gicp_detach(device_t dev) 160 { 161 162 return (EBUSY); 163 } 164 165 static uint32_t 166 mv_ap806_gicp_msi_to_spi(struct mv_ap806_gicp_softc *sc, int irq) 167 { 168 int i; 169 170 for (i = 0; i < sc->spi_ranges_cnt; i += 2) { 171 if (irq < sc->spi_ranges[i + 1]) { 172 irq += sc->spi_ranges[i]; 173 break; 174 } 175 irq -= sc->spi_ranges[i + 1]; 176 } 177 178 return (irq - GIC_FIRST_SPI); 179 } 180 181 static uint32_t 182 mv_ap806_gicp_irq_to_msi(struct mv_ap806_gicp_softc *sc, int irq) 183 { 184 int i; 185 186 for (i = 0; i < sc->spi_ranges_cnt; i += 2) { 187 if (irq >= sc->spi_ranges[i] && 188 irq - sc->spi_ranges[i] < sc->spi_ranges[i + 1]) { 189 irq -= sc->spi_ranges[i]; 190 break; 191 } 192 } 193 194 return (irq); 195 } 196 197 static struct intr_map_data * 198 mv_ap806_gicp_convert_map_data(struct mv_ap806_gicp_softc *sc, 199 struct intr_map_data *data) 200 { 201 struct intr_map_data_fdt *daf; 202 uint32_t irq_num; 203 204 daf = (struct intr_map_data_fdt *)data; 205 if (daf->ncells != 2) 206 return (NULL); 207 208 irq_num = daf->cells[0]; 209 if (irq_num >= MV_AP806_GICP_MAX_NIRQS) 210 return (NULL); 211 212 /* Construct GIC compatible mapping. */ 213 sc->parent_map_data->ncells = 3; 214 sc->parent_map_data->cells[0] = 0; /* SPI */ 215 sc->parent_map_data->cells[1] = mv_ap806_gicp_msi_to_spi(sc, irq_num); 216 sc->parent_map_data->cells[2] = IRQ_TYPE_LEVEL_HIGH; 217 218 return ((struct intr_map_data *)sc->parent_map_data); 219 } 220 221 static int 222 mv_ap806_gicp_activate_intr(device_t dev, struct intr_irqsrc *isrc, 223 struct resource *res, struct intr_map_data *data) 224 { 225 struct mv_ap806_gicp_softc *sc; 226 227 sc = device_get_softc(dev); 228 data = mv_ap806_gicp_convert_map_data(sc, data); 229 if (data == NULL) 230 return (EINVAL); 231 232 return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data)); 233 } 234 235 static void 236 mv_ap806_gicp_enable_intr(device_t dev, struct intr_irqsrc *isrc) 237 { 238 struct mv_ap806_gicp_softc *sc; 239 240 sc = device_get_softc(dev); 241 242 PIC_ENABLE_INTR(sc->parent, isrc); 243 } 244 245 static void 246 mv_ap806_gicp_disable_intr(device_t dev, struct intr_irqsrc *isrc) 247 { 248 struct mv_ap806_gicp_softc *sc; 249 250 sc = device_get_softc(dev); 251 252 PIC_DISABLE_INTR(sc->parent, isrc); 253 } 254 255 static int 256 mv_ap806_gicp_map_intr(device_t dev, struct intr_map_data *data, 257 struct intr_irqsrc **isrcp) 258 { 259 260 panic("%s: MSI interface has to be used to map an interrupt.\n", 261 __func__); 262 } 263 264 static int 265 mv_ap806_gicp_deactivate_intr(device_t dev, struct intr_irqsrc *isrc, 266 struct resource *res, struct intr_map_data *data) 267 { 268 struct mv_ap806_gicp_softc *sc; 269 270 sc = device_get_softc(dev); 271 272 data = mv_ap806_gicp_convert_map_data(sc, data); 273 if (data == NULL) 274 return (EINVAL); 275 276 return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data)); 277 } 278 279 static int 280 mv_ap806_gicp_setup_intr(device_t dev, struct intr_irqsrc *isrc, 281 struct resource *res, struct intr_map_data *data) 282 { 283 struct mv_ap806_gicp_softc *sc; 284 285 sc = device_get_softc(dev); 286 data = mv_ap806_gicp_convert_map_data(sc, data); 287 if (data == NULL) 288 return (EINVAL); 289 290 return (PIC_SETUP_INTR(sc->parent, isrc, res, data)); 291 } 292 293 static int 294 mv_ap806_gicp_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 295 struct resource *res, struct intr_map_data *data) 296 { 297 struct mv_ap806_gicp_softc *sc; 298 299 sc = device_get_softc(dev); 300 data = mv_ap806_gicp_convert_map_data(sc, data); 301 if (data == NULL) 302 return (EINVAL); 303 304 return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data)); 305 } 306 307 static void 308 mv_ap806_gicp_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 309 { 310 struct mv_ap806_gicp_softc *sc; 311 312 sc = device_get_softc(dev); 313 314 PIC_PRE_ITHREAD(sc->parent, isrc); 315 } 316 317 static void 318 mv_ap806_gicp_post_ithread(device_t dev, struct intr_irqsrc *isrc) 319 { 320 struct mv_ap806_gicp_softc *sc; 321 322 sc = device_get_softc(dev); 323 324 PIC_POST_ITHREAD(sc->parent, isrc); 325 } 326 327 static void 328 mv_ap806_gicp_post_filter(device_t dev, struct intr_irqsrc *isrc) 329 { 330 struct mv_ap806_gicp_softc *sc; 331 332 sc = device_get_softc(dev); 333 334 PIC_POST_FILTER(sc->parent, isrc); 335 } 336 337 static int 338 mv_ap806_gicp_alloc_msi(device_t dev, device_t child, int count, int maxcount, 339 device_t *pic, struct intr_irqsrc **srcs) 340 { 341 struct mv_ap806_gicp_softc *sc; 342 int i, ret, vector; 343 344 sc = device_get_softc(dev); 345 346 for (i = 0; i < count; i++) { 347 /* 348 * Find first available vector represented by first set bit 349 * in the bitmap. BIT_FFS starts the count from 1, 0 means 350 * that nothing was found. 351 */ 352 vector = BIT_FFS(sc->msi_bitmap_size, sc->msi_bitmap); 353 if (vector == 0) { 354 ret = ENOMEM; 355 i--; 356 goto fail; 357 } 358 vector--; 359 BIT_CLR(sc->msi_bitmap_size, vector, sc->msi_bitmap); 360 361 /* Create GIC compatible SPI interrupt description. */ 362 sc->parent_map_data->ncells = 3; 363 sc->parent_map_data->cells[0] = 0; /* SPI */ 364 sc->parent_map_data->cells[1] = mv_ap806_gicp_msi_to_spi(sc, vector); 365 sc->parent_map_data->cells[2] = IRQ_TYPE_LEVEL_HIGH; 366 367 ret = PIC_MAP_INTR(sc->parent, 368 (struct intr_map_data *)sc->parent_map_data, 369 &srcs[i]); 370 if (ret != 0) 371 goto fail; 372 373 srcs[i]->isrc_dev = dev; 374 } 375 376 return (0); 377 fail: 378 mv_ap806_gicp_release_msi(dev, child, i + 1, srcs); 379 return (ret); 380 } 381 382 static int 383 mv_ap806_gicp_release_msi(device_t dev, device_t child, int count, 384 struct intr_irqsrc **srcs) 385 { 386 struct mv_ap806_gicp_softc *sc; 387 int i; 388 389 sc = device_get_softc(dev); 390 391 for (i = 0; i < count; i++) { 392 BIT_SET(sc->msi_bitmap_size, 393 mv_ap806_gicp_irq_to_msi(sc, srcs[i]->isrc_irq), 394 sc->msi_bitmap); 395 } 396 397 return (0); 398 } 399 400 static int 401 mv_ap806_gicp_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, 402 uint64_t *addr, uint32_t *data) 403 { 404 struct mv_ap806_gicp_softc *sc; 405 406 sc = device_get_softc(dev); 407 408 *addr = rman_get_start(sc->res); 409 *data = mv_ap806_gicp_irq_to_msi(sc, isrc->isrc_irq); 410 411 return (0); 412 } 413 414 static device_method_t mv_ap806_gicp_methods[] = { 415 /* Device interface */ 416 DEVMETHOD(device_probe, mv_ap806_gicp_probe), 417 DEVMETHOD(device_attach, mv_ap806_gicp_attach), 418 DEVMETHOD(device_detach, mv_ap806_gicp_detach), 419 420 /* Interrupt controller interface */ 421 DEVMETHOD(pic_activate_intr, mv_ap806_gicp_activate_intr), 422 DEVMETHOD(pic_disable_intr, mv_ap806_gicp_disable_intr), 423 DEVMETHOD(pic_enable_intr, mv_ap806_gicp_enable_intr), 424 DEVMETHOD(pic_map_intr, mv_ap806_gicp_map_intr), 425 DEVMETHOD(pic_deactivate_intr, mv_ap806_gicp_deactivate_intr), 426 DEVMETHOD(pic_setup_intr, mv_ap806_gicp_setup_intr), 427 DEVMETHOD(pic_teardown_intr, mv_ap806_gicp_teardown_intr), 428 DEVMETHOD(pic_post_filter, mv_ap806_gicp_post_filter), 429 DEVMETHOD(pic_post_ithread, mv_ap806_gicp_post_ithread), 430 DEVMETHOD(pic_pre_ithread, mv_ap806_gicp_pre_ithread), 431 432 /* MSI interface */ 433 DEVMETHOD(msi_alloc_msi, mv_ap806_gicp_alloc_msi), 434 DEVMETHOD(msi_release_msi, mv_ap806_gicp_release_msi), 435 DEVMETHOD(msi_map_msi, mv_ap806_gicp_map_msi), 436 437 DEVMETHOD_END 438 }; 439 440 static driver_t mv_ap806_gicp_driver = { 441 "mv_ap806_gicp", 442 mv_ap806_gicp_methods, 443 sizeof(struct mv_ap806_gicp_softc), 444 }; 445 446 EARLY_DRIVER_MODULE(mv_ap806_gicp, simplebus, mv_ap806_gicp_driver, 0, 0, 447 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 448