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