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