1/* 2 * Misc utility routines for accessing chip-specific features 3 * of the SiliconBackplane-based Broadcom chips. 4 * 5 * Copyright (C) 2010, 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,v 1.27.2.5 2011-01-26 18:24:11 Exp $ 20 */ 21 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 44/* EROM parsing */ 45 46static uint32 47get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) 48{ 49 uint32 ent; 50 uint inv = 0, nom = 0; 51 52 while (TRUE) { 53 ent = R_REG(si_osh(sih), *eromptr); 54 (*eromptr)++; 55 56 if (mask == 0) 57 break; 58 59 if ((ent & ER_VALID) == 0) { 60 inv++; 61 continue; 62 } 63 64 if (ent == (ER_END | ER_VALID)) 65 break; 66 67 if ((ent & mask) == match) 68 break; 69 70 nom++; 71 } 72 73 SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); 74 if (inv + nom) { 75 SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); 76 } 77 return ent; 78} 79 80static uint32 81get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, 82 uint32 *sizel, uint32 *sizeh) 83{ 84 uint32 asd, sz, szd; 85 86 asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); 87 if (((asd & ER_TAG1) != ER_ADD) || 88 (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || 89 ((asd & AD_ST_MASK) != st)) { 90 /* This is not what we want, "push" it back */ 91 (*eromptr)--; 92 return 0; 93 } 94 *addrl = asd & AD_ADDR_MASK; 95 if (asd & AD_AG32) 96 *addrh = get_erom_ent(sih, eromptr, 0, 0); 97 else 98 *addrh = 0; 99 *sizeh = 0; 100 sz = asd & AD_SZ_MASK; 101 if (sz == AD_SZ_SZD) { 102 szd = get_erom_ent(sih, eromptr, 0, 0); 103 *sizel = szd & SD_SZ_MASK; 104 if (szd & SD_SG32) 105 *sizeh = get_erom_ent(sih, eromptr, 0, 0); 106 } else 107 *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); 108 109 SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", 110 sp, ad, st, *sizeh, *sizel, *addrh, *addrl)); 111 112 return asd; 113} 114 115static void 116ai_hwfixup(si_info_t *sii) 117{ 118#ifdef _CFE_ 119 /* Fixup the interrupts in 4716 for i2s core so that ai_flag 120 * works without having to look at the core sinking the 121 * interrupt. We should have done this as the hardware default. 122 * 123 * Future chips should allocate interrupt lines in order (meaning 124 * no line should be skipped), without regard for core index. 125 */ 126 if (BUSTYPE(sii->pub.bustype) == SI_BUS && 127 ((CHIPID(sii->pub.chip) == BCM4716_CHIP_ID) || 128 (CHIPID(sii->pub.chip) == BCM4748_CHIP_ID))) { 129 aidmp_t *i2s, *pcie, *cpu; 130 131 ASSERT(sii->coreid[3] == MIPS74K_CORE_ID); 132 cpu = REG_MAP(sii->wrapba[3], SI_CORE_SIZE); 133 ASSERT(sii->coreid[5] == PCIE_CORE_ID); 134 pcie = REG_MAP(sii->wrapba[5], SI_CORE_SIZE); 135 ASSERT(sii->coreid[8] == I2S_CORE_ID); 136 i2s = REG_MAP(sii->wrapba[8], SI_CORE_SIZE); 137 if ((R_REG(sii->osh, &cpu->oobselina74) != 0x08060504) || 138 (R_REG(sii->osh, &pcie->oobselina74) != 0x08060504) || 139 (R_REG(sii->osh, &i2s->oobselouta30) != 0x88)) { 140 SI_VMSG(("Unexpected oob values, not fixing i2s interrupt\n")); 141 } else { 142 /* Move i2s interrupt to oob line 7 instead of 8 */ 143 W_REG(sii->osh, &cpu->oobselina74, 0x07060504); 144 W_REG(sii->osh, &pcie->oobselina74, 0x07060504); 145 W_REG(sii->osh, &i2s->oobselouta30, 0x87); 146 SI_VMSG(("Changed i2s interrupt to use oob line 7 instead of 8\n")); 147 } 148 } 149#endif /* _CFE_ */ 150} 151 152struct _corerev_entry { 153 uint corerev; 154 uint corerev_alias; 155}; 156static struct _corerev_entry bcm4706_corerev_cc[] = { 157 { 0x1f, CC_4706B0_CORE_REV }, 158 { 0, 0 } 159}; 160static struct _corerev_entry bcm4706_corerev_socsram[] = { 161 { 0x05, SOCRAM_4706B0_CORE_REV }, 162 { 0, 0 } 163}; 164static struct _corerev_entry bcm4706_corerev_gmac[] = { 165 { 0x00, GMAC_4706B0_CORE_REV }, 166 { 0, 0 } 167}; 168 169struct _coreid_entry { 170 uint coreid; 171 uint coreid_alias; 172}; 173static struct _coreid_entry bcm4706_coreid_table[] = { 174 { CC_4706_CORE_ID, CC_CORE_ID }, 175 { SOCRAM_4706_CORE_ID, SOCRAM_CORE_ID }, 176 { GMAC_4706_CORE_ID, GMAC_CORE_ID }, 177 { 0, 0 } 178}; 179 180static uint 181remap_coreid(si_t *sih, uint coreid) 182{ 183 struct _coreid_entry *coreid_table = NULL; 184 185 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) 186 coreid_table = &bcm4706_coreid_table[0]; 187 188 if (coreid_table != NULL) { 189 uint i; 190 191 for (i = 0; coreid_table[i].coreid; i++) 192 if (coreid_table[i].coreid == coreid) 193 return coreid_table[i].coreid_alias; 194 } 195 196 return coreid; 197} 198 199static uint 200remap_corerev(si_t *sih, uint corerev) 201{ 202 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 203 si_info_t *sii = SI_INFO(sih); 204 uint i, coreid = sii->coreid[sii->curidx]; 205 struct _corerev_entry *corerev_table = NULL; 206 207 if (coreid == CC_CORE_ID) 208 corerev_table = bcm4706_corerev_cc; 209 else if (coreid == GMAC_CORE_ID) 210 corerev_table = bcm4706_corerev_gmac; 211 else if (coreid == SOCRAM_CORE_ID) 212 corerev_table = bcm4706_corerev_socsram; 213 if (corerev_table != NULL) { 214 for (i = 0; corerev_table[i].corerev_alias; i++) 215 if (corerev_table[i].corerev == corerev) 216 return corerev_table[i].corerev_alias; 217 } 218 } 219 220 return corerev; 221} 222 223/* parse the enumeration rom to identify all cores */ 224void 225BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid) 226{ 227 si_info_t *sii = SI_INFO(sih); 228 chipcregs_t *cc = (chipcregs_t *)regs; 229 uint32 erombase, *eromptr, *eromlim; 230 231 erombase = R_REG(sii->osh, &cc->eromptr); 232 233 switch (BUSTYPE(sih->bustype)) { 234 case SI_BUS: 235 eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); 236 break; 237 238 case PCI_BUS: 239 /* Set wrappers address */ 240 sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); 241 242 /* Now point the window at the erom */ 243 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); 244 eromptr = regs; 245 break; 246 247#ifdef BCMJTAG 248 case JTAG_BUS: 249 eromptr = (uint32 *)(uintptr)erombase; 250 break; 251#endif /* BCMJTAG */ 252 253 case PCMCIA_BUS: 254 default: 255 SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype)); 256 ASSERT(0); 257 return; 258 } 259 eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); 260 261 SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", 262 regs, erombase, eromptr, eromlim)); 263 while (eromptr < eromlim) { 264 uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; 265 uint32 mpd, asd, addrl, addrh, sizel, sizeh; 266 uint32 *base; 267 uint i, j, idx; 268 bool br; 269 270 br = FALSE; 271 272 /* Grok a component */ 273 cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); 274 if (cia == (ER_END | ER_VALID)) { 275 SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); 276 ai_hwfixup(sii); 277 return; 278 } 279 base = eromptr - 1; 280 cib = get_erom_ent(sih, &eromptr, 0, 0); 281 282 if ((cib & ER_TAG) != ER_CI) { 283 SI_ERROR(("CIA not followed by CIB\n")); 284 goto error; 285 } 286 287 cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; 288 mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; 289 crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; 290 nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; 291 nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; 292 nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; 293 nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; 294 295 SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " 296 "nsw = %d, nmp = %d & nsp = %d\n", 297 mfg, cid, crev, base, nmw, nsw, nmp, nsp)); 298 299 if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) 300 continue; 301 if ((nmw + nsw == 0)) { 302 /* A component which is not a core */ 303 if (cid == OOB_ROUTER_CORE_ID) { 304 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, 305 &addrl, &addrh, &sizel, &sizeh); 306 if (asd != 0) { 307 sii->oob_router = addrl; 308 } 309 } 310 if (cid != GMAC_COMMON_4706_CORE_ID) 311 continue; 312 } 313 314 idx = sii->numcores; 315/* sii->eromptr[idx] = base; */ 316 sii->cia[idx] = cia; 317 sii->cib[idx] = cib; 318 sii->coreid[idx] = remap_coreid(sih, cid); 319 320 for (i = 0; i < nmp; i++) { 321 mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); 322 if ((mpd & ER_TAG) != ER_MP) { 323 SI_ERROR(("Not enough MP entries for component 0x%x\n", cid)); 324 goto error; 325 } 326 SI_VMSG((" Master port %d, mp: %d id: %d\n", i, 327 (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, 328 (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); 329 } 330 331 /* First Slave Address Descriptor should be port 0: 332 * the main register space for the core 333 */ 334 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); 335 if (asd == 0) { 336 /* Try again to see if it is a bridge */ 337 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, 338 &sizel, &sizeh); 339 if (asd != 0) 340 br = TRUE; 341 else 342 if ((addrh != 0) || (sizeh != 0) || (sizel != SI_CORE_SIZE)) { 343 SI_ERROR(("First Slave ASD for core 0x%04x malformed " 344 "(0x%08x)\n", cid, asd)); 345 goto error; 346 } 347 } 348 sii->coresba[idx] = addrl; 349 sii->coresba_size[idx] = sizel; 350 /* Get any more ASDs in port 0 */ 351 j = 1; 352 do { 353 asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, 354 &sizel, &sizeh); 355 if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { 356 sii->coresba2[idx] = addrl; 357 sii->coresba2_size[idx] = sizel; 358 } 359 j++; 360 } while (asd != 0); 361 362 /* Go through the ASDs for other slave ports */ 363 for (i = 1; i < nsp; i++) { 364 j = 0; 365 do { 366 asd = get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE, &addrl, &addrh, 367 &sizel, &sizeh); 368 } while (asd != 0); 369 if (j == 0) { 370 SI_ERROR((" SP %d has no address descriptors\n", i)); 371 goto error; 372 } 373 } 374 375 /* Now get master wrappers */ 376 for (i = 0; i < nmw; i++) { 377 asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh, 378 &sizel, &sizeh); 379 if (asd == 0) { 380 SI_ERROR(("Missing descriptor for MW %d\n", i)); 381 goto error; 382 } 383 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { 384 SI_ERROR(("Master wrapper %d is not 4KB\n", i)); 385 goto error; 386 } 387 if (i == 0) 388 sii->wrapba[idx] = addrl; 389 } 390 391 /* And finally slave wrappers */ 392 for (i = 0; i < nsw; i++) { 393 uint fwp = (nsp == 1) ? 0 : 1; 394 asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh, 395 &sizel, &sizeh); 396 if (asd == 0) { 397 SI_ERROR(("Missing descriptor for SW %d\n", i)); 398 goto error; 399 } 400 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { 401 SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); 402 goto error; 403 } 404 if ((nmw == 0) && (i == 0)) 405 sii->wrapba[idx] = addrl; 406 } 407 408 /* Don't record bridges */ 409 if (br) 410 continue; 411 412 /* Done with core */ 413 sii->numcores++; 414 } 415 416 SI_ERROR(("Reached end of erom without finding END")); 417 418error: 419 sii->numcores = 0; 420 return; 421} 422 423/* This function changes the logical "focus" to the indicated core. 424 * Return the current core's virtual address. 425 */ 426void * 427ai_setcoreidx(si_t *sih, uint coreidx) 428{ 429 si_info_t *sii = SI_INFO(sih); 430 uint32 addr = sii->coresba[coreidx]; 431 uint32 wrap = sii->wrapba[coreidx]; 432 void *regs; 433 434 if (coreidx >= sii->numcores) 435 return (NULL); 436 437 /* 438 * If the user has provided an interrupt mask enabled function, 439 * then assert interrupts are disabled before switching the core. 440 */ 441 ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); 442 443 switch (BUSTYPE(sih->bustype)) { 444 case SI_BUS: 445 /* map new one */ 446 if (!sii->regs[coreidx]) { 447 sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); 448 ASSERT(GOODREGS(sii->regs[coreidx])); 449 } 450 sii->curmap = regs = sii->regs[coreidx]; 451 if (!sii->wrappers[coreidx]) { 452 sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); 453 ASSERT(GOODREGS(sii->wrappers[coreidx])); 454 } 455 sii->curwrap = sii->wrappers[coreidx]; 456 break; 457 458 case PCI_BUS: 459 /* point bar0 window */ 460 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); 461 regs = sii->curmap; 462 /* point bar0 2nd 4KB window */ 463 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); 464 break; 465 466#ifdef BCMJTAG 467 case JTAG_BUS: 468 sii->curmap = regs = (void *)((uintptr)addr); 469 sii->curwrap = (void *)((uintptr)wrap); 470 break; 471#endif /* BCMJTAG */ 472 473 case PCMCIA_BUS: 474 default: 475 ASSERT(0); 476 regs = NULL; 477 break; 478 } 479 480 sii->curmap = regs; 481 sii->curidx = coreidx; 482 483 return regs; 484} 485 486/* Return the number of address spaces in current core */ 487int 488ai_numaddrspaces(si_t *sih) 489{ 490 return 2; 491} 492 493/* Return the address of the nth address space in the current core */ 494uint32 495ai_addrspace(si_t *sih, uint asidx) 496{ 497 si_info_t *sii; 498 uint cidx; 499 500 sii = SI_INFO(sih); 501 cidx = sii->curidx; 502 503 if (asidx == 0) 504 return sii->coresba[cidx]; 505 else if (asidx == 1) 506 return sii->coresba2[cidx]; 507 else { 508 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", 509 __FUNCTION__, asidx)); 510 return 0; 511 } 512} 513 514/* Return the size of the nth address space in the current core */ 515uint32 516ai_addrspacesize(si_t *sih, uint asidx) 517{ 518 si_info_t *sii; 519 uint cidx; 520 521 sii = SI_INFO(sih); 522 cidx = sii->curidx; 523 524 if (asidx == 0) 525 return sii->coresba_size[cidx]; 526 else if (asidx == 1) 527 return sii->coresba2_size[cidx]; 528 else { 529 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", 530 __FUNCTION__, asidx)); 531 return 0; 532 } 533} 534 535uint 536ai_flag(si_t *sih) 537{ 538 si_info_t *sii; 539 aidmp_t *ai; 540 541 sii = SI_INFO(sih); 542 if (BCM47162_DMP()) { 543 SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); 544 return sii->curidx; 545 } 546 if (BCM5357_DMP()) { 547 SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); 548 return sii->curidx; 549 } 550 ai = sii->curwrap; 551 552 return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); 553} 554 555void 556ai_setint(si_t *sih, int siflag) 557{ 558} 559 560void 561ai_write_wrap_reg(si_t *sih, uint32 offset, uint32 val) 562{ 563 si_info_t *sii = SI_INFO(sih); 564 uint32 *w = (uint32 *) sii->curwrap; 565 W_REG(sii->osh, w+(offset/4), val); 566 return; 567} 568 569uint 570ai_corevendor(si_t *sih) 571{ 572 si_info_t *sii; 573 uint32 cia; 574 575 sii = SI_INFO(sih); 576 cia = sii->cia[sii->curidx]; 577 return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); 578} 579 580uint 581ai_corerev(si_t *sih) 582{ 583 si_info_t *sii; 584 uint32 cib; 585 586 sii = SI_INFO(sih); 587 cib = sii->cib[sii->curidx]; 588 return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); 589} 590 591bool 592ai_iscoreup(si_t *sih) 593{ 594 si_info_t *sii; 595 aidmp_t *ai; 596 597 sii = SI_INFO(sih); 598 ai = sii->curwrap; 599 600 return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && 601 ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); 602} 603 604/* 605 * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, 606 * switch back to the original core, and return the new value. 607 * 608 * When using the silicon backplane, no fiddling with interrupts or core switches is needed. 609 * 610 * Also, when using pci/pcie, we can optimize away the core switching for pci registers 611 * and (on newer pci cores) chipcommon registers. 612 */ 613uint 614ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) 615{ 616 uint origidx = 0; 617 uint32 *r = NULL; 618 uint w; 619 uint intr_val = 0; 620 bool fast = FALSE; 621 si_info_t *sii; 622 623 sii = SI_INFO(sih); 624 625 ASSERT(GOODIDX(coreidx)); 626 ASSERT(regoff < SI_CORE_SIZE); 627 ASSERT((val & ~mask) == 0); 628 629 if (coreidx >= SI_MAXCORES) 630 return 0; 631 632 if (BUSTYPE(sih->bustype) == SI_BUS) { 633 /* If internal bus, we can always get at everything */ 634 fast = TRUE; 635 /* map if does not exist */ 636 if (!sii->regs[coreidx]) { 637 sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], 638 SI_CORE_SIZE); 639 ASSERT(GOODREGS(sii->regs[coreidx])); 640 } 641 r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); 642 } else if (BUSTYPE(sih->bustype) == PCI_BUS) { 643 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ 644 645 if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { 646 /* Chipc registers are mapped at 12KB */ 647 648 fast = TRUE; 649 r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); 650 } else if (sii->pub.buscoreidx == coreidx) { 651 /* pci registers are at either in the last 2KB of an 8KB window 652 * or, in pcie and pci rev 13 at 8KB 653 */ 654 fast = TRUE; 655 if (SI_FAST(sii)) 656 r = (uint32 *)((char *)sii->curmap + 657 PCI_16KB0_PCIREGS_OFFSET + regoff); 658 else 659 r = (uint32 *)((char *)sii->curmap + 660 ((regoff >= SBCONFIGOFF) ? 661 PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + 662 regoff); 663 } 664 } 665 666 if (!fast) { 667 INTR_OFF(sii, intr_val); 668 669 /* save current core index */ 670 origidx = si_coreidx(&sii->pub); 671 672 /* switch core */ 673 r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); 674 } 675 ASSERT(r != NULL); 676 677 /* mask and set */ 678 if (mask || val) { 679 w = (R_REG(sii->osh, r) & ~mask) | val; 680 W_REG(sii->osh, r, w); 681 } 682 683 /* readback */ 684 w = R_REG(sii->osh, r); 685 686 if (!fast) { 687 /* restore core index */ 688 if (origidx != coreidx) 689 ai_setcoreidx(&sii->pub, origidx); 690 691 INTR_RESTORE(sii, intr_val); 692 } 693 694 return (w); 695} 696 697void 698ai_core_disable(si_t *sih, uint32 bits) 699{ 700 si_info_t *sii; 701 volatile uint32 dummy; 702 aidmp_t *ai; 703 704 sii = SI_INFO(sih); 705 706 ASSERT(GOODREGS(sii->curwrap)); 707 ai = sii->curwrap; 708 709 /* if core is already in reset, just return */ 710 if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) 711 return; 712 713 W_REG(sii->osh, &ai->ioctrl, bits); 714 dummy = R_REG(sii->osh, &ai->ioctrl); 715 OSL_DELAY(10); 716 717 W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); 718 dummy = R_REG(sii->osh, &ai->resetctrl); 719 OSL_DELAY(1); 720} 721 722/* reset and re-enable a core 723 * inputs: 724 * bits - core specific bits that are set during and after reset sequence 725 * resetbits - core specific bits that are set only during reset sequence 726 */ 727void 728ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) 729{ 730 si_info_t *sii; 731 aidmp_t *ai; 732 volatile uint32 dummy; 733 734 sii = SI_INFO(sih); 735 ASSERT(GOODREGS(sii->curwrap)); 736 ai = sii->curwrap; 737 738 /* 739 * Must do the disable sequence first to work for arbitrary current core state. 740 */ 741 ai_core_disable(sih, (bits | resetbits)); 742 743 /* 744 * Now do the initialization sequence. 745 */ 746 W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); 747 dummy = R_REG(sii->osh, &ai->ioctrl); 748 W_REG(sii->osh, &ai->resetctrl, 0); 749 OSL_DELAY(1); 750 751 W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); 752 dummy = R_REG(sii->osh, &ai->ioctrl); 753 OSL_DELAY(1); 754} 755 756 757void 758ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) 759{ 760 si_info_t *sii; 761 aidmp_t *ai; 762 uint32 w; 763 764 sii = SI_INFO(sih); 765 766 if (BCM47162_DMP()) { 767 SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", 768 __FUNCTION__)); 769 return; 770 } 771 if (BCM5357_DMP()) { 772 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", 773 __FUNCTION__)); 774 return; 775 } 776 777 ASSERT(GOODREGS(sii->curwrap)); 778 ai = sii->curwrap; 779 780 ASSERT((val & ~mask) == 0); 781 782 if (mask || val) { 783 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); 784 W_REG(sii->osh, &ai->ioctrl, w); 785 } 786} 787 788uint32 789ai_core_cflags(si_t *sih, uint32 mask, uint32 val) 790{ 791 si_info_t *sii; 792 aidmp_t *ai; 793 uint32 w; 794 795 sii = SI_INFO(sih); 796 if (BCM47162_DMP()) { 797 SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", 798 __FUNCTION__)); 799 return 0; 800 } 801 if (BCM5357_DMP()) { 802 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", 803 __FUNCTION__)); 804 return 0; 805 } 806 807 ASSERT(GOODREGS(sii->curwrap)); 808 ai = sii->curwrap; 809 810 ASSERT((val & ~mask) == 0); 811 812 if (mask || val) { 813 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); 814 W_REG(sii->osh, &ai->ioctrl, w); 815 } 816 817 return R_REG(sii->osh, &ai->ioctrl); 818} 819 820uint32 821ai_core_sflags(si_t *sih, uint32 mask, uint32 val) 822{ 823 si_info_t *sii; 824 aidmp_t *ai; 825 uint32 w; 826 827 sii = SI_INFO(sih); 828 if (BCM47162_DMP()) { 829 SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", 830 __FUNCTION__)); 831 return 0; 832 } 833 if (BCM5357_DMP()) { 834 SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", 835 __FUNCTION__)); 836 return 0; 837 } 838 839 ASSERT(GOODREGS(sii->curwrap)); 840 ai = sii->curwrap; 841 842 ASSERT((val & ~mask) == 0); 843 ASSERT((mask & ~SISF_CORE_BITS) == 0); 844 845 if (mask || val) { 846 w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); 847 W_REG(sii->osh, &ai->iostatus, w); 848 } 849 850 return R_REG(sii->osh, &ai->iostatus); 851} 852 853#if defined(BCMDBG_DUMP) 854/* print interesting aidmp registers */ 855void 856ai_dumpregs(si_t *sih, struct bcmstrbuf *b) 857{ 858 si_info_t *sii; 859 osl_t *osh; 860 aidmp_t *ai; 861 uint i; 862 863 sii = SI_INFO(sih); 864 osh = sii->osh; 865 866 for (i = 0; i < sii->numcores; i++) { 867 si_setcoreidx(&sii->pub, i); 868 ai = sii->curwrap; 869 870 bcm_bprintf(b, "core 0x%x: \n", sii->coreid[i]); 871 if (BCM47162_DMP()) { 872 bcm_bprintf(b, "Skipping mips74k in 47162a0\n"); 873 continue; 874 } 875 if (BCM5357_DMP()) { 876 bcm_bprintf(b, "Skipping usb20h in 5357\n"); 877 continue; 878 } 879 880 bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x" 881 "ioctrlwidth 0x%x iostatuswidth 0x%x\n" 882 "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n" 883 "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x" 884 "errlogaddrlo 0x%x errlogaddrhi 0x%x\n" 885 "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n" 886 "intstatus 0x%x config 0x%x itcr 0x%x\n", 887 R_REG(osh, &ai->ioctrlset), 888 R_REG(osh, &ai->ioctrlclear), 889 R_REG(osh, &ai->ioctrl), 890 R_REG(osh, &ai->iostatus), 891 R_REG(osh, &ai->ioctrlwidth), 892 R_REG(osh, &ai->iostatuswidth), 893 R_REG(osh, &ai->resetctrl), 894 R_REG(osh, &ai->resetstatus), 895 R_REG(osh, &ai->resetreadid), 896 R_REG(osh, &ai->resetwriteid), 897 R_REG(osh, &ai->errlogctrl), 898 R_REG(osh, &ai->errlogdone), 899 R_REG(osh, &ai->errlogstatus), 900 R_REG(osh, &ai->errlogaddrlo), 901 R_REG(osh, &ai->errlogaddrhi), 902 R_REG(osh, &ai->errlogid), 903 R_REG(osh, &ai->errloguser), 904 R_REG(osh, &ai->errlogflags), 905 R_REG(osh, &ai->intstatus), 906 R_REG(osh, &ai->config), 907 R_REG(osh, &ai->itcr)); 908 if ((sih->chip == BCM4331_CHIP_ID) && (sii->coreid[i] == PCIE_CORE_ID)) { 909 /* point bar0 2nd 4KB window */ 910 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, 0x18103000); 911 bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x" 912 "ioctrlwidth 0x%x iostatuswidth 0x%x\n" 913 "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x" 914 " resetwriteid 0x%x\n" 915 "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x" 916 "errlogaddrlo 0x%x errlogaddrhi 0x%x\n" 917 "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n" 918 "intstatus 0x%x config 0x%x itcr 0x%x\n", 919 R_REG(osh, &ai->ioctrlset), 920 R_REG(osh, &ai->ioctrlclear), 921 R_REG(osh, &ai->ioctrl), 922 R_REG(osh, &ai->iostatus), 923 R_REG(osh, &ai->ioctrlwidth), 924 R_REG(osh, &ai->iostatuswidth), 925 R_REG(osh, &ai->resetctrl), 926 R_REG(osh, &ai->resetstatus), 927 R_REG(osh, &ai->resetreadid), 928 R_REG(osh, &ai->resetwriteid), 929 R_REG(osh, &ai->errlogctrl), 930 R_REG(osh, &ai->errlogdone), 931 R_REG(osh, &ai->errlogstatus), 932 R_REG(osh, &ai->errlogaddrlo), 933 R_REG(osh, &ai->errlogaddrhi), 934 R_REG(osh, &ai->errlogid), 935 R_REG(osh, &ai->errloguser), 936 R_REG(osh, &ai->errlogflags), 937 R_REG(osh, &ai->intstatus), 938 R_REG(osh, &ai->config), 939 R_REG(osh, &ai->itcr)); 940 /* bar0 2nd 4KB window will be fixed in the next setcore */ 941 } 942 } 943} 944#endif 945