RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / shared / aiutils.c
blobf2710644aa2d9b98b8e74de2debbe55be841e6c7
1 /*
2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
5 * Copyright (C) 2011, 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.
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.
19 * $Id: aiutils.c 321248 2012-03-14 21:17:30Z $
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>
31 #include "siutils_priv.h"
33 #include <bcmdevs.h>
35 #define BCM47162_DMP() ((CHIPID(sih->chip) == BCM47162_CHIP_ID) && \
36 (CHIPREV(sih->chiprev) == 0) && \
37 (sii->coreid[sii->curidx] == MIPS74K_CORE_ID))
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))
44 /* EROM parsing */
46 static uint32
47 get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match)
49 uint32 ent;
50 uint inv = 0, nom = 0;
52 while (TRUE) {
53 ent = R_REG(si_osh(sih), *eromptr);
54 (*eromptr)++;
56 if (mask == 0)
57 break;
59 if ((ent & ER_VALID) == 0) {
60 inv++;
61 continue;
64 if (ent == (ER_END | ER_VALID))
65 break;
67 if ((ent & mask) == match)
68 break;
70 nom++;
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));
77 return ent;
80 static uint32
81 get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh,
82 uint32 *sizel, uint32 *sizeh)
84 uint32 asd, sz, szd;
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;
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);
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));
112 return asd;
115 static void
116 ai_hwfixup(si_info_t *sii)
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.
123 * Future chips should allocate interrupt lines in order (meaning
124 * no line should be skipped), without regard for core index.
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;
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"));
149 #endif /* _CFE_ */
152 struct _corerev_entry {
153 uint corerev;
154 uint corerev_alias;
156 static struct _corerev_entry bcm4706_corerev_cc[] = {
157 { 0x1f, CC_4706B0_CORE_REV },
158 { 0, 0 }
160 static struct _corerev_entry bcm4706_corerev_socsram[] = {
161 { 0x05, SOCRAM_4706B0_CORE_REV },
162 { 0, 0 }
164 static struct _corerev_entry bcm4706_corerev_gmac[] = {
165 { 0x00, GMAC_4706B0_CORE_REV },
166 { 0, 0 }
169 struct _coreid_entry {
170 uint coreid;
171 uint coreid_alias;
173 static 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 }
180 static uint
181 remap_coreid(si_t *sih, uint coreid)
183 struct _coreid_entry *coreid_table = NULL;
185 if (CHIPID(sih->chip) == BCM4706_CHIP_ID)
186 coreid_table = &bcm4706_coreid_table[0];
188 if (coreid_table != NULL) {
189 uint i;
191 for (i = 0; coreid_table[i].coreid; i++)
192 if (coreid_table[i].coreid == coreid)
193 return coreid_table[i].coreid_alias;
196 return coreid;
199 static uint
200 remap_corerev(si_t *sih, uint corerev)
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;
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;
220 return corerev;
223 /* parse the enumeration rom to identify all cores */
224 void
225 BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid)
227 si_info_t *sii = SI_INFO(sih);
228 chipcregs_t *cc = (chipcregs_t *)regs;
229 uint32 erombase, *eromptr, *eromlim;
231 erombase = R_REG(sii->osh, &cc->eromptr);
233 switch (BUSTYPE(sih->bustype)) {
234 case SI_BUS:
235 eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE);
236 break;
238 case PCI_BUS:
239 /* Set wrappers address */
240 sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE);
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;
247 #ifdef BCMJTAG
248 case JTAG_BUS:
249 eromptr = (uint32 *)(uintptr)erombase;
250 break;
251 #endif /* BCMJTAG */
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;
259 eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32));
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 uint i, j, idx;
267 bool br;
269 br = FALSE;
271 /* Grok a component */
272 cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI);
273 if (cia == (ER_END | ER_VALID)) {
274 SI_VMSG(("Found END of erom after %d cores\n", sii->numcores));
275 ai_hwfixup(sii);
276 return;
279 cib = get_erom_ent(sih, &eromptr, 0, 0);
281 if ((cib & ER_TAG) != ER_CI) {
282 SI_ERROR(("CIA not followed by CIB\n"));
283 goto error;
286 cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT;
287 mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
288 crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
289 nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT;
290 nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT;
291 nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
292 nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
294 #ifdef BCMDBG_SI
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, eromptr - 1, nmw, nsw, nmp, nsp));
298 #else
299 BCM_REFERENCE(crev);
300 #endif
302 if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
303 continue;
304 if ((nmw + nsw == 0)) {
305 /* A component which is not a core */
306 if (cid == OOB_ROUTER_CORE_ID) {
307 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE,
308 &addrl, &addrh, &sizel, &sizeh);
309 if (asd != 0) {
310 sii->oob_router = addrl;
313 if (cid != GMAC_COMMON_4706_CORE_ID)
314 continue;
317 idx = sii->numcores;
319 sii->cia[idx] = cia;
320 sii->cib[idx] = cib;
321 sii->coreid[idx] = remap_coreid(sih, cid);
323 for (i = 0; i < nmp; i++) {
324 mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
325 if ((mpd & ER_TAG) != ER_MP) {
326 SI_ERROR(("Not enough MP entries for component 0x%x\n", cid));
327 goto error;
329 SI_VMSG((" Master port %d, mp: %d id: %d\n", i,
330 (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT,
331 (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT));
334 /* First Slave Address Descriptor should be port 0:
335 * the main register space for the core
337 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh);
338 if (asd == 0) {
339 do {
340 /* Try again to see if it is a bridge */
341 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh,
342 &sizel, &sizeh);
343 if (asd != 0)
344 br = TRUE;
345 else {
346 if (br == TRUE) {
347 break;
349 else if ((addrh != 0) || (sizeh != 0) ||
350 (sizel != SI_CORE_SIZE)) {
351 SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 ="
352 "0x%x\n", addrh, sizeh, sizel));
353 SI_ERROR(("First Slave ASD for"
354 "core 0x%04x malformed "
355 "(0x%08x)\n", cid, asd));
356 goto error;
359 } while (1);
361 sii->coresba[idx] = addrl;
362 sii->coresba_size[idx] = sizel;
363 /* Get any more ASDs in port 0 */
364 j = 1;
365 do {
366 asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh,
367 &sizel, &sizeh);
368 if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) {
369 sii->coresba2[idx] = addrl;
370 sii->coresba2_size[idx] = sizel;
372 j++;
373 } while (asd != 0);
375 /* Go through the ASDs for other slave ports */
376 for (i = 1; i < nsp; i++) {
377 j = 0;
378 do {
379 asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh,
380 &sizel, &sizeh);
382 if (asd == 0)
383 break;
384 j++;
385 } while (1);
386 if (j == 0) {
387 SI_ERROR((" SP %d has no address descriptors\n", i));
388 goto error;
392 /* Now get master wrappers */
393 for (i = 0; i < nmw; i++) {
394 asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh,
395 &sizel, &sizeh);
396 if (asd == 0) {
397 SI_ERROR(("Missing descriptor for MW %d\n", i));
398 goto error;
400 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
401 SI_ERROR(("Master wrapper %d is not 4KB\n", i));
402 goto error;
404 if (i == 0)
405 sii->wrapba[idx] = addrl;
408 /* And finally slave wrappers */
409 for (i = 0; i < nsw; i++) {
410 uint fwp = (nsp == 1) ? 0 : 1;
411 asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh,
412 &sizel, &sizeh);
413 if (asd == 0) {
414 SI_ERROR(("Missing descriptor for SW %d\n", i));
415 goto error;
417 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
418 SI_ERROR(("Slave wrapper %d is not 4KB\n", i));
419 goto error;
421 if ((nmw == 0) && (i == 0))
422 sii->wrapba[idx] = addrl;
425 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
426 /* Check if it's a low cost package */
427 i = (R_REG(sii->osh, &cc->chipid) & CID_PKG_MASK) >> CID_PKG_SHIFT;
428 if (i == BCM4706L_PKG_ID) {
429 /* bcm4706L: only one GMAC */
430 if (cid == GMAC_4706_CORE_ID) {
431 for (j = 0; j < sii->numcores; j++) {
432 if (sii->coreid[j] == GMAC_CORE_ID)
433 break;
435 if (j != sii->numcores) {
436 /* Found one GMAC already, ignore this one */
437 continue;
443 /* Don't record bridges */
444 if (br)
445 continue;
447 /* Done with core */
448 sii->numcores++;
451 SI_ERROR(("Reached end of erom without finding END"));
453 error:
454 sii->numcores = 0;
455 return;
458 /* This function changes the logical "focus" to the indicated core.
459 * Return the current core's virtual address.
461 void *
462 ai_setcoreidx(si_t *sih, uint coreidx)
464 si_info_t *sii = SI_INFO(sih);
465 uint32 addr, wrap;
466 void *regs;
468 if (coreidx >= MIN(sii->numcores, SI_MAXCORES))
469 return (NULL);
471 addr = sii->coresba[coreidx];
472 wrap = sii->wrapba[coreidx];
475 * If the user has provided an interrupt mask enabled function,
476 * then assert interrupts are disabled before switching the core.
478 ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg));
480 switch (BUSTYPE(sih->bustype)) {
481 case SI_BUS:
482 /* map new one */
483 if (!sii->regs[coreidx]) {
484 sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE);
485 ASSERT(GOODREGS(sii->regs[coreidx]));
487 sii->curmap = regs = sii->regs[coreidx];
488 if (!sii->wrappers[coreidx]) {
489 sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE);
490 ASSERT(GOODREGS(sii->wrappers[coreidx]));
492 sii->curwrap = sii->wrappers[coreidx];
493 break;
495 case PCI_BUS:
496 /* point bar0 window */
497 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr);
498 regs = sii->curmap;
499 /* point bar0 2nd 4KB window to the primary wrapper */
500 if (PCIE_GEN2(sii))
501 OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap);
502 else
503 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap);
504 break;
506 #ifdef BCMJTAG
507 case JTAG_BUS:
508 sii->curmap = regs = (void *)((uintptr)addr);
509 sii->curwrap = (void *)((uintptr)wrap);
510 break;
511 #endif /* BCMJTAG */
513 case PCMCIA_BUS:
514 default:
515 ASSERT(0);
516 regs = NULL;
517 break;
520 sii->curmap = regs;
521 sii->curidx = coreidx;
523 return regs;
526 void
527 ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size)
529 si_info_t *sii = SI_INFO(sih);
530 chipcregs_t *cc = NULL;
531 uint32 erombase, *eromptr, *eromlim;
532 uint i, j, cidx;
533 uint32 cia, cib, nmp, nsp;
534 uint32 asd, addrl, addrh, sizel, sizeh;
536 for (i = 0; i < sii->numcores; i++) {
537 if (sii->coreid[i] == CC_CORE_ID) {
538 cc = (chipcregs_t *)sii->regs[i];
539 break;
542 if (cc == NULL)
543 goto error;
545 erombase = R_REG(sii->osh, &cc->eromptr);
546 eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE);
547 eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32));
549 cidx = sii->curidx;
550 cia = sii->cia[cidx];
551 cib = sii->cib[cidx];
553 nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
554 nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
556 /* scan for cores */
557 while (eromptr < eromlim) {
558 if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) &&
559 (get_erom_ent(sih, &eromptr, 0, 0) == cib)) {
560 break;
564 /* skip master ports */
565 for (i = 0; i < nmp; i++)
566 get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
568 /* Skip ASDs in port 0 */
569 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh);
570 if (asd == 0) {
571 /* Try again to see if it is a bridge */
572 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh,
573 &sizel, &sizeh);
576 j = 1;
577 do {
578 asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh,
579 &sizel, &sizeh);
580 j++;
581 } while (asd != 0);
583 /* Go through the ASDs for other slave ports */
584 for (i = 1; i < nsp; i++) {
585 j = 0;
586 do {
587 asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh,
588 &sizel, &sizeh);
589 if (asd == 0)
590 break;
592 if (!asidx--) {
593 *addr = addrl;
594 *size = sizel;
595 return;
597 j++;
598 } while (1);
600 if (j == 0) {
601 SI_ERROR((" SP %d has no address descriptors\n", i));
602 break;
606 error:
607 *size = 0;
608 return;
611 /* Return the number of address spaces in current core */
613 ai_numaddrspaces(si_t *sih)
615 return 2;
618 /* Return the address of the nth address space in the current core */
619 uint32
620 ai_addrspace(si_t *sih, uint asidx)
622 si_info_t *sii;
623 uint cidx;
625 sii = SI_INFO(sih);
626 cidx = sii->curidx;
628 if (asidx == 0)
629 return sii->coresba[cidx];
630 else if (asidx == 1)
631 return sii->coresba2[cidx];
632 else {
633 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
634 __FUNCTION__, asidx));
635 return 0;
639 /* Return the size of the nth address space in the current core */
640 uint32
641 ai_addrspacesize(si_t *sih, uint asidx)
643 si_info_t *sii;
644 uint cidx;
646 sii = SI_INFO(sih);
647 cidx = sii->curidx;
649 if (asidx == 0)
650 return sii->coresba_size[cidx];
651 else if (asidx == 1)
652 return sii->coresba2_size[cidx];
653 else {
654 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
655 __FUNCTION__, asidx));
656 return 0;
660 uint
661 ai_flag(si_t *sih)
663 si_info_t *sii;
664 aidmp_t *ai;
666 sii = SI_INFO(sih);
667 if (BCM47162_DMP()) {
668 SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__));
669 return sii->curidx;
671 if (BCM5357_DMP()) {
672 SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__));
673 return sii->curidx;
675 ai = sii->curwrap;
677 return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f);
680 void
681 ai_setint(si_t *sih, int siflag)
685 uint
686 ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val)
688 si_info_t *sii = SI_INFO(sih);
689 uint32 *map = (uint32 *) sii->curwrap;
691 if (mask || val) {
692 uint32 w = R_REG(sii->osh, map+(offset/4));
693 w &= ~mask;
694 w |= val;
695 W_REG(sii->osh, map+(offset/4), val);
698 return (R_REG(sii->osh, map+(offset/4)));
701 uint
702 ai_corevendor(si_t *sih)
704 si_info_t *sii;
705 uint32 cia;
707 sii = SI_INFO(sih);
708 cia = sii->cia[sii->curidx];
709 return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT);
712 uint
713 ai_corerev(si_t *sih)
715 si_info_t *sii;
716 uint32 cib;
718 sii = SI_INFO(sih);
719 cib = sii->cib[sii->curidx];
720 return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT);
723 bool
724 ai_iscoreup(si_t *sih)
726 si_info_t *sii;
727 aidmp_t *ai;
729 sii = SI_INFO(sih);
730 ai = sii->curwrap;
732 return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) &&
733 ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0));
737 * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
738 * switch back to the original core, and return the new value.
740 * When using the silicon backplane, no fiddling with interrupts or core switches is needed.
742 * Also, when using pci/pcie, we can optimize away the core switching for pci registers
743 * and (on newer pci cores) chipcommon registers.
745 uint
746 ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
748 uint origidx = 0;
749 uint32 *r = NULL;
750 uint w;
751 uint intr_val = 0;
752 bool fast = FALSE;
753 si_info_t *sii;
755 sii = SI_INFO(sih);
757 ASSERT(GOODIDX(coreidx));
758 ASSERT(regoff < SI_CORE_SIZE);
759 ASSERT((val & ~mask) == 0);
761 if (coreidx >= SI_MAXCORES)
762 return 0;
764 if (BUSTYPE(sih->bustype) == SI_BUS) {
765 /* If internal bus, we can always get at everything */
766 fast = TRUE;
767 /* map if does not exist */
768 if (!sii->regs[coreidx]) {
769 sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx],
770 SI_CORE_SIZE);
771 ASSERT(GOODREGS(sii->regs[coreidx]));
773 r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff);
774 } else if (BUSTYPE(sih->bustype) == PCI_BUS) {
775 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
777 if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
778 /* Chipc registers are mapped at 12KB */
780 fast = TRUE;
781 r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
782 } else if (sii->pub.buscoreidx == coreidx) {
783 /* pci registers are at either in the last 2KB of an 8KB window
784 * or, in pcie and pci rev 13 at 8KB
786 fast = TRUE;
787 if (SI_FAST(sii))
788 r = (uint32 *)((char *)sii->curmap +
789 PCI_16KB0_PCIREGS_OFFSET + regoff);
790 else
791 r = (uint32 *)((char *)sii->curmap +
792 ((regoff >= SBCONFIGOFF) ?
793 PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
794 regoff);
798 if (!fast) {
799 INTR_OFF(sii, intr_val);
801 /* save current core index */
802 origidx = si_coreidx(&sii->pub);
804 /* switch core */
805 r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff);
807 ASSERT(r != NULL);
809 /* mask and set */
810 if (mask || val) {
811 w = (R_REG(sii->osh, r) & ~mask) | val;
812 W_REG(sii->osh, r, w);
815 /* readback */
816 w = R_REG(sii->osh, r);
818 if (!fast) {
819 /* restore core index */
820 if (origidx != coreidx)
821 ai_setcoreidx(&sii->pub, origidx);
823 INTR_RESTORE(sii, intr_val);
826 return (w);
829 void
830 ai_core_disable(si_t *sih, uint32 bits)
832 si_info_t *sii;
833 volatile uint32 dummy;
834 uint32 status;
835 aidmp_t *ai;
837 sii = SI_INFO(sih);
839 ASSERT(GOODREGS(sii->curwrap));
840 ai = sii->curwrap;
842 /* if core is already in reset, just return */
843 if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET)
844 return;
846 /* ensure there are no pending backplane operations */
847 SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300);
849 /* if pending backplane ops still, try waiting longer */
850 if (status != 0) {
851 /* 300usecs was sufficient to allow backplane ops to clear for big hammer */
852 /* during driver load we may need more time */
853 SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000);
854 /* if still pending ops, continue on and try disable anyway */
855 /* this is in big hammer path, so don't call wl_reinit in this case... */
856 #ifdef BCMDBG
857 if (status != 0) {
858 printf("%s: WARN: resetstatus=%0x on core disable\n", __FUNCTION__, status);
860 #endif
863 W_REG(sii->osh, &ai->ioctrl, bits);
864 dummy = R_REG(sii->osh, &ai->ioctrl);
865 BCM_REFERENCE(dummy);
866 OSL_DELAY(10);
868 W_REG(sii->osh, &ai->resetctrl, AIRC_RESET);
869 dummy = R_REG(sii->osh, &ai->resetctrl);
870 BCM_REFERENCE(dummy);
871 OSL_DELAY(1);
874 /* reset and re-enable a core
875 * inputs:
876 * bits - core specific bits that are set during and after reset sequence
877 * resetbits - core specific bits that are set only during reset sequence
879 void
880 ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
882 si_info_t *sii;
883 aidmp_t *ai;
884 volatile uint32 dummy;
886 sii = SI_INFO(sih);
887 ASSERT(GOODREGS(sii->curwrap));
888 ai = sii->curwrap;
891 * Must do the disable sequence first to work for arbitrary current core state.
893 ai_core_disable(sih, (bits | resetbits));
896 * Now do the initialization sequence.
898 W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN));
899 dummy = R_REG(sii->osh, &ai->ioctrl);
900 BCM_REFERENCE(dummy);
902 W_REG(sii->osh, &ai->resetctrl, 0);
903 dummy = R_REG(sii->osh, &ai->resetctrl);
904 BCM_REFERENCE(dummy);
905 OSL_DELAY(1);
907 W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN));
908 dummy = R_REG(sii->osh, &ai->ioctrl);
909 BCM_REFERENCE(dummy);
910 OSL_DELAY(1);
913 void
914 ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
916 si_info_t *sii;
917 aidmp_t *ai;
918 uint32 w;
920 sii = SI_INFO(sih);
922 if (BCM47162_DMP()) {
923 SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
924 __FUNCTION__));
925 return;
927 if (BCM5357_DMP()) {
928 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n",
929 __FUNCTION__));
930 return;
933 ASSERT(GOODREGS(sii->curwrap));
934 ai = sii->curwrap;
936 ASSERT((val & ~mask) == 0);
938 if (mask || val) {
939 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
940 W_REG(sii->osh, &ai->ioctrl, w);
944 uint32
945 ai_core_cflags(si_t *sih, uint32 mask, uint32 val)
947 si_info_t *sii;
948 aidmp_t *ai;
949 uint32 w;
951 sii = SI_INFO(sih);
952 if (BCM47162_DMP()) {
953 SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
954 __FUNCTION__));
955 return 0;
957 if (BCM5357_DMP()) {
958 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n",
959 __FUNCTION__));
960 return 0;
963 ASSERT(GOODREGS(sii->curwrap));
964 ai = sii->curwrap;
966 ASSERT((val & ~mask) == 0);
968 if (mask || val) {
969 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
970 W_REG(sii->osh, &ai->ioctrl, w);
973 return R_REG(sii->osh, &ai->ioctrl);
976 uint32
977 ai_core_sflags(si_t *sih, uint32 mask, uint32 val)
979 si_info_t *sii;
980 aidmp_t *ai;
981 uint32 w;
983 sii = SI_INFO(sih);
984 if (BCM47162_DMP()) {
985 SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0",
986 __FUNCTION__));
987 return 0;
989 if (BCM5357_DMP()) {
990 SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n",
991 __FUNCTION__));
992 return 0;
995 ASSERT(GOODREGS(sii->curwrap));
996 ai = sii->curwrap;
998 ASSERT((val & ~mask) == 0);
999 ASSERT((mask & ~SISF_CORE_BITS) == 0);
1001 if (mask || val) {
1002 w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val);
1003 W_REG(sii->osh, &ai->iostatus, w);
1006 return R_REG(sii->osh, &ai->iostatus);
1009 #if defined(BCMDBG)
1010 /* print interesting aidmp registers */
1011 void
1012 ai_dumpregs(si_t *sih, struct bcmstrbuf *b)
1014 si_info_t *sii;
1015 osl_t *osh;
1016 aidmp_t *ai;
1017 uint i;
1019 sii = SI_INFO(sih);
1020 osh = sii->osh;
1022 for (i = 0; i < sii->numcores; i++) {
1023 si_setcoreidx(&sii->pub, i);
1024 ai = sii->curwrap;
1026 bcm_bprintf(b, "core 0x%x: \n", sii->coreid[i]);
1027 if (BCM47162_DMP()) {
1028 bcm_bprintf(b, "Skipping mips74k in 47162a0\n");
1029 continue;
1031 if (BCM5357_DMP()) {
1032 bcm_bprintf(b, "Skipping usb20h in 5357\n");
1033 continue;
1036 bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x"
1037 "ioctrlwidth 0x%x iostatuswidth 0x%x\n"
1038 "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n"
1039 "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x"
1040 "errlogaddrlo 0x%x errlogaddrhi 0x%x\n"
1041 "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n"
1042 "intstatus 0x%x config 0x%x itcr 0x%x\n",
1043 R_REG(osh, &ai->ioctrlset),
1044 R_REG(osh, &ai->ioctrlclear),
1045 R_REG(osh, &ai->ioctrl),
1046 R_REG(osh, &ai->iostatus),
1047 R_REG(osh, &ai->ioctrlwidth),
1048 R_REG(osh, &ai->iostatuswidth),
1049 R_REG(osh, &ai->resetctrl),
1050 R_REG(osh, &ai->resetstatus),
1051 R_REG(osh, &ai->resetreadid),
1052 R_REG(osh, &ai->resetwriteid),
1053 R_REG(osh, &ai->errlogctrl),
1054 R_REG(osh, &ai->errlogdone),
1055 R_REG(osh, &ai->errlogstatus),
1056 R_REG(osh, &ai->errlogaddrlo),
1057 R_REG(osh, &ai->errlogaddrhi),
1058 R_REG(osh, &ai->errlogid),
1059 R_REG(osh, &ai->errloguser),
1060 R_REG(osh, &ai->errlogflags),
1061 R_REG(osh, &ai->intstatus),
1062 R_REG(osh, &ai->config),
1063 R_REG(osh, &ai->itcr));
1064 if ((sih->chip == BCM4331_CHIP_ID) && (sii->coreid[i] == PCIE_CORE_ID)) {
1065 /* point bar0 2nd 4KB window */
1066 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, 0x18103000);
1067 bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x"
1068 "ioctrlwidth 0x%x iostatuswidth 0x%x\n"
1069 "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x"
1070 " resetwriteid 0x%x\n"
1071 "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x"
1072 "errlogaddrlo 0x%x errlogaddrhi 0x%x\n"
1073 "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n"
1074 "intstatus 0x%x config 0x%x itcr 0x%x\n",
1075 R_REG(osh, &ai->ioctrlset),
1076 R_REG(osh, &ai->ioctrlclear),
1077 R_REG(osh, &ai->ioctrl),
1078 R_REG(osh, &ai->iostatus),
1079 R_REG(osh, &ai->ioctrlwidth),
1080 R_REG(osh, &ai->iostatuswidth),
1081 R_REG(osh, &ai->resetctrl),
1082 R_REG(osh, &ai->resetstatus),
1083 R_REG(osh, &ai->resetreadid),
1084 R_REG(osh, &ai->resetwriteid),
1085 R_REG(osh, &ai->errlogctrl),
1086 R_REG(osh, &ai->errlogdone),
1087 R_REG(osh, &ai->errlogstatus),
1088 R_REG(osh, &ai->errlogaddrlo),
1089 R_REG(osh, &ai->errlogaddrhi),
1090 R_REG(osh, &ai->errlogid),
1091 R_REG(osh, &ai->errloguser),
1092 R_REG(osh, &ai->errlogflags),
1093 R_REG(osh, &ai->intstatus),
1094 R_REG(osh, &ai->config),
1095 R_REG(osh, &ai->itcr));
1096 /* bar0 2nd 4KB window will be fixed in the next setcore */
1100 #endif
1102 #ifdef BCMDBG
1103 static void
1104 _ai_view(osl_t *osh, aidmp_t *ai, uint32 cid, uint32 addr, bool verbose)
1106 uint32 config;
1108 config = R_REG(osh, &ai->config);
1109 SI_ERROR(("\nCore ID: 0x%x, addr 0x%x, config 0x%x\n", cid, addr, config));
1111 if (config & AICFG_RST)
1112 SI_ERROR(("resetctrl 0x%x, resetstatus 0x%x, resetreadid 0x%x, resetwriteid 0x%x\n",
1113 R_REG(osh, &ai->resetctrl), R_REG(osh, &ai->resetstatus),
1114 R_REG(osh, &ai->resetreadid), R_REG(osh, &ai->resetwriteid)));
1116 if (config & AICFG_IOC)
1117 SI_ERROR(("ioctrl 0x%x, width %d\n", R_REG(osh, &ai->ioctrl),
1118 R_REG(osh, &ai->ioctrlwidth)));
1120 if (config & AICFG_IOS)
1121 SI_ERROR(("iostatus 0x%x, width %d\n", R_REG(osh, &ai->iostatus),
1122 R_REG(osh, &ai->iostatuswidth)));
1124 if (config & AICFG_ERRL) {
1125 SI_ERROR(("errlogctrl 0x%x, errlogdone 0x%x, errlogstatus 0x%x, intstatus 0x%x\n",
1126 R_REG(osh, &ai->errlogctrl), R_REG(osh, &ai->errlogdone),
1127 R_REG(osh, &ai->errlogstatus), R_REG(osh, &ai->intstatus)));
1128 SI_ERROR(("errlogid 0x%x, errloguser 0x%x, errlogflags 0x%x, errlogaddr "
1129 "0x%x/0x%x\n",
1130 R_REG(osh, &ai->errlogid), R_REG(osh, &ai->errloguser),
1131 R_REG(osh, &ai->errlogflags), R_REG(osh, &ai->errlogaddrhi),
1132 R_REG(osh, &ai->errlogaddrlo)));
1135 if (verbose && (config & AICFG_OOB)) {
1136 SI_ERROR(("oobselina30 0x%x, oobselina74 0x%x\n",
1137 R_REG(osh, &ai->oobselina30), R_REG(osh, &ai->oobselina74)));
1138 SI_ERROR(("oobselinb30 0x%x, oobselinb74 0x%x\n",
1139 R_REG(osh, &ai->oobselinb30), R_REG(osh, &ai->oobselinb74)));
1140 SI_ERROR(("oobselinc30 0x%x, oobselinc74 0x%x\n",
1141 R_REG(osh, &ai->oobselinc30), R_REG(osh, &ai->oobselinc74)));
1142 SI_ERROR(("oobselind30 0x%x, oobselind74 0x%x\n",
1143 R_REG(osh, &ai->oobselind30), R_REG(osh, &ai->oobselind74)));
1144 SI_ERROR(("oobselouta30 0x%x, oobselouta74 0x%x\n",
1145 R_REG(osh, &ai->oobselouta30), R_REG(osh, &ai->oobselouta74)));
1146 SI_ERROR(("oobseloutb30 0x%x, oobseloutb74 0x%x\n",
1147 R_REG(osh, &ai->oobseloutb30), R_REG(osh, &ai->oobseloutb74)));
1148 SI_ERROR(("oobseloutc30 0x%x, oobseloutc74 0x%x\n",
1149 R_REG(osh, &ai->oobseloutc30), R_REG(osh, &ai->oobseloutc74)));
1150 SI_ERROR(("oobseloutd30 0x%x, oobseloutd74 0x%x\n",
1151 R_REG(osh, &ai->oobseloutd30), R_REG(osh, &ai->oobseloutd74)));
1152 SI_ERROR(("oobsynca 0x%x, oobseloutaen 0x%x\n",
1153 R_REG(osh, &ai->oobsynca), R_REG(osh, &ai->oobseloutaen)));
1154 SI_ERROR(("oobsyncb 0x%x, oobseloutben 0x%x\n",
1155 R_REG(osh, &ai->oobsyncb), R_REG(osh, &ai->oobseloutben)));
1156 SI_ERROR(("oobsyncc 0x%x, oobseloutcen 0x%x\n",
1157 R_REG(osh, &ai->oobsyncc), R_REG(osh, &ai->oobseloutcen)));
1158 SI_ERROR(("oobsyncd 0x%x, oobseloutden 0x%x\n",
1159 R_REG(osh, &ai->oobsyncd), R_REG(osh, &ai->oobseloutden)));
1160 SI_ERROR(("oobaextwidth 0x%x, oobainwidth 0x%x, oobaoutwidth 0x%x\n",
1161 R_REG(osh, &ai->oobaextwidth), R_REG(osh, &ai->oobainwidth),
1162 R_REG(osh, &ai->oobaoutwidth)));
1163 SI_ERROR(("oobbextwidth 0x%x, oobbinwidth 0x%x, oobboutwidth 0x%x\n",
1164 R_REG(osh, &ai->oobbextwidth), R_REG(osh, &ai->oobbinwidth),
1165 R_REG(osh, &ai->oobboutwidth)));
1166 SI_ERROR(("oobcextwidth 0x%x, oobcinwidth 0x%x, oobcoutwidth 0x%x\n",
1167 R_REG(osh, &ai->oobcextwidth), R_REG(osh, &ai->oobcinwidth),
1168 R_REG(osh, &ai->oobcoutwidth)));
1169 SI_ERROR(("oobdextwidth 0x%x, oobdinwidth 0x%x, oobdoutwidth 0x%x\n",
1170 R_REG(osh, &ai->oobdextwidth), R_REG(osh, &ai->oobdinwidth),
1171 R_REG(osh, &ai->oobdoutwidth)));
1175 void
1176 ai_view(si_t *sih, bool verbose)
1178 si_info_t *sii;
1179 osl_t *osh;
1180 aidmp_t *ai;
1181 uint32 cid, addr;
1183 sii = SI_INFO(sih);
1184 ai = sii->curwrap;
1185 osh = sii->osh;
1186 if (BCM47162_DMP()) {
1187 SI_ERROR(("Cannot access mips74k DMP in 47162a0\n"));
1188 return;
1190 if (BCM5357_DMP()) {
1191 SI_ERROR(("Cannot access usb20h DMP in 5357\n"));
1192 return;
1194 cid = sii->coreid[sii->curidx];
1195 addr = sii->wrapba[sii->curidx];
1196 _ai_view(osh, ai, cid, addr, verbose);
1199 void
1200 ai_viewall(si_t *sih, bool verbose)
1202 si_info_t *sii;
1203 osl_t *osh;
1204 aidmp_t *ai;
1205 uint32 cid, addr;
1206 uint i;
1208 sii = SI_INFO(sih);
1209 osh = sii->osh;
1210 for (i = 0; i < sii->numcores; i++) {
1211 si_setcoreidx(sih, i);
1212 if (BCM47162_DMP()) {
1213 SI_ERROR(("Skipping mips74k DMP in 47162a0\n"));
1214 continue;
1216 if (BCM5357_DMP()) {
1217 SI_ERROR(("Skipping usb20h DMP in 5357\n"));
1218 continue;
1220 ai = sii->curwrap;
1221 cid = sii->coreid[sii->curidx];
1222 addr = sii->wrapba[sii->curidx];
1223 _ai_view(osh, ai, cid, addr, verbose);
1224 if ((sih->chip == BCM4331_CHIP_ID) && (sii->coreid[i] == PCIE_CORE_ID)) {
1225 /* point bar0 2nd 4KB window */
1226 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, 0x18103000);
1227 _ai_view(osh, ai, cid, 0x18103000, verbose);
1228 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, 0x18104000);
1229 _ai_view(osh, ai, 0x135, 0x18104000, verbose);
1230 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, 0x18105000);
1231 _ai_view(osh, ai, 0x135, 0x18105000, verbose);
1232 /* bar0 2nd 4KB window will be fixed in the next setcore */
1236 #endif /* BCMDBG */