1/* 2 * Misc utility routines for accessing chip-specific features 3 * of the SiliconBackplane-based Broadcom chips. 4 * 5 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 16 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 * 19 * $Id: aiutils.c 401759 2013-05-13 16:08:08Z $ 20 */ 21#include <bcm_cfg.h> 22#include <typedefs.h> 23#include <bcmdefs.h> 24#include <osl.h> 25#include <bcmutils.h> 26#include <siutils.h> 27#include <hndsoc.h> 28#include <sbchipc.h> 29#include <pcicfg.h> 30 31#include "siutils_priv.h" 32 33#include <bcmdevs.h> 34 35#define BCM47162_DMP() ((CHIPID(sih->chip) == BCM47162_CHIP_ID) && \ 36 (CHIPREV(sih->chiprev) == 0) && \ 37 (sii->coreid[sii->curidx] == MIPS74K_CORE_ID)) 38 39#define BCM5357_DMP() (((CHIPID(sih->chip) == BCM5357_CHIP_ID) || \ 40 (CHIPID(sih->chip) == BCM4749_CHIP_ID)) && \ 41 (sih->chippkg == BCM5357_PKG_ID) && \ 42 (sii->coreid[sii->curidx] == USB20H_CORE_ID)) 43#define BCM4707_DMP() (BCM4707_CHIP(CHIPID(sih->chip)) && \ 44 (sii->coreid[sii->curidx] == NS_CCB_CORE_ID)) 45 46/* EROM parsing */ 47 48static uint32 49get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) 50{ 51 uint32 ent; 52 uint inv = 0, nom = 0; 53 54 while (TRUE) { 55 ent = R_REG(si_osh(sih), *eromptr); 56 (*eromptr)++; 57 58 if (mask == 0) 59 break; 60 61 if ((ent & ER_VALID) == 0) { 62 inv++; 63 continue; 64 } 65 66 if (ent == (ER_END | ER_VALID)) 67 break; 68 69 if ((ent & mask) == match) 70 break; 71 72 nom++; 73 } 74 75 SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); 76 if (inv + nom) { 77 SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); 78 } 79 return ent; 80} 81 82static uint32 83get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, 84 uint32 *sizel, uint32 *sizeh) 85{ 86 uint32 asd, sz, szd; 87 88 asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); 89 if (((asd & ER_TAG1) != ER_ADD) || 90 (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || 91 ((asd & AD_ST_MASK) != st)) { 92 /* This is not what we want, "push" it back */ 93 (*eromptr)--; 94 return 0; 95 } 96 *addrl = asd & AD_ADDR_MASK; 97 if (asd & AD_AG32) 98 *addrh = get_erom_ent(sih, eromptr, 0, 0); 99 else 100 *addrh = 0; 101 *sizeh = 0; 102 sz = asd & AD_SZ_MASK; 103 if (sz == AD_SZ_SZD) { 104 szd = get_erom_ent(sih, eromptr, 0, 0); 105 *sizel = szd & SD_SZ_MASK; 106 if (szd & SD_SG32) 107 *sizeh = get_erom_ent(sih, eromptr, 0, 0); 108 } else 109 *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); 110 111 SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", 112 sp, ad, st, *sizeh, *sizel, *addrh, *addrl)); 113 114 return asd; 115} 116 117static void 118ai_hwfixup(si_info_t *sii) 119{ 120#ifdef _CFE_ 121 /* Fixup the interrupts in 4716 for i2s core so that ai_flag 122 * works without having to look at the core sinking the 123 * interrupt. We should have done this as the hardware default. 124 * 125 * Future chips should allocate interrupt lines in order (meaning 126 * no line should be skipped), without regard for core index. 127 */ 128 if (BUSTYPE(sii->pub.bustype) == SI_BUS && 129 ((CHIPID(sii->pub.chip) == BCM4716_CHIP_ID) || 130 (CHIPID(sii->pub.chip) == BCM4748_CHIP_ID))) { 131 aidmp_t *i2s, *pcie, *cpu; 132 133 ASSERT(sii->coreid[3] == MIPS74K_CORE_ID); 134 cpu = REG_MAP(sii->wrapba[3], SI_CORE_SIZE); 135 ASSERT(sii->coreid[5] == PCIE_CORE_ID); 136 pcie = REG_MAP(sii->wrapba[5], SI_CORE_SIZE); 137 ASSERT(sii->coreid[8] == I2S_CORE_ID); 138 i2s = REG_MAP(sii->wrapba[8], SI_CORE_SIZE); 139 if ((R_REG(sii->osh, &cpu->oobselina74) != 0x08060504) || 140 (R_REG(sii->osh, &pcie->oobselina74) != 0x08060504) || 141 (R_REG(sii->osh, &i2s->oobselouta30) != 0x88)) { 142 SI_VMSG(("Unexpected oob values, not fixing i2s interrupt\n")); 143 } else { 144 /* Move i2s interrupt to oob line 7 instead of 8 */ 145 W_REG(sii->osh, &cpu->oobselina74, 0x07060504); 146 W_REG(sii->osh, &pcie->oobselina74, 0x07060504); 147 W_REG(sii->osh, &i2s->oobselouta30, 0x87); 148 SI_VMSG(("Changed i2s interrupt to use oob line 7 instead of 8\n")); 149 } 150 } 151#endif /* _CFE_ */ 152} 153 154struct _corerev_entry { 155 uint corerev; 156 uint corerev_alias; 157}; 158static struct _corerev_entry bcm4706_corerev_cc[] = { 159 { 0x1f, CC_4706B0_CORE_REV }, 160 { 0, 0 } 161}; 162static struct _corerev_entry bcm4706_corerev_socsram[] = { 163 { 0x05, SOCRAM_4706B0_CORE_REV }, 164 { 0, 0 } 165}; 166static struct _corerev_entry bcm4706_corerev_gmac[] = { 167 { 0x00, GMAC_4706B0_CORE_REV }, 168 { 0, 0 } 169}; 170 171struct _coreid_entry { 172 uint coreid; 173 uint coreid_alias; 174}; 175static struct _coreid_entry bcm4706_coreid_table[] = { 176 { CC_4706_CORE_ID, CC_CORE_ID }, 177 { SOCRAM_4706_CORE_ID, SOCRAM_CORE_ID }, 178 { GMAC_4706_CORE_ID, GMAC_CORE_ID }, 179 { 0, 0 } 180}; 181 182static uint 183BCMATTACHFN(remap_coreid)(si_t *sih, uint coreid) 184{ 185 struct _coreid_entry *coreid_table = NULL; 186 187 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) 188 coreid_table = &bcm4706_coreid_table[0]; 189 190 if (coreid_table != NULL) { 191 uint i; 192 193 for (i = 0; coreid_table[i].coreid; i++) 194 if (coreid_table[i].coreid == coreid) 195 return coreid_table[i].coreid_alias; 196 } 197 198 return coreid; 199} 200 201static uint 202remap_corerev(si_t *sih, uint corerev) 203{ 204 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 205 si_info_t *sii = SI_INFO(sih); 206 uint i, coreid = sii->coreid[sii->curidx]; 207 struct _corerev_entry *corerev_table = NULL; 208 209 if (coreid == CC_CORE_ID) 210 corerev_table = bcm4706_corerev_cc; 211 else if (coreid == GMAC_CORE_ID) 212 corerev_table = bcm4706_corerev_gmac; 213 else if (coreid == SOCRAM_CORE_ID) 214 corerev_table = bcm4706_corerev_socsram; 215 if (corerev_table != NULL) { 216 for (i = 0; corerev_table[i].corerev_alias; i++) 217 if (corerev_table[i].corerev == corerev) 218 return corerev_table[i].corerev_alias; 219 } 220 } 221 222 return corerev; 223} 224 225/* parse the enumeration rom to identify all cores */ 226void 227BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid) 228{ 229 si_info_t *sii = SI_INFO(sih); 230 chipcregs_t *cc = (chipcregs_t *)regs; 231 uint32 erombase, *eromptr, *eromlim; 232 233 erombase = R_REG(sii->osh, &cc->eromptr); 234 235 switch (BUSTYPE(sih->bustype)) { 236 case SI_BUS: 237 eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); 238 break; 239 240 case PCI_BUS: 241 /* Set wrappers address */ 242 sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); 243 244 /* Now point the window at the erom */ 245 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); 246 eromptr = regs; 247 break; 248 249#ifdef BCMJTAG 250 case JTAG_BUS: 251 eromptr = (uint32 *)(uintptr)erombase; 252 break; 253#endif /* BCMJTAG */ 254 255 case PCMCIA_BUS: 256 default: 257 SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype)); 258 ASSERT(0); 259 return; 260 } 261 eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); 262 263 SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", 264 regs, erombase, eromptr, eromlim)); 265 while (eromptr < eromlim) { 266 uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; 267 uint32 mpd, asd, addrl, addrh, sizel, sizeh; 268 uint i, j, idx; 269 bool br; 270 271 br = FALSE; 272 273 /* Grok a component */ 274 cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); 275 if (cia == (ER_END | ER_VALID)) { 276 SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); 277 ai_hwfixup(sii); 278 return; 279 } 280 281 cib = get_erom_ent(sih, &eromptr, 0, 0); 282 283 if ((cib & ER_TAG) != ER_CI) { 284 SI_ERROR(("CIA not followed by CIB\n")); 285 goto error; 286 } 287 288 cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; 289 mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; 290 crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; 291 nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; 292 nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; 293 nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; 294 nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; 295 296#ifdef BCMDBG_SI 297 SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " 298 "nsw = %d, nmp = %d & nsp = %d\n", 299 mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp)); 300#else 301 BCM_REFERENCE(crev); 302#endif 303 304 if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) 305 continue; 306 if ((nmw + nsw == 0)) { 307 /* A component which is not a core */ 308 if (cid == OOB_ROUTER_CORE_ID) { 309 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, 310 &addrl, &addrh, &sizel, &sizeh); 311 if (asd != 0) { 312 sii->oob_router = addrl; 313 } 314 } 315 if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID) 316 continue; 317 } 318 319 idx = sii->numcores; 320 321 sii->cia[idx] = cia; 322 sii->cib[idx] = cib; 323 sii->coreid[idx] = remap_coreid(sih, cid); 324 325 for (i = 0; i < nmp; i++) { 326 mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); 327 if ((mpd & ER_TAG) != ER_MP) { 328 SI_ERROR(("Not enough MP entries for component 0x%x\n", cid)); 329 goto error; 330 } 331 SI_VMSG((" Master port %d, mp: %d id: %d\n", i, 332 (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, 333 (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); 334 } 335 336 /* First Slave Address Descriptor should be port 0: 337 * the main register space for the core 338 */ 339 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); 340 if (asd == 0) { 341 do { 342 /* Try again to see if it is a bridge */ 343 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, 344 &sizel, &sizeh); 345 if (asd != 0) 346 br = TRUE; 347 else { 348 if (br == TRUE) { 349 break; 350 } 351 else if ((addrh != 0) || (sizeh != 0) || 352 (sizel != SI_CORE_SIZE)) { 353 SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 =" 354 "0x%x\n", addrh, sizeh, sizel)); 355 SI_ERROR(("First Slave ASD for" 356 "core 0x%04x malformed " 357 "(0x%08x)\n", cid, asd)); 358 goto error; 359 } 360 } 361 } while (1); 362 } 363 sii->coresba[idx] = addrl; 364 sii->coresba_size[idx] = sizel; 365 /* Get any more ASDs in port 0 */ 366 j = 1; 367 do { 368 asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, 369 &sizel, &sizeh); 370 if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { 371 sii->coresba2[idx] = addrl; 372 sii->coresba2_size[idx] = sizel; 373 } 374 j++; 375 } while (asd != 0); 376 377 /* Go through the ASDs for other slave ports */ 378 for (i = 1; i < nsp; i++) { 379 j = 0; 380 do { 381 asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, 382 &sizel, &sizeh); 383 384 if (asd == 0) 385 break; 386 j++; 387 } while (1); 388 if (j == 0) { 389 SI_ERROR((" SP %d has no address descriptors\n", i)); 390 goto error; 391 } 392 } 393 394 /* Now get master wrappers */ 395 for (i = 0; i < nmw; i++) { 396 asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh, 397 &sizel, &sizeh); 398 if (asd == 0) { 399 SI_ERROR(("Missing descriptor for MW %d\n", i)); 400 goto error; 401 } 402 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { 403 SI_ERROR(("Master wrapper %d is not 4KB\n", i)); 404 goto error; 405 } 406 if (i == 0) 407 sii->wrapba[idx] = addrl; 408 } 409 410 /* And finally slave wrappers */ 411 for (i = 0; i < nsw; i++) { 412 uint fwp = (nsp == 1) ? 0 : 1; 413 asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh, 414 &sizel, &sizeh); 415 if (asd == 0) { 416 SI_ERROR(("Missing descriptor for SW %d\n", i)); 417 goto error; 418 } 419 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { 420 SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); 421 goto error; 422 } 423 if ((nmw == 0) && (i == 0)) 424 sii->wrapba[idx] = addrl; 425 } 426 427 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 428 /* Check if it's a low cost package */ 429 i = (R_REG(sii->osh, &cc->chipid) & CID_PKG_MASK) >> CID_PKG_SHIFT; 430 if (i == BCM4706L_PKG_ID) { 431 /* bcm4706L: only one GMAC */ 432 if (cid == GMAC_4706_CORE_ID) { 433 for (j = 0; j < sii->numcores; j++) { 434 if (sii->coreid[j] == GMAC_CORE_ID) 435 break; 436 } 437 if (j != sii->numcores) { 438 /* Found one GMAC already, ignore this one */ 439 continue; 440 } 441 } 442 } 443 } 444 445 /* Don't record bridges */ 446 if (br) 447 continue; 448 449 /* Done with core */ 450 sii->numcores++; 451 } 452 453 SI_ERROR(("Reached end of erom without finding END")); 454 455error: 456 sii->numcores = 0; 457 return; 458} 459 460/* This function changes the logical "focus" to the indicated core. 461 * Return the current core's virtual address. 462 */ 463void * 464ai_setcoreidx(si_t *sih, uint coreidx) 465{ 466 si_info_t *sii = SI_INFO(sih); 467 uint32 addr, wrap; 468 void *regs; 469 470 if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) 471 return (NULL); 472 473 addr = sii->coresba[coreidx]; 474 wrap = sii->wrapba[coreidx]; 475 476 /* 477 * If the user has provided an interrupt mask enabled function, 478 * then assert interrupts are disabled before switching the core. 479 */ 480 ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); 481 482 switch (BUSTYPE(sih->bustype)) { 483 case SI_BUS: 484 /* map new one */ 485 if (!sii->regs[coreidx]) { 486 sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); 487 ASSERT(GOODREGS(sii->regs[coreidx])); 488 } 489 sii->curmap = regs = sii->regs[coreidx]; 490 if (!sii->wrappers[coreidx] && (wrap != 0)) { 491 sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); 492 ASSERT(GOODREGS(sii->wrappers[coreidx])); 493 } 494 sii->curwrap = sii->wrappers[coreidx]; 495 break; 496 497 case PCI_BUS: 498 /* point bar0 window */ 499 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); 500 regs = sii->curmap; 501 /* point bar0 2nd 4KB window to the primary wrapper */ 502 if (PCIE_GEN2(sii)) 503 OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap); 504 else 505 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); 506 break; 507 508#ifdef BCMJTAG 509 case JTAG_BUS: 510 sii->curmap = regs = (void *)((uintptr)addr); 511 sii->curwrap = (void *)((uintptr)wrap); 512 break; 513#endif /* BCMJTAG */ 514 515 case PCMCIA_BUS: 516 default: 517 ASSERT(0); 518 regs = NULL; 519 break; 520 } 521 522 sii->curmap = regs; 523 sii->curidx = coreidx; 524 525 return regs; 526} 527 528void 529ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) 530{ 531 si_info_t *sii = SI_INFO(sih); 532 chipcregs_t *cc = NULL; 533 uint32 erombase, *eromptr, *eromlim; 534 uint i, j, cidx; 535 uint32 cia, cib, nmp, nsp; 536 uint32 asd, addrl, addrh, sizel, sizeh; 537 538 for (i = 0; i < sii->numcores; i++) { 539 if (sii->coreid[i] == CC_CORE_ID) { 540 cc = (chipcregs_t *)sii->regs[i]; 541 break; 542 } 543 } 544 if (cc == NULL) 545 goto error; 546 547 erombase = R_REG(sii->osh, &cc->eromptr); 548 eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); 549 eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); 550 551 cidx = sii->curidx; 552 cia = sii->cia[cidx]; 553 cib = sii->cib[cidx]; 554 555 nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; 556 nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; 557 558 /* scan for cores */ 559 while (eromptr < eromlim) { 560 if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && 561 (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { 562 break; 563 } 564 } 565 566 /* skip master ports */ 567 for (i = 0; i < nmp; i++) 568 get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); 569 570 /* Skip ASDs in port 0 */ 571 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); 572 if (asd == 0) { 573 /* Try again to see if it is a bridge */ 574 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, 575 &sizel, &sizeh); 576 } 577 578 j = 1; 579 do { 580 asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, 581 &sizel, &sizeh); 582 j++; 583 } while (asd != 0); 584 585 /* Go through the ASDs for other slave ports */ 586 for (i = 1; i < nsp; i++) { 587 j = 0; 588 do { 589 asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, 590 &sizel, &sizeh); 591 if (asd == 0) 592 break; 593 594 if (!asidx--) { 595 *addr = addrl; 596 *size = sizel; 597 return; 598 } 599 j++; 600 } while (1); 601 602 if (j == 0) { 603 SI_ERROR((" SP %d has no address descriptors\n", i)); 604 break; 605 } 606 } 607 608error: 609 *size = 0; 610 return; 611} 612 613/* Return the number of address spaces in current core */ 614int 615ai_numaddrspaces(si_t *sih) 616{ 617 return 2; 618} 619 620/* Return the address of the nth address space in the current core */ 621uint32 622ai_addrspace(si_t *sih, uint asidx) 623{ 624 si_info_t *sii; 625 uint cidx; 626 627 sii = SI_INFO(sih); 628 cidx = sii->curidx; 629 630 if (asidx == 0) 631 return sii->coresba[cidx]; 632 else if (asidx == 1) 633 return sii->coresba2[cidx]; 634 else { 635 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", 636 __FUNCTION__, asidx)); 637 return 0; 638 } 639} 640 641/* Return the size of the nth address space in the current core */ 642uint32 643ai_addrspacesize(si_t *sih, uint asidx) 644{ 645 si_info_t *sii; 646 uint cidx; 647 648 sii = SI_INFO(sih); 649 cidx = sii->curidx; 650 651 if (asidx == 0) 652 return sii->coresba_size[cidx]; 653 else if (asidx == 1) 654 return sii->coresba2_size[cidx]; 655 else { 656 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", 657 __FUNCTION__, asidx)); 658 return 0; 659 } 660} 661 662uint 663ai_flag(si_t *sih) 664{ 665 si_info_t *sii; 666 aidmp_t *ai; 667 668 sii = SI_INFO(sih); 669 if (BCM47162_DMP()) { 670 SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); 671 return sii->curidx; 672 } 673 if (BCM5357_DMP()) { 674 SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); 675 return sii->curidx; 676 } 677 if (BCM4707_DMP()) { 678 SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", 679 __FUNCTION__)); 680 return sii->curidx; 681 } 682 ai = sii->curwrap; 683 684 return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); 685} 686 687uint 688ai_flag_alt(si_t *sih) 689{ 690 si_info_t *sii; 691 aidmp_t *ai; 692 693 sii = SI_INFO(sih); 694 if (BCM47162_DMP()) { 695 SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); 696 return sii->curidx; 697 } 698 if (BCM5357_DMP()) { 699 SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); 700 return sii->curidx; 701 } 702 if (BCM4707_DMP()) { 703 SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", 704 __FUNCTION__)); 705 return sii->curidx; 706 } 707 ai = sii->curwrap; 708 709 return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK); 710} 711 712void 713ai_setint(si_t *sih, int siflag) 714{ 715} 716 717uint 718ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) 719{ 720 si_info_t *sii = SI_INFO(sih); 721 uint32 *map = (uint32 *) sii->curwrap; 722 723 if (mask || val) { 724 uint32 w = R_REG(sii->osh, map+(offset/4)); 725 w &= ~mask; 726 w |= val; 727 W_REG(sii->osh, map+(offset/4), w); 728 } 729 730 return (R_REG(sii->osh, map+(offset/4))); 731} 732 733uint 734ai_corevendor(si_t *sih) 735{ 736 si_info_t *sii; 737 uint32 cia; 738 739 sii = SI_INFO(sih); 740 cia = sii->cia[sii->curidx]; 741 return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); 742} 743 744uint 745ai_corerev(si_t *sih) 746{ 747 si_info_t *sii; 748 uint32 cib; 749 750 sii = SI_INFO(sih); 751 cib = sii->cib[sii->curidx]; 752 return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); 753} 754 755bool 756ai_iscoreup(si_t *sih) 757{ 758 si_info_t *sii; 759 aidmp_t *ai; 760 761 sii = SI_INFO(sih); 762 ai = sii->curwrap; 763 764 return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && 765 ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); 766} 767 768/* 769 * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, 770 * switch back to the original core, and return the new value. 771 * 772 * When using the silicon backplane, no fiddling with interrupts or core switches is needed. 773 * 774 * Also, when using pci/pcie, we can optimize away the core switching for pci registers 775 * and (on newer pci cores) chipcommon registers. 776 */ 777uint 778ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) 779{ 780 uint origidx = 0; 781 uint32 *r = NULL; 782 uint w; 783 uint intr_val = 0; 784 bool fast = FALSE; 785 si_info_t *sii; 786 787 sii = SI_INFO(sih); 788 789 ASSERT(GOODIDX(coreidx)); 790 ASSERT(regoff < SI_CORE_SIZE); 791 ASSERT((val & ~mask) == 0); 792 793 if (coreidx >= SI_MAXCORES) 794 return 0; 795 796 if (BUSTYPE(sih->bustype) == SI_BUS) { 797 /* If internal bus, we can always get at everything */ 798 fast = TRUE; 799 /* map if does not exist */ 800 if (!sii->regs[coreidx]) { 801 sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], 802 SI_CORE_SIZE); 803 ASSERT(GOODREGS(sii->regs[coreidx])); 804 } 805 r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); 806 } else if (BUSTYPE(sih->bustype) == PCI_BUS) { 807 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ 808 809 if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { 810 /* Chipc registers are mapped at 12KB */ 811 812 fast = TRUE; 813 r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); 814 } else if (sii->pub.buscoreidx == coreidx) { 815 /* pci registers are at either in the last 2KB of an 8KB window 816 * or, in pcie and pci rev 13 at 8KB 817 */ 818 fast = TRUE; 819 if (SI_FAST(sii)) 820 r = (uint32 *)((char *)sii->curmap + 821 PCI_16KB0_PCIREGS_OFFSET + regoff); 822 else 823 r = (uint32 *)((char *)sii->curmap + 824 ((regoff >= SBCONFIGOFF) ? 825 PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + 826 regoff); 827 } 828 } 829 830 if (!fast) { 831 INTR_OFF(sii, intr_val); 832 833 /* save current core index */ 834 origidx = si_coreidx(&sii->pub); 835 836 /* switch core */ 837 r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); 838 } 839 ASSERT(r != NULL); 840 841 /* mask and set */ 842 if (mask || val) { 843 w = (R_REG(sii->osh, r) & ~mask) | val; 844 W_REG(sii->osh, r, w); 845 } 846 847 /* readback */ 848 w = R_REG(sii->osh, r); 849 850 if (!fast) { 851 /* restore core index */ 852 if (origidx != coreidx) 853 ai_setcoreidx(&sii->pub, origidx); 854 855 INTR_RESTORE(sii, intr_val); 856 } 857 858 return (w); 859} 860 861void 862ai_core_disable(si_t *sih, uint32 bits) 863{ 864 si_info_t *sii; 865 volatile uint32 dummy; 866 uint32 status; 867 aidmp_t *ai; 868 869 sii = SI_INFO(sih); 870 871 ASSERT(GOODREGS(sii->curwrap)); 872 ai = sii->curwrap; 873 874 /* if core is already in reset, just return */ 875 if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) 876 return; 877 878 /* ensure there are no pending backplane operations */ 879 SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); 880 881 /* if pending backplane ops still, try waiting longer */ 882 if (status != 0) { 883 /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ 884 /* during driver load we may need more time */ 885 SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); 886 /* if still pending ops, continue on and try disable anyway */ 887 /* this is in big hammer path, so don't call wl_reinit in this case... */ 888 } 889 890 W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); 891 dummy = R_REG(sii->osh, &ai->resetctrl); 892 BCM_REFERENCE(dummy); 893 OSL_DELAY(1); 894 895 W_REG(sii->osh, &ai->ioctrl, bits); 896 dummy = R_REG(sii->osh, &ai->ioctrl); 897 BCM_REFERENCE(dummy); 898 OSL_DELAY(10); 899} 900 901/* reset and re-enable a core 902 * inputs: 903 * bits - core specific bits that are set during and after reset sequence 904 * resetbits - core specific bits that are set only during reset sequence 905 */ 906void 907ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) 908{ 909 si_info_t *sii; 910 aidmp_t *ai; 911 volatile uint32 dummy; 912 uint loop_counter = 10; 913 914 sii = SI_INFO(sih); 915 ASSERT(GOODREGS(sii->curwrap)); 916 ai = sii->curwrap; 917 918 /* ensure there are no pending backplane operations */ 919 SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); 920 921 922 W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN)); 923 dummy = R_REG(sii->osh, &ai->ioctrl); 924 BCM_REFERENCE(dummy); 925 926 /* ensure there are no pending backplane operations */ 927 SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); 928 929 930 /* put core into reset state */ 931 W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); 932 OSL_DELAY(10); 933 934 while (R_REG(sii->osh, &ai->resetctrl) != 0 && --loop_counter != 0) { 935 /* ensure there are no pending backplane operations */ 936 SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); 937 938 939 /* take core out of reset */ 940 W_REG(sii->osh, &ai->resetctrl, 0); 941 942 /* ensure there are no pending backplane operations */ 943 SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); 944 } 945 946 947 W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); 948 dummy = R_REG(sii->osh, &ai->ioctrl); 949 BCM_REFERENCE(dummy); 950 OSL_DELAY(1); 951} 952 953void 954ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) 955{ 956 si_info_t *sii; 957 aidmp_t *ai; 958 uint32 w; 959 960 sii = SI_INFO(sih); 961 962 if (BCM47162_DMP()) { 963 SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", 964 __FUNCTION__)); 965 return; 966 } 967 if (BCM5357_DMP()) { 968 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", 969 __FUNCTION__)); 970 return; 971 } 972 if (BCM4707_DMP()) { 973 SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", 974 __FUNCTION__)); 975 return; 976 } 977 978 ASSERT(GOODREGS(sii->curwrap)); 979 ai = sii->curwrap; 980 981 ASSERT((val & ~mask) == 0); 982 983 if (mask || val) { 984 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); 985 W_REG(sii->osh, &ai->ioctrl, w); 986 } 987} 988 989uint32 990ai_core_cflags(si_t *sih, uint32 mask, uint32 val) 991{ 992 si_info_t *sii; 993 aidmp_t *ai; 994 uint32 w; 995 996 sii = SI_INFO(sih); 997 if (BCM47162_DMP()) { 998 SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", 999 __FUNCTION__)); 1000 return 0; 1001 } 1002 if (BCM5357_DMP()) { 1003 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", 1004 __FUNCTION__)); 1005 return 0; 1006 } 1007 if (BCM4707_DMP()) { 1008 SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", 1009 __FUNCTION__)); 1010 return 0; 1011 } 1012 1013 ASSERT(GOODREGS(sii->curwrap)); 1014 ai = sii->curwrap; 1015 1016 ASSERT((val & ~mask) == 0); 1017 1018 if (mask || val) { 1019 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); 1020 W_REG(sii->osh, &ai->ioctrl, w); 1021 } 1022 1023 return R_REG(sii->osh, &ai->ioctrl); 1024} 1025 1026uint32 1027ai_core_sflags(si_t *sih, uint32 mask, uint32 val) 1028{ 1029 si_info_t *sii; 1030 aidmp_t *ai; 1031 uint32 w; 1032 1033 sii = SI_INFO(sih); 1034 if (BCM47162_DMP()) { 1035 SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", 1036 __FUNCTION__)); 1037 return 0; 1038 } 1039 if (BCM5357_DMP()) { 1040 SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", 1041 __FUNCTION__)); 1042 return 0; 1043 } 1044 if (BCM4707_DMP()) { 1045 SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", 1046 __FUNCTION__)); 1047 return 0; 1048 } 1049 1050 ASSERT(GOODREGS(sii->curwrap)); 1051 ai = sii->curwrap; 1052 1053 ASSERT((val & ~mask) == 0); 1054 ASSERT((mask & ~SISF_CORE_BITS) == 0); 1055 1056 if (mask || val) { 1057 w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); 1058 W_REG(sii->osh, &ai->iostatus, w); 1059 } 1060 1061 return R_REG(sii->osh, &ai->iostatus); 1062} 1063 1064#if defined(BCMDBG_DUMP) 1065/* print interesting aidmp registers */ 1066void 1067ai_dumpregs(si_t *sih, struct bcmstrbuf *b) 1068{ 1069 si_info_t *sii; 1070 osl_t *osh; 1071 aidmp_t *ai; 1072 uint i; 1073 1074 sii = SI_INFO(sih); 1075 osh = sii->osh; 1076 1077 for (i = 0; i < sii->numcores; i++) { 1078 si_setcoreidx(&sii->pub, i); 1079 ai = sii->curwrap; 1080 1081 bcm_bprintf(b, "core 0x%x: \n", sii->coreid[i]); 1082 if (BCM47162_DMP()) { 1083 bcm_bprintf(b, "Skipping mips74k in 47162a0\n"); 1084 continue; 1085 } 1086 if (BCM5357_DMP()) { 1087 bcm_bprintf(b, "Skipping usb20h in 5357\n"); 1088 continue; 1089 } 1090 if (BCM4707_DMP()) { 1091 bcm_bprintf(b, "Skipping chipcommonb in 4707\n"); 1092 continue; 1093 } 1094 1095 bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x" 1096 "ioctrlwidth 0x%x iostatuswidth 0x%x\n" 1097 "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n" 1098 "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x" 1099 "errlogaddrlo 0x%x errlogaddrhi 0x%x\n" 1100 "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n" 1101 "intstatus 0x%x config 0x%x itcr 0x%x\n", 1102 R_REG(osh, &ai->ioctrlset), 1103 R_REG(osh, &ai->ioctrlclear), 1104 R_REG(osh, &ai->ioctrl), 1105 R_REG(osh, &ai->iostatus), 1106 R_REG(osh, &ai->ioctrlwidth), 1107 R_REG(osh, &ai->iostatuswidth), 1108 R_REG(osh, &ai->resetctrl), 1109 R_REG(osh, &ai->resetstatus), 1110 R_REG(osh, &ai->resetreadid), 1111 R_REG(osh, &ai->resetwriteid), 1112 R_REG(osh, &ai->errlogctrl), 1113 R_REG(osh, &ai->errlogdone), 1114 R_REG(osh, &ai->errlogstatus), 1115 R_REG(osh, &ai->errlogaddrlo), 1116 R_REG(osh, &ai->errlogaddrhi), 1117 R_REG(osh, &ai->errlogid), 1118 R_REG(osh, &ai->errloguser), 1119 R_REG(osh, &ai->errlogflags), 1120 R_REG(osh, &ai->intstatus), 1121 R_REG(osh, &ai->config), 1122 R_REG(osh, &ai->itcr)); 1123 if ((sih->chip == BCM4331_CHIP_ID) && (sii->coreid[i] == PCIE_CORE_ID)) { 1124 /* point bar0 2nd 4KB window */ 1125 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, 0x18103000); 1126 bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x" 1127 "ioctrlwidth 0x%x iostatuswidth 0x%x\n" 1128 "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x" 1129 " resetwriteid 0x%x\n" 1130 "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x" 1131 "errlogaddrlo 0x%x errlogaddrhi 0x%x\n" 1132 "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n" 1133 "intstatus 0x%x config 0x%x itcr 0x%x\n", 1134 R_REG(osh, &ai->ioctrlset), 1135 R_REG(osh, &ai->ioctrlclear), 1136 R_REG(osh, &ai->ioctrl), 1137 R_REG(osh, &ai->iostatus), 1138 R_REG(osh, &ai->ioctrlwidth), 1139 R_REG(osh, &ai->iostatuswidth), 1140 R_REG(osh, &ai->resetctrl), 1141 R_REG(osh, &ai->resetstatus), 1142 R_REG(osh, &ai->resetreadid), 1143 R_REG(osh, &ai->resetwriteid), 1144 R_REG(osh, &ai->errlogctrl), 1145 R_REG(osh, &ai->errlogdone), 1146 R_REG(osh, &ai->errlogstatus), 1147 R_REG(osh, &ai->errlogaddrlo), 1148 R_REG(osh, &ai->errlogaddrhi), 1149 R_REG(osh, &ai->errlogid), 1150 R_REG(osh, &ai->errloguser), 1151 R_REG(osh, &ai->errlogflags), 1152 R_REG(osh, &ai->intstatus), 1153 R_REG(osh, &ai->config), 1154 R_REG(osh, &ai->itcr)); 1155 /* bar0 2nd 4KB window will be fixed in the next setcore */ 1156 } 1157 } 1158} 1159#endif 1160