1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com> 5 * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 6 * All rights reserved. 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 * without modification. 14 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 15 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 16 * redistribution must be conditioned upon including a substantially 17 * similar Disclaimer requirement for further binary redistribution. 18 * 19 * NO WARRANTY 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 23 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 24 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 25 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 28 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGES. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/kernel.h> 38 39 #include "chipc_private.h" 40 #include "chipcvar.h" 41 42 /** 43 * Return a human-readable name for the given flash @p type. 44 */ 45 const char * 46 chipc_flash_name(chipc_flash type) 47 { 48 switch (type) { 49 case CHIPC_PFLASH_CFI: 50 return ("CFI Flash"); 51 52 case CHIPC_SFLASH_ST: 53 case CHIPC_SFLASH_AT: 54 return ("SPI Flash"); 55 56 case CHIPC_QSFLASH_ST: 57 case CHIPC_QSFLASH_AT: 58 return ("QSPI Flash"); 59 60 case CHIPC_NFLASH: 61 case CHIPC_NFLASH_4706: 62 return ("NAND"); 63 64 case CHIPC_FLASH_NONE: 65 default: 66 return ("unknown"); 67 } 68 } 69 70 /** 71 * Return the name of the bus device class used by flash @p type, 72 * or NULL if @p type is unsupported. 73 */ 74 const char * 75 chipc_flash_bus_name(chipc_flash type) 76 { 77 switch (type) { 78 case CHIPC_PFLASH_CFI: 79 return ("cfi"); 80 81 case CHIPC_SFLASH_ST: 82 case CHIPC_SFLASH_AT: 83 return ("spi"); 84 85 case CHIPC_QSFLASH_ST: 86 case CHIPC_QSFLASH_AT: 87 /* unimplemented; spi? */ 88 return (NULL); 89 90 case CHIPC_NFLASH: 91 case CHIPC_NFLASH_4706: 92 /* unimplemented; nandbus? */ 93 return (NULL); 94 95 case CHIPC_FLASH_NONE: 96 default: 97 return (NULL); 98 } 99 } 100 101 /** 102 * Return the name of the flash device class for SPI flash @p type, 103 * or NULL if @p type does not use SPI, or is unsupported. 104 */ 105 const char * 106 chipc_sflash_device_name(chipc_flash type) 107 { 108 switch (type) { 109 case CHIPC_SFLASH_ST: 110 return ("mx25l"); 111 112 case CHIPC_SFLASH_AT: 113 return ("at45d"); 114 115 case CHIPC_QSFLASH_ST: 116 case CHIPC_QSFLASH_AT: 117 /* unimplemented */ 118 return (NULL); 119 120 case CHIPC_PFLASH_CFI: 121 case CHIPC_NFLASH: 122 case CHIPC_NFLASH_4706: 123 case CHIPC_FLASH_NONE: 124 default: 125 return (NULL); 126 } 127 } 128 129 /** 130 * Initialize child resource @p r with a virtual address, tag, and handle 131 * copied from @p parent, adjusted to contain only the range defined by 132 * @p offsize and @p size. 133 * 134 * @param r The register to be initialized. 135 * @param parent The parent bus resource that fully contains the subregion. 136 * @param offset The subregion offset within @p parent. 137 * @param size The subregion size. 138 */ 139 int 140 chipc_init_child_resource(struct resource *r, 141 struct resource *parent, bhnd_size_t offset, bhnd_size_t size) 142 { 143 bus_space_handle_t bh, child_bh; 144 bus_space_tag_t bt; 145 uintptr_t vaddr; 146 int error; 147 148 /* Fetch the parent resource's bus values */ 149 vaddr = (uintptr_t) rman_get_virtual(parent); 150 bt = rman_get_bustag(parent); 151 bh = rman_get_bushandle(parent); 152 153 /* Configure child resource with offset-adjusted values */ 154 vaddr += offset; 155 error = bus_space_subregion(bt, bh, offset, size, &child_bh); 156 if (error) 157 return (error); 158 159 rman_set_virtual(r, (void *) vaddr); 160 rman_set_bustag(r, bt); 161 rman_set_bushandle(r, child_bh); 162 163 return (0); 164 } 165 166 /** 167 * Map an interrupt line to an IRQ, and then register a corresponding SYS_RES_IRQ 168 * with @p child's resource list. 169 * 170 * @param sc chipc driver state. 171 * @param child The device to set the resource on. 172 * @param rid The resource ID. 173 * @param intr The interrupt line to be mapped. 174 * @param count The length of the resource. 175 * @param port The mapping port number (ignored if not SYS_RES_MEMORY). 176 * @param region The mapping region number (ignored if not SYS_RES_MEMORY). 177 */ 178 int 179 chipc_set_irq_resource(struct chipc_softc *sc, device_t child, int rid, 180 u_int intr) 181 { 182 struct chipc_devinfo *dinfo; 183 int error; 184 185 KASSERT(device_get_parent(child) == sc->dev, ("not a direct child")); 186 dinfo = device_get_ivars(child); 187 188 /* We currently only support a single IRQ mapping */ 189 if (dinfo->irq_mapped) { 190 device_printf(sc->dev, "irq already mapped for child\n"); 191 return (ENOMEM); 192 } 193 194 /* Map the IRQ */ 195 if ((error = bhnd_map_intr(sc->dev, intr, &dinfo->irq))) { 196 device_printf(sc->dev, "failed to map intr %u: %d\n", intr, 197 error); 198 return (error); 199 } 200 201 dinfo->irq_mapped = true; 202 203 /* Add to child's resource list */ 204 error = bus_set_resource(child, SYS_RES_IRQ, rid, dinfo->irq, 1); 205 if (error) { 206 device_printf(sc->dev, "failed to set child irq resource %d to " 207 "%ju: %d\n", rid, dinfo->irq, error); 208 209 bhnd_unmap_intr(sc->dev, dinfo->irq); 210 return (error); 211 } 212 213 return (0); 214 } 215 216 217 /** 218 * Add a SYS_RES_MEMORY resource with a given resource ID, relative to the 219 * given port and region, to @p child's resource list. 220 * 221 * The specified @p region's address and size will be fetched from the bhnd(4) 222 * bus, and bus_set_resource() will be called with @p start added the region's 223 * actual base address. 224 * 225 * To use the default region values for @p start and @p count, specify 226 * a @p start value of 0ul, and an end value of RMAN_MAX_END 227 * 228 * @param sc chipc driver state. 229 * @param child The device to set the resource on. 230 * @param rid The resource ID. 231 * @param start The resource start address (if SYS_RES_MEMORY, this is 232 * relative to @p region's base address). 233 * @param count The length of the resource. 234 * @param port The mapping port number (ignored if not SYS_RES_MEMORY). 235 * @param region The mapping region number (ignored if not SYS_RES_MEMORY). 236 */ 237 int 238 chipc_set_mem_resource(struct chipc_softc *sc, device_t child, int rid, 239 rman_res_t start, rman_res_t count, u_int port, u_int region) 240 { 241 bhnd_addr_t region_addr; 242 bhnd_size_t region_size; 243 bool isdefault; 244 int error; 245 246 KASSERT(device_get_parent(child) == sc->dev, ("not a direct child")); 247 isdefault = RMAN_IS_DEFAULT_RANGE(start, count); 248 249 /* Fetch region address and size */ 250 error = bhnd_get_region_addr(sc->dev, BHND_PORT_DEVICE, port, 251 region, ®ion_addr, ®ion_size); 252 if (error) { 253 device_printf(sc->dev, 254 "lookup of %s%u.%u failed: %d\n", 255 bhnd_port_type_name(BHND_PORT_DEVICE), port, region, error); 256 return (error); 257 } 258 259 /* Populate defaults */ 260 if (isdefault) { 261 start = 0; 262 count = region_size; 263 } 264 265 /* Verify requested range is mappable */ 266 if (start > region_size || region_size - start < count) { 267 device_printf(sc->dev, 268 "%s%u.%u region cannot map requested range %#jx+%#jx\n", 269 bhnd_port_type_name(BHND_PORT_DEVICE), port, region, start, 270 count); 271 return (ERANGE); 272 } 273 274 return (bus_set_resource(child, SYS_RES_MEMORY, rid, 275 region_addr + start, count)); 276 } 277 278 279 /* 280 * Print a capability structure. 281 */ 282 void 283 chipc_print_caps(device_t dev, struct chipc_caps *caps) 284 { 285 #define CC_TFS(_flag) (caps->_flag ? "yes" : "no") 286 287 device_printf(dev, "MIPSEB: %-3s | BP64: %s\n", 288 CC_TFS(mipseb), CC_TFS(backplane_64)); 289 device_printf(dev, "UARTs: %-3hhu | UGPIO: %s\n", 290 caps->num_uarts, CC_TFS(uart_gpio)); 291 // XXX: hitting a kvprintf bug with '%#02x' not prefixing '0x' in 292 // some cases, and not apply the field width in others 293 device_printf(dev, "UARTClk: 0x%02x | Flash: %u\n", 294 caps->uart_clock, caps->flash_type); 295 device_printf(dev, "SPROM: %-3s | OTP: %s\n", 296 CC_TFS(sprom), CC_TFS(otp_size)); 297 device_printf(dev, "CFIsz: 0x%02x | OTPsz: 0x%02x\n", 298 caps->cfi_width, caps->otp_size); 299 device_printf(dev, "ExtBus: 0x%02x | PwrCtrl: %s\n", 300 caps->extbus_type, CC_TFS(pwr_ctrl)); 301 device_printf(dev, "PLL: 0x%02x | JTAGM: %s\n", 302 caps->pll_type, CC_TFS(jtag_master)); 303 device_printf(dev, "PMU: %-3s | ECI: %s\n", 304 CC_TFS(pmu), CC_TFS(eci)); 305 device_printf(dev, "SECI: %-3s | GSIO: %s\n", 306 CC_TFS(seci), CC_TFS(gsio)); 307 device_printf(dev, "AOB: %-3s | BootROM: %s\n", 308 CC_TFS(aob), CC_TFS(boot_rom)); 309 310 #undef CC_TFS 311 } 312 313 /** 314 * Allocate and initialize new region record. 315 * 316 * @param sc Driver instance state. 317 * @param type The port type to query. 318 * @param port The port number to query. 319 * @param region The region number to query. 320 */ 321 struct chipc_region * 322 chipc_alloc_region(struct chipc_softc *sc, bhnd_port_type type, 323 u_int port, u_int region) 324 { 325 struct chipc_region *cr; 326 int error; 327 328 /* Don't bother allocating a chipc_region if init will fail */ 329 if (!bhnd_is_region_valid(sc->dev, type, port, region)) 330 return (NULL); 331 332 /* Allocate and initialize region info */ 333 cr = malloc(sizeof(*cr), M_BHND, M_NOWAIT); 334 if (cr == NULL) 335 return (NULL); 336 337 cr->cr_port_type = type; 338 cr->cr_port_num = port; 339 cr->cr_region_num = region; 340 cr->cr_res = NULL; 341 cr->cr_refs = 0; 342 cr->cr_act_refs = 0; 343 344 error = bhnd_get_region_addr(sc->dev, type, port, region, &cr->cr_addr, 345 &cr->cr_count); 346 if (error) { 347 device_printf(sc->dev, 348 "fetching chipc region address failed: %d\n", error); 349 goto failed; 350 } 351 352 cr->cr_end = cr->cr_addr + cr->cr_count - 1; 353 354 /* Fetch default resource ID for this region. Not all regions have an 355 * assigned rid, in which case this will return -1 */ 356 cr->cr_rid = bhnd_get_port_rid(sc->dev, type, port, region); 357 358 return (cr); 359 360 failed: 361 device_printf(sc->dev, "chipc region alloc failed for %s%u.%u\n", 362 bhnd_port_type_name(type), port, region); 363 free(cr, M_BHND); 364 return (NULL); 365 } 366 367 /** 368 * Deallocate the given region record and its associated resource, if any. 369 * 370 * @param sc Driver instance state. 371 * @param cr Region record to be deallocated. 372 */ 373 void 374 chipc_free_region(struct chipc_softc *sc, struct chipc_region *cr) 375 { 376 KASSERT(cr->cr_refs == 0, 377 ("chipc %s%u.%u region has %u active references", 378 bhnd_port_type_name(cr->cr_port_type), cr->cr_port_num, 379 cr->cr_region_num, cr->cr_refs)); 380 381 if (cr->cr_res != NULL) { 382 bhnd_release_resource(sc->dev, SYS_RES_MEMORY, cr->cr_res_rid, 383 cr->cr_res); 384 } 385 386 free(cr, M_BHND); 387 } 388 389 /** 390 * Locate the region mapping the given range, if any. Returns NULL if no 391 * valid region is found. 392 * 393 * @param sc Driver instance state. 394 * @param start start of address range. 395 * @param end end of address range. 396 */ 397 struct chipc_region * 398 chipc_find_region(struct chipc_softc *sc, rman_res_t start, rman_res_t end) 399 { 400 struct chipc_region *cr; 401 402 if (start > end) 403 return (NULL); 404 405 STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) { 406 if (start < cr->cr_addr || end > cr->cr_end) 407 continue; 408 409 /* Found */ 410 return (cr); 411 } 412 413 /* Not found */ 414 return (NULL); 415 } 416 417 /** 418 * Locate a region mapping by its bhnd-assigned resource id (as returned by 419 * bhnd_get_port_rid). 420 * 421 * @param sc Driver instance state. 422 * @param rid Resource ID to query for. 423 */ 424 struct chipc_region * 425 chipc_find_region_by_rid(struct chipc_softc *sc, int rid) 426 { 427 struct chipc_region *cr; 428 int port_rid; 429 430 STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) { 431 port_rid = bhnd_get_port_rid(sc->dev, cr->cr_port_type, 432 cr->cr_port_num, cr->cr_region_num); 433 if (port_rid == -1 || port_rid != rid) 434 continue; 435 436 /* Found */ 437 return (cr); 438 } 439 440 /* Not found */ 441 return (NULL); 442 } 443 444 /** 445 * Retain a reference to a chipc_region, allocating and activating the 446 * backing resource as required. 447 * 448 * @param sc chipc driver instance state 449 * @param cr region to retain. 450 * @param flags specify RF_ALLOCATED to retain an allocation reference, 451 * RF_ACTIVE to retain an activation reference. 452 */ 453 int 454 chipc_retain_region(struct chipc_softc *sc, struct chipc_region *cr, int flags) 455 { 456 int error; 457 458 KASSERT(!(flags &~ (RF_ACTIVE|RF_ALLOCATED)), ("unsupported flags")); 459 460 CHIPC_LOCK(sc); 461 462 /* Handle allocation */ 463 if (flags & RF_ALLOCATED) { 464 /* If this is the first reference, allocate the resource */ 465 if (cr->cr_refs == 0) { 466 KASSERT(cr->cr_res == NULL, 467 ("non-NULL resource has refcount")); 468 469 /* Fetch initial resource ID */ 470 if ((cr->cr_res_rid = cr->cr_rid) == -1) { 471 CHIPC_UNLOCK(sc); 472 return (EINVAL); 473 } 474 475 /* Allocate resource */ 476 cr->cr_res = bhnd_alloc_resource(sc->dev, 477 SYS_RES_MEMORY, &cr->cr_res_rid, cr->cr_addr, 478 cr->cr_end, cr->cr_count, RF_SHAREABLE); 479 if (cr->cr_res == NULL) { 480 CHIPC_UNLOCK(sc); 481 return (ENXIO); 482 } 483 } 484 485 /* Increment allocation refcount */ 486 cr->cr_refs++; 487 } 488 489 490 /* Handle activation */ 491 if (flags & RF_ACTIVE) { 492 KASSERT(cr->cr_refs > 0, 493 ("cannot activate unallocated resource")); 494 495 /* If this is the first reference, activate the resource */ 496 if (cr->cr_act_refs == 0) { 497 error = bhnd_activate_resource(sc->dev, SYS_RES_MEMORY, 498 cr->cr_res_rid, cr->cr_res); 499 if (error) { 500 /* Drop any allocation reference acquired 501 * above */ 502 CHIPC_UNLOCK(sc); 503 chipc_release_region(sc, cr, 504 flags &~ RF_ACTIVE); 505 return (error); 506 } 507 } 508 509 /* Increment activation refcount */ 510 cr->cr_act_refs++; 511 } 512 513 CHIPC_UNLOCK(sc); 514 return (0); 515 } 516 517 /** 518 * Release a reference to a chipc_region, deactivating and releasing the 519 * backing resource if the reference count hits zero. 520 * 521 * @param sc chipc driver instance state 522 * @param cr region to retain. 523 * @param flags specify RF_ALLOCATED to release an allocation reference, 524 * RF_ACTIVE to release an activation reference. 525 */ 526 int 527 chipc_release_region(struct chipc_softc *sc, struct chipc_region *cr, 528 int flags) 529 { 530 int error; 531 532 CHIPC_LOCK(sc); 533 error = 0; 534 535 KASSERT(cr->cr_res != NULL, ("release on NULL region resource")); 536 537 if (flags & RF_ACTIVE) { 538 KASSERT(cr->cr_act_refs > 0, ("RF_ACTIVE over-released")); 539 KASSERT(cr->cr_act_refs <= cr->cr_refs, 540 ("RF_ALLOCATED released with RF_ACTIVE held")); 541 542 /* If this is the last reference, deactivate the resource */ 543 if (cr->cr_act_refs == 1) { 544 error = bhnd_deactivate_resource(sc->dev, 545 SYS_RES_MEMORY, cr->cr_res_rid, cr->cr_res); 546 if (error) 547 goto done; 548 } 549 550 /* Drop our activation refcount */ 551 cr->cr_act_refs--; 552 } 553 554 if (flags & RF_ALLOCATED) { 555 KASSERT(cr->cr_refs > 0, ("overrelease of refs")); 556 /* If this is the last reference, release the resource */ 557 if (cr->cr_refs == 1) { 558 error = bhnd_release_resource(sc->dev, SYS_RES_MEMORY, 559 cr->cr_res_rid, cr->cr_res); 560 if (error) 561 goto done; 562 563 cr->cr_res = NULL; 564 } 565 566 /* Drop our allocation refcount */ 567 cr->cr_refs--; 568 } 569 570 done: 571 CHIPC_UNLOCK(sc); 572 return (error); 573 } 574