2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
5 * Copyright (C) 1999-2017, Broadcom Corporation
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
26 * <<Broadcom-WL-IPTag/Open:>>
28 * $Id: aiutils.c 625027 2016-03-15 08:20:18Z $
40 #include "siutils_priv.h"
43 #define BCM5357_DMP() (0)
44 #define BCM53573_DMP() (0)
45 #define BCM4707_DMP() (0)
48 #define remap_coreid(sih, coreid) (coreid)
49 #define remap_corerev(sih, corerev) (corerev)
54 get_erom_ent(si_t
*sih
, uint32
**eromptr
, uint32 mask
, uint32 match
)
57 uint inv
= 0, nom
= 0;
61 ent
= R_REG(si_osh(sih
), *eromptr
);
67 if ((ent
& ER_VALID
) == 0) {
72 if (ent
== (ER_END
| ER_VALID
))
75 if ((ent
& mask
) == match
)
78 /* escape condition related EROM size if it has invalid values */
79 size
+= sizeof(*eromptr
);
80 if (size
>= ER_SZ_MAX
) {
81 SI_ERROR(("Failed to find end of EROM marker\n"));
88 SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__
, ent
));
90 SI_VMSG((" after %d invalid and %d non-matching entries\n", inv
, nom
));
96 get_asd(si_t
*sih
, uint32
**eromptr
, uint sp
, uint ad
, uint st
, uint32
*addrl
, uint32
*addrh
,
97 uint32
*sizel
, uint32
*sizeh
)
103 asd
= get_erom_ent(sih
, eromptr
, ER_VALID
, ER_VALID
);
104 if (((asd
& ER_TAG1
) != ER_ADD
) ||
105 (((asd
& AD_SP_MASK
) >> AD_SP_SHIFT
) != sp
) ||
106 ((asd
& AD_ST_MASK
) != st
)) {
107 /* This is not what we want, "push" it back */
111 *addrl
= asd
& AD_ADDR_MASK
;
113 *addrh
= get_erom_ent(sih
, eromptr
, 0, 0);
117 sz
= asd
& AD_SZ_MASK
;
118 if (sz
== AD_SZ_SZD
) {
119 szd
= get_erom_ent(sih
, eromptr
, 0, 0);
120 *sizel
= szd
& SD_SZ_MASK
;
122 *sizeh
= get_erom_ent(sih
, eromptr
, 0, 0);
124 *sizel
= AD_SZ_BASE
<< (sz
>> AD_SZ_SHIFT
);
126 SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n",
127 sp
, ad
, st
, *sizeh
, *sizel
, *addrh
, *addrl
));
133 /* parse the enumeration rom to identify all cores */
135 ai_scan(si_t
*sih
, void *regs
, uint devid
)
137 si_info_t
*sii
= SI_INFO(sih
);
138 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
139 chipcregs_t
*cc
= (chipcregs_t
*)regs
;
140 uint32 erombase
, *eromptr
, *eromlim
;
141 axi_wrapper_t
* axi_wrapper
= sii
->axi_wrapper
;
143 BCM_REFERENCE(devid
);
145 erombase
= R_REG(sii
->osh
, &cc
->eromptr
);
147 switch (BUSTYPE(sih
->bustype
)) {
149 eromptr
= (uint32
*)REG_MAP(erombase
, SI_CORE_SIZE
);
153 /* Set wrappers address */
154 sii
->curwrap
= (void *)((uintptr
)regs
+ SI_CORE_SIZE
);
156 /* Now point the window at the erom */
157 OSL_PCI_WRITE_CONFIG(sii
->osh
, PCI_BAR0_WIN
, 4, erombase
);
164 eromptr
= (uint32
*)(uintptr
)erombase
;
170 SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih
->bustype
));
174 eromlim
= eromptr
+ (ER_REMAPCONTROL
/ sizeof(uint32
));
175 sii
->axi_num_wrappers
= 0;
177 SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n",
178 OSL_OBFUSCATE_BUF(regs
), erombase
,
179 OSL_OBFUSCATE_BUF(eromptr
), OSL_OBFUSATE_BUF(eromlim
)));
180 while (eromptr
< eromlim
) {
181 uint32 cia
, cib
, cid
, mfg
, crev
, nmw
, nsw
, nmp
, nsp
;
182 uint32 mpd
, asd
, addrl
, addrh
, sizel
, sizeh
;
188 /* Grok a component */
189 cia
= get_erom_ent(sih
, &eromptr
, ER_TAG
, ER_CI
);
190 if (cia
== (ER_END
| ER_VALID
)) {
191 SI_VMSG(("Found END of erom after %d cores\n", sii
->numcores
));
195 cib
= get_erom_ent(sih
, &eromptr
, 0, 0);
197 if ((cib
& ER_TAG
) != ER_CI
) {
198 SI_ERROR(("CIA not followed by CIB\n"));
202 cid
= (cia
& CIA_CID_MASK
) >> CIA_CID_SHIFT
;
203 mfg
= (cia
& CIA_MFG_MASK
) >> CIA_MFG_SHIFT
;
204 crev
= (cib
& CIB_REV_MASK
) >> CIB_REV_SHIFT
;
205 nmw
= (cib
& CIB_NMW_MASK
) >> CIB_NMW_SHIFT
;
206 nsw
= (cib
& CIB_NSW_MASK
) >> CIB_NSW_SHIFT
;
207 nmp
= (cib
& CIB_NMP_MASK
) >> CIB_NMP_SHIFT
;
208 nsp
= (cib
& CIB_NSP_MASK
) >> CIB_NSP_SHIFT
;
211 SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, "
212 "nsw = %d, nmp = %d & nsp = %d\n",
213 mfg
, cid
, crev
, OSL_OBFUSCATE_BUF(eromptr
- 1), nmw
, nsw
, nmp
, nsp
));
218 if (CHIPID(sih
->chip
) == BCM4347_CHIP_ID
) {
219 /* 4347 has more entries for ARM core
220 * This should apply to all chips but crashes on router
221 * This is a temp fix to be further analyze
226 /* Include Default slave wrapper for timeout monitoring */
228 #if !defined(AXI_TIMEOUTS) && !defined(BCM_BACKPLANE_TIMEOUT)
229 ((mfg
== MFGID_ARM
) && (cid
== DEF_AI_COMP
)) ||
230 #endif /* !defined(AXI_TIMEOUTS) && !defined(BCM_BACKPLANE_TIMEOUT) */
236 if ((nmw
+ nsw
== 0)) {
237 /* A component which is not a core */
238 if (cid
== OOB_ROUTER_CORE_ID
) {
239 asd
= get_asd(sih
, &eromptr
, 0, 0, AD_ST_SLAVE
,
240 &addrl
, &addrh
, &sizel
, &sizeh
);
242 sii
->oob_router
= addrl
;
245 if (cid
!= GMAC_COMMON_4706_CORE_ID
&& cid
!= NS_CCB_CORE_ID
&&
246 cid
!= PMU_CORE_ID
&& cid
!= GCI_CORE_ID
)
252 cores_info
->cia
[idx
] = cia
;
253 cores_info
->cib
[idx
] = cib
;
254 cores_info
->coreid
[idx
] = remap_coreid(sih
, cid
);
256 for (i
= 0; i
< nmp
; i
++) {
257 mpd
= get_erom_ent(sih
, &eromptr
, ER_VALID
, ER_VALID
);
258 if ((mpd
& ER_TAG
) != ER_MP
) {
259 SI_ERROR(("Not enough MP entries for component 0x%x\n", cid
));
262 SI_VMSG((" Master port %d, mp: %d id: %d\n", i
,
263 (mpd
& MPD_MP_MASK
) >> MPD_MP_SHIFT
,
264 (mpd
& MPD_MUI_MASK
) >> MPD_MUI_SHIFT
));
267 /* First Slave Address Descriptor should be port 0:
268 * the main register space for the core
270 asd
= get_asd(sih
, &eromptr
, 0, 0, AD_ST_SLAVE
, &addrl
, &addrh
, &sizel
, &sizeh
);
273 /* Try again to see if it is a bridge */
274 asd
= get_asd(sih
, &eromptr
, 0, 0, AD_ST_BRIDGE
, &addrl
, &addrh
,
282 else if ((addrh
!= 0) || (sizeh
!= 0) ||
283 (sizel
!= SI_CORE_SIZE
)) {
284 SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 ="
285 "0x%x\n", addrh
, sizeh
, sizel
));
286 SI_ERROR(("First Slave ASD for"
287 "core 0x%04x malformed "
288 "(0x%08x)\n", cid
, asd
));
294 cores_info
->coresba
[idx
] = addrl
;
295 cores_info
->coresba_size
[idx
] = sizel
;
296 /* Get any more ASDs in port 0 */
299 asd
= get_asd(sih
, &eromptr
, 0, j
, AD_ST_SLAVE
, &addrl
, &addrh
,
301 if ((asd
!= 0) && (j
== 1) && (sizel
== SI_CORE_SIZE
)) {
302 cores_info
->coresba2
[idx
] = addrl
;
303 cores_info
->coresba2_size
[idx
] = sizel
;
308 /* Go through the ASDs for other slave ports */
309 for (i
= 1; i
< nsp
; i
++) {
312 asd
= get_asd(sih
, &eromptr
, i
, j
, AD_ST_SLAVE
, &addrl
, &addrh
,
320 SI_ERROR((" SP %d has no address descriptors\n", i
));
325 /* Now get master wrappers */
326 for (i
= 0; i
< nmw
; i
++) {
327 asd
= get_asd(sih
, &eromptr
, i
, 0, AD_ST_MWRAP
, &addrl
, &addrh
,
330 SI_ERROR(("Missing descriptor for MW %d\n", i
));
333 if ((sizeh
!= 0) || (sizel
!= SI_CORE_SIZE
)) {
334 SI_ERROR(("Master wrapper %d is not 4KB\n", i
));
338 cores_info
->wrapba
[idx
] = addrl
;
340 cores_info
->wrapba2
[idx
] = addrl
;
343 ASSERT(sii
->axi_num_wrappers
< SI_MAX_AXI_WRAPPERS
);
344 axi_wrapper
[sii
->axi_num_wrappers
].mfg
= mfg
;
345 axi_wrapper
[sii
->axi_num_wrappers
].cid
= cid
;
346 axi_wrapper
[sii
->axi_num_wrappers
].rev
= crev
;
347 axi_wrapper
[sii
->axi_num_wrappers
].wrapper_type
= AI_MASTER_WRAPPER
;
348 axi_wrapper
[sii
->axi_num_wrappers
].wrapper_addr
= addrl
;
349 sii
->axi_num_wrappers
++;
350 SI_VMSG(("MASTER WRAPPER: %d, mfg:%x, cid:%x, rev:%x, addr:%x, size:%x\n",
351 sii
->axi_num_wrappers
, mfg
, cid
, crev
, addrl
, sizel
));
354 /* And finally slave wrappers */
355 for (i
= 0; i
< nsw
; i
++) {
356 uint fwp
= (nsp
== 1) ? 0 : 1;
357 asd
= get_asd(sih
, &eromptr
, fwp
+ i
, 0, AD_ST_SWRAP
, &addrl
, &addrh
,
360 /* cache APB bridge wrapper address for set/clear timeout */
361 if ((mfg
== MFGID_ARM
) && (cid
== APB_BRIDGE_ID
)) {
362 ASSERT(sii
->num_br
< SI_MAXBR
);
363 sii
->br_wrapba
[sii
->num_br
++] = addrl
;
367 SI_ERROR(("Missing descriptor for SW %d\n", i
));
370 if ((sizeh
!= 0) || (sizel
!= SI_CORE_SIZE
)) {
371 SI_ERROR(("Slave wrapper %d is not 4KB\n", i
));
374 if ((nmw
== 0) && (i
== 0))
375 cores_info
->wrapba
[idx
] = addrl
;
376 else if ((nmw
== 0) && (i
== 1))
377 cores_info
->wrapba2
[idx
] = addrl
;
379 /* Include all slave wrappers to the list to
380 * enable and monitor watchdog timeouts
383 ASSERT(sii
->axi_num_wrappers
< SI_MAX_AXI_WRAPPERS
);
384 axi_wrapper
[sii
->axi_num_wrappers
].mfg
= mfg
;
385 axi_wrapper
[sii
->axi_num_wrappers
].cid
= cid
;
386 axi_wrapper
[sii
->axi_num_wrappers
].rev
= crev
;
387 axi_wrapper
[sii
->axi_num_wrappers
].wrapper_type
= AI_SLAVE_WRAPPER
;
388 axi_wrapper
[sii
->axi_num_wrappers
].wrapper_addr
= addrl
;
389 sii
->axi_num_wrappers
++;
391 SI_VMSG(("SLAVE WRAPPER: %d, mfg:%x, cid:%x, rev:%x, addr:%x, size:%x\n",
392 sii
->axi_num_wrappers
, mfg
, cid
, crev
, addrl
, sizel
));
396 #ifndef BCM_BACKPLANE_TIMEOUT
397 /* Don't record bridges */
406 SI_ERROR(("Reached end of erom without finding END"));
413 #define AI_SETCOREIDX_MAPSIZE(coreid) \
414 (((coreid) == NS_CCB_CORE_ID) ? 15 * SI_CORE_SIZE : SI_CORE_SIZE)
416 /* This function changes the logical "focus" to the indicated core.
417 * Return the current core's virtual address.
419 static volatile void *
420 _ai_setcoreidx(si_t
*sih
, uint coreidx
, uint use_wrap2
)
422 si_info_t
*sii
= SI_INFO(sih
);
423 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
424 uint32 addr
, wrap
, wrap2
;
427 if (coreidx
>= MIN(sii
->numcores
, SI_MAXCORES
))
430 addr
= cores_info
->coresba
[coreidx
];
431 wrap
= cores_info
->wrapba
[coreidx
];
432 wrap2
= cores_info
->wrapba2
[coreidx
];
434 #ifdef BCM_BACKPLANE_TIMEOUT
435 /* No need to disable interrupts while entering/exiting APB bridge core */
436 if ((cores_info
->coreid
[coreidx
] != APB_BRIDGE_CORE_ID
) &&
437 (cores_info
->coreid
[sii
->curidx
] != APB_BRIDGE_CORE_ID
))
438 #endif /* BCM_BACKPLANE_TIMEOUT */
441 * If the user has provided an interrupt mask enabled function,
442 * then assert interrupts are disabled before switching the core.
444 ASSERT((sii
->intrsenabled_fn
== NULL
) ||
445 !(*(sii
)->intrsenabled_fn
)((sii
)->intr_arg
));
448 switch (BUSTYPE(sih
->bustype
)) {
451 if (!cores_info
->regs
[coreidx
]) {
452 cores_info
->regs
[coreidx
] = REG_MAP(addr
,
453 AI_SETCOREIDX_MAPSIZE(cores_info
->coreid
[coreidx
]));
454 ASSERT(GOODREGS(cores_info
->regs
[coreidx
]));
456 sii
->curmap
= regs
= cores_info
->regs
[coreidx
];
457 if (!cores_info
->wrappers
[coreidx
] && (wrap
!= 0)) {
458 cores_info
->wrappers
[coreidx
] = REG_MAP(wrap
, SI_CORE_SIZE
);
459 ASSERT(GOODREGS(cores_info
->wrappers
[coreidx
]));
461 if (!cores_info
->wrappers2
[coreidx
] && (wrap2
!= 0)) {
462 cores_info
->wrappers2
[coreidx
] = REG_MAP(wrap2
, SI_CORE_SIZE
);
463 ASSERT(GOODREGS(cores_info
->wrappers2
[coreidx
]));
466 sii
->curwrap
= cores_info
->wrappers2
[coreidx
];
468 sii
->curwrap
= cores_info
->wrappers
[coreidx
];
472 #ifdef BCM_BACKPLANE_TIMEOUT
473 /* No need to set the BAR0 if core is APB Bridge.
474 * This is to reduce 2 PCI writes while checkng for errlog
476 if (cores_info
->coreid
[coreidx
] != APB_BRIDGE_CORE_ID
)
477 #endif /* BCM_BACKPLANE_TIMEOUT */
479 /* point bar0 window */
480 OSL_PCI_WRITE_CONFIG(sii
->osh
, PCI_BAR0_WIN
, 4, addr
);
484 /* point bar0 2nd 4KB window to the primary wrapper */
488 OSL_PCI_WRITE_CONFIG(sii
->osh
, PCIE2_BAR0_WIN2
, 4, wrap
);
490 OSL_PCI_WRITE_CONFIG(sii
->osh
, PCI_BAR0_WIN2
, 4, wrap
);
496 sii
->curmap
= regs
= (void *)((uintptr
)addr
);
498 sii
->curwrap
= (void *)((uintptr
)wrap2
);
500 sii
->curwrap
= (void *)((uintptr
)wrap
);
512 sii
->curidx
= coreidx
;
518 ai_setcoreidx(si_t
*sih
, uint coreidx
)
520 return _ai_setcoreidx(sih
, coreidx
, 0);
524 ai_setcoreidx_2ndwrap(si_t
*sih
, uint coreidx
)
526 return _ai_setcoreidx(sih
, coreidx
, 1);
530 ai_coreaddrspaceX(si_t
*sih
, uint asidx
, uint32
*addr
, uint32
*size
)
532 si_info_t
*sii
= SI_INFO(sih
);
533 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
534 chipcregs_t
*cc
= NULL
;
535 uint32 erombase
, *eromptr
, *eromlim
;
537 uint32 cia
, cib
, nmp
, nsp
;
538 uint32 asd
, addrl
, addrh
, sizel
, sizeh
;
540 for (i
= 0; i
< sii
->numcores
; i
++) {
541 if (cores_info
->coreid
[i
] == CC_CORE_ID
) {
542 cc
= (chipcregs_t
*)cores_info
->regs
[i
];
549 erombase
= R_REG(sii
->osh
, &cc
->eromptr
);
550 eromptr
= (uint32
*)REG_MAP(erombase
, SI_CORE_SIZE
);
551 eromlim
= eromptr
+ (ER_REMAPCONTROL
/ sizeof(uint32
));
554 cia
= cores_info
->cia
[cidx
];
555 cib
= cores_info
->cib
[cidx
];
557 nmp
= (cib
& CIB_NMP_MASK
) >> CIB_NMP_SHIFT
;
558 nsp
= (cib
& CIB_NSP_MASK
) >> CIB_NSP_SHIFT
;
561 while (eromptr
< eromlim
) {
562 if ((get_erom_ent(sih
, &eromptr
, ER_TAG
, ER_CI
) == cia
) &&
563 (get_erom_ent(sih
, &eromptr
, 0, 0) == cib
)) {
568 /* skip master ports */
569 for (i
= 0; i
< nmp
; i
++)
570 get_erom_ent(sih
, &eromptr
, ER_VALID
, ER_VALID
);
572 /* Skip ASDs in port 0 */
573 asd
= get_asd(sih
, &eromptr
, 0, 0, AD_ST_SLAVE
, &addrl
, &addrh
, &sizel
, &sizeh
);
575 /* Try again to see if it is a bridge */
576 asd
= get_asd(sih
, &eromptr
, 0, 0, AD_ST_BRIDGE
, &addrl
, &addrh
,
582 asd
= get_asd(sih
, &eromptr
, 0, j
, AD_ST_SLAVE
, &addrl
, &addrh
,
587 /* Go through the ASDs for other slave ports */
588 for (i
= 1; i
< nsp
; i
++) {
591 asd
= get_asd(sih
, &eromptr
, i
, j
, AD_ST_SLAVE
, &addrl
, &addrh
,
605 SI_ERROR((" SP %d has no address descriptors\n", i
));
615 /* Return the number of address spaces in current core */
617 ai_numaddrspaces(si_t
*sih
)
625 /* Return the address of the nth address space in the current core */
627 ai_addrspace(si_t
*sih
, uint asidx
)
629 si_info_t
*sii
= SI_INFO(sih
);
630 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
636 return cores_info
->coresba
[cidx
];
638 return cores_info
->coresba2
[cidx
];
640 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
641 __FUNCTION__
, asidx
));
646 /* Return the size of the nth address space in the current core */
648 ai_addrspacesize(si_t
*sih
, uint asidx
)
650 si_info_t
*sii
= SI_INFO(sih
);
651 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
657 return cores_info
->coresba_size
[cidx
];
659 return cores_info
->coresba2_size
[cidx
];
661 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
662 __FUNCTION__
, asidx
));
670 si_info_t
*sii
= SI_INFO(sih
);
674 SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__
));
678 SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n",
682 if (BCM53573_DMP()) {
683 SI_ERROR(("%s: Attempting to read DMP registers on 53573\n", __FUNCTION__
));
686 #ifdef REROUTE_OOBINT
688 SI_ERROR(("%s: Attempting to read PMU DMP registers\n",
696 ai_setcoreidx(sih
, SI_CC_IDX
);
697 flag
= ai_flag_alt(sih
);
698 ai_setcoreidx(sih
, idx
);
701 #endif /* REROUTE_OOBINT */
706 return (R_REG(sii
->osh
, &ai
->oobselouta30
) & 0x1f);
710 ai_flag_alt(si_t
*sih
)
712 si_info_t
*sii
= SI_INFO(sih
);
716 SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__
));
720 SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n",
724 #ifdef REROUTE_OOBINT
726 SI_ERROR(("%s: Attempting to read PMU DMP registers\n",
730 #endif /* REROUTE_OOBINT */
734 return ((R_REG(sii
->osh
, &ai
->oobselouta30
) >> AI_OOBSEL_1_SHIFT
) & AI_OOBSEL_MASK
);
738 ai_setint(si_t
*sih
, int siflag
)
741 BCM_REFERENCE(siflag
);
746 ai_wrap_reg(si_t
*sih
, uint32 offset
, uint32 mask
, uint32 val
)
748 si_info_t
*sii
= SI_INFO(sih
);
749 uint32
*map
= (uint32
*) sii
->curwrap
;
752 uint32 w
= R_REG(sii
->osh
, map
+(offset
/4));
755 W_REG(sii
->osh
, map
+(offset
/4), w
);
758 return (R_REG(sii
->osh
, map
+(offset
/4)));
762 ai_corevendor(si_t
*sih
)
764 si_info_t
*sii
= SI_INFO(sih
);
765 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
768 cia
= cores_info
->cia
[sii
->curidx
];
769 return ((cia
& CIA_MFG_MASK
) >> CIA_MFG_SHIFT
);
773 ai_corerev(si_t
*sih
)
775 si_info_t
*sii
= SI_INFO(sih
);
776 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
780 cib
= cores_info
->cib
[sii
->curidx
];
781 return remap_corerev(sih
, (cib
& CIB_REV_MASK
) >> CIB_REV_SHIFT
);
785 ai_iscoreup(si_t
*sih
)
787 si_info_t
*sii
= SI_INFO(sih
);
792 return (((R_REG(sii
->osh
, &ai
->ioctrl
) & (SICF_FGC
| SICF_CLOCK_EN
)) == SICF_CLOCK_EN
) &&
793 ((R_REG(sii
->osh
, &ai
->resetctrl
) & AIRC_RESET
) == 0));
797 * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
798 * switch back to the original core, and return the new value.
800 * When using the silicon backplane, no fiddling with interrupts or core switches is needed.
802 * Also, when using pci/pcie, we can optimize away the core switching for pci registers
803 * and (on newer pci cores) chipcommon registers.
806 ai_corereg(si_t
*sih
, uint coreidx
, uint regoff
, uint mask
, uint val
)
809 volatile uint32
*r
= NULL
;
813 si_info_t
*sii
= SI_INFO(sih
);
814 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
817 ASSERT(GOODIDX(coreidx
));
818 ASSERT(regoff
< SI_CORE_SIZE
);
819 ASSERT((val
& ~mask
) == 0);
821 if (coreidx
>= SI_MAXCORES
)
824 if (BUSTYPE(sih
->bustype
) == SI_BUS
) {
825 /* If internal bus, we can always get at everything */
827 /* map if does not exist */
828 if (!cores_info
->regs
[coreidx
]) {
829 cores_info
->regs
[coreidx
] = REG_MAP(cores_info
->coresba
[coreidx
],
831 ASSERT(GOODREGS(cores_info
->regs
[coreidx
]));
833 r
= (volatile uint32
*)((volatile uchar
*)cores_info
->regs
[coreidx
] + regoff
);
834 } else if (BUSTYPE(sih
->bustype
) == PCI_BUS
) {
835 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
837 if ((cores_info
->coreid
[coreidx
] == CC_CORE_ID
) && SI_FAST(sii
)) {
838 /* Chipc registers are mapped at 12KB */
841 r
= (volatile uint32
*)((volatile char *)sii
->curmap
+
842 PCI_16KB0_CCREGS_OFFSET
+ regoff
);
843 } else if (sii
->pub
.buscoreidx
== coreidx
) {
844 /* pci registers are at either in the last 2KB of an 8KB window
845 * or, in pcie and pci rev 13 at 8KB
849 r
= (volatile uint32
*)((volatile char *)sii
->curmap
+
850 PCI_16KB0_PCIREGS_OFFSET
+ regoff
);
852 r
= (volatile uint32
*)((volatile char *)sii
->curmap
+
853 ((regoff
>= SBCONFIGOFF
) ?
854 PCI_BAR0_PCISBR_OFFSET
: PCI_BAR0_PCIREGS_OFFSET
) +
860 INTR_OFF(sii
, intr_val
);
862 /* save current core index */
863 origidx
= si_coreidx(&sii
->pub
);
866 r
= (volatile uint32
*) ((volatile uchar
*) ai_setcoreidx(&sii
->pub
, coreidx
) +
873 w
= (R_REG(sii
->osh
, r
) & ~mask
) | val
;
874 W_REG(sii
->osh
, r
, w
);
878 w
= R_REG(sii
->osh
, r
);
881 /* restore core index */
882 if (origidx
!= coreidx
)
883 ai_setcoreidx(&sii
->pub
, origidx
);
885 INTR_RESTORE(sii
, intr_val
);
892 * If there is no need for fiddling with interrupts or core switches (typically silicon
893 * back plane registers, pci registers and chipcommon registers), this function
894 * returns the register offset on this core to a mapped address. This address can
895 * be used for W_REG/R_REG directly.
897 * For accessing registers that would need a core switch, this function will return
901 ai_corereg_addr(si_t
*sih
, uint coreidx
, uint regoff
)
903 volatile uint32
*r
= NULL
;
905 si_info_t
*sii
= SI_INFO(sih
);
906 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
909 ASSERT(GOODIDX(coreidx
));
910 ASSERT(regoff
< SI_CORE_SIZE
);
912 if (coreidx
>= SI_MAXCORES
)
915 if (BUSTYPE(sih
->bustype
) == SI_BUS
) {
916 /* If internal bus, we can always get at everything */
918 /* map if does not exist */
919 if (!cores_info
->regs
[coreidx
]) {
920 cores_info
->regs
[coreidx
] = REG_MAP(cores_info
->coresba
[coreidx
],
922 ASSERT(GOODREGS(cores_info
->regs
[coreidx
]));
924 r
= (volatile uint32
*)((volatile uchar
*)cores_info
->regs
[coreidx
] + regoff
);
925 } else if (BUSTYPE(sih
->bustype
) == PCI_BUS
) {
926 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
928 if ((cores_info
->coreid
[coreidx
] == CC_CORE_ID
) && SI_FAST(sii
)) {
929 /* Chipc registers are mapped at 12KB */
932 r
= (volatile uint32
*)((volatile char *)sii
->curmap
+
933 PCI_16KB0_CCREGS_OFFSET
+ regoff
);
934 } else if (sii
->pub
.buscoreidx
== coreidx
) {
935 /* pci registers are at either in the last 2KB of an 8KB window
936 * or, in pcie and pci rev 13 at 8KB
940 r
= (volatile uint32
*)((volatile char *)sii
->curmap
+
941 PCI_16KB0_PCIREGS_OFFSET
+ regoff
);
943 r
= (volatile uint32
*)((volatile char *)sii
->curmap
+
944 ((regoff
>= SBCONFIGOFF
) ?
945 PCI_BAR0_PCISBR_OFFSET
: PCI_BAR0_PCIREGS_OFFSET
) +
951 ASSERT(sii
->curidx
== coreidx
);
952 r
= (volatile uint32
*) ((volatile uchar
*)sii
->curmap
+ regoff
);
959 ai_core_disable(si_t
*sih
, uint32 bits
)
961 si_info_t
*sii
= SI_INFO(sih
);
962 volatile uint32 dummy
;
967 ASSERT(GOODREGS(sii
->curwrap
));
970 /* if core is already in reset, just return */
971 if (R_REG(sii
->osh
, &ai
->resetctrl
) & AIRC_RESET
) {
975 /* ensure there are no pending backplane operations */
976 SPINWAIT(((status
= R_REG(sii
->osh
, &ai
->resetstatus
)) != 0), 300);
978 /* if pending backplane ops still, try waiting longer */
980 /* 300usecs was sufficient to allow backplane ops to clear for big hammer */
981 /* during driver load we may need more time */
982 SPINWAIT(((status
= R_REG(sii
->osh
, &ai
->resetstatus
)) != 0), 10000);
983 /* if still pending ops, continue on and try disable anyway */
984 /* this is in big hammer path, so don't call wl_reinit in this case... */
987 W_REG(sii
->osh
, &ai
->resetctrl
, AIRC_RESET
);
988 dummy
= R_REG(sii
->osh
, &ai
->resetctrl
);
989 BCM_REFERENCE(dummy
);
992 W_REG(sii
->osh
, &ai
->ioctrl
, bits
);
993 dummy
= R_REG(sii
->osh
, &ai
->ioctrl
);
994 BCM_REFERENCE(dummy
);
998 /* reset and re-enable a core
1000 * bits - core specific bits that are set during and after reset sequence
1001 * resetbits - core specific bits that are set only during reset sequence
1004 _ai_core_reset(si_t
*sih
, uint32 bits
, uint32 resetbits
)
1006 si_info_t
*sii
= SI_INFO(sih
);
1008 volatile uint32 dummy
;
1009 uint loop_counter
= 10;
1011 ASSERT(GOODREGS(sii
->curwrap
));
1014 /* if core is already out of reset, just return */
1016 /* ensure there are no pending backplane operations */
1017 SPINWAIT(((dummy
= R_REG(sii
->osh
, &ai
->resetstatus
)) != 0), 300);
1020 /* put core into reset state */
1021 W_REG(sii
->osh
, &ai
->resetctrl
, AIRC_RESET
);
1024 /* ensure there are no pending backplane operations */
1025 SPINWAIT((R_REG(sii
->osh
, &ai
->resetstatus
) != 0), 300);
1027 W_REG(sii
->osh
, &ai
->ioctrl
, (bits
| resetbits
| SICF_FGC
| SICF_CLOCK_EN
));
1028 dummy
= R_REG(sii
->osh
, &ai
->ioctrl
);
1029 BCM_REFERENCE(dummy
);
1031 /* ensure there are no pending backplane operations */
1032 SPINWAIT(((dummy
= R_REG(sii
->osh
, &ai
->resetstatus
)) != 0), 300);
1035 while (R_REG(sii
->osh
, &ai
->resetctrl
) != 0 && --loop_counter
!= 0) {
1036 /* ensure there are no pending backplane operations */
1037 SPINWAIT(((dummy
= R_REG(sii
->osh
, &ai
->resetstatus
)) != 0), 300);
1040 /* take core out of reset */
1041 W_REG(sii
->osh
, &ai
->resetctrl
, 0);
1043 /* ensure there are no pending backplane operations */
1044 SPINWAIT((R_REG(sii
->osh
, &ai
->resetstatus
) != 0), 300);
1048 W_REG(sii
->osh
, &ai
->ioctrl
, (bits
| SICF_CLOCK_EN
));
1049 dummy
= R_REG(sii
->osh
, &ai
->ioctrl
);
1050 BCM_REFERENCE(dummy
);
1055 ai_core_reset(si_t
*sih
, uint32 bits
, uint32 resetbits
)
1057 si_info_t
*sii
= SI_INFO(sih
);
1058 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
1059 uint idx
= sii
->curidx
;
1061 if (cores_info
->wrapba2
[idx
] != 0) {
1062 ai_setcoreidx_2ndwrap(sih
, idx
);
1063 _ai_core_reset(sih
, bits
, resetbits
);
1064 ai_setcoreidx(sih
, idx
);
1067 _ai_core_reset(sih
, bits
, resetbits
);
1071 ai_core_cflags_wo(si_t
*sih
, uint32 mask
, uint32 val
)
1073 si_info_t
*sii
= SI_INFO(sih
);
1077 if (BCM5357_DMP()) {
1078 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n",
1082 if (BCM4707_DMP()) {
1083 SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n",
1088 SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n",
1093 ASSERT(GOODREGS(sii
->curwrap
));
1096 ASSERT((val
& ~mask
) == 0);
1099 w
= ((R_REG(sii
->osh
, &ai
->ioctrl
) & ~mask
) | val
);
1100 W_REG(sii
->osh
, &ai
->ioctrl
, w
);
1105 ai_core_cflags(si_t
*sih
, uint32 mask
, uint32 val
)
1107 si_info_t
*sii
= SI_INFO(sih
);
1111 if (BCM5357_DMP()) {
1112 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n",
1116 if (BCM4707_DMP()) {
1117 SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n",
1123 SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n",
1127 ASSERT(GOODREGS(sii
->curwrap
));
1130 ASSERT((val
& ~mask
) == 0);
1133 w
= ((R_REG(sii
->osh
, &ai
->ioctrl
) & ~mask
) | val
);
1134 W_REG(sii
->osh
, &ai
->ioctrl
, w
);
1137 return R_REG(sii
->osh
, &ai
->ioctrl
);
1141 ai_core_sflags(si_t
*sih
, uint32 mask
, uint32 val
)
1143 si_info_t
*sii
= SI_INFO(sih
);
1147 if (BCM5357_DMP()) {
1148 SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n",
1152 if (BCM4707_DMP()) {
1153 SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n",
1158 SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n",
1163 ASSERT(GOODREGS(sii
->curwrap
));
1166 ASSERT((val
& ~mask
) == 0);
1167 ASSERT((mask
& ~SISF_CORE_BITS
) == 0);
1170 w
= ((R_REG(sii
->osh
, &ai
->iostatus
) & ~mask
) | val
);
1171 W_REG(sii
->osh
, &ai
->iostatus
, w
);
1174 return R_REG(sii
->osh
, &ai
->iostatus
);
1177 #if defined(BCMDBG_PHYDUMP)
1178 /* print interesting aidmp registers */
1180 ai_dumpregs(si_t
*sih
, struct bcmstrbuf
*b
)
1182 si_info_t
*sii
= SI_INFO(sih
);
1186 uint32 prev_value
= 0;
1187 axi_wrapper_t
* axi_wrapper
= sii
->axi_wrapper
;
1189 uint bar0_win_offset
= 0;
1194 /* Save and restore wrapper access window */
1195 if (BUSTYPE(sii
->pub
.bustype
) == PCI_BUS
) {
1196 if (PCIE_GEN2(sii
)) {
1197 cfg_reg
= PCIE2_BAR0_CORE2_WIN2
;
1198 bar0_win_offset
= PCIE2_BAR0_CORE2_WIN2_OFFSET
;
1200 cfg_reg
= PCI_BAR0_WIN2
;
1201 bar0_win_offset
= PCI_BAR0_WIN2_OFFSET
;
1204 prev_value
= OSL_PCI_READ_CONFIG(osh
, cfg_reg
, 4);
1206 if (prev_value
== ID32_INVALID
) {
1207 SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__
, prev_value
));
1212 bcm_bprintf(b
, "ChipNum:%x, ChipRev;%x, BusType:%x, BoardType:%x, BoardVendor:%x\n\n",
1213 sih
->chip
, sih
->chiprev
, sih
->bustype
, sih
->boardtype
, sih
->boardvendor
);
1215 for (i
= 0; i
< sii
->axi_num_wrappers
; i
++) {
1217 if (BUSTYPE(sii
->pub
.bustype
) == PCI_BUS
) {
1218 /* Set BAR0 window to bridge wapper base address */
1219 OSL_PCI_WRITE_CONFIG(osh
,
1220 cfg_reg
, 4, axi_wrapper
[i
].wrapper_addr
);
1222 ai
= (aidmp_t
*) ((volatile uint8
*)sii
->curmap
+ bar0_win_offset
);
1224 ai
= (aidmp_t
*)(uintptr
) axi_wrapper
[i
].wrapper_addr
;
1227 bcm_bprintf(b
, "core 0x%x: core_rev:%d, %s_WR ADDR:%x \n", axi_wrapper
[i
].cid
,
1229 axi_wrapper
[i
].wrapper_type
== AI_SLAVE_WRAPPER
? "SLAVE" : "MASTER",
1230 axi_wrapper
[i
].wrapper_addr
);
1233 if (((CHIPID(sih
->chip
) == BCM5357_CHIP_ID
) ||
1234 (CHIPID(sih
->chip
) == BCM4749_CHIP_ID
)) &&
1235 (sih
->chippkg
== BCM5357_PKG_ID
) &&
1236 (axi_wrapper
[i
].cid
== USB20H_CORE_ID
)) {
1237 bcm_bprintf(b
, "Skipping usb20h in 5357\n");
1242 if (BCM4707_CHIP(CHIPID(sih
->chip
)) &&
1243 (axi_wrapper
[i
].cid
== NS_CCB_CORE_ID
)) {
1244 bcm_bprintf(b
, "Skipping chipcommonb in 4707\n");
1248 bcm_bprintf(b
, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x "
1249 "ioctrlwidth 0x%x iostatuswidth 0x%x\n"
1250 "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n"
1251 "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x "
1252 "errlogaddrlo 0x%x errlogaddrhi 0x%x\n"
1253 "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n"
1254 "intstatus 0x%x config 0x%x itcr 0x%x\n\n",
1255 R_REG(osh
, &ai
->ioctrlset
),
1256 R_REG(osh
, &ai
->ioctrlclear
),
1257 R_REG(osh
, &ai
->ioctrl
),
1258 R_REG(osh
, &ai
->iostatus
),
1259 R_REG(osh
, &ai
->ioctrlwidth
),
1260 R_REG(osh
, &ai
->iostatuswidth
),
1261 R_REG(osh
, &ai
->resetctrl
),
1262 R_REG(osh
, &ai
->resetstatus
),
1263 R_REG(osh
, &ai
->resetreadid
),
1264 R_REG(osh
, &ai
->resetwriteid
),
1265 R_REG(osh
, &ai
->errlogctrl
),
1266 R_REG(osh
, &ai
->errlogdone
),
1267 R_REG(osh
, &ai
->errlogstatus
),
1268 R_REG(osh
, &ai
->errlogaddrlo
),
1269 R_REG(osh
, &ai
->errlogaddrhi
),
1270 R_REG(osh
, &ai
->errlogid
),
1271 R_REG(osh
, &ai
->errloguser
),
1272 R_REG(osh
, &ai
->errlogflags
),
1273 R_REG(osh
, &ai
->intstatus
),
1274 R_REG(osh
, &ai
->config
),
1275 R_REG(osh
, &ai
->itcr
));
1278 /* Restore the initial wrapper space */
1279 if (prev_value
&& cfg_reg
) {
1280 OSL_PCI_WRITE_CONFIG(osh
, cfg_reg
, 4, prev_value
);
1288 ai_enable_backplane_timeouts(si_t
*sih
)
1290 #if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT)
1291 si_info_t
*sii
= SI_INFO(sih
);
1294 axi_wrapper_t
* axi_wrapper
= sii
->axi_wrapper
;
1296 #ifdef BCM_BACKPLANE_TIMEOUT
1297 uint32 prev_value
= 0;
1298 osl_t
*osh
= sii
->osh
;
1301 #endif /* BCM_BACKPLANE_TIMEOUT */
1303 if ((sii
->axi_num_wrappers
== 0) ||
1304 #ifdef BCM_BACKPLANE_TIMEOUT
1306 #endif /* BCM_BACKPLANE_TIMEOUT */
1308 SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n",
1309 __FUNCTION__
, sii
->axi_num_wrappers
, PCIE(sii
),
1310 BUSTYPE(sii
->pub
.bustype
), sii
->pub
.buscoretype
));
1314 #ifdef BCM_BACKPLANE_TIMEOUT
1315 /* Save and restore the wrapper access window */
1316 if (BUSTYPE(sii
->pub
.bustype
) == PCI_BUS
) {
1317 if (PCIE_GEN1(sii
)) {
1318 cfg_reg
= PCI_BAR0_WIN2
;
1319 offset
= PCI_BAR0_WIN2_OFFSET
;
1320 } else if (PCIE_GEN2(sii
)) {
1321 cfg_reg
= PCIE2_BAR0_CORE2_WIN2
;
1322 offset
= PCIE2_BAR0_CORE2_WIN2_OFFSET
;
1325 osl_panic("!PCIE_GEN1 && !PCIE_GEN2\n");
1328 prev_value
= OSL_PCI_READ_CONFIG(osh
, cfg_reg
, 4);
1329 if (prev_value
== ID32_INVALID
) {
1330 SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__
, prev_value
));
1335 #endif /* BCM_BACKPLANE_TIMEOUT */
1337 for (i
= 0; i
< sii
->axi_num_wrappers
; ++i
) {
1339 if (axi_wrapper
[i
].wrapper_type
!= AI_SLAVE_WRAPPER
) {
1340 SI_VMSG(("SKIP ENABLE BPT: MFG:%x, CID:%x, ADDR:%x\n",
1343 axi_wrapper
[i
].wrapper_addr
));
1347 #ifdef BCM_BACKPLANE_TIMEOUT
1348 if (BUSTYPE(sii
->pub
.bustype
) == PCI_BUS
) {
1349 /* Set BAR0_CORE2_WIN2 to wapper base address */
1350 OSL_PCI_WRITE_CONFIG(osh
,
1351 cfg_reg
, 4, axi_wrapper
[i
].wrapper_addr
);
1353 /* set AI to BAR0 + Offset corresponding to Gen1 or gen2 */
1354 ai
= (aidmp_t
*) ((uint8
*)sii
->curmap
+ offset
);
1357 #endif /* BCM_BACKPLANE_TIMEOUT */
1359 ai
= (aidmp_t
*)(uintptr
) axi_wrapper
[i
].wrapper_addr
;
1362 W_REG(sii
->osh
, &ai
->errlogctrl
, (1 << AIELC_TO_ENAB_SHIFT
) |
1363 ((AXI_TO_VAL
<< AIELC_TO_EXP_SHIFT
) & AIELC_TO_EXP_MASK
));
1365 SI_VMSG(("ENABLED BPT: MFG:%x, CID:%x, ADDR:%x, ERR_CTRL:%x\n",
1368 axi_wrapper
[i
].wrapper_addr
,
1369 R_REG(sii
->osh
, &ai
->errlogctrl
)));
1372 #ifdef BCM_BACKPLANE_TIMEOUT
1373 /* Restore the initial wrapper space */
1375 OSL_PCI_WRITE_CONFIG(osh
, cfg_reg
, 4, prev_value
);
1377 #endif /* BCM_BACKPLANE_TIMEOUT */
1379 #endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */
1382 #if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT)
1384 /* slave error is ignored, so account for those cases */
1385 static uint32 si_ignore_errlog_cnt
= 0;
1388 ai_ignore_errlog(si_info_t
*sii
, uint32 lo_addr
, uint32 hi_addr
, uint32 err_axi_id
, uint32 errsts
)
1392 /* ignore the BT slave errors if the errlog is to chipcommon addr 0x190 */
1393 switch (CHIPID(sii
->pub
.chip
)) {
1394 case BCM4350_CHIP_ID
:
1395 axi_id
= BCM4350_BT_AXI_ID
;
1397 case BCM4345_CHIP_ID
:
1398 axi_id
= BCM4345_BT_AXI_ID
;
1405 if ((err_axi_id
& AI_ERRLOGID_AXI_ID_MASK
) != axi_id
)
1409 if ((errsts
& AIELS_TIMEOUT_MASK
) != AIELS_SLAVE_ERR
)
1412 /* chipc reg 0x190 */
1413 if ((hi_addr
!= BT_CC_SPROM_BADREG_HI
) || (lo_addr
!= BT_CC_SPROM_BADREG_LO
))
1418 #endif /* defined (AXI_TIMEOUTS) || defined (BCM_BACKPLANE_TIMEOUT) */
1420 #ifdef BCM_BACKPLANE_TIMEOUT
1422 /* Function to return the APB bridge details corresponding to the core */
1424 ai_get_apb_bridge(si_t
* sih
, uint32 coreidx
, uint32
*apb_id
, uint32
* apb_coreuinit
)
1427 uint32 core_base
, core_end
;
1428 si_info_t
*sii
= SI_INFO(sih
);
1429 static uint32 coreidx_cached
= 0, apb_id_cached
= 0, apb_coreunit_cached
= 0;
1430 uint32 tmp_coreunit
= 0;
1431 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
1433 if (coreidx
>= MIN(sii
->numcores
, SI_MAXCORES
))
1436 /* Most of the time apb bridge query will be for d11 core.
1437 * Maintain the last cache and return if found rather than iterating the table
1439 if (coreidx_cached
== coreidx
) {
1440 *apb_id
= apb_id_cached
;
1441 *apb_coreuinit
= apb_coreunit_cached
;
1445 core_base
= cores_info
->coresba
[coreidx
];
1446 core_end
= core_base
+ cores_info
->coresba_size
[coreidx
];
1448 for (i
= 0; i
< sii
->numcores
; i
++) {
1449 if (cores_info
->coreid
[i
] == APB_BRIDGE_ID
) {
1453 apb_base
= cores_info
->coresba
[i
];
1454 apb_end
= apb_base
+ cores_info
->coresba_size
[i
];
1456 if ((core_base
>= apb_base
) &&
1457 (core_end
<= apb_end
)) {
1458 /* Current core is attached to this APB bridge */
1459 *apb_id
= apb_id_cached
= APB_BRIDGE_ID
;
1460 *apb_coreuinit
= apb_coreunit_cached
= tmp_coreunit
;
1461 coreidx_cached
= coreidx
;
1464 /* Increment the coreunit */
1473 ai_clear_backplane_to_fast(si_t
*sih
, void * addr
)
1475 si_info_t
*sii
= SI_INFO(sih
);
1476 void * curmap
= sii
->curmap
;
1477 bool core_reg
= FALSE
;
1479 /* Use fast path only for core register access */
1480 if ((addr
>= curmap
) && (addr
< (curmap
+ SI_CORE_SIZE
))) {
1481 /* address being accessed is within current core reg map */
1486 uint32 apb_id
, apb_coreuinit
;
1488 if (ai_get_apb_bridge(sih
, si_coreidx(&sii
->pub
),
1489 &apb_id
, &apb_coreuinit
) == TRUE
) {
1490 /* Found the APB bridge corresponding to current core,
1491 * Check for bus errors in APB wrapper
1493 return ai_clear_backplane_to_per_core(sih
,
1494 apb_id
, apb_coreuinit
, NULL
);
1498 /* Default is to poll for errors on all slave wrappers */
1499 return si_clear_backplane_to(sih
);
1501 #endif /* BCM_BACKPLANE_TIMEOUT */
1503 #if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT)
1505 * API to clear the back plane timeout per core.
1506 * Caller may passs optional wrapper address. If present this will be used as
1507 * the wrapper base address. If wrapper base address is provided then caller
1508 * must provide the coreid also.
1509 * If both coreid and wrapper is zero, then err status of current bridge
1513 ai_clear_backplane_to_per_core(si_t
*sih
, uint coreid
, uint coreunit
, void * wrap
)
1515 int ret
= AXI_WRAP_STS_NONE
;
1517 uint32 errlog_status
= 0;
1518 si_info_t
*sii
= SI_INFO(sih
);
1519 uint32 errlog_lo
= 0, errlog_hi
= 0, errlog_id
= 0, errlog_flags
= 0;
1520 uint32 current_coreidx
= si_coreidx(sih
);
1521 uint32 target_coreidx
= si_findcoreidx(sih
, coreid
, coreunit
);
1523 #if defined(BCM_BACKPLANE_TIMEOUT)
1524 si_axi_error_t
* axi_error
= &sih
->err_info
->axi_error
[sih
->err_info
->count
];
1525 #endif /* BCM_BACKPLANE_TIMEOUT */
1526 bool restore_core
= FALSE
;
1528 if ((sii
->axi_num_wrappers
== 0) ||
1529 #ifdef BCM_BACKPLANE_TIMEOUT
1531 #endif /* BCM_BACKPLANE_TIMEOUT */
1533 SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n",
1534 __FUNCTION__
, sii
->axi_num_wrappers
, PCIE(sii
),
1535 BUSTYPE(sii
->pub
.bustype
), sii
->pub
.buscoretype
));
1536 return AXI_WRAP_STS_NONE
;
1540 ai
= (aidmp_t
*)wrap
;
1541 } else if (coreid
&& (target_coreidx
!= current_coreidx
)) {
1543 if (ai_setcoreidx(sih
, target_coreidx
) == NULL
) {
1544 /* Unable to set the core */
1545 SI_PRINT(("Set Code Failed: coreid:%x, unit:%d, target_coreidx:%d\n",
1546 coreid
, coreunit
, target_coreidx
));
1547 errlog_lo
= target_coreidx
;
1548 ret
= AXI_WRAP_STS_SET_CORE_FAIL
;
1552 restore_core
= TRUE
;
1553 ai
= (aidmp_t
*)si_wrapperregs(sih
);
1555 /* Read error status of current wrapper */
1556 ai
= (aidmp_t
*)si_wrapperregs(sih
);
1558 /* Update CoreID to current Code ID */
1559 coreid
= si_coreid(sih
);
1562 /* read error log status */
1563 errlog_status
= R_REG(sii
->osh
, &ai
->errlogstatus
);
1565 if (errlog_status
== ID32_INVALID
) {
1566 /* Do not try to peek further */
1567 SI_PRINT(("%s, errlogstatus:%x - Slave Wrapper:%x\n",
1568 __FUNCTION__
, errlog_status
, coreid
));
1569 ret
= AXI_WRAP_STS_WRAP_RD_ERR
;
1570 errlog_lo
= (uint32
)&ai
->errlogstatus
;
1574 if ((errlog_status
& AIELS_TIMEOUT_MASK
) != 0) {
1577 /* set ErrDone to clear the condition */
1578 W_REG(sii
->osh
, &ai
->errlogdone
, AIELD_ERRDONE_MASK
);
1580 /* SPINWAIT on errlogstatus timeout status bits */
1581 while ((tmp
= R_REG(sii
->osh
, &ai
->errlogstatus
)) & AIELS_TIMEOUT_MASK
) {
1583 if (tmp
== ID32_INVALID
) {
1584 SI_PRINT(("%s: prev errlogstatus:%x, errlogstatus:%x\n",
1585 __FUNCTION__
, errlog_status
, tmp
));
1586 ret
= AXI_WRAP_STS_WRAP_RD_ERR
;
1587 errlog_lo
= (uint32
)&ai
->errlogstatus
;
1591 * Clear again, to avoid getting stuck in the loop, if a new error
1592 * is logged after we cleared the first timeout
1594 W_REG(sii
->osh
, &ai
->errlogdone
, AIELD_ERRDONE_MASK
);
1598 if ((10 * count
) > AI_REG_READ_TIMEOUT
) {
1599 errlog_status
= tmp
;
1604 errlog_lo
= R_REG(sii
->osh
, &ai
->errlogaddrlo
);
1605 errlog_hi
= R_REG(sii
->osh
, &ai
->errlogaddrhi
);
1606 errlog_id
= R_REG(sii
->osh
, &ai
->errlogid
);
1607 errlog_flags
= R_REG(sii
->osh
, &ai
->errlogflags
);
1609 /* we are already in the error path, so OK to check for the slave error */
1610 if (ai_ignore_errlog(sii
, errlog_lo
, errlog_hi
, errlog_id
,
1612 si_ignore_errlog_cnt
++;
1616 /* only reset APB Bridge on timeout (not slave error, or dec error) */
1617 switch (errlog_status
& AIELS_TIMEOUT_MASK
) {
1618 case AIELS_SLAVE_ERR
:
1619 SI_PRINT(("AXI slave error"));
1620 ret
= AXI_WRAP_STS_SLAVE_ERR
;
1624 /* reset APB Bridge */
1625 OR_REG(sii
->osh
, &ai
->resetctrl
, AIRC_RESET
);
1627 (void)R_REG(sii
->osh
, &ai
->resetctrl
);
1628 /* clear Reset bit */
1629 AND_REG(sii
->osh
, &ai
->resetctrl
, ~(AIRC_RESET
));
1631 (void)R_REG(sii
->osh
, &ai
->resetctrl
);
1632 SI_PRINT(("AXI timeout"));
1633 ret
= AXI_WRAP_STS_TIMEOUT
;
1637 SI_PRINT(("AXI decode error"));
1638 ret
= AXI_WRAP_STS_DECODE_ERR
;
1641 ASSERT(0); /* should be impossible */
1644 SI_PRINT(("\tCoreID: %x\n", coreid
));
1645 SI_PRINT(("\t errlog: lo 0x%08x, hi 0x%08x, id 0x%08x, flags 0x%08x"
1646 ", status 0x%08x\n",
1647 errlog_lo
, errlog_hi
, errlog_id
, errlog_flags
,
1653 #if defined(BCM_BACKPLANE_TIMEOUT)
1654 if (axi_error
&& (ret
!= AXI_WRAP_STS_NONE
)) {
1655 axi_error
->error
= ret
;
1656 axi_error
->coreid
= coreid
;
1657 axi_error
->errlog_lo
= errlog_lo
;
1658 axi_error
->errlog_hi
= errlog_hi
;
1659 axi_error
->errlog_id
= errlog_id
;
1660 axi_error
->errlog_flags
= errlog_flags
;
1661 axi_error
->errlog_status
= errlog_status
;
1662 sih
->err_info
->count
++;
1664 if (sih
->err_info
->count
== SI_MAX_ERRLOG_SIZE
) {
1665 sih
->err_info
->count
= SI_MAX_ERRLOG_SIZE
- 1;
1666 SI_PRINT(("AXI Error log overflow\n"));
1669 #endif /* BCM_BACKPLANE_TIMEOUT */
1672 if (ai_setcoreidx(sih
, current_coreidx
) == NULL
) {
1673 /* Unable to set the core */
1674 return ID32_INVALID
;
1680 #endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */
1683 * This API polls all slave wrappers for errors and returns bit map of
1684 * all reported errors.
1685 * return - bit map of
1687 * AXI_WRAP_STS_TIMEOUT
1688 * AXI_WRAP_STS_SLAVE_ERR
1689 * AXI_WRAP_STS_DECODE_ERR
1690 * AXI_WRAP_STS_PCI_RD_ERR
1691 * AXI_WRAP_STS_WRAP_RD_ERR
1692 * AXI_WRAP_STS_SET_CORE_FAIL
1693 * On timeout detection, correspondign bridge will be reset to
1695 * Error reported in each wrapper can be retrieved using the API
1696 * si_get_axi_errlog_info()
1699 ai_clear_backplane_to(si_t
*sih
)
1702 #if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT)
1704 si_info_t
*sii
= SI_INFO(sih
);
1707 axi_wrapper_t
* axi_wrapper
= sii
->axi_wrapper
;
1709 #ifdef BCM_BACKPLANE_TIMEOUT
1710 uint32 prev_value
= 0;
1711 osl_t
*osh
= sii
->osh
;
1715 if ((sii
->axi_num_wrappers
== 0) || (!PCIE(sii
)))
1717 if (sii
->axi_num_wrappers
== 0)
1720 SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n",
1721 __FUNCTION__
, sii
->axi_num_wrappers
, PCIE(sii
),
1722 BUSTYPE(sii
->pub
.bustype
), sii
->pub
.buscoretype
));
1723 return AXI_WRAP_STS_NONE
;
1726 #ifdef BCM_BACKPLANE_TIMEOUT
1727 /* Save and restore wrapper access window */
1728 if (BUSTYPE(sii
->pub
.bustype
) == PCI_BUS
) {
1729 if (PCIE_GEN1(sii
)) {
1730 cfg_reg
= PCI_BAR0_WIN2
;
1731 offset
= PCI_BAR0_WIN2_OFFSET
;
1732 } else if (PCIE_GEN2(sii
)) {
1733 cfg_reg
= PCIE2_BAR0_CORE2_WIN2
;
1734 offset
= PCIE2_BAR0_CORE2_WIN2_OFFSET
;
1737 osl_panic("!PCIE_GEN1 && !PCIE_GEN2\n");
1740 prev_value
= OSL_PCI_READ_CONFIG(osh
, cfg_reg
, 4);
1742 if (prev_value
== ID32_INVALID
) {
1743 si_axi_error_t
* axi_error
=
1744 &sih
->err_info
->axi_error
[sih
->err_info
->count
];
1745 SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__
, prev_value
));
1747 axi_error
->error
= ret
= AXI_WRAP_STS_PCI_RD_ERR
;
1748 axi_error
->errlog_lo
= cfg_reg
;
1749 sih
->err_info
->count
++;
1751 if (sih
->err_info
->count
== SI_MAX_ERRLOG_SIZE
) {
1752 sih
->err_info
->count
= SI_MAX_ERRLOG_SIZE
- 1;
1753 SI_PRINT(("AXI Error log overflow\n"));
1759 #endif /* BCM_BACKPLANE_TIMEOUT */
1761 for (i
= 0; i
< sii
->axi_num_wrappers
; ++i
) {
1764 if (axi_wrapper
[i
].wrapper_type
!= AI_SLAVE_WRAPPER
) {
1768 #ifdef BCM_BACKPLANE_TIMEOUT
1770 if (BUSTYPE(sii
->pub
.bustype
) == PCI_BUS
) {
1771 /* Set BAR0_CORE2_WIN2 to bridge wapper base address */
1772 OSL_PCI_WRITE_CONFIG(osh
,
1773 cfg_reg
, 4, axi_wrapper
[i
].wrapper_addr
);
1775 /* set AI to BAR0 + Offset corresponding to Gen1 or gen2 */
1776 ai
= (aidmp_t
*) ((uint8
*)sii
->curmap
+ offset
);
1779 #endif /* BCM_BACKPLANE_TIMEOUT */
1781 ai
= (aidmp_t
*)(uintptr
) axi_wrapper
[i
].wrapper_addr
;
1784 tmp
= ai_clear_backplane_to_per_core(sih
, axi_wrapper
[i
].cid
, 0, (void*)ai
);
1789 #ifdef BCM_BACKPLANE_TIMEOUT
1790 /* Restore the initial wrapper space */
1792 OSL_PCI_WRITE_CONFIG(osh
, cfg_reg
, 4, prev_value
);
1794 #endif /* BCM_BACKPLANE_TIMEOUT */
1796 #endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */
1802 ai_num_slaveports(si_t
*sih
, uint coreidx
)
1804 si_info_t
*sii
= SI_INFO(sih
);
1805 si_cores_info_t
*cores_info
= (si_cores_info_t
*)sii
->cores_info
;
1808 cib
= cores_info
->cib
[coreidx
];
1809 return ((cib
& CIB_NSP_MASK
) >> CIB_NSP_SHIFT
);