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 * Add a SYS_RES_MEMORY resource with a given resource ID, relative to the 218 * given port and region, to @p child's resource list. 219 * 220 * The specified @p region's address and size will be fetched from the bhnd(4) 221 * bus, and bus_set_resource() will be called with @p start added the region's 222 * actual base address. 223 * 224 * To use the default region values for @p start and @p count, specify 225 * a @p start value of 0ul, and an end value of RMAN_MAX_END 226 * 227 * @param sc chipc driver state. 228 * @param child The device to set the resource on. 229 * @param rid The resource ID. 230 * @param start The resource start address (if SYS_RES_MEMORY, this is 231 * relative to @p region's base address). 232 * @param count The length of the resource. 233 * @param port The mapping port number (ignored if not SYS_RES_MEMORY). 234 * @param region The mapping region number (ignored if not SYS_RES_MEMORY). 235 */ 236 int 237 chipc_set_mem_resource(struct chipc_softc *sc, device_t child, int rid, 238 rman_res_t start, rman_res_t count, u_int port, u_int region) 239 { 240 bhnd_addr_t region_addr; 241 bhnd_size_t region_size; 242 bool isdefault; 243 int error; 244 245 KASSERT(device_get_parent(child) == sc->dev, ("not a direct child")); 246 isdefault = RMAN_IS_DEFAULT_RANGE(start, count); 247 248 /* Fetch region address and size */ 249 error = bhnd_get_region_addr(sc->dev, BHND_PORT_DEVICE, port, 250 region, ®ion_addr, ®ion_size); 251 if (error) { 252 device_printf(sc->dev, 253 "lookup of %s%u.%u failed: %d\n", 254 bhnd_port_type_name(BHND_PORT_DEVICE), port, region, error); 255 return (error); 256 } 257 258 /* Populate defaults */ 259 if (isdefault) { 260 start = 0; 261 count = region_size; 262 } 263 264 /* Verify requested range is mappable */ 265 if (start > region_size || region_size - start < count) { 266 device_printf(sc->dev, 267 "%s%u.%u region cannot map requested range %#jx+%#jx\n", 268 bhnd_port_type_name(BHND_PORT_DEVICE), port, region, start, 269 count); 270 return (ERANGE); 271 } 272 273 return (bus_set_resource(child, SYS_RES_MEMORY, rid, 274 region_addr + start, count)); 275 } 276 277 /* 278 * Print a capability structure. 279 */ 280 void 281 chipc_print_caps(device_t dev, struct chipc_caps *caps) 282 { 283 #define CC_TFS(_flag) (caps->_flag ? "yes" : "no") 284 285 device_printf(dev, "MIPSEB: %-3s | BP64: %s\n", 286 CC_TFS(mipseb), CC_TFS(backplane_64)); 287 device_printf(dev, "UARTs: %-3hhu | UGPIO: %s\n", 288 caps->num_uarts, CC_TFS(uart_gpio)); 289 // XXX: hitting a kvprintf bug with '%#02x' not prefixing '0x' in 290 // some cases, and not apply the field width in others 291 device_printf(dev, "UARTClk: 0x%02x | Flash: %u\n", 292 caps->uart_clock, caps->flash_type); 293 device_printf(dev, "SPROM: %-3s | OTP: %s\n", 294 CC_TFS(sprom), CC_TFS(otp_size)); 295 device_printf(dev, "CFIsz: 0x%02x | OTPsz: 0x%02x\n", 296 caps->cfi_width, caps->otp_size); 297 device_printf(dev, "ExtBus: 0x%02x | PwrCtrl: %s\n", 298 caps->extbus_type, CC_TFS(pwr_ctrl)); 299 device_printf(dev, "PLL: 0x%02x | JTAGM: %s\n", 300 caps->pll_type, CC_TFS(jtag_master)); 301 device_printf(dev, "PMU: %-3s | ECI: %s\n", 302 CC_TFS(pmu), CC_TFS(eci)); 303 device_printf(dev, "SECI: %-3s | GSIO: %s\n", 304 CC_TFS(seci), CC_TFS(gsio)); 305 device_printf(dev, "AOB: %-3s | BootROM: %s\n", 306 CC_TFS(aob), CC_TFS(boot_rom)); 307 308 #undef CC_TFS 309 } 310 311 /** 312 * Allocate and initialize new region record. 313 * 314 * @param sc Driver instance state. 315 * @param type The port type to query. 316 * @param port The port number to query. 317 * @param region The region number to query. 318 */ 319 struct chipc_region * 320 chipc_alloc_region(struct chipc_softc *sc, bhnd_port_type type, 321 u_int port, u_int region) 322 { 323 struct chipc_region *cr; 324 int error; 325 326 /* Don't bother allocating a chipc_region if init will fail */ 327 if (!bhnd_is_region_valid(sc->dev, type, port, region)) 328 return (NULL); 329 330 /* Allocate and initialize region info */ 331 cr = malloc(sizeof(*cr), M_BHND, M_NOWAIT); 332 if (cr == NULL) 333 return (NULL); 334 335 cr->cr_port_type = type; 336 cr->cr_port_num = port; 337 cr->cr_region_num = region; 338 cr->cr_res = NULL; 339 cr->cr_refs = 0; 340 cr->cr_act_refs = 0; 341 342 error = bhnd_get_region_addr(sc->dev, type, port, region, &cr->cr_addr, 343 &cr->cr_count); 344 if (error) { 345 device_printf(sc->dev, 346 "fetching chipc region address failed: %d\n", error); 347 goto failed; 348 } 349 350 cr->cr_end = cr->cr_addr + cr->cr_count - 1; 351 352 /* Fetch default resource ID for this region. Not all regions have an 353 * assigned rid, in which case this will return -1 */ 354 cr->cr_rid = bhnd_get_port_rid(sc->dev, type, port, region); 355 356 return (cr); 357 358 failed: 359 device_printf(sc->dev, "chipc region alloc failed for %s%u.%u\n", 360 bhnd_port_type_name(type), port, region); 361 free(cr, M_BHND); 362 return (NULL); 363 } 364 365 /** 366 * Deallocate the given region record and its associated resource, if any. 367 * 368 * @param sc Driver instance state. 369 * @param cr Region record to be deallocated. 370 */ 371 void 372 chipc_free_region(struct chipc_softc *sc, struct chipc_region *cr) 373 { 374 KASSERT(cr->cr_refs == 0, 375 ("chipc %s%u.%u region has %u active references", 376 bhnd_port_type_name(cr->cr_port_type), cr->cr_port_num, 377 cr->cr_region_num, cr->cr_refs)); 378 379 if (cr->cr_res != NULL) { 380 bhnd_release_resource(sc->dev, SYS_RES_MEMORY, cr->cr_res_rid, 381 cr->cr_res); 382 } 383 384 free(cr, M_BHND); 385 } 386 387 /** 388 * Locate the region mapping the given range, if any. Returns NULL if no 389 * valid region is found. 390 * 391 * @param sc Driver instance state. 392 * @param start start of address range. 393 * @param end end of address range. 394 */ 395 struct chipc_region * 396 chipc_find_region(struct chipc_softc *sc, rman_res_t start, rman_res_t end) 397 { 398 struct chipc_region *cr; 399 400 if (start > end) 401 return (NULL); 402 403 STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) { 404 if (start < cr->cr_addr || end > cr->cr_end) 405 continue; 406 407 /* Found */ 408 return (cr); 409 } 410 411 /* Not found */ 412 return (NULL); 413 } 414 415 /** 416 * Locate a region mapping by its bhnd-assigned resource id (as returned by 417 * bhnd_get_port_rid). 418 * 419 * @param sc Driver instance state. 420 * @param rid Resource ID to query for. 421 */ 422 struct chipc_region * 423 chipc_find_region_by_rid(struct chipc_softc *sc, int rid) 424 { 425 struct chipc_region *cr; 426 int port_rid; 427 428 STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) { 429 port_rid = bhnd_get_port_rid(sc->dev, cr->cr_port_type, 430 cr->cr_port_num, cr->cr_region_num); 431 if (port_rid == -1 || port_rid != rid) 432 continue; 433 434 /* Found */ 435 return (cr); 436 } 437 438 /* Not found */ 439 return (NULL); 440 } 441 442 /** 443 * Retain a reference to a chipc_region, allocating and activating the 444 * backing resource as required. 445 * 446 * @param sc chipc driver instance state 447 * @param cr region to retain. 448 * @param flags specify RF_ALLOCATED to retain an allocation reference, 449 * RF_ACTIVE to retain an activation reference. 450 */ 451 int 452 chipc_retain_region(struct chipc_softc *sc, struct chipc_region *cr, int flags) 453 { 454 int error; 455 456 KASSERT(!(flags &~ (RF_ACTIVE|RF_ALLOCATED)), ("unsupported flags")); 457 458 CHIPC_LOCK(sc); 459 460 /* Handle allocation */ 461 if (flags & RF_ALLOCATED) { 462 /* If this is the first reference, allocate the resource */ 463 if (cr->cr_refs == 0) { 464 KASSERT(cr->cr_res == NULL, 465 ("non-NULL resource has refcount")); 466 467 /* Fetch initial resource ID */ 468 if ((cr->cr_res_rid = cr->cr_rid) == -1) { 469 CHIPC_UNLOCK(sc); 470 return (EINVAL); 471 } 472 473 /* Allocate resource */ 474 cr->cr_res = bhnd_alloc_resource(sc->dev, 475 SYS_RES_MEMORY, &cr->cr_res_rid, cr->cr_addr, 476 cr->cr_end, cr->cr_count, RF_SHAREABLE); 477 if (cr->cr_res == NULL) { 478 CHIPC_UNLOCK(sc); 479 return (ENXIO); 480 } 481 } 482 483 /* Increment allocation refcount */ 484 cr->cr_refs++; 485 } 486 487 /* Handle activation */ 488 if (flags & RF_ACTIVE) { 489 KASSERT(cr->cr_refs > 0, 490 ("cannot activate unallocated resource")); 491 492 /* If this is the first reference, activate the resource */ 493 if (cr->cr_act_refs == 0) { 494 error = bhnd_activate_resource(sc->dev, SYS_RES_MEMORY, 495 cr->cr_res_rid, cr->cr_res); 496 if (error) { 497 /* Drop any allocation reference acquired 498 * above */ 499 CHIPC_UNLOCK(sc); 500 chipc_release_region(sc, cr, 501 flags &~ RF_ACTIVE); 502 return (error); 503 } 504 } 505 506 /* Increment activation refcount */ 507 cr->cr_act_refs++; 508 } 509 510 CHIPC_UNLOCK(sc); 511 return (0); 512 } 513 514 /** 515 * Release a reference to a chipc_region, deactivating and releasing the 516 * backing resource if the reference count hits zero. 517 * 518 * @param sc chipc driver instance state 519 * @param cr region to retain. 520 * @param flags specify RF_ALLOCATED to release an allocation reference, 521 * RF_ACTIVE to release an activation reference. 522 */ 523 int 524 chipc_release_region(struct chipc_softc *sc, struct chipc_region *cr, 525 int flags) 526 { 527 int error; 528 529 CHIPC_LOCK(sc); 530 error = 0; 531 532 KASSERT(cr->cr_res != NULL, ("release on NULL region resource")); 533 534 if (flags & RF_ACTIVE) { 535 KASSERT(cr->cr_act_refs > 0, ("RF_ACTIVE over-released")); 536 KASSERT(cr->cr_act_refs <= cr->cr_refs, 537 ("RF_ALLOCATED released with RF_ACTIVE held")); 538 539 /* If this is the last reference, deactivate the resource */ 540 if (cr->cr_act_refs == 1) { 541 error = bhnd_deactivate_resource(sc->dev, 542 SYS_RES_MEMORY, cr->cr_res_rid, cr->cr_res); 543 if (error) 544 goto done; 545 } 546 547 /* Drop our activation refcount */ 548 cr->cr_act_refs--; 549 } 550 551 if (flags & RF_ALLOCATED) { 552 KASSERT(cr->cr_refs > 0, ("overrelease of refs")); 553 /* If this is the last reference, release the resource */ 554 if (cr->cr_refs == 1) { 555 error = bhnd_release_resource(sc->dev, SYS_RES_MEMORY, 556 cr->cr_res_rid, cr->cr_res); 557 if (error) 558 goto done; 559 560 cr->cr_res = NULL; 561 } 562 563 /* Drop our allocation refcount */ 564 cr->cr_refs--; 565 } 566 567 done: 568 CHIPC_UNLOCK(sc); 569 return (error); 570 } 571