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