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