xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/siutils.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Misc utility routines for accessing chip-specific features
3*4882a593Smuzhiyun  * of the SiliconBackplane-based Broadcom chips.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2020, Broadcom.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *      Unless you and Broadcom execute a separate written software license
8*4882a593Smuzhiyun  * agreement governing use of this software, this software is licensed to you
9*4882a593Smuzhiyun  * under the terms of the GNU General Public License version 2 (the "GPL"),
10*4882a593Smuzhiyun  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11*4882a593Smuzhiyun  * following added to such license:
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  *      As a special exception, the copyright holders of this software give you
14*4882a593Smuzhiyun  * permission to link this software with independent modules, and to copy and
15*4882a593Smuzhiyun  * distribute the resulting executable under terms of your choice, provided that
16*4882a593Smuzhiyun  * you also meet, for each linked independent module, the terms and conditions of
17*4882a593Smuzhiyun  * the license of that module.  An independent module is a module which is not
18*4882a593Smuzhiyun  * derived from this software.  The special exception does not apply to any
19*4882a593Smuzhiyun  * modifications of the software.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  * <<Broadcom-WL-IPTag/Dual:>>
23*4882a593Smuzhiyun  */
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <typedefs.h>
26*4882a593Smuzhiyun #include <bcmdefs.h>
27*4882a593Smuzhiyun #include <osl.h>
28*4882a593Smuzhiyun #include <bcmutils.h>
29*4882a593Smuzhiyun #include <siutils.h>
30*4882a593Smuzhiyun #include <bcmdevs.h>
31*4882a593Smuzhiyun #include <hndsoc.h>
32*4882a593Smuzhiyun #include <sbchipc.h>
33*4882a593Smuzhiyun #include <sbgci.h>
34*4882a593Smuzhiyun #ifndef BCMSDIO
35*4882a593Smuzhiyun #include <pcie_core.h>
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
38*4882a593Smuzhiyun #include <pci_core.h>
39*4882a593Smuzhiyun #include <nicpci.h>
40*4882a593Smuzhiyun #include <bcmnvram.h>
41*4882a593Smuzhiyun #include <bcmsrom.h>
42*4882a593Smuzhiyun #include <hndtcam.h>
43*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
44*4882a593Smuzhiyun #ifdef BCMPCIEDEV
45*4882a593Smuzhiyun #include <pcieregsoffs.h>
46*4882a593Smuzhiyun #include <pciedev.h>
47*4882a593Smuzhiyun #endif /* BCMPCIEDEV */
48*4882a593Smuzhiyun #include <pcicfg.h>
49*4882a593Smuzhiyun #include <sbpcmcia.h>
50*4882a593Smuzhiyun #include <sbsysmem.h>
51*4882a593Smuzhiyun #include <sbsocram.h>
52*4882a593Smuzhiyun #if defined(BCMECICOEX) || !defined(BCMDONGLEHOST)
53*4882a593Smuzhiyun #include <bcmotp.h>
54*4882a593Smuzhiyun #endif /* BCMECICOEX || !BCMDONGLEHOST */
55*4882a593Smuzhiyun #ifdef BCMSDIO
56*4882a593Smuzhiyun #include <bcmsdh.h>
57*4882a593Smuzhiyun #include <sdio.h>
58*4882a593Smuzhiyun #include <sbsdio.h>
59*4882a593Smuzhiyun #include <sbhnddma.h>
60*4882a593Smuzhiyun #include <sbsdpcmdev.h>
61*4882a593Smuzhiyun #include <bcmsdpcm.h>
62*4882a593Smuzhiyun #endif /* BCMSDIO */
63*4882a593Smuzhiyun #include <hndpmu.h>
64*4882a593Smuzhiyun #ifdef BCMSPI
65*4882a593Smuzhiyun #include <spid.h>
66*4882a593Smuzhiyun #endif /* BCMSPI */
67*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST) && !defined(BCM_BOOTLOADER) && defined(SR_ESSENTIALS)
68*4882a593Smuzhiyun #include <saverestore.h>
69*4882a593Smuzhiyun #endif
70*4882a593Smuzhiyun #include <dhd_config.h>
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #ifdef BCM_SDRBL
73*4882a593Smuzhiyun #include <hndcpu.h>
74*4882a593Smuzhiyun #endif /* BCM_SDRBL */
75*4882a593Smuzhiyun #ifdef HNDGCI
76*4882a593Smuzhiyun #include <hndgci.h>
77*4882a593Smuzhiyun #endif /* HNDGCI */
78*4882a593Smuzhiyun #ifdef DONGLEBUILD
79*4882a593Smuzhiyun #include <hnd_gci.h>
80*4882a593Smuzhiyun #endif /* DONGLEBUILD */
81*4882a593Smuzhiyun #include <hndlhl.h>
82*4882a593Smuzhiyun #include <hndoobr.h>
83*4882a593Smuzhiyun #include <lpflags.h>
84*4882a593Smuzhiyun #ifdef BCM_SFLASH
85*4882a593Smuzhiyun #include <sflash.h>
86*4882a593Smuzhiyun #endif
87*4882a593Smuzhiyun #ifdef BCM_SH_SFLASH
88*4882a593Smuzhiyun #include <sh_sflash.h>
89*4882a593Smuzhiyun #endif
90*4882a593Smuzhiyun #ifdef BCMGCISHM
91*4882a593Smuzhiyun #include <hnd_gcishm.h>
92*4882a593Smuzhiyun #endif
93*4882a593Smuzhiyun #include "siutils_priv.h"
94*4882a593Smuzhiyun #include "sbhndarm.h"
95*4882a593Smuzhiyun #include <hndchipc.h>
96*4882a593Smuzhiyun #ifdef SOCI_NCI_BUS
97*4882a593Smuzhiyun #include <nci.h>
98*4882a593Smuzhiyun #endif /* SOCI_NCI_BUS */
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun #ifdef SECI_UART
101*4882a593Smuzhiyun /* Defines the set of GPIOs to be used for SECI UART if not specified in NVRAM */
102*4882a593Smuzhiyun /* For further details on each ppin functionality please refer to PINMUX table in
103*4882a593Smuzhiyun  * Top level architecture of BCMXXXX Chip
104*4882a593Smuzhiyun  */
105*4882a593Smuzhiyun #define DEFAULT_SECI_UART_PINMUX	0x08090a0b
106*4882a593Smuzhiyun static bool force_seci_clk = 0;
107*4882a593Smuzhiyun #endif /* SECI_UART */
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun #define XTAL_FREQ_26000KHZ		26000
110*4882a593Smuzhiyun #define XTAL_FREQ_59970KHZ		59970
111*4882a593Smuzhiyun #define WCI2_UART_RX_BUF_SIZE	64
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun /**
114*4882a593Smuzhiyun  * A set of PMU registers is clocked in the ILP domain, which has an implication on register write
115*4882a593Smuzhiyun  * behavior: if such a register is written, it takes multiple ILP clocks for the PMU block to absorb
116*4882a593Smuzhiyun  * the write. During that time the 'SlowWritePending' bit in the PMUStatus register is set.
117*4882a593Smuzhiyun  */
118*4882a593Smuzhiyun #define PMUREGS_ILP_SENSITIVE(regoff) \
119*4882a593Smuzhiyun 	((regoff) == OFFSETOF(pmuregs_t, pmutimer) || \
120*4882a593Smuzhiyun 	 (regoff) == OFFSETOF(pmuregs_t, pmuwatchdog) || \
121*4882a593Smuzhiyun 	 (regoff) == OFFSETOF(pmuregs_t, res_req_timer))
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun #define CHIPCREGS_ILP_SENSITIVE(regoff) \
124*4882a593Smuzhiyun 	((regoff) == OFFSETOF(chipcregs_t, pmutimer) || \
125*4882a593Smuzhiyun 	 (regoff) == OFFSETOF(chipcregs_t, pmuwatchdog) || \
126*4882a593Smuzhiyun 	 (regoff) == OFFSETOF(chipcregs_t, res_req_timer))
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun #define GCI_FEM_CTRL_WAR 0x11111111
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun #ifndef AXI_TO_VAL
131*4882a593Smuzhiyun #define AXI_TO_VAL 19
132*4882a593Smuzhiyun #endif	/* AXI_TO_VAL */
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun #ifndef AXI_TO_VAL_25
135*4882a593Smuzhiyun /*
136*4882a593Smuzhiyun  * Increase BP timeout for fast clock and short PCIe timeouts
137*4882a593Smuzhiyun  * New timeout: 2 ** 25 cycles
138*4882a593Smuzhiyun  */
139*4882a593Smuzhiyun #define AXI_TO_VAL_25	25
140*4882a593Smuzhiyun #endif /* AXI_TO_VAL_25 */
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun #define si_srpwr_domain_mask(rval, mask) \
143*4882a593Smuzhiyun 	(((rval) >> SRPWR_STATUS_SHIFT) & (mask))
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /* local prototypes */
146*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
147*4882a593Smuzhiyun static void si_43012_lp_enable(si_t *sih);
148*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
149*4882a593Smuzhiyun static int32 BCMATTACHFN(si_alloc_wrapper)(si_info_t *sii);
150*4882a593Smuzhiyun static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs,
151*4882a593Smuzhiyun                               uint bustype, void *sdh, char **vars, uint *varsz);
152*4882a593Smuzhiyun static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh);
153*4882a593Smuzhiyun static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
154*4882a593Smuzhiyun 	uint *origidx, volatile const void *regs);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
157*4882a593Smuzhiyun static void si_nvram_process(si_info_t *sii, char *pvars);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun /* dev path concatenation util */
160*4882a593Smuzhiyun static char *si_devpathvar(const si_t *sih, char *var, int len, const char *name);
161*4882a593Smuzhiyun static char *si_pcie_devpathvar(const si_t *sih, char *var, int len, const char *name);
162*4882a593Smuzhiyun static bool _si_clkctl_cc(si_info_t *sii, uint mode);
163*4882a593Smuzhiyun static bool si_ispcie(const si_info_t *sii);
164*4882a593Smuzhiyun static uint sysmem_banksize(const si_info_t *sii, sysmemregs_t *r, uint8 idx);
165*4882a593Smuzhiyun static uint socram_banksize(const si_info_t *sii, sbsocramregs_t *r, uint8 idx, uint8 mtype);
166*4882a593Smuzhiyun static void si_gci_get_chipctrlreg_ringidx_base4(uint32 pin, uint32 *regidx, uint32 *pos);
167*4882a593Smuzhiyun static uint8 si_gci_get_chipctrlreg_ringidx_base8(uint32 pin, uint32 *regidx, uint32 *pos);
168*4882a593Smuzhiyun static void si_gci_gpio_chipcontrol(si_t *si, uint8 gpoi, uint8 opt);
169*4882a593Smuzhiyun static void si_gci_enable_gpioint(si_t *sih, bool enable);
170*4882a593Smuzhiyun #if defined(BCMECICOEX) || defined(SECI_UART)
171*4882a593Smuzhiyun static chipcregs_t * seci_set_core(si_t *sih, uint32 *origidx, bool *fast);
172*4882a593Smuzhiyun #endif
173*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun static bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun static void si_oob_war_BT_F1(si_t *sih);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun #if defined(DONGLEBUILD)
180*4882a593Smuzhiyun #if	!defined(NVSRCX)
181*4882a593Smuzhiyun static char * BCMATTACHFN(si_getkvars)(void);
182*4882a593Smuzhiyun static int BCMATTACHFN(si_getkvarsz)(void);
183*4882a593Smuzhiyun #endif
184*4882a593Smuzhiyun #endif /* DONGLEBUILD */
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun #if defined(BCMLTECOEX) && !defined(WLTEST)
187*4882a593Smuzhiyun static void si_wci2_rxfifo_intr_handler_process(si_t *sih, uint32 intstatus);
188*4882a593Smuzhiyun #endif /* BCMLTECOEX && !WLTEST */
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun /* global variable to indicate reservation/release of gpio's */
191*4882a593Smuzhiyun static uint32 si_gpioreservation = 0;
192*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
193*4882a593Smuzhiyun /* global variable to indicate GCI reset is done */
194*4882a593Smuzhiyun static bool gci_reset_done = FALSE;
195*4882a593Smuzhiyun #endif
196*4882a593Smuzhiyun /* global flag to prevent shared resources from being initialized multiple times in si_attach() */
197*4882a593Smuzhiyun static bool si_onetimeinit = FALSE;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun #ifdef SR_DEBUG
200*4882a593Smuzhiyun static const uint32 si_power_island_test_array[] = {
201*4882a593Smuzhiyun 	0x0000, 0x0001, 0x0010, 0x0011,
202*4882a593Smuzhiyun 	0x0100, 0x0101, 0x0110, 0x0111,
203*4882a593Smuzhiyun 	0x1000, 0x1001, 0x1010, 0x1011,
204*4882a593Smuzhiyun 	0x1100, 0x1101, 0x1110, 0x1111
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun #endif /* SR_DEBUG */
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun /* 4360 pcie2 WAR */
209*4882a593Smuzhiyun int do_4360_pcie2_war = 0;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun /* global kernel resource */
212*4882a593Smuzhiyun static si_info_t ksii;
213*4882a593Smuzhiyun static si_cores_info_t ksii_cores_info;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun #ifndef BCMDONGLEHOST
216*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_rmin)[] = "rmin";
217*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_rmax)[] = "rmax";
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_lhl_ps_mode)[] = "lhl_ps_mode";
220*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_ext_wakeup_dis)[] = "ext_wakeup_dis";
221*4882a593Smuzhiyun #if defined(BCMSRTOPOFF) && !defined(BCMSRTOPOFF_DISABLED)
222*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_srtopoff_enab)[] = "srtopoff_enab";
223*4882a593Smuzhiyun #endif
224*4882a593Smuzhiyun #endif /* BCMDONGLEHOST */
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun static uint32	wd_msticks;		/**< watchdog timer ticks normalized to ms */
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun #ifdef DONGLEBUILD
229*4882a593Smuzhiyun /**
230*4882a593Smuzhiyun  * As si_kattach goes thru full srom initialisation same can be used
231*4882a593Smuzhiyun  * for all subsequent calls
232*4882a593Smuzhiyun  */
233*4882a593Smuzhiyun #if	!defined(NVSRCX)
234*4882a593Smuzhiyun static char *
BCMATTACHFN(si_getkvars)235*4882a593Smuzhiyun BCMATTACHFN(si_getkvars)(void)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
238*4882a593Smuzhiyun 		return NULL;
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 	return (ksii.vars);
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun static int
BCMATTACHFN(si_getkvarsz)244*4882a593Smuzhiyun BCMATTACHFN(si_getkvarsz)(void)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
247*4882a593Smuzhiyun 		return NULL;
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 	return (ksii.varsz);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun #endif /* !defined(NVSRCX) */
252*4882a593Smuzhiyun #endif /* DONGLEBUILD */
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun /** Returns the backplane address of the chipcommon core for a particular chip */
255*4882a593Smuzhiyun uint32
BCMATTACHFN(si_enum_base)256*4882a593Smuzhiyun BCMATTACHFN(si_enum_base)(uint devid)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	return SI_ENUM_BASE_DEFAULT;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun /**
262*4882a593Smuzhiyun  * Allocate an si handle. This function may be called multiple times.
263*4882a593Smuzhiyun  *
264*4882a593Smuzhiyun  * devid - pci device id (used to determine chip#)
265*4882a593Smuzhiyun  * osh - opaque OS handle
266*4882a593Smuzhiyun  * regs - virtual address of initial core registers
267*4882a593Smuzhiyun  * bustype - pci/sb/sdio/etc
268*4882a593Smuzhiyun  * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this
269*4882a593Smuzhiyun  *        function set 'vars' to NULL, making dereferencing of this parameter undesired.
270*4882a593Smuzhiyun  * varsz - pointer to int to return the size of the vars
271*4882a593Smuzhiyun  */
272*4882a593Smuzhiyun si_t *
BCMATTACHFN(si_attach)273*4882a593Smuzhiyun BCMATTACHFN(si_attach)(uint devid, osl_t *osh, volatile void *regs,
274*4882a593Smuzhiyun                        uint bustype, void *sdh, char **vars, uint *varsz)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	si_info_t *sii;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	/* alloc si_info_t */
279*4882a593Smuzhiyun 	/* freed after ucode download for firmware builds */
280*4882a593Smuzhiyun 	if ((sii = MALLOCZ_NOPERSIST(osh, sizeof(si_info_t))) == NULL) {
281*4882a593Smuzhiyun 		SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));
282*4882a593Smuzhiyun 		return (NULL);
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun #ifdef BCMDVFS
286*4882a593Smuzhiyun 	if (BCMDVFS_ENAB() && si_dvfs_info_init((si_t *)sii, osh) == NULL) {
287*4882a593Smuzhiyun 		SI_ERROR(("si_dvfs_info_init failed\n"));
288*4882a593Smuzhiyun 		return (NULL);
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun #endif /* BCMDVFS */
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) {
293*4882a593Smuzhiyun 		MFREE(osh, sii, sizeof(si_info_t));
294*4882a593Smuzhiyun 		return (NULL);
295*4882a593Smuzhiyun 	}
296*4882a593Smuzhiyun 	sii->vars = vars ? *vars : NULL;
297*4882a593Smuzhiyun 	sii->varsz = varsz ? *varsz : 0;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun #if defined(BCM_SH_SFLASH) && !defined(BCM_SH_SFLASH_DISABLED)
300*4882a593Smuzhiyun 	sh_sflash_attach(osh, (si_t *)sii);
301*4882a593Smuzhiyun #endif
302*4882a593Smuzhiyun 	return (si_t *)sii;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun /** generic kernel variant of si_attach(). Is not called for Linux WLAN NIC builds. */
306*4882a593Smuzhiyun si_t *
BCMATTACHFN(si_kattach)307*4882a593Smuzhiyun BCMATTACHFN(si_kattach)(osl_t *osh)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	static bool ksii_attached = FALSE;
310*4882a593Smuzhiyun 	si_cores_info_t *cores_info;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	if (!ksii_attached) {
313*4882a593Smuzhiyun 		void *regs = NULL;
314*4882a593Smuzhiyun 		const uint device_id = BCM4710_DEVICE_ID; // pick an arbitrary default device_id
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 		regs = REG_MAP(si_enum_base(device_id), SI_CORE_SIZE); // map physical to virtual
317*4882a593Smuzhiyun 		cores_info = (si_cores_info_t *)&ksii_cores_info;
318*4882a593Smuzhiyun 		ksii.cores_info = cores_info;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 		/* Use osh as the deciding factor if the memory management
321*4882a593Smuzhiyun 		 * system has been initialized. Pass non-NULL vars & varsz only
322*4882a593Smuzhiyun 		 * if memory management has been initialized. Otherwise MALLOC()
323*4882a593Smuzhiyun 		 * will fail/crash.
324*4882a593Smuzhiyun 		 */
325*4882a593Smuzhiyun #if defined(BCMDONGLEHOST)
326*4882a593Smuzhiyun 		ASSERT(osh);
327*4882a593Smuzhiyun #endif
328*4882a593Smuzhiyun 		if (si_doattach(&ksii, device_id, osh, regs,
329*4882a593Smuzhiyun 		                SI_BUS, NULL,
330*4882a593Smuzhiyun 		                osh != SI_OSH ? &(ksii.vars) : NULL,
331*4882a593Smuzhiyun 		                osh != SI_OSH ? &(ksii.varsz) : NULL) == NULL) {
332*4882a593Smuzhiyun 			SI_ERROR(("si_kattach: si_doattach failed\n"));
333*4882a593Smuzhiyun 			REG_UNMAP(regs);
334*4882a593Smuzhiyun 			return NULL;
335*4882a593Smuzhiyun 		}
336*4882a593Smuzhiyun 		REG_UNMAP(regs);
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 		/* save ticks normalized to ms for si_watchdog_ms() */
339*4882a593Smuzhiyun 		if (PMUCTL_ENAB(&ksii.pub)) {
340*4882a593Smuzhiyun 			/* based on 32KHz ILP clock */
341*4882a593Smuzhiyun 			wd_msticks = 32;
342*4882a593Smuzhiyun 		} else {
343*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
344*4882a593Smuzhiyun 			if (CCREV(ksii.pub.ccrev) < 18)
345*4882a593Smuzhiyun 				wd_msticks = si_clock(&ksii.pub) / 1000;
346*4882a593Smuzhiyun 			else
347*4882a593Smuzhiyun 				wd_msticks = si_alp_clock(&ksii.pub) / 1000;
348*4882a593Smuzhiyun #else
349*4882a593Smuzhiyun 			wd_msticks = ALP_CLOCK / 1000;
350*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
351*4882a593Smuzhiyun 		}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 		ksii_attached = TRUE;
354*4882a593Smuzhiyun 		SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n",
355*4882a593Smuzhiyun 		        CCREV(ksii.pub.ccrev), wd_msticks));
356*4882a593Smuzhiyun 	}
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	return &ksii.pub;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun static bool
BCMATTACHFN(si_buscore_prep)362*4882a593Smuzhiyun BCMATTACHFN(si_buscore_prep)(si_info_t *sii, uint bustype, uint devid, void *sdh)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	BCM_REFERENCE(sdh);
365*4882a593Smuzhiyun 	BCM_REFERENCE(devid);
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
368*4882a593Smuzhiyun 	/* kludge to enable the clock on the 4306 which lacks a slowclock */
369*4882a593Smuzhiyun 	if (BUSTYPE(bustype) == PCI_BUS && !si_ispcie(sii))
370*4882a593Smuzhiyun 		si_clkctl_xtal(&sii->pub, XTAL|PLL, ON);
371*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun #if defined(BCMSDIO) && defined(BCMDONGLEHOST) && !defined(BCMSDIOLITE)
374*4882a593Smuzhiyun 	/* PR 39902, 43618, 44891, 41539 -- avoid backplane accesses that may
375*4882a593Smuzhiyun 	 * cause SDIO clock requests before a stable ALP clock.  Originally had
376*4882a593Smuzhiyun 	 * this later (just before srom_var_init() below) to guarantee ALP for
377*4882a593Smuzhiyun 	 * CIS read, but due to these PRs moving it here before backplane use.
378*4882a593Smuzhiyun 	 */
379*4882a593Smuzhiyun 	/* As it precedes any backplane access, can't check chipid; but may
380*4882a593Smuzhiyun 	 * be able to qualify with devid if underlying SDIO allows.  But should
381*4882a593Smuzhiyun 	 * be ok for all our SDIO (4318 doesn't support clock and pullup regs,
382*4882a593Smuzhiyun 	 * but the access attempts don't seem to hurt.)  Might elimiante the
383*4882a593Smuzhiyun 	 * the need for ALP for CIS at all if underlying SDIO uses CMD53...
384*4882a593Smuzhiyun 	 */
385*4882a593Smuzhiyun 	if (BUSTYPE(bustype) == SDIO_BUS) {
386*4882a593Smuzhiyun 		int err;
387*4882a593Smuzhiyun 		uint8 clkset;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 		/* Try forcing SDIO core to do ALPAvail request only */
390*4882a593Smuzhiyun 		clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
391*4882a593Smuzhiyun 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
392*4882a593Smuzhiyun 		if (!err) {
393*4882a593Smuzhiyun 			uint8 clkval;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 			/* If register supported, wait for ALPAvail and then force ALP */
396*4882a593Smuzhiyun 			clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL);
397*4882a593Smuzhiyun 			if ((clkval & ~SBSDIO_AVBITS) == clkset) {
398*4882a593Smuzhiyun 				SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
399*4882a593Smuzhiyun 					SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)),
400*4882a593Smuzhiyun 					PMU_MAX_TRANSITION_DLY);
401*4882a593Smuzhiyun 				if (!SBSDIO_ALPAV(clkval)) {
402*4882a593Smuzhiyun 					SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n",
403*4882a593Smuzhiyun 						clkval));
404*4882a593Smuzhiyun 					return FALSE;
405*4882a593Smuzhiyun 				}
406*4882a593Smuzhiyun 				clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
407*4882a593Smuzhiyun 				bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
408*4882a593Smuzhiyun 					clkset, &err);
409*4882a593Smuzhiyun 				/* PR 40613: account for possible ALP delay */
410*4882a593Smuzhiyun 				OSL_DELAY(65);
411*4882a593Smuzhiyun 			}
412*4882a593Smuzhiyun 		}
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 		/* Also, disable the extra SDIO pull-ups */
415*4882a593Smuzhiyun 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
416*4882a593Smuzhiyun 	}
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun #ifdef BCMSPI
419*4882a593Smuzhiyun 	/* Avoid backplane accesses before wake-wlan (i.e. htavail) for spi.
420*4882a593Smuzhiyun 	 * F1 read accesses may return correct data but with data-not-available dstatus bit set.
421*4882a593Smuzhiyun 	 */
422*4882a593Smuzhiyun 	if (BUSTYPE(bustype) == SPI_BUS) {
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 		int err;
425*4882a593Smuzhiyun 		uint32 regdata;
426*4882a593Smuzhiyun 		/* wake up wlan function :WAKE_UP goes as HT_AVAIL request in hardware */
427*4882a593Smuzhiyun 		regdata = bcmsdh_cfg_read_word(sdh, SDIO_FUNC_0, SPID_CONFIG, NULL);
428*4882a593Smuzhiyun 		SI_MSG(("F0 REG0 rd = 0x%x\n", regdata));
429*4882a593Smuzhiyun 		regdata |= WAKE_UP;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 		bcmsdh_cfg_write_word(sdh, SDIO_FUNC_0, SPID_CONFIG, regdata, &err);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 		/* It takes time for wakeup to take effect. */
434*4882a593Smuzhiyun 		OSL_DELAY(100000);
435*4882a593Smuzhiyun 	}
436*4882a593Smuzhiyun #endif /* BCMSPI */
437*4882a593Smuzhiyun #endif /* BCMSDIO && BCMDONGLEHOST && !BCMSDIOLITE */
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	return TRUE;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun /* note: this function is used by dhd */
443*4882a593Smuzhiyun uint32
si_get_pmu_reg_addr(si_t * sih,uint32 offset)444*4882a593Smuzhiyun si_get_pmu_reg_addr(si_t *sih, uint32 offset)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
447*4882a593Smuzhiyun 	uint32 pmuaddr = INVALID_ADDR;
448*4882a593Smuzhiyun 	uint origidx = 0;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	SI_MSG(("si_get_pmu_reg_addr: pmu access, offset: %x\n", offset));
451*4882a593Smuzhiyun 	if (!(sii->pub.cccaps & CC_CAP_PMU)) {
452*4882a593Smuzhiyun 		goto done;
453*4882a593Smuzhiyun 	}
454*4882a593Smuzhiyun 	if (AOB_ENAB(&sii->pub)) {
455*4882a593Smuzhiyun 		uint pmucoreidx;
456*4882a593Smuzhiyun 		pmuregs_t *pmu;
457*4882a593Smuzhiyun 		SI_MSG(("si_get_pmu_reg_addr: AOBENAB: %x\n", offset));
458*4882a593Smuzhiyun 		origidx = sii->curidx;
459*4882a593Smuzhiyun 		pmucoreidx = si_findcoreidx(&sii->pub, PMU_CORE_ID, 0);
460*4882a593Smuzhiyun 		pmu = si_setcoreidx(&sii->pub, pmucoreidx);
461*4882a593Smuzhiyun 		/* note: this function is used by dhd and possible 64 bit compilation needs
462*4882a593Smuzhiyun 		 * a cast to (unsigned long) for avoiding a compilation error.
463*4882a593Smuzhiyun 		 */
464*4882a593Smuzhiyun 		pmuaddr = (uint32)(uintptr)((volatile uint8*)pmu + offset);
465*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
466*4882a593Smuzhiyun 	} else
467*4882a593Smuzhiyun 		pmuaddr = SI_ENUM_BASE(sih) + offset;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun done:
470*4882a593Smuzhiyun 	SI_MSG(("%s: addrRET: %x\n", __FUNCTION__, pmuaddr));
471*4882a593Smuzhiyun 	return pmuaddr;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun static bool
BCMATTACHFN(si_buscore_setup)475*4882a593Smuzhiyun BCMATTACHFN(si_buscore_setup)(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
476*4882a593Smuzhiyun 	uint *origidx, volatile const void *regs)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun 	const si_cores_info_t *cores_info = sii->cores_info;
479*4882a593Smuzhiyun 	bool pci, pcie, pcie_gen2 = FALSE;
480*4882a593Smuzhiyun 	uint i;
481*4882a593Smuzhiyun 	uint pciidx, pcieidx, pcirev, pcierev;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun #if defined(AXI_TIMEOUTS_NIC) || defined(AXI_TIMEOUTS)
484*4882a593Smuzhiyun 	/* first, enable backplane timeouts */
485*4882a593Smuzhiyun 	si_slave_wrapper_add(&sii->pub);
486*4882a593Smuzhiyun #endif
487*4882a593Smuzhiyun 	sii->curidx = 0;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	cc = si_setcoreidx(&sii->pub, SI_CC_IDX);
490*4882a593Smuzhiyun 	ASSERT((uintptr)cc);
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	/* get chipcommon rev */
493*4882a593Smuzhiyun 	sii->pub.ccrev = (int)si_corerev(&sii->pub);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	/* get chipcommon chipstatus */
496*4882a593Smuzhiyun 	if (CCREV(sii->pub.ccrev) >= 11)
497*4882a593Smuzhiyun 		sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus);
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	/* get chipcommon capabilites */
500*4882a593Smuzhiyun 	sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities);
501*4882a593Smuzhiyun 	/* get chipcommon extended capabilities */
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	if (CCREV(sii->pub.ccrev) >= 35) /* PR77565 */
504*4882a593Smuzhiyun 		sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	/* get pmu rev and caps */
507*4882a593Smuzhiyun 	if (sii->pub.cccaps & CC_CAP_PMU) {
508*4882a593Smuzhiyun 		if (AOB_ENAB(&sii->pub)) {
509*4882a593Smuzhiyun 			uint pmucoreidx;
510*4882a593Smuzhiyun 			pmuregs_t *pmu;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 			pmucoreidx = si_findcoreidx(&sii->pub, PMU_CORE_ID, 0);
513*4882a593Smuzhiyun 			if (!GOODIDX(pmucoreidx, sii->numcores)) {
514*4882a593Smuzhiyun 				SI_ERROR(("si_buscore_setup: si_findcoreidx failed\n"));
515*4882a593Smuzhiyun 				return FALSE;
516*4882a593Smuzhiyun 			}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 			pmu = si_setcoreidx(&sii->pub, pmucoreidx);
519*4882a593Smuzhiyun 			sii->pub.pmucaps = R_REG(sii->osh, &pmu->pmucapabilities);
520*4882a593Smuzhiyun 			si_setcoreidx(&sii->pub, SI_CC_IDX);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 			sii->pub.gcirev = si_corereg(&sii->pub, GCI_CORE_IDX(&sii->pub),
523*4882a593Smuzhiyun 				GCI_OFFSETOF(&sii->pub, gci_corecaps0), 0, 0) & GCI_CAP0_REV_MASK;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 			if (GCIREV(sii->pub.gcirev) >= 9) {
526*4882a593Smuzhiyun 				sii->pub.lhlrev = si_corereg(&sii->pub, GCI_CORE_IDX(&sii->pub),
527*4882a593Smuzhiyun 					OFFSETOF(gciregs_t, lhl_core_capab_adr), 0, 0) &
528*4882a593Smuzhiyun 					LHL_CAP_REV_MASK;
529*4882a593Smuzhiyun 			} else {
530*4882a593Smuzhiyun 				sii->pub.lhlrev = NOREV;
531*4882a593Smuzhiyun 			}
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 		} else
534*4882a593Smuzhiyun 			sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities);
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 		sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK;
537*4882a593Smuzhiyun 	}
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n",
540*4882a593Smuzhiyun 		CCREV(sii->pub.ccrev), sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev,
541*4882a593Smuzhiyun 		sii->pub.pmucaps));
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	/* figure out bus/orignal core idx */
544*4882a593Smuzhiyun 	/* note for PCI_BUS the buscoretype variable is setup in ai_scan() */
545*4882a593Smuzhiyun 	if (BUSTYPE(sii->pub.bustype) != PCI_BUS) {
546*4882a593Smuzhiyun 		sii->pub.buscoretype = NODEV_CORE_ID;
547*4882a593Smuzhiyun 	}
548*4882a593Smuzhiyun 	sii->pub.buscorerev = NOREV;
549*4882a593Smuzhiyun 	sii->pub.buscoreidx = BADIDX;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	pci = pcie = FALSE;
552*4882a593Smuzhiyun 	pcirev = pcierev = NOREV;
553*4882a593Smuzhiyun 	pciidx = pcieidx = BADIDX;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	/* This loop can be optimized */
556*4882a593Smuzhiyun 	for (i = 0; i < sii->numcores; i++) {
557*4882a593Smuzhiyun 		uint cid, crev;
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 		si_setcoreidx(&sii->pub, i);
560*4882a593Smuzhiyun 		cid = si_coreid(&sii->pub);
561*4882a593Smuzhiyun 		crev = si_corerev(&sii->pub);
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 		/* Display cores found */
564*4882a593Smuzhiyun 		if (CHIPTYPE(sii->pub.socitype) != SOCI_NCI) {
565*4882a593Smuzhiyun 			SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x size:%x regs 0x%p\n",
566*4882a593Smuzhiyun 				i, cid, crev, cores_info->coresba[i], cores_info->coresba_size[i],
567*4882a593Smuzhiyun 				OSL_OBFUSCATE_BUF(cores_info->regs[i])));
568*4882a593Smuzhiyun 		}
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 		if (BUSTYPE(bustype) == SI_BUS) {
571*4882a593Smuzhiyun 			/* now look at the chipstatus register to figure the pacakge */
572*4882a593Smuzhiyun 			/* this shoudl be a general change to cover all teh chips */
573*4882a593Smuzhiyun 			/* this also shoudl validate the build where the dongle is built */
574*4882a593Smuzhiyun 			/* for SDIO but downloaded on PCIE dev */
575*4882a593Smuzhiyun #ifdef BCMPCIEDEV_ENABLED
576*4882a593Smuzhiyun 			if (cid == PCIE2_CORE_ID) {
577*4882a593Smuzhiyun 				pcieidx = i;
578*4882a593Smuzhiyun 				pcierev = crev;
579*4882a593Smuzhiyun 				pcie = TRUE;
580*4882a593Smuzhiyun 				pcie_gen2 = TRUE;
581*4882a593Smuzhiyun 			}
582*4882a593Smuzhiyun #endif
583*4882a593Smuzhiyun 			/* rest fill it up here */
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 		} else if (BUSTYPE(bustype) == PCI_BUS) {
586*4882a593Smuzhiyun 			if (cid == PCI_CORE_ID) {
587*4882a593Smuzhiyun 				pciidx = i;
588*4882a593Smuzhiyun 				pcirev = crev;
589*4882a593Smuzhiyun 				pci = TRUE;
590*4882a593Smuzhiyun 			} else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) {
591*4882a593Smuzhiyun 				pcieidx = i;
592*4882a593Smuzhiyun 				pcierev = crev;
593*4882a593Smuzhiyun 				pcie = TRUE;
594*4882a593Smuzhiyun 				if (cid == PCIE2_CORE_ID)
595*4882a593Smuzhiyun 					pcie_gen2 = TRUE;
596*4882a593Smuzhiyun 			}
597*4882a593Smuzhiyun 		}
598*4882a593Smuzhiyun #ifdef BCMSDIO
599*4882a593Smuzhiyun 		else if (((BUSTYPE(bustype) == SDIO_BUS) ||
600*4882a593Smuzhiyun 		          (BUSTYPE(bustype) == SPI_BUS)) &&
601*4882a593Smuzhiyun 		         (cid == SDIOD_CORE_ID)) {
602*4882a593Smuzhiyun 			sii->pub.buscorerev = (int16)crev;
603*4882a593Smuzhiyun 			sii->pub.buscoretype = (uint16)cid;
604*4882a593Smuzhiyun 			sii->pub.buscoreidx = (uint16)i;
605*4882a593Smuzhiyun 		}
606*4882a593Smuzhiyun #endif /* BCMSDIO */
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 		/* find the core idx before entering this func. */
609*4882a593Smuzhiyun 		if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) {
610*4882a593Smuzhiyun 			if (regs == sii->curmap) {
611*4882a593Smuzhiyun 				*origidx = i;
612*4882a593Smuzhiyun 			}
613*4882a593Smuzhiyun 		} else {
614*4882a593Smuzhiyun 			/* find the core idx before entering this func. */
615*4882a593Smuzhiyun 			if ((savewin && (savewin == cores_info->coresba[i])) ||
616*4882a593Smuzhiyun 			(regs == cores_info->regs[i])) {
617*4882a593Smuzhiyun 				*origidx = i;
618*4882a593Smuzhiyun 			}
619*4882a593Smuzhiyun 		}
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
623*4882a593Smuzhiyun 	if (pci && pcie) {
624*4882a593Smuzhiyun 		if (si_ispcie(sii))
625*4882a593Smuzhiyun 			pci = FALSE;
626*4882a593Smuzhiyun 		else
627*4882a593Smuzhiyun 			pcie = FALSE;
628*4882a593Smuzhiyun 	}
629*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun #if defined(PCIE_FULL_DONGLE)
632*4882a593Smuzhiyun 	if (pcie) {
633*4882a593Smuzhiyun 		if (pcie_gen2)
634*4882a593Smuzhiyun 			sii->pub.buscoretype = PCIE2_CORE_ID;
635*4882a593Smuzhiyun 		else
636*4882a593Smuzhiyun 			sii->pub.buscoretype = PCIE_CORE_ID;
637*4882a593Smuzhiyun 		sii->pub.buscorerev = (int16)pcierev;
638*4882a593Smuzhiyun 		sii->pub.buscoreidx = (uint16)pcieidx;
639*4882a593Smuzhiyun 	}
640*4882a593Smuzhiyun 	BCM_REFERENCE(pci);
641*4882a593Smuzhiyun 	BCM_REFERENCE(pcirev);
642*4882a593Smuzhiyun 	BCM_REFERENCE(pciidx);
643*4882a593Smuzhiyun #else
644*4882a593Smuzhiyun 	if (pci) {
645*4882a593Smuzhiyun 		sii->pub.buscoretype = PCI_CORE_ID;
646*4882a593Smuzhiyun 		sii->pub.buscorerev = (int16)pcirev;
647*4882a593Smuzhiyun 		sii->pub.buscoreidx = (uint16)pciidx;
648*4882a593Smuzhiyun 	} else if (pcie) {
649*4882a593Smuzhiyun 		if (pcie_gen2)
650*4882a593Smuzhiyun 			sii->pub.buscoretype = PCIE2_CORE_ID;
651*4882a593Smuzhiyun 		else
652*4882a593Smuzhiyun 			sii->pub.buscoretype = PCIE_CORE_ID;
653*4882a593Smuzhiyun 		sii->pub.buscorerev = (int16)pcierev;
654*4882a593Smuzhiyun 		sii->pub.buscoreidx = (uint16)pcieidx;
655*4882a593Smuzhiyun 	}
656*4882a593Smuzhiyun #endif /* defined(PCIE_FULL_DONGLE) */
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype,
659*4882a593Smuzhiyun 	         sii->pub.buscorerev));
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
662*4882a593Smuzhiyun 	/* fixup necessary chip/core configurations */
663*4882a593Smuzhiyun 	if (!FWSIGN_ENAB() && BUSTYPE(sii->pub.bustype) == PCI_BUS) {
664*4882a593Smuzhiyun 		if (SI_FAST(sii)) {
665*4882a593Smuzhiyun 			if (!sii->pch &&
666*4882a593Smuzhiyun 			    ((sii->pch = (void *)(uintptr)pcicore_init(&sii->pub, sii->osh,
667*4882a593Smuzhiyun 				(volatile void *)PCIEREGS(sii))) == NULL))
668*4882a593Smuzhiyun 				return FALSE;
669*4882a593Smuzhiyun 		}
670*4882a593Smuzhiyun 		if (si_pci_fixcfg(&sii->pub)) {
671*4882a593Smuzhiyun 			SI_ERROR(("si_buscore_setup: si_pci_fixcfg failed\n"));
672*4882a593Smuzhiyun 			return FALSE;
673*4882a593Smuzhiyun 		}
674*4882a593Smuzhiyun 	}
675*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun #if defined(BCMSDIO) && defined(BCMDONGLEHOST)
678*4882a593Smuzhiyun 	/* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was
679*4882a593Smuzhiyun 	 * already running.
680*4882a593Smuzhiyun 	 */
681*4882a593Smuzhiyun 	if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) {
682*4882a593Smuzhiyun 		if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) ||
683*4882a593Smuzhiyun 		    si_setcore(&sii->pub, ARMCM3_CORE_ID, 0))
684*4882a593Smuzhiyun 			si_core_disable(&sii->pub, 0);
685*4882a593Smuzhiyun 	}
686*4882a593Smuzhiyun #endif /* BCMSDIO && BCMDONGLEHOST */
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	/* return to the original core */
689*4882a593Smuzhiyun 	si_setcoreidx(&sii->pub, *origidx);
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	return TRUE;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST) /* if not a DHD build */
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_boardvendor)[] = "boardvendor";
697*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_boardtype)[] = "boardtype";
698*4882a593Smuzhiyun #if defined(BCMPCIEDEV_SROM_FORMAT)
699*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_subvid)[] = "subvid";
700*4882a593Smuzhiyun #endif /* defined(BCMPCIEDEV_SROM_FORMAT) */
701*4882a593Smuzhiyun #ifdef BCMSDIO
702*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_manfid)[] = "manfid";
703*4882a593Smuzhiyun #endif
704*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_prodid)[] = "prodid";
705*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_boardrev)[] = "boardrev";
706*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_boardflags)[] = "boardflags";
707*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_boardflags4)[] = "boardflags4";
708*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_xtalfreq)[] = "xtalfreq";
709*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_muxenab)[] = "muxenab";
710*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_gpiopulldown)[] = "gpdn";
711*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_devid)[] = "devid";
712*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_wl0id)[] = "wl0id";
713*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_devpathD)[] = "devpath%d";
714*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_D_S)[] = "%d:%s";
715*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_swdenab)[] = "swdenable";
716*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_spurconfig)[] = "spurconfig";
717*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_lpflags)[] = "lpflags";
718*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_armclk)[] = "armclk";
719*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_rfldo3p3_cap_war)[] = "rfldo3p3_cap_war";
720*4882a593Smuzhiyun #if defined(SECI_UART)
721*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_fuart_pup_rx_cts)[] = "fuart_pup_rx_cts";
722*4882a593Smuzhiyun #endif /* defined(SECI_UART) */
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun static uint32
BCMATTACHFN(si_fixup_vid_overrides)725*4882a593Smuzhiyun BCMATTACHFN(si_fixup_vid_overrides)(si_info_t *sii, char *pvars, uint32 conf_vid)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun 	BCM_REFERENCE(pvars);
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	if ((sii->pub.boardvendor != VENDOR_APPLE)) {
730*4882a593Smuzhiyun 		return conf_vid;
731*4882a593Smuzhiyun 	}
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	switch (sii->pub.boardtype)
734*4882a593Smuzhiyun 	{
735*4882a593Smuzhiyun 		/* Check for the SROM value */
736*4882a593Smuzhiyun 		case BCM94360X51P2:
737*4882a593Smuzhiyun 		case BCM94360X29C:
738*4882a593Smuzhiyun 		case BCM94360X29CP2:
739*4882a593Smuzhiyun 		case BCM94360X51:
740*4882a593Smuzhiyun 		case BCM943602X87:
741*4882a593Smuzhiyun 		case BCM943602X238D:
742*4882a593Smuzhiyun 			/* Take the PCIe configuration space subsystem ID */
743*4882a593Smuzhiyun 			sii->pub.boardtype = (conf_vid >> 16) & 0xffff;
744*4882a593Smuzhiyun 			break;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 		default:
747*4882a593Smuzhiyun 			/* Do nothing */
748*4882a593Smuzhiyun 			break;
749*4882a593Smuzhiyun 	}
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	return conf_vid;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun static void
BCMATTACHFN(si_nvram_process)755*4882a593Smuzhiyun BCMATTACHFN(si_nvram_process)(si_info_t *sii, char *pvars)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun 	uint w = 0;
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
760*4882a593Smuzhiyun 		return;
761*4882a593Smuzhiyun 	}
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	/* get boardtype and boardrev */
764*4882a593Smuzhiyun 	switch (BUSTYPE(sii->pub.bustype)) {
765*4882a593Smuzhiyun 	case PCI_BUS:
766*4882a593Smuzhiyun 		/* do a pci config read to get subsystem id and subvendor id */
767*4882a593Smuzhiyun 		w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_SVID, sizeof(uint32));
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 		/* Let nvram variables override subsystem Vend/ID */
770*4882a593Smuzhiyun 		if ((sii->pub.boardvendor = (uint16)si_getdevpathintvar(&sii->pub,
771*4882a593Smuzhiyun 			rstr_boardvendor)) == 0) {
772*4882a593Smuzhiyun #ifdef BCMHOSTVARS
773*4882a593Smuzhiyun 			if ((w & 0xffff) == 0)
774*4882a593Smuzhiyun 				sii->pub.boardvendor = VENDOR_BROADCOM;
775*4882a593Smuzhiyun 			else
776*4882a593Smuzhiyun #endif /* BCMHOSTVARS */
777*4882a593Smuzhiyun 				sii->pub.boardvendor = w & 0xffff;
778*4882a593Smuzhiyun 		} else {
779*4882a593Smuzhiyun 			SI_ERROR(("Overriding boardvendor: 0x%x instead of 0x%x\n",
780*4882a593Smuzhiyun 				sii->pub.boardvendor, w & 0xffff));
781*4882a593Smuzhiyun 		}
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 		if ((sii->pub.boardtype = (uint16)si_getdevpathintvar(&sii->pub, rstr_boardtype))
784*4882a593Smuzhiyun 			== 0) {
785*4882a593Smuzhiyun 			if ((sii->pub.boardtype = getintvar(pvars, rstr_boardtype)) == 0)
786*4882a593Smuzhiyun 				sii->pub.boardtype = (w >> 16) & 0xffff;
787*4882a593Smuzhiyun 		} else {
788*4882a593Smuzhiyun 			SI_ERROR(("Overriding boardtype: 0x%x instead of 0x%x\n",
789*4882a593Smuzhiyun 				sii->pub.boardtype, (w >> 16) & 0xffff));
790*4882a593Smuzhiyun 		}
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 		/* Override high priority fixups */
793*4882a593Smuzhiyun 		if (!FWSIGN_ENAB()) {
794*4882a593Smuzhiyun 			si_fixup_vid_overrides(sii, pvars, w);
795*4882a593Smuzhiyun 		}
796*4882a593Smuzhiyun 		break;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun #ifdef BCMSDIO
799*4882a593Smuzhiyun 	case SDIO_BUS:
800*4882a593Smuzhiyun 		sii->pub.boardvendor = getintvar(pvars, rstr_manfid);
801*4882a593Smuzhiyun 		sii->pub.boardtype = getintvar(pvars, rstr_prodid);
802*4882a593Smuzhiyun 		break;
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	case SPI_BUS:
805*4882a593Smuzhiyun 		sii->pub.boardvendor = VENDOR_BROADCOM;
806*4882a593Smuzhiyun 		sii->pub.boardtype = QT4710_BOARD;
807*4882a593Smuzhiyun 		break;
808*4882a593Smuzhiyun #endif
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	case SI_BUS:
811*4882a593Smuzhiyun #ifdef BCMPCIEDEV_SROM_FORMAT
812*4882a593Smuzhiyun 		if (BCMPCIEDEV_ENAB() && si_is_sprom_available(&sii->pub) && pvars &&
813*4882a593Smuzhiyun 			getvar(pvars, rstr_subvid)) {
814*4882a593Smuzhiyun 			sii->pub.boardvendor = getintvar(pvars, rstr_subvid);
815*4882a593Smuzhiyun 		} else
816*4882a593Smuzhiyun #endif
817*4882a593Smuzhiyun 		sii->pub.boardvendor = VENDOR_BROADCOM;
818*4882a593Smuzhiyun 		if (pvars == NULL || ((sii->pub.boardtype = getintvar(pvars, rstr_prodid)) == 0))
819*4882a593Smuzhiyun 			if ((sii->pub.boardtype = getintvar(pvars, rstr_boardtype)) == 0)
820*4882a593Smuzhiyun 				sii->pub.boardtype = 0xffff;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 		if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) {
823*4882a593Smuzhiyun 			/* do a pci config read to get subsystem id and subvendor id */
824*4882a593Smuzhiyun 			w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_SVID, sizeof(uint32));
825*4882a593Smuzhiyun 			sii->pub.boardvendor = w & 0xffff;
826*4882a593Smuzhiyun 			sii->pub.boardtype = (w >> 16) & 0xffff;
827*4882a593Smuzhiyun 		}
828*4882a593Smuzhiyun 		break;
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	default:
831*4882a593Smuzhiyun 		break;
832*4882a593Smuzhiyun 	}
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	if (sii->pub.boardtype == 0) {
835*4882a593Smuzhiyun 		SI_ERROR(("si_doattach: unknown board type\n"));
836*4882a593Smuzhiyun 		ASSERT(sii->pub.boardtype);
837*4882a593Smuzhiyun 	}
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	sii->pub.lpflags = getintvar(pvars, rstr_lpflags);
840*4882a593Smuzhiyun 	sii->pub.boardrev = getintvar(pvars, rstr_boardrev);
841*4882a593Smuzhiyun 	sii->pub.boardflags = getintvar(pvars, rstr_boardflags);
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun #ifdef BCM_SDRBL
844*4882a593Smuzhiyun 	sii->pub.boardflags2 |= ((!CHIP_HOSTIF_USB(&(sii->pub))) ? ((si_arm_sflags(&(sii->pub))
845*4882a593Smuzhiyun 				 & SISF_SDRENABLE) ?  BFL2_SDR_EN:0):
846*4882a593Smuzhiyun 				 (((uint)getintvar(pvars, "boardflags2")) & BFL2_SDR_EN));
847*4882a593Smuzhiyun #endif /* BCM_SDRBL */
848*4882a593Smuzhiyun 	sii->pub.boardflags4 = getintvar(pvars, rstr_boardflags4);
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun #if defined(CONFIG_XIP) && defined(BCMTCAM)
855*4882a593Smuzhiyun extern uint8 patch_pair;
856*4882a593Smuzhiyun #endif /* CONFIG_XIP && BCMTCAM */
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
859*4882a593Smuzhiyun typedef struct {
860*4882a593Smuzhiyun 	uint8 uart_tx;
861*4882a593Smuzhiyun 	uint32 uart_rx;
862*4882a593Smuzhiyun } si_mux_uartopt_t;
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun /* note: each index corr to MUXENAB43012_HOSTWAKE_MASK > shift - 1 */
865*4882a593Smuzhiyun static const uint8 BCMATTACHDATA(mux43012_hostwakeopt)[] = {
866*4882a593Smuzhiyun 		CC_PIN_GPIO_00
867*4882a593Smuzhiyun };
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun static const si_mux_uartopt_t BCMATTACHDATA(mux_uartopt)[] = {
870*4882a593Smuzhiyun 		{CC_PIN_GPIO_00, CC_PIN_GPIO_01},
871*4882a593Smuzhiyun 		{CC_PIN_GPIO_05, CC_PIN_GPIO_04},
872*4882a593Smuzhiyun 		{CC_PIN_GPIO_15, CC_PIN_GPIO_14},
873*4882a593Smuzhiyun };
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun /* note: each index corr to MUXENAB_DEF_HOSTWAKE mask >> shift - 1 */
876*4882a593Smuzhiyun static const uint8 BCMATTACHDATA(mux_hostwakeopt)[] = {
877*4882a593Smuzhiyun 		CC_PIN_GPIO_00,
878*4882a593Smuzhiyun };
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun #ifdef SECI_UART
881*4882a593Smuzhiyun #define NUM_SECI_UART_GPIOS	4
882*4882a593Smuzhiyun static bool fuart_pullup_rx_cts_enab = FALSE;
883*4882a593Smuzhiyun static bool fast_uart_init = FALSE;
884*4882a593Smuzhiyun static uint32 fast_uart_tx;
885*4882a593Smuzhiyun static uint32 fast_uart_functionsel;
886*4882a593Smuzhiyun static uint32 fast_uart_pup;
887*4882a593Smuzhiyun static uint32 fast_uart_rx;
888*4882a593Smuzhiyun static uint32 fast_uart_cts_in;
889*4882a593Smuzhiyun #endif /* SECI_UART */
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun void
BCMATTACHFN(si_swdenable)892*4882a593Smuzhiyun BCMATTACHFN(si_swdenable)(si_t *sih, uint32 swdflag)
893*4882a593Smuzhiyun {
894*4882a593Smuzhiyun 	/* FIXME Need a more generic test for SWD instead of check on specific chipid */
895*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
896*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
897*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
898*4882a593Smuzhiyun 		if (swdflag) {
899*4882a593Smuzhiyun 			/* Enable ARM debug clk, which is required for the ARM debug
900*4882a593Smuzhiyun 			 * unit to operate
901*4882a593Smuzhiyun 			 */
902*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL5, (1 << ARMCR4_DBG_CLK_BIT),
903*4882a593Smuzhiyun 				(1 << ARMCR4_DBG_CLK_BIT));
904*4882a593Smuzhiyun 			/* Force HT clock in Chipcommon. The HT clock is required for backplane
905*4882a593Smuzhiyun 			 * access via SWD
906*4882a593Smuzhiyun 			 */
907*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), CCS_FORCEHT,
908*4882a593Smuzhiyun 				CCS_FORCEHT);
909*4882a593Smuzhiyun 			/* Set TAP_SEL so that ARM is the first and the only TAP on the TAP chain.
910*4882a593Smuzhiyun 			 * Must do a chip reset to clear this bit
911*4882a593Smuzhiyun 			 */
912*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, jtagctrl),
913*4882a593Smuzhiyun 				JCTRL_TAPSEL_BIT, JCTRL_TAPSEL_BIT);
914*4882a593Smuzhiyun 			SI_MSG(("si_swdenable: set arm_dbgclk, ForceHTClock and tap_sel bit\n"));
915*4882a593Smuzhiyun 		}
916*4882a593Smuzhiyun 		break;
917*4882a593Smuzhiyun 	default:
918*4882a593Smuzhiyun 		/* swdenable specified for an unsupported chip */
919*4882a593Smuzhiyun 		ASSERT(0);
920*4882a593Smuzhiyun 		break;
921*4882a593Smuzhiyun 	}
922*4882a593Smuzhiyun }
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun /** want to have this available all the time to switch mux for debugging */
925*4882a593Smuzhiyun void
BCMATTACHFN(si_muxenab)926*4882a593Smuzhiyun BCMATTACHFN(si_muxenab)(si_t *sih, uint32 w)
927*4882a593Smuzhiyun {
928*4882a593Smuzhiyun 	uint32 chipcontrol, pmu_chipcontrol;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	pmu_chipcontrol = si_pmu_chipcontrol(sih, 1, 0, 0);
931*4882a593Smuzhiyun 	chipcontrol = si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol),
932*4882a593Smuzhiyun 	                         0, 0);
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
935*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
936*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
937*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
938*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
939*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
940*4882a593Smuzhiyun 		if (w & MUXENAB_UART)
941*4882a593Smuzhiyun 			chipcontrol |= CCTRL4360_UART_MODE;
942*4882a593Smuzhiyun 		break;
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
945*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
946*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
947*4882a593Smuzhiyun 		/*
948*4882a593Smuzhiyun 		 * 0x10 : use GPIO0 as host wake up pin
949*4882a593Smuzhiyun 		 * 0x20 ~ 0xf0: Reserved
950*4882a593Smuzhiyun 		 */
951*4882a593Smuzhiyun 		if (w & MUXENAB43012_HOSTWAKE_MASK) {
952*4882a593Smuzhiyun 			uint8 hostwake = 0;
953*4882a593Smuzhiyun 			uint8 hostwake_ix = MUXENAB43012_GETIX(w, HOSTWAKE);
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 			if (hostwake_ix >
956*4882a593Smuzhiyun 				sizeof(mux43012_hostwakeopt)/sizeof(mux43012_hostwakeopt[0]) - 1) {
957*4882a593Smuzhiyun 				SI_ERROR(("si_muxenab: wrong index %d for hostwake\n",
958*4882a593Smuzhiyun 					hostwake_ix));
959*4882a593Smuzhiyun 				break;
960*4882a593Smuzhiyun 			}
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 			hostwake = mux43012_hostwakeopt[hostwake_ix];
963*4882a593Smuzhiyun 			si_gci_set_functionsel(sih, hostwake, CC_FNSEL_MISC1);
964*4882a593Smuzhiyun 		}
965*4882a593Smuzhiyun 		break;
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun case BCM4385_CHIP_GRPID:
968*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
969*4882a593Smuzhiyun 		if (w & MUXENAB_DEF_UART_MASK) {
970*4882a593Smuzhiyun 			uint32 uart_rx = 0, uart_tx = 0;
971*4882a593Smuzhiyun 			uint8 uartopt_idx = (w & MUXENAB_DEF_UART_MASK) - 1;
972*4882a593Smuzhiyun 			uint8 uartopt_size = sizeof(mux_uartopt)/sizeof(mux_uartopt[0]);
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 			if (uartopt_idx < uartopt_size) {
975*4882a593Smuzhiyun 				uart_rx = mux_uartopt[uartopt_idx].uart_rx;
976*4882a593Smuzhiyun 				uart_tx = mux_uartopt[uartopt_idx].uart_tx;
977*4882a593Smuzhiyun #ifdef BOOTLOADER_CONSOLE_OUTPUT
978*4882a593Smuzhiyun 				uart_rx = 0;
979*4882a593Smuzhiyun 				uart_tx = 1;
980*4882a593Smuzhiyun #endif
981*4882a593Smuzhiyun 				if (CHIPREV(sih->chiprev) >= 3) {
982*4882a593Smuzhiyun 					si_gci_set_functionsel(sih, uart_rx, CC_FNSEL_GPIO1);
983*4882a593Smuzhiyun 					si_gci_set_functionsel(sih, uart_tx, CC_FNSEL_GPIO1);
984*4882a593Smuzhiyun 				} else {
985*4882a593Smuzhiyun 					si_gci_set_functionsel(sih, uart_rx, CC_FNSEL_GPIO0);
986*4882a593Smuzhiyun 					si_gci_set_functionsel(sih, uart_tx, CC_FNSEL_GPIO0);
987*4882a593Smuzhiyun 				}
988*4882a593Smuzhiyun 			} else {
989*4882a593Smuzhiyun 				SI_MSG(("si_muxenab: Invalid uart OTP setting\n"));
990*4882a593Smuzhiyun 			}
991*4882a593Smuzhiyun 		}
992*4882a593Smuzhiyun 		if (w & MUXENAB_DEF_HOSTWAKE_MASK) {
993*4882a593Smuzhiyun 			uint8 hostwake = 0;
994*4882a593Smuzhiyun 			/*
995*4882a593Smuzhiyun 			* SDIO
996*4882a593Smuzhiyun 			* 0x10 : use GPIO0 as host wake up pin
997*4882a593Smuzhiyun 			*/
998*4882a593Smuzhiyun 			uint8 hostwake_ix = MUXENAB_DEF_GETIX(w, HOSTWAKE);
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun 			if (hostwake_ix > (sizeof(mux_hostwakeopt) /
1001*4882a593Smuzhiyun 				sizeof(mux_hostwakeopt[0]) - 1)) {
1002*4882a593Smuzhiyun 				SI_ERROR(("si_muxenab: wrong index %d for hostwake\n",
1003*4882a593Smuzhiyun 					hostwake_ix));
1004*4882a593Smuzhiyun 				break;
1005*4882a593Smuzhiyun 			}
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 			hostwake = mux_hostwakeopt[hostwake_ix];
1008*4882a593Smuzhiyun 			si_gci_set_functionsel(sih, hostwake, CC_FNSEL_GPIO0);
1009*4882a593Smuzhiyun 		}
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 		break;
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
1014*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
1015*4882a593Smuzhiyun 		/* TBD fill */
1016*4882a593Smuzhiyun 		if (w & MUXENAB_HOST_WAKE) {
1017*4882a593Smuzhiyun 			si_gci_set_functionsel(sih, CC_PIN_GPIO_00, CC_FNSEL_MISC1);
1018*4882a593Smuzhiyun 		}
1019*4882a593Smuzhiyun 		break;
1020*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
1021*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
1022*4882a593Smuzhiyun 		/* TBD fill */
1023*4882a593Smuzhiyun 		break;
1024*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
1025*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
1026*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
1027*4882a593Smuzhiyun 		/* TBD fill */
1028*4882a593Smuzhiyun 		break;
1029*4882a593Smuzhiyun 	default:
1030*4882a593Smuzhiyun 		/* muxenab specified for an unsupported chip */
1031*4882a593Smuzhiyun 		ASSERT(0);
1032*4882a593Smuzhiyun 		break;
1033*4882a593Smuzhiyun 	}
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun 	/* write both updated values to hw */
1036*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, 1, ~0, pmu_chipcontrol);
1037*4882a593Smuzhiyun 	si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol),
1038*4882a593Smuzhiyun 	           ~0, chipcontrol);
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun /** ltecx GCI reg access */
1042*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_gci_direct)1043*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_direct)(si_t *sih, uint offset, uint32 mask, uint32 val)
1044*4882a593Smuzhiyun {
1045*4882a593Smuzhiyun 	/* gci direct reg access */
1046*4882a593Smuzhiyun 	return si_corereg(sih, GCI_CORE_IDX(sih), offset, mask, val);
1047*4882a593Smuzhiyun }
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun uint32
si_gci_indirect(si_t * sih,uint regidx,uint offset,uint32 mask,uint32 val)1050*4882a593Smuzhiyun si_gci_indirect(si_t *sih, uint regidx, uint offset, uint32 mask, uint32 val)
1051*4882a593Smuzhiyun {
1052*4882a593Smuzhiyun 	/* gci indirect reg access */
1053*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_indirect_addr), ~0, regidx);
1054*4882a593Smuzhiyun 	return si_corereg(sih, GCI_CORE_IDX(sih), offset, mask, val);
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun uint32
si_gci_input(si_t * sih,uint reg)1058*4882a593Smuzhiyun si_gci_input(si_t *sih, uint reg)
1059*4882a593Smuzhiyun {
1060*4882a593Smuzhiyun 	/* gci_input[] */
1061*4882a593Smuzhiyun 	return si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_input[reg]), 0, 0);
1062*4882a593Smuzhiyun }
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun uint32
si_gci_output(si_t * sih,uint reg,uint32 mask,uint32 val)1065*4882a593Smuzhiyun si_gci_output(si_t *sih, uint reg, uint32 mask, uint32 val)
1066*4882a593Smuzhiyun {
1067*4882a593Smuzhiyun 	/* gci_output[] */
1068*4882a593Smuzhiyun 	return si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_output[reg]), mask, val);
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun uint32
si_gci_int_enable(si_t * sih,bool enable)1072*4882a593Smuzhiyun si_gci_int_enable(si_t *sih, bool enable)
1073*4882a593Smuzhiyun {
1074*4882a593Smuzhiyun 	uint offs;
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	/* enable GCI interrupt */
1077*4882a593Smuzhiyun 	offs = OFFSETOF(chipcregs_t, intmask);
1078*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, offs, CI_ECI, (enable ? CI_ECI : 0)));
1079*4882a593Smuzhiyun }
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun void
si_gci_reset(si_t * sih)1082*4882a593Smuzhiyun si_gci_reset(si_t *sih)
1083*4882a593Smuzhiyun {
1084*4882a593Smuzhiyun 	int i;
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	if (gci_reset_done == FALSE) {
1087*4882a593Smuzhiyun 		gci_reset_done = TRUE;
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 		/* Set ForceRegClk and ForceSeciClk */
1090*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl),
1091*4882a593Smuzhiyun 			((1 << GCI_CCTL_FREGCLK_OFFSET)
1092*4882a593Smuzhiyun 			|(1 << GCI_CCTL_FSECICLK_OFFSET)),
1093*4882a593Smuzhiyun 			((1 << GCI_CCTL_FREGCLK_OFFSET)
1094*4882a593Smuzhiyun 			|(1 << GCI_CCTL_FSECICLK_OFFSET)));
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 		/* Some Delay */
1097*4882a593Smuzhiyun 		for (i = 0; i < 2; i++) {
1098*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl), 0, 0);
1099*4882a593Smuzhiyun 		}
1100*4882a593Smuzhiyun 		/* Reset SECI block */
1101*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl),
1102*4882a593Smuzhiyun 			((1 << GCI_CCTL_SECIRST_OFFSET)
1103*4882a593Smuzhiyun 			|(1 << GCI_CCTL_RSTSL_OFFSET)
1104*4882a593Smuzhiyun 			|(1 << GCI_CCTL_RSTOCC_OFFSET)),
1105*4882a593Smuzhiyun 			((1 << GCI_CCTL_SECIRST_OFFSET)
1106*4882a593Smuzhiyun 			|(1 << GCI_CCTL_RSTSL_OFFSET)
1107*4882a593Smuzhiyun 			|(1 << GCI_CCTL_RSTOCC_OFFSET)));
1108*4882a593Smuzhiyun 		/* Some Delay */
1109*4882a593Smuzhiyun 		for (i = 0; i < 10; i++) {
1110*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl), 0, 0);
1111*4882a593Smuzhiyun 		}
1112*4882a593Smuzhiyun 		/* Remove SECI Reset */
1113*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl),
1114*4882a593Smuzhiyun 			((1 << GCI_CCTL_SECIRST_OFFSET)
1115*4882a593Smuzhiyun 			|(1 << GCI_CCTL_RSTSL_OFFSET)
1116*4882a593Smuzhiyun 			|(1 << GCI_CCTL_RSTOCC_OFFSET)),
1117*4882a593Smuzhiyun 			((0 << GCI_CCTL_SECIRST_OFFSET)
1118*4882a593Smuzhiyun 			|(0 << GCI_CCTL_RSTSL_OFFSET)
1119*4882a593Smuzhiyun 			|(0 << GCI_CCTL_RSTOCC_OFFSET)));
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 		/* Some Delay */
1122*4882a593Smuzhiyun 		for (i = 0; i < 2; i++) {
1123*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl), 0, 0);
1124*4882a593Smuzhiyun 		}
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun 		/* Clear ForceRegClk and ForceSeciClk */
1127*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl),
1128*4882a593Smuzhiyun 			((1 << GCI_CCTL_FREGCLK_OFFSET)
1129*4882a593Smuzhiyun 			|(1 << GCI_CCTL_FSECICLK_OFFSET)),
1130*4882a593Smuzhiyun 			((0 << GCI_CCTL_FREGCLK_OFFSET)
1131*4882a593Smuzhiyun 			|(0 << GCI_CCTL_FSECICLK_OFFSET)));
1132*4882a593Smuzhiyun 	}
1133*4882a593Smuzhiyun 	/* clear events */
1134*4882a593Smuzhiyun 	for (i = 0; i < 32; i++) {
1135*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_event[i]), ALLONES_32, 0x00);
1136*4882a593Smuzhiyun 	}
1137*4882a593Smuzhiyun }
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun void
si_gci_gpio_chipcontrol_ex(si_t * sih,uint8 gci_gpio,uint8 opt)1140*4882a593Smuzhiyun si_gci_gpio_chipcontrol_ex(si_t *sih, uint8 gci_gpio, uint8 opt)
1141*4882a593Smuzhiyun {
1142*4882a593Smuzhiyun 	si_gci_gpio_chipcontrol(sih, gci_gpio, opt);
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun 
1145*4882a593Smuzhiyun static void
BCMPOSTTRAPFN(si_gci_gpio_chipcontrol)1146*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_gpio_chipcontrol)(si_t *sih, uint8 gci_gpio, uint8 opt)
1147*4882a593Smuzhiyun {
1148*4882a593Smuzhiyun 	uint32 ring_idx = 0, pos = 0;
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	si_gci_get_chipctrlreg_ringidx_base8(gci_gpio, &ring_idx, &pos);
1151*4882a593Smuzhiyun 	SI_MSG(("si_gci_gpio_chipcontrol:rngidx is %d, pos is %d, opt is %d, mask is 0x%04x,"
1152*4882a593Smuzhiyun 		" value is 0x%04x\n",
1153*4882a593Smuzhiyun 		ring_idx, pos, opt, GCIMASK_8B(pos), GCIPOSVAL_8B(opt, pos)));
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_indirect_addr), ~0, ring_idx);
1156*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_gpioctl),
1157*4882a593Smuzhiyun 		GCIMASK_8B(pos), GCIPOSVAL_8B(opt, pos));
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun static uint8
BCMPOSTTRAPFN(si_gci_gpio_reg)1161*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_gpio_reg)(si_t *sih, uint8 gci_gpio, uint8 mask, uint8 value,
1162*4882a593Smuzhiyun 	uint32 reg_offset)
1163*4882a593Smuzhiyun {
1164*4882a593Smuzhiyun 	uint32 ring_idx = 0, pos = 0; /**< FunctionSel register idx and bits to use */
1165*4882a593Smuzhiyun 	uint32 val_32;
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 	si_gci_get_chipctrlreg_ringidx_base4(gci_gpio, &ring_idx, &pos);
1168*4882a593Smuzhiyun 	SI_MSG(("si_gci_gpio_reg:rngidx is %d, pos is %d, val is %d, mask is 0x%04x,"
1169*4882a593Smuzhiyun 		" value is 0x%04x\n",
1170*4882a593Smuzhiyun 		ring_idx, pos, value, GCIMASK_4B(pos), GCIPOSVAL_4B(value, pos)));
1171*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_indirect_addr), ~0, ring_idx);
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	if (mask || value) {
1174*4882a593Smuzhiyun 		/* set operation */
1175*4882a593Smuzhiyun 		si_corereg(sih, GCI_CORE_IDX(sih),
1176*4882a593Smuzhiyun 			reg_offset, GCIMASK_4B(pos), GCIPOSVAL_4B(value, pos));
1177*4882a593Smuzhiyun 	}
1178*4882a593Smuzhiyun 	val_32 = si_corereg(sih, GCI_CORE_IDX(sih), reg_offset, 0, 0);
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	value  = (uint8)((val_32 >> pos) & 0xFF);
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	return value;
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun /**
1186*4882a593Smuzhiyun  * In order to route a ChipCommon originated GPIO towards a package pin, both CC and GCI cores have
1187*4882a593Smuzhiyun  * to be written to.
1188*4882a593Smuzhiyun  * @param[in] sih
1189*4882a593Smuzhiyun  * @param[in] gpio   chip specific package pin number. See Toplevel Arch page, GCI chipcontrol reg
1190*4882a593Smuzhiyun  *                   section.
1191*4882a593Smuzhiyun  * @param[in] mask   chip common gpio mask
1192*4882a593Smuzhiyun  * @param[in] val    chip common gpio value
1193*4882a593Smuzhiyun  */
1194*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_gci_enable_gpio)1195*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_enable_gpio)(si_t *sih, uint8 gpio, uint32 mask, uint32 value)
1196*4882a593Smuzhiyun {
1197*4882a593Smuzhiyun 	uint32 ring_idx = 0, pos = 0;
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun 	si_gci_get_chipctrlreg_ringidx_base4(gpio, &ring_idx, &pos);
1200*4882a593Smuzhiyun 	SI_MSG(("si_gci_enable_gpio:rngidx is %d, pos is %d, val is %d, mask is 0x%04x,"
1201*4882a593Smuzhiyun 		" value is 0x%04x\n",
1202*4882a593Smuzhiyun 		ring_idx, pos, value, GCIMASK_4B(pos), GCIPOSVAL_4B(value, pos)));
1203*4882a593Smuzhiyun 	si_gci_set_functionsel(sih, gpio, CC_FNSEL_SAMEASPIN);
1204*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_indirect_addr), ~0, ring_idx);
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	si_gpiocontrol(sih, mask, 0, GPIO_HI_PRIORITY);
1207*4882a593Smuzhiyun 	si_gpioouten(sih, mask, mask, GPIO_HI_PRIORITY);
1208*4882a593Smuzhiyun 	si_gpioout(sih, mask, value, GPIO_HI_PRIORITY);
1209*4882a593Smuzhiyun }
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun /*
1212*4882a593Smuzhiyun  * The above seems to be for gpio output only (forces gpioouten).
1213*4882a593Smuzhiyun  * This function is to configure GPIO as input, and accepts a mask of bits.
1214*4882a593Smuzhiyun  * Also: doesn't force the gpiocontrol (chipc) functionality, assumes it
1215*4882a593Smuzhiyun  * is the default, and rejects the request (BUSY => gpio in use) if it's
1216*4882a593Smuzhiyun  * already configured for a different function... but it will override the
1217*4882a593Smuzhiyun  * output enable.
1218*4882a593Smuzhiyun  */
1219*4882a593Smuzhiyun int
si_gpio_enable(si_t * sih,uint32 mask)1220*4882a593Smuzhiyun si_gpio_enable(si_t *sih, uint32 mask)
1221*4882a593Smuzhiyun {
1222*4882a593Smuzhiyun 	uint bit;
1223*4882a593Smuzhiyun 	int fnsel = -1; /* Valid fnsel is a small positive number */
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun 	BCM_REFERENCE(bit);
1226*4882a593Smuzhiyun 	BCM_REFERENCE(fnsel);
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	/* Bail if any bit is explicitly set for some other function */
1229*4882a593Smuzhiyun 	if (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiocontrol), 0, 0) & mask) {
1230*4882a593Smuzhiyun 		return BCME_BUSY;
1231*4882a593Smuzhiyun 	}
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
1234*4882a593Smuzhiyun 	/* Some chips need to be explicitly set */
1235*4882a593Smuzhiyun 	switch (CHIPID(sih->chip))
1236*4882a593Smuzhiyun 	{
1237*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
1238*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
1239*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
1240*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
1241*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
1242*4882a593Smuzhiyun 		fnsel = CC_FNSEL_SAMEASPIN;
1243*4882a593Smuzhiyun 	default:
1244*4882a593Smuzhiyun 		;
1245*4882a593Smuzhiyun 	}
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun 	if (fnsel != -1) {
1248*4882a593Smuzhiyun 		for (bit = 0; mask; bit++) {
1249*4882a593Smuzhiyun 			if (mask & (1 << bit)) {
1250*4882a593Smuzhiyun 				si_gci_set_functionsel(sih, bit, (uint8)fnsel);
1251*4882a593Smuzhiyun 				mask ^= (1 << bit);
1252*4882a593Smuzhiyun 			}
1253*4882a593Smuzhiyun 		}
1254*4882a593Smuzhiyun 	}
1255*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
1256*4882a593Smuzhiyun 	si_gpioouten(sih, mask, 0, GPIO_HI_PRIORITY);
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun 	return BCME_OK;
1259*4882a593Smuzhiyun }
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_host_wake_opt)[] = "host_wake_opt";
1262*4882a593Smuzhiyun uint8
BCMATTACHFN(si_gci_host_wake_gpio_init)1263*4882a593Smuzhiyun BCMATTACHFN(si_gci_host_wake_gpio_init)(si_t *sih)
1264*4882a593Smuzhiyun {
1265*4882a593Smuzhiyun 	uint8  host_wake_gpio = CC_GCI_GPIO_INVALID;
1266*4882a593Smuzhiyun 	uint32 host_wake_opt;
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	/* parse the device wake opt from nvram */
1269*4882a593Smuzhiyun 	/* decode what that means for specific chip */
1270*4882a593Smuzhiyun 	if (getvar(NULL, rstr_host_wake_opt) == NULL)
1271*4882a593Smuzhiyun 		return host_wake_gpio;
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 	host_wake_opt = getintvar(NULL, rstr_host_wake_opt);
1274*4882a593Smuzhiyun 	host_wake_gpio = host_wake_opt & 0xff;
1275*4882a593Smuzhiyun 	si_gci_host_wake_gpio_enable(sih, host_wake_gpio, FALSE);
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	return host_wake_gpio;
1278*4882a593Smuzhiyun }
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_gci_host_wake_gpio_enable)1281*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_host_wake_gpio_enable)(si_t *sih, uint8 gpio, bool state)
1282*4882a593Smuzhiyun {
1283*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
1284*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
1285*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
1286*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
1287*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
1288*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
1289*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
1290*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
1291*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
1292*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
1293*4882a593Smuzhiyun 		si_gci_enable_gpio(sih, gpio, 1 << gpio,
1294*4882a593Smuzhiyun 			state ? 1 << gpio : 0x00);
1295*4882a593Smuzhiyun 		break;
1296*4882a593Smuzhiyun 	default:
1297*4882a593Smuzhiyun 		SI_ERROR(("host wake not supported for 0x%04x yet\n", CHIPID(sih->chip)));
1298*4882a593Smuzhiyun 		break;
1299*4882a593Smuzhiyun 	}
1300*4882a593Smuzhiyun }
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun void
si_gci_time_sync_gpio_enable(si_t * sih,uint8 gpio,bool state)1303*4882a593Smuzhiyun si_gci_time_sync_gpio_enable(si_t *sih, uint8 gpio, bool state)
1304*4882a593Smuzhiyun {
1305*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
1306*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
1307*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
1308*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
1309*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
1310*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
1311*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
1312*4882a593Smuzhiyun 		si_gci_enable_gpio(sih, gpio, 1 << gpio,
1313*4882a593Smuzhiyun 			state ? 1 << gpio : 0x00);
1314*4882a593Smuzhiyun 		break;
1315*4882a593Smuzhiyun 	default:
1316*4882a593Smuzhiyun 		SI_ERROR(("Time sync not supported for 0x%04x yet\n", CHIPID(sih->chip)));
1317*4882a593Smuzhiyun 		break;
1318*4882a593Smuzhiyun 	}
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun #define	TIMESYNC_GPIO_NUM	12 /* Hardcoded for now. Will be removed later */
1322*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_time_sync_opt)[] = "time_sync_opt";
1323*4882a593Smuzhiyun uint8
BCMATTACHFN(si_gci_time_sync_gpio_init)1324*4882a593Smuzhiyun BCMATTACHFN(si_gci_time_sync_gpio_init)(si_t *sih)
1325*4882a593Smuzhiyun {
1326*4882a593Smuzhiyun 	uint8  time_sync_gpio = TIMESYNC_GPIO_NUM;
1327*4882a593Smuzhiyun 	uint32 time_sync_opt;
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun 	/* parse the device wake opt from nvram */
1330*4882a593Smuzhiyun 	/* decode what that means for specific chip */
1331*4882a593Smuzhiyun 	if (getvar(NULL, rstr_time_sync_opt) == NULL) {
1332*4882a593Smuzhiyun 		time_sync_opt = TIMESYNC_GPIO_NUM;
1333*4882a593Smuzhiyun 	} else {
1334*4882a593Smuzhiyun 		time_sync_opt = getintvar(NULL, rstr_time_sync_opt);
1335*4882a593Smuzhiyun 	}
1336*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
1337*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
1338*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
1339*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
1340*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
1341*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
1342*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
1343*4882a593Smuzhiyun 		time_sync_gpio = time_sync_opt & 0xff;
1344*4882a593Smuzhiyun 		si_gci_enable_gpio(sih, time_sync_gpio,
1345*4882a593Smuzhiyun 			1 << time_sync_gpio, 0x00);
1346*4882a593Smuzhiyun 		break;
1347*4882a593Smuzhiyun 	default:
1348*4882a593Smuzhiyun 		SI_ERROR(("time sync not supported for 0x%04x yet\n", CHIPID(sih->chip)));
1349*4882a593Smuzhiyun 		break;
1350*4882a593Smuzhiyun 	}
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 	return time_sync_gpio;
1353*4882a593Smuzhiyun }
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun uint8
BCMPOSTTRAPFN(si_gci_gpio_wakemask)1356*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_gpio_wakemask)(si_t *sih, uint8 gpio, uint8 mask, uint8 value)
1357*4882a593Smuzhiyun {
1358*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_wakemask),
1359*4882a593Smuzhiyun 		GCI_WAKEMASK_GPIOWAKE, GCI_WAKEMASK_GPIOWAKE);
1360*4882a593Smuzhiyun 	return (si_gci_gpio_reg(sih, gpio, mask, value, GCI_OFFSETOF(sih, gci_gpiowakemask)));
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun uint8
BCMPOSTTRAPFN(si_gci_gpio_intmask)1364*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_gpio_intmask)(si_t *sih, uint8 gpio, uint8 mask, uint8 value)
1365*4882a593Smuzhiyun {
1366*4882a593Smuzhiyun 	return (si_gci_gpio_reg(sih, gpio, mask, value, GCI_OFFSETOF(sih, gci_gpiointmask)));
1367*4882a593Smuzhiyun }
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun uint8
BCMPOSTTRAPFN(si_gci_gpio_status)1370*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_gpio_status)(si_t *sih, uint8 gpio, uint8 mask, uint8 value)
1371*4882a593Smuzhiyun {
1372*4882a593Smuzhiyun 	return (si_gci_gpio_reg(sih, gpio, mask, value, GCI_OFFSETOF(sih, gci_gpiostatus)));
1373*4882a593Smuzhiyun }
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun static void
si_gci_enable_gpioint(si_t * sih,bool enable)1376*4882a593Smuzhiyun si_gci_enable_gpioint(si_t *sih, bool enable)
1377*4882a593Smuzhiyun {
1378*4882a593Smuzhiyun 	if (enable)
1379*4882a593Smuzhiyun 		si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_intmask),
1380*4882a593Smuzhiyun 			GCI_INTSTATUS_GPIOINT, GCI_INTSTATUS_GPIOINT);
1381*4882a593Smuzhiyun 	else
1382*4882a593Smuzhiyun 		si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_intmask),
1383*4882a593Smuzhiyun 			GCI_INTSTATUS_GPIOINT, 0);
1384*4882a593Smuzhiyun }
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun /* assumes function select is performed separately */
1387*4882a593Smuzhiyun void
BCMINITFN(si_enable_gpio_wake)1388*4882a593Smuzhiyun BCMINITFN(si_enable_gpio_wake)(si_t *sih, uint8 *wake_mask, uint8 *cur_status, uint8 gci_gpio,
1389*4882a593Smuzhiyun 	uint32 pmu_cc2_mask, uint32 pmu_cc2_value)
1390*4882a593Smuzhiyun {
1391*4882a593Smuzhiyun 	si_gci_gpio_chipcontrol(sih, gci_gpio,
1392*4882a593Smuzhiyun 	                        (1 << GCI_GPIO_CHIPCTRL_ENAB_IN_BIT));
1393*4882a593Smuzhiyun 
1394*4882a593Smuzhiyun 	si_gci_gpio_intmask(sih, gci_gpio, *wake_mask, *wake_mask);
1395*4882a593Smuzhiyun 	si_gci_gpio_wakemask(sih, gci_gpio, *wake_mask, *wake_mask);
1396*4882a593Smuzhiyun 
1397*4882a593Smuzhiyun 	/* clear the existing status bits */
1398*4882a593Smuzhiyun 	*cur_status = si_gci_gpio_status(sih, gci_gpio,
1399*4882a593Smuzhiyun 	                                 GCI_GPIO_STS_CLEAR, GCI_GPIO_STS_CLEAR);
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 	/* top level gci int enable */
1402*4882a593Smuzhiyun 	si_gci_enable_gpioint(sih, TRUE);
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	/* enable the pmu chip control bit to enable wake */
1405*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL2, pmu_cc2_mask, pmu_cc2_value);
1406*4882a593Smuzhiyun }
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_gci_config_wake_pin)1409*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_config_wake_pin)(si_t *sih, uint8 gpio_n, uint8 wake_events, bool gci_gpio)
1410*4882a593Smuzhiyun {
1411*4882a593Smuzhiyun 	uint8 chipcontrol = 0;
1412*4882a593Smuzhiyun 	uint32 pmu_chipcontrol2 = 0;
1413*4882a593Smuzhiyun 
1414*4882a593Smuzhiyun 	if (!gci_gpio)
1415*4882a593Smuzhiyun 		chipcontrol = (1 << GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT);
1416*4882a593Smuzhiyun 
1417*4882a593Smuzhiyun 	chipcontrol |= (1 << GCI_GPIO_CHIPCTRL_PULLUP_BIT);
1418*4882a593Smuzhiyun 	si_gci_gpio_chipcontrol(sih, gpio_n,
1419*4882a593Smuzhiyun 		(chipcontrol | (1 << GCI_GPIO_CHIPCTRL_ENAB_IN_BIT)));
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	/* enable gci gpio int/wake events */
1422*4882a593Smuzhiyun 	si_gci_gpio_intmask(sih, gpio_n, wake_events, wake_events);
1423*4882a593Smuzhiyun 	si_gci_gpio_wakemask(sih, gpio_n, wake_events, wake_events);
1424*4882a593Smuzhiyun 
1425*4882a593Smuzhiyun 	/* clear the existing status bits */
1426*4882a593Smuzhiyun 	si_gci_gpio_status(sih, gpio_n,
1427*4882a593Smuzhiyun 		GCI_GPIO_STS_CLEAR, GCI_GPIO_STS_CLEAR);
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 	/* Enable gci2wl_wake */
1430*4882a593Smuzhiyun 	pmu_chipcontrol2 = si_pmu_chipcontrol(sih, PMU_CHIPCTL2, 0, 0);
1431*4882a593Smuzhiyun 	pmu_chipcontrol2 |= si_pmu_wake_bit_offset(sih);
1432*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL2, ~0, pmu_chipcontrol2);
1433*4882a593Smuzhiyun 
1434*4882a593Smuzhiyun 	/* enable gci int/wake events */
1435*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_intmask),
1436*4882a593Smuzhiyun 		GCI_INTSTATUS_GPIOINT, GCI_INTSTATUS_GPIOINT);
1437*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_wakemask),
1438*4882a593Smuzhiyun 		GCI_INTSTATUS_GPIOWAKE, GCI_INTSTATUS_GPIOWAKE);
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun void
si_gci_free_wake_pin(si_t * sih,uint8 gpio_n)1442*4882a593Smuzhiyun si_gci_free_wake_pin(si_t *sih, uint8 gpio_n)
1443*4882a593Smuzhiyun {
1444*4882a593Smuzhiyun 	uint8 chipcontrol = 0;
1445*4882a593Smuzhiyun 	uint8 wake_events;
1446*4882a593Smuzhiyun 
1447*4882a593Smuzhiyun 	si_gci_gpio_chipcontrol(sih, gpio_n, chipcontrol);
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	/* enable gci gpio int/wake events */
1450*4882a593Smuzhiyun 	wake_events = si_gci_gpio_intmask(sih, gpio_n, 0, 0);
1451*4882a593Smuzhiyun 	si_gci_gpio_intmask(sih, gpio_n, wake_events, 0);
1452*4882a593Smuzhiyun 	wake_events = si_gci_gpio_wakemask(sih, gpio_n, 0, 0);
1453*4882a593Smuzhiyun 	si_gci_gpio_wakemask(sih, gpio_n, wake_events, 0);
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 	/* clear the existing status bits */
1456*4882a593Smuzhiyun 	si_gci_gpio_status(sih, gpio_n,
1457*4882a593Smuzhiyun 		GCI_GPIO_STS_CLEAR, GCI_GPIO_STS_CLEAR);
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun #if defined(BCMPCIEDEV)
1461*4882a593Smuzhiyun static const char BCMINITDATA(rstr_device_wake_opt)[] = "device_wake_opt";
1462*4882a593Smuzhiyun #else
1463*4882a593Smuzhiyun static const char BCMINITDATA(rstr_device_wake_opt)[] = "sd_devwake";
1464*4882a593Smuzhiyun #endif
1465*4882a593Smuzhiyun #define DEVICE_WAKE_GPIO3	3
1466*4882a593Smuzhiyun 
1467*4882a593Smuzhiyun uint8
BCMATTACHFN(si_enable_perst_wake)1468*4882a593Smuzhiyun BCMATTACHFN(si_enable_perst_wake)(si_t *sih, uint8 *perst_wake_mask, uint8 *perst_cur_status)
1469*4882a593Smuzhiyun {
1470*4882a593Smuzhiyun 	uint8  gci_perst = CC_GCI_GPIO_15;
1471*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
1472*4882a593Smuzhiyun 	default:
1473*4882a593Smuzhiyun 		SI_ERROR(("device wake not supported for 0x%04x yet\n", CHIPID(sih->chip)));
1474*4882a593Smuzhiyun 		break;
1475*4882a593Smuzhiyun 	}
1476*4882a593Smuzhiyun 	return gci_perst;
1477*4882a593Smuzhiyun 
1478*4882a593Smuzhiyun }
1479*4882a593Smuzhiyun 
1480*4882a593Smuzhiyun uint8
BCMINITFN(si_get_device_wake_opt)1481*4882a593Smuzhiyun BCMINITFN(si_get_device_wake_opt)(si_t *sih)
1482*4882a593Smuzhiyun {
1483*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
1484*4882a593Smuzhiyun 
1485*4882a593Smuzhiyun 	if (getvar(NULL, rstr_device_wake_opt) == NULL)
1486*4882a593Smuzhiyun 		return CC_GCI_GPIO_INVALID;
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun 	sii->device_wake_opt = (uint8)getintvar(NULL, rstr_device_wake_opt);
1489*4882a593Smuzhiyun 	return sii->device_wake_opt;
1490*4882a593Smuzhiyun }
1491*4882a593Smuzhiyun 
1492*4882a593Smuzhiyun uint8
si_enable_device_wake(si_t * sih,uint8 * wake_mask,uint8 * cur_status)1493*4882a593Smuzhiyun si_enable_device_wake(si_t *sih, uint8 *wake_mask, uint8 *cur_status)
1494*4882a593Smuzhiyun {
1495*4882a593Smuzhiyun 	uint8  gci_gpio = CC_GCI_GPIO_INVALID;		/* DEVICE_WAKE GCI GPIO */
1496*4882a593Smuzhiyun 	uint32 device_wake_opt;
1497*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun 	device_wake_opt = sii->device_wake_opt;
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	if (device_wake_opt == CC_GCI_GPIO_INVALID) {
1502*4882a593Smuzhiyun 		/* parse the device wake opt from nvram */
1503*4882a593Smuzhiyun 		/* decode what that means for specific chip */
1504*4882a593Smuzhiyun 		/* apply the right gci config */
1505*4882a593Smuzhiyun 		/* enable the internal interrupts */
1506*4882a593Smuzhiyun 		/* assume: caller already registered handler for that GCI int */
1507*4882a593Smuzhiyun 		if (getvar(NULL, rstr_device_wake_opt) == NULL)
1508*4882a593Smuzhiyun 			return gci_gpio;
1509*4882a593Smuzhiyun 
1510*4882a593Smuzhiyun 		device_wake_opt = getintvar(NULL, rstr_device_wake_opt);
1511*4882a593Smuzhiyun 	}
1512*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
1513*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
1514*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
1515*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
1516*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
1517*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
1518*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
1519*4882a593Smuzhiyun 		/* device_wake op 1:
1520*4882a593Smuzhiyun 		 * gpio 1, func sel 4,
1521*4882a593Smuzhiyun 		 * gcigpioctrl: input pin, exra gpio
1522*4882a593Smuzhiyun 		 * since GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT is used, gci gpio is same as GPIO num
1523*4882a593Smuzhiyun 		 * GCI GPIO 1,wakemask/intmask: any edge, both positive negative
1524*4882a593Smuzhiyun 		 * enable the wake mask, intmask in GCI top level
1525*4882a593Smuzhiyun 		 * enable the chip common to get the G/ECI interrupt
1526*4882a593Smuzhiyun 		 * enable the PMU ctrl to wake the chip on wakemask set
1527*4882a593Smuzhiyun 		 */
1528*4882a593Smuzhiyun 		if (device_wake_opt == 1) {
1529*4882a593Smuzhiyun 			gci_gpio = CC_GCI_GPIO_1;
1530*4882a593Smuzhiyun 			*wake_mask = (1 << GCI_GPIO_STS_VALUE_BIT) |
1531*4882a593Smuzhiyun 				(1 << GCI_GPIO_STS_POS_EDGE_BIT) |
1532*4882a593Smuzhiyun 				(1 << GCI_GPIO_STS_NEG_EDGE_BIT);
1533*4882a593Smuzhiyun 			si_gci_set_functionsel(sih, gci_gpio, CC_FNSEL_GCI0);
1534*4882a593Smuzhiyun 			si_enable_gpio_wake(sih, wake_mask, cur_status, gci_gpio,
1535*4882a593Smuzhiyun 				PMU_CC2_GCI2_WAKE | PMU_CC2_MASK_WL_DEV_WAKE,
1536*4882a593Smuzhiyun 				PMU_CC2_GCI2_WAKE | PMU_CC2_MASK_WL_DEV_WAKE);
1537*4882a593Smuzhiyun 			/* hack: add a pulldown to HOST_WAKE */
1538*4882a593Smuzhiyun 			si_gci_gpio_chipcontrol(sih, 0,
1539*4882a593Smuzhiyun 					(1 << GCI_GPIO_CHIPCTRL_PULLDN_BIT));
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun 			/* Enable wake on GciWake */
1542*4882a593Smuzhiyun 			si_gci_indirect(sih, 0,
1543*4882a593Smuzhiyun 				GCI_OFFSETOF(sih, gci_wakemask),
1544*4882a593Smuzhiyun 				(GCI_INTSTATUS_GPIOWAKE | GCI_INTSTATUS_GPIOINT),
1545*4882a593Smuzhiyun 				(GCI_INTSTATUS_GPIOWAKE | GCI_INTSTATUS_GPIOINT));
1546*4882a593Smuzhiyun 
1547*4882a593Smuzhiyun 		} else {
1548*4882a593Smuzhiyun 			SI_ERROR(("0x%04x: don't know about device_wake_opt %d\n",
1549*4882a593Smuzhiyun 				CHIPID(sih->chip), device_wake_opt));
1550*4882a593Smuzhiyun 		}
1551*4882a593Smuzhiyun 		break;
1552*4882a593Smuzhiyun 	default:
1553*4882a593Smuzhiyun 		SI_ERROR(("device wake not supported for 0x%04x yet\n", CHIPID(sih->chip)));
1554*4882a593Smuzhiyun 		break;
1555*4882a593Smuzhiyun 	}
1556*4882a593Smuzhiyun 	return gci_gpio;
1557*4882a593Smuzhiyun }
1558*4882a593Smuzhiyun 
1559*4882a593Smuzhiyun void
si_gci_gpioint_handler_unregister(si_t * sih,void * gci_i)1560*4882a593Smuzhiyun si_gci_gpioint_handler_unregister(si_t *sih, void *gci_i)
1561*4882a593Smuzhiyun {
1562*4882a593Smuzhiyun 	si_info_t *sii;
1563*4882a593Smuzhiyun 	gci_gpio_item_t *p, *n;
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun 	sii = SI_INFO(sih);
1566*4882a593Smuzhiyun 
1567*4882a593Smuzhiyun 	ASSERT(gci_i != NULL);
1568*4882a593Smuzhiyun 
1569*4882a593Smuzhiyun 	sii = SI_INFO(sih);
1570*4882a593Smuzhiyun 
1571*4882a593Smuzhiyun 	if (!(sih->cccaps_ext & CC_CAP_EXT_GCI_PRESENT)) {
1572*4882a593Smuzhiyun 		SI_ERROR(("si_gci_gpioint_handler_unregister: not GCI capable\n"));
1573*4882a593Smuzhiyun 		return;
1574*4882a593Smuzhiyun 	}
1575*4882a593Smuzhiyun 	ASSERT(sii->gci_gpio_head != NULL);
1576*4882a593Smuzhiyun 
1577*4882a593Smuzhiyun 	if ((void*)sii->gci_gpio_head == gci_i) {
1578*4882a593Smuzhiyun 		sii->gci_gpio_head = sii->gci_gpio_head->next;
1579*4882a593Smuzhiyun 		MFREE(sii->osh, gci_i, sizeof(gci_gpio_item_t));
1580*4882a593Smuzhiyun 		return;
1581*4882a593Smuzhiyun 	} else {
1582*4882a593Smuzhiyun 		p = sii->gci_gpio_head;
1583*4882a593Smuzhiyun 		n = p->next;
1584*4882a593Smuzhiyun 		while (n) {
1585*4882a593Smuzhiyun 			if ((void*)n == gci_i) {
1586*4882a593Smuzhiyun 				p->next = n->next;
1587*4882a593Smuzhiyun 				MFREE(sii->osh, gci_i, sizeof(gci_gpio_item_t));
1588*4882a593Smuzhiyun 				return;
1589*4882a593Smuzhiyun 			}
1590*4882a593Smuzhiyun 			p = n;
1591*4882a593Smuzhiyun 			n = n->next;
1592*4882a593Smuzhiyun 		}
1593*4882a593Smuzhiyun 	}
1594*4882a593Smuzhiyun }
1595*4882a593Smuzhiyun 
1596*4882a593Smuzhiyun void*
si_gci_gpioint_handler_register(si_t * sih,uint8 gci_gpio,uint8 gpio_status,gci_gpio_handler_t cb,void * arg)1597*4882a593Smuzhiyun si_gci_gpioint_handler_register(si_t *sih, uint8 gci_gpio, uint8 gpio_status,
1598*4882a593Smuzhiyun 	gci_gpio_handler_t cb, void *arg)
1599*4882a593Smuzhiyun {
1600*4882a593Smuzhiyun 	si_info_t *sii;
1601*4882a593Smuzhiyun 	gci_gpio_item_t *gci_i;
1602*4882a593Smuzhiyun 
1603*4882a593Smuzhiyun 	sii = SI_INFO(sih);
1604*4882a593Smuzhiyun 
1605*4882a593Smuzhiyun 	ASSERT(cb != NULL);
1606*4882a593Smuzhiyun 
1607*4882a593Smuzhiyun 	sii = SI_INFO(sih);
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun 	if (!(sih->cccaps_ext & CC_CAP_EXT_GCI_PRESENT)) {
1610*4882a593Smuzhiyun 		SI_ERROR(("si_gci_gpioint_handler_register: not GCI capable\n"));
1611*4882a593Smuzhiyun 		return NULL;
1612*4882a593Smuzhiyun 	}
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun 	SI_MSG(("si_gci_gpioint_handler_register: gci_gpio  is %d\n", gci_gpio));
1615*4882a593Smuzhiyun 	if (gci_gpio >= SI_GPIO_MAX) {
1616*4882a593Smuzhiyun 		SI_ERROR(("isi_gci_gpioint_handler_register: Invalid GCI GPIO NUM %d\n", gci_gpio));
1617*4882a593Smuzhiyun 		return NULL;
1618*4882a593Smuzhiyun 	}
1619*4882a593Smuzhiyun 
1620*4882a593Smuzhiyun 	gci_i = MALLOC(sii->osh, (sizeof(gci_gpio_item_t)));
1621*4882a593Smuzhiyun 
1622*4882a593Smuzhiyun 	ASSERT(gci_i);
1623*4882a593Smuzhiyun 	if (gci_i == NULL) {
1624*4882a593Smuzhiyun 		SI_ERROR(("si_gci_gpioint_handler_register: GCI Item MALLOC failure\n"));
1625*4882a593Smuzhiyun 		return NULL;
1626*4882a593Smuzhiyun 	}
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 	if (sii->gci_gpio_head)
1629*4882a593Smuzhiyun 		gci_i->next = sii->gci_gpio_head;
1630*4882a593Smuzhiyun 	else
1631*4882a593Smuzhiyun 		gci_i->next = NULL;
1632*4882a593Smuzhiyun 
1633*4882a593Smuzhiyun 	sii->gci_gpio_head = gci_i;
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 	gci_i->handler = cb;
1636*4882a593Smuzhiyun 	gci_i->arg = arg;
1637*4882a593Smuzhiyun 	gci_i->gci_gpio = gci_gpio;
1638*4882a593Smuzhiyun 	gci_i->status = gpio_status;
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	return (void *)(gci_i);
1641*4882a593Smuzhiyun }
1642*4882a593Smuzhiyun 
1643*4882a593Smuzhiyun static void
si_gci_gpioint_handler_process(si_t * sih)1644*4882a593Smuzhiyun si_gci_gpioint_handler_process(si_t *sih)
1645*4882a593Smuzhiyun {
1646*4882a593Smuzhiyun 	si_info_t *sii;
1647*4882a593Smuzhiyun 	uint32 gpio_status[2], status;
1648*4882a593Smuzhiyun 	gci_gpio_item_t *gci_i;
1649*4882a593Smuzhiyun 
1650*4882a593Smuzhiyun 	sii = SI_INFO(sih);
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun 	/* most probably there are going to be 1 or 2 GPIOs used this way, so do for each GPIO */
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	/* go through the GPIO handlers and call them back if their intstatus is set */
1655*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_indirect_addr), ~0, 0);
1656*4882a593Smuzhiyun 	gpio_status[0] = si_corereg(sih, GCI_CORE_IDX(sih),
1657*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_gpiostatus), 0, 0);
1658*4882a593Smuzhiyun 	/* Only clear the status bits that have been read. Other bits (if present) should not
1659*4882a593Smuzhiyun 	* get cleared, so that they can be handled later.
1660*4882a593Smuzhiyun 	*/
1661*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_gpiostatus), ~0, gpio_status[0]);
1662*4882a593Smuzhiyun 
1663*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_indirect_addr), ~0, 1);
1664*4882a593Smuzhiyun 	gpio_status[1] = si_corereg(sih, GCI_CORE_IDX(sih),
1665*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_gpiostatus), 0, 0);
1666*4882a593Smuzhiyun 	/* Only clear the status bits that have been read. Other bits (if present) should not
1667*4882a593Smuzhiyun 	* get cleared, so that they can be handled later.
1668*4882a593Smuzhiyun 	*/
1669*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_gpiostatus), ~0, gpio_status[1]);
1670*4882a593Smuzhiyun 
1671*4882a593Smuzhiyun 	gci_i = sii->gci_gpio_head;
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun 	SI_MSG(("si_gci_gpioint_handler_process: status 0x%04x, 0x%04x\n",
1674*4882a593Smuzhiyun 		gpio_status[0], gpio_status[1]));
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 	while (gci_i) {
1677*4882a593Smuzhiyun 		if (gci_i->gci_gpio < 8)
1678*4882a593Smuzhiyun 			status = ((gpio_status[0] >> (gci_i->gci_gpio * 4)) & 0x0F);
1679*4882a593Smuzhiyun 		else
1680*4882a593Smuzhiyun 			status = ((gpio_status[1] >> ((gci_i->gci_gpio - 8) * 4)) & 0x0F);
1681*4882a593Smuzhiyun 		/* should we mask these */
1682*4882a593Smuzhiyun 		/* call back */
1683*4882a593Smuzhiyun 		ASSERT(gci_i->handler);
1684*4882a593Smuzhiyun 		if (gci_i->status & status)
1685*4882a593Smuzhiyun 			gci_i->handler(status, gci_i->arg);
1686*4882a593Smuzhiyun 		gci_i = gci_i->next;
1687*4882a593Smuzhiyun 	}
1688*4882a593Smuzhiyun }
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun void
si_gci_handler_process(si_t * sih)1691*4882a593Smuzhiyun si_gci_handler_process(si_t *sih)
1692*4882a593Smuzhiyun {
1693*4882a593Smuzhiyun 	uint32 gci_intstatus;
1694*4882a593Smuzhiyun 
1695*4882a593Smuzhiyun 	/* check the intmask, wakemask in the interrupt routine and call the right ones */
1696*4882a593Smuzhiyun 	/* for now call the gpio interrupt */
1697*4882a593Smuzhiyun 	gci_intstatus = si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_intstat), 0, 0);
1698*4882a593Smuzhiyun 
1699*4882a593Smuzhiyun 	if (gci_intstatus & GCI_INTMASK_GPIOINT) {
1700*4882a593Smuzhiyun 		SI_MSG(("si_gci_handler_process: gci_intstatus is 0x%04x\n", gci_intstatus));
1701*4882a593Smuzhiyun 		si_gci_gpioint_handler_process(sih);
1702*4882a593Smuzhiyun 	}
1703*4882a593Smuzhiyun 	if ((gci_intstatus & ~(GCI_INTMASK_GPIOINT))) {
1704*4882a593Smuzhiyun #ifdef	HNDGCI
1705*4882a593Smuzhiyun 		hndgci_handler_process(gci_intstatus, sih);
1706*4882a593Smuzhiyun #endif /* HNDGCI */
1707*4882a593Smuzhiyun 	}
1708*4882a593Smuzhiyun #ifdef WLGCIMBHLR
1709*4882a593Smuzhiyun 	if (gci_intstatus & GCI_INTSTATUS_EVENT) {
1710*4882a593Smuzhiyun 		hnd_gci_mb_handler_process(gci_intstatus, sih);
1711*4882a593Smuzhiyun 	}
1712*4882a593Smuzhiyun #endif /* WLGCIMBHLR */
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun #if defined(BCMLTECOEX) && !defined(WLTEST)
1715*4882a593Smuzhiyun 	if (gci_intstatus & GCI_INTMASK_SRFNE) {
1716*4882a593Smuzhiyun 		si_wci2_rxfifo_intr_handler_process(sih, gci_intstatus);
1717*4882a593Smuzhiyun 	}
1718*4882a593Smuzhiyun #endif /* BCMLTECOEX && !WLTEST */
1719*4882a593Smuzhiyun 
1720*4882a593Smuzhiyun #ifdef BCMGCISHM
1721*4882a593Smuzhiyun 	if (gci_intstatus & (GCI_INTSTATUS_EVENT | GCI_INTSTATUS_EVENTWAKE)) {
1722*4882a593Smuzhiyun 		hnd_gcishm_handler_process(sih, gci_intstatus);
1723*4882a593Smuzhiyun 	}
1724*4882a593Smuzhiyun #endif /* BCMGCISHM */
1725*4882a593Smuzhiyun }
1726*4882a593Smuzhiyun 
1727*4882a593Smuzhiyun void
si_gci_seci_init(si_t * sih)1728*4882a593Smuzhiyun si_gci_seci_init(si_t *sih)
1729*4882a593Smuzhiyun {
1730*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl), ALLONES_32,
1731*4882a593Smuzhiyun 	              (GCI_CCTL_SCS << GCI_CCTL_SCS_OFFSET) |
1732*4882a593Smuzhiyun 	              (GCI_MODE_SECI << GCI_CCTL_SMODE_OFFSET) |
1733*4882a593Smuzhiyun 	              (1 << GCI_CCTL_SECIEN_OFFSET));
1734*4882a593Smuzhiyun 
1735*4882a593Smuzhiyun 	si_gci_indirect(sih, 0, GCI_OFFSETOF(sih, gci_chipctrl), ALLONES_32, 0x0080000); //0x200
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun 	si_gci_indirect(sih, 1, GCI_OFFSETOF(sih, gci_gpioctl), ALLONES_32, 0x00010280); //0x044
1738*4882a593Smuzhiyun 
1739*4882a593Smuzhiyun 	/* baudrate:4Mbps at 40MHz xtal, escseq:0xdb, high baudrate, enable seci_tx/rx */
1740*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv), //0x1e0
1741*4882a593Smuzhiyun 	              ALLONES_32, 0xF6);
1742*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_baudadj), ALLONES_32, 0xFF); //0x1f8
1743*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secifcr), ALLONES_32, 0x00); //0x1e4
1744*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr), ALLONES_32, 0x08); //0x1ec
1745*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secilcr), ALLONES_32, 0xA8); //0x1e8
1746*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_seciuartescval), //0x1d0
1747*4882a593Smuzhiyun 	              ALLONES_32, 0xDB);
1748*4882a593Smuzhiyun 
1749*4882a593Smuzhiyun 	/* Atlas/GMAC3 configuration for SECI */
1750*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_miscctl), ALLONES_32, 0xFFFF); //0xc54
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun 	/* config GPIO pins 5/6 as SECI_IN/SECI_OUT */
1753*4882a593Smuzhiyun 	si_gci_indirect(sih, 0,
1754*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_seciin_ctrl), ALLONES_32, 0x161); //0x218
1755*4882a593Smuzhiyun 	si_gci_indirect(sih, 0,
1756*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_seciout_ctrl), ALLONES_32, 0x10051); //0x21c
1757*4882a593Smuzhiyun 
1758*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_seciout_txen_txbr), ALLONES_32, 0x01); //0x224
1759*4882a593Smuzhiyun 
1760*4882a593Smuzhiyun 	/* WLAN rx offset assignment */
1761*4882a593Smuzhiyun 	/* WLCX: RX offset assignment from WLAN core to WLAN core (faked as BT TX) */
1762*4882a593Smuzhiyun 	si_gci_indirect(sih, 0,
1763*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_secif0rx_offset), ALLONES_32, 0x13121110); //0x1bc
1764*4882a593Smuzhiyun 	si_gci_indirect(sih, 1,
1765*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_secif0rx_offset), ALLONES_32, 0x17161514);
1766*4882a593Smuzhiyun 	si_gci_indirect(sih, 2,
1767*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_secif0rx_offset), ALLONES_32, 0x1b1a1918);
1768*4882a593Smuzhiyun 
1769*4882a593Smuzhiyun 	/* first 12 nibbles configured for format-0 */
1770*4882a593Smuzhiyun 	/* note: we can only select 1st 12 nibbles of each IP for format_0 */
1771*4882a593Smuzhiyun 	si_gci_indirect(sih, 0,  GCI_OFFSETOF(sih, gci_seciusef0tx_reg), //0x1b4
1772*4882a593Smuzhiyun 	                ALLONES_32, 0xFFF); // first 12 nibbles
1773*4882a593Smuzhiyun 
1774*4882a593Smuzhiyun 	si_gci_indirect(sih, 0,  GCI_OFFSETOF(sih, gci_secitx_datatag),
1775*4882a593Smuzhiyun 			ALLONES_32, 0x0F0); // gci_secitx_datatag(nibbles 4 to 7 tagged)
1776*4882a593Smuzhiyun 	si_gci_indirect(sih, 0,  GCI_OFFSETOF(sih, gci_secirx_datatag),
1777*4882a593Smuzhiyun 	                ALLONES_32, 0x0F0); // gci_secirx_datatag(nibbles 4 to 7 tagged)
1778*4882a593Smuzhiyun 
1779*4882a593Smuzhiyun 	/* TX offset assignment (wlan to bt) */
1780*4882a593Smuzhiyun 	si_gci_indirect(sih, 0,
1781*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_secif0tx_offset), 0xFFFFFFFF, 0x76543210); //0x1b8
1782*4882a593Smuzhiyun 	si_gci_indirect(sih, 1,
1783*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_secif0tx_offset), 0xFFFFFFFF, 0x0000ba98);
1784*4882a593Smuzhiyun 	if (CHIPID(sih->chip) == BCM43602_CHIP_ID) {
1785*4882a593Smuzhiyun 		/* Request	BT side to update SECI information */
1786*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(chipcregs_t, gci_seciauxtx),
1787*4882a593Smuzhiyun 			(SECI_AUX_TX_START | SECI_REFRESH_REQ),
1788*4882a593Smuzhiyun 			(SECI_AUX_TX_START | SECI_REFRESH_REQ));
1789*4882a593Smuzhiyun 		/* WLAN to update SECI information */
1790*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(chipcregs_t, gci_corectrl),
1791*4882a593Smuzhiyun 			SECI_UPD_SECI, SECI_UPD_SECI);
1792*4882a593Smuzhiyun 	}
1793*4882a593Smuzhiyun 
1794*4882a593Smuzhiyun 	// HW ECI bus directly driven from IP
1795*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_control_0), ALLONES_32, 0x00000000);
1796*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_control_1), ALLONES_32, 0x00000000);
1797*4882a593Smuzhiyun }
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun #if defined(BCMLTECOEX) && !defined(WLTEST)
1800*4882a593Smuzhiyun int
si_wci2_rxfifo_handler_register(si_t * sih,wci2_handler_t rx_cb,void * ctx)1801*4882a593Smuzhiyun si_wci2_rxfifo_handler_register(si_t *sih, wci2_handler_t rx_cb, void *ctx)
1802*4882a593Smuzhiyun {
1803*4882a593Smuzhiyun 	si_info_t *sii;
1804*4882a593Smuzhiyun 	wci2_rxfifo_info_t *wci2_info;
1805*4882a593Smuzhiyun 
1806*4882a593Smuzhiyun 	sii = SI_INFO(sih);
1807*4882a593Smuzhiyun 
1808*4882a593Smuzhiyun 	ASSERT(rx_cb != NULL);
1809*4882a593Smuzhiyun 
1810*4882a593Smuzhiyun 	if (!(sih->cccaps_ext & CC_CAP_EXT_GCI_PRESENT)) {
1811*4882a593Smuzhiyun 		SI_ERROR(("si_wci2_rxfifo_handler_register: not GCI capable\n"));
1812*4882a593Smuzhiyun 		return BCME_ERROR;
1813*4882a593Smuzhiyun 	}
1814*4882a593Smuzhiyun 
1815*4882a593Smuzhiyun 	if ((wci2_info = (wci2_rxfifo_info_t *)MALLOCZ(sii->osh,
1816*4882a593Smuzhiyun 			sizeof(wci2_rxfifo_info_t))) == NULL) {
1817*4882a593Smuzhiyun 		SI_ERROR(("si_wci2_rxfifo_handler_register: WCI2 RXFIFO INFO MALLOC failure\n"));
1818*4882a593Smuzhiyun 		return BCME_NOMEM;
1819*4882a593Smuzhiyun 	}
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun 	if ((wci2_info->rx_buf = (char *)MALLOCZ(sii->osh, WCI2_UART_RX_BUF_SIZE)) == NULL) {
1822*4882a593Smuzhiyun 		MFREE(sii->osh, wci2_info, sizeof(wci2_rxfifo_info_t));
1823*4882a593Smuzhiyun 
1824*4882a593Smuzhiyun 		SI_ERROR(("si_wci2_rxfifo_handler_register: WCI2 RXFIFO INFO MALLOC failure\n"));
1825*4882a593Smuzhiyun 		return BCME_NOMEM;
1826*4882a593Smuzhiyun 	}
1827*4882a593Smuzhiyun 
1828*4882a593Smuzhiyun 	if ((wci2_info->cbs = (wci2_cbs_t *)MALLOCZ(sii->osh, sizeof(wci2_cbs_t))) == NULL) {
1829*4882a593Smuzhiyun 		MFREE(sii->osh, wci2_info->rx_buf, WCI2_UART_RX_BUF_SIZE);
1830*4882a593Smuzhiyun 		MFREE(sii->osh, wci2_info, sizeof(wci2_rxfifo_info_t));
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun 		SI_ERROR(("si_wci2_rxfifo_handler_register: WCI2 RXFIFO INFO MALLOC failure\n"));
1833*4882a593Smuzhiyun 		return BCME_NOMEM;
1834*4882a593Smuzhiyun 	}
1835*4882a593Smuzhiyun 
1836*4882a593Smuzhiyun 	sii->wci2_info = wci2_info;
1837*4882a593Smuzhiyun 
1838*4882a593Smuzhiyun 	/* init callback */
1839*4882a593Smuzhiyun 	wci2_info->cbs->handler = rx_cb;
1840*4882a593Smuzhiyun 	wci2_info->cbs->context = ctx;
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun 	return BCME_OK;
1843*4882a593Smuzhiyun }
1844*4882a593Smuzhiyun 
1845*4882a593Smuzhiyun void
si_wci2_rxfifo_handler_unregister(si_t * sih)1846*4882a593Smuzhiyun si_wci2_rxfifo_handler_unregister(si_t *sih)
1847*4882a593Smuzhiyun {
1848*4882a593Smuzhiyun 
1849*4882a593Smuzhiyun 	si_info_t *sii;
1850*4882a593Smuzhiyun 	wci2_rxfifo_info_t *wci2_info;
1851*4882a593Smuzhiyun 
1852*4882a593Smuzhiyun 	sii = SI_INFO(sih);
1853*4882a593Smuzhiyun 	ASSERT(sii);
1854*4882a593Smuzhiyun 
1855*4882a593Smuzhiyun 	if (!(sih->cccaps_ext & CC_CAP_EXT_GCI_PRESENT)) {
1856*4882a593Smuzhiyun 		SI_ERROR(("si_wci2_rxfifo_handler_unregister: not GCI capable\n"));
1857*4882a593Smuzhiyun 		return;
1858*4882a593Smuzhiyun 	}
1859*4882a593Smuzhiyun 
1860*4882a593Smuzhiyun 	wci2_info = sii->wci2_info;
1861*4882a593Smuzhiyun 
1862*4882a593Smuzhiyun 	if (wci2_info == NULL) {
1863*4882a593Smuzhiyun 		return;
1864*4882a593Smuzhiyun 	}
1865*4882a593Smuzhiyun 
1866*4882a593Smuzhiyun 	if (wci2_info->rx_buf != NULL) {
1867*4882a593Smuzhiyun 		MFREE(sii->osh, wci2_info->rx_buf, WCI2_UART_RX_BUF_SIZE);
1868*4882a593Smuzhiyun 	}
1869*4882a593Smuzhiyun 
1870*4882a593Smuzhiyun 	if (wci2_info->cbs != NULL) {
1871*4882a593Smuzhiyun 		MFREE(sii->osh, wci2_info->cbs, sizeof(wci2_cbs_t));
1872*4882a593Smuzhiyun 	}
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun 	MFREE(sii->osh, wci2_info, sizeof(wci2_rxfifo_info_t));
1875*4882a593Smuzhiyun 
1876*4882a593Smuzhiyun }
1877*4882a593Smuzhiyun 
1878*4882a593Smuzhiyun /* GCI WCI2 UART RXFIFO interrupt handler */
1879*4882a593Smuzhiyun static void
si_wci2_rxfifo_intr_handler_process(si_t * sih,uint32 intstatus)1880*4882a593Smuzhiyun si_wci2_rxfifo_intr_handler_process(si_t *sih, uint32 intstatus)
1881*4882a593Smuzhiyun {
1882*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
1883*4882a593Smuzhiyun 	uint32 udata;
1884*4882a593Smuzhiyun 	char ubyte;
1885*4882a593Smuzhiyun 	wci2_rxfifo_info_t *wci2_info;
1886*4882a593Smuzhiyun 	bool call_cb = FALSE;
1887*4882a593Smuzhiyun 
1888*4882a593Smuzhiyun 	wci2_info = sii->wci2_info;
1889*4882a593Smuzhiyun 
1890*4882a593Smuzhiyun 	if (wci2_info == NULL) {
1891*4882a593Smuzhiyun 		return;
1892*4882a593Smuzhiyun 	}
1893*4882a593Smuzhiyun 
1894*4882a593Smuzhiyun 	if (intstatus & GCI_INTSTATUS_SRFOF) {
1895*4882a593Smuzhiyun 		SI_ERROR(("*** rx fifo overflow *** \n"));
1896*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_intstat),
1897*4882a593Smuzhiyun 			GCI_INTSTATUS_SRFOF, GCI_INTSTATUS_SRFOF);
1898*4882a593Smuzhiyun 	}
1899*4882a593Smuzhiyun 
1900*4882a593Smuzhiyun 	/* Check if RF FIFO has any data */
1901*4882a593Smuzhiyun 	if (intstatus & GCI_INTMASK_SRFNE) {
1902*4882a593Smuzhiyun 
1903*4882a593Smuzhiyun 		/* Read seci uart data */
1904*4882a593Smuzhiyun 		udata = si_gci_direct(sih, GCI_OFFSETOF(sih, gci_seciuartdata), 0, 0);
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun 		while (udata & SECI_UART_DATA_RF_NOT_EMPTY_BIT) {
1907*4882a593Smuzhiyun 
1908*4882a593Smuzhiyun 			ubyte = (char) udata;
1909*4882a593Smuzhiyun 			if (wci2_info) {
1910*4882a593Smuzhiyun 				wci2_info->rx_buf[wci2_info->rx_idx] = ubyte;
1911*4882a593Smuzhiyun 				wci2_info->rx_idx++;
1912*4882a593Smuzhiyun 				call_cb = TRUE;
1913*4882a593Smuzhiyun 				/* if the buffer is full, break
1914*4882a593Smuzhiyun 				 * remaining will be processed in next callback
1915*4882a593Smuzhiyun 				 */
1916*4882a593Smuzhiyun 				if (wci2_info->rx_idx == WCI2_UART_RX_BUF_SIZE) {
1917*4882a593Smuzhiyun 					break;
1918*4882a593Smuzhiyun 				}
1919*4882a593Smuzhiyun 			}
1920*4882a593Smuzhiyun 
1921*4882a593Smuzhiyun 			udata = si_gci_direct(sih, GCI_OFFSETOF(sih, gci_seciuartdata), 0, 0);
1922*4882a593Smuzhiyun 		}
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun 		/* if callback registered; call it */
1925*4882a593Smuzhiyun 		if (call_cb && wci2_info && wci2_info->cbs) {
1926*4882a593Smuzhiyun 			wci2_info->cbs->handler(wci2_info->cbs->context, wci2_info->rx_buf,
1927*4882a593Smuzhiyun 				wci2_info->rx_idx);
1928*4882a593Smuzhiyun 			bzero(wci2_info->rx_buf, WCI2_UART_RX_BUF_SIZE);
1929*4882a593Smuzhiyun 			wci2_info->rx_idx = 0;
1930*4882a593Smuzhiyun 		}
1931*4882a593Smuzhiyun 	}
1932*4882a593Smuzhiyun }
1933*4882a593Smuzhiyun #endif /* BCMLTECOEX && !WLTEST */
1934*4882a593Smuzhiyun 
1935*4882a593Smuzhiyun #ifdef BCMLTECOEX
1936*4882a593Smuzhiyun /* Program GCI GpioMask and GCI GpioControl Registers */
1937*4882a593Smuzhiyun static void
si_config_gcigpio(si_t * sih,uint32 gci_pos,uint8 gcigpio,uint8 gpioctl_mask,uint8 gpioctl_val)1938*4882a593Smuzhiyun si_config_gcigpio(si_t *sih, uint32 gci_pos, uint8 gcigpio,
1939*4882a593Smuzhiyun 	uint8 gpioctl_mask, uint8 gpioctl_val)
1940*4882a593Smuzhiyun {
1941*4882a593Smuzhiyun 	uint32 indirect_idx =
1942*4882a593Smuzhiyun 		GCI_REGIDX(gci_pos) | (gcigpio << GCI_GPIOIDX_OFFSET);
1943*4882a593Smuzhiyun 	si_gci_indirect(sih, indirect_idx, GCI_OFFSETOF(sih, gci_gpiomask),
1944*4882a593Smuzhiyun 		(1 << GCI_BITOFFSET(gci_pos)),
1945*4882a593Smuzhiyun 		(1 << GCI_BITOFFSET(gci_pos)));
1946*4882a593Smuzhiyun 	/* Write GPIO Configuration to GCI Registers */
1947*4882a593Smuzhiyun 	si_gci_indirect(sih, gcigpio/4, GCI_OFFSETOF(sih, gci_gpioctl),
1948*4882a593Smuzhiyun 		(gpioctl_mask << (gcigpio%4)*8), (gpioctl_val << (gcigpio%4)*8));
1949*4882a593Smuzhiyun }
1950*4882a593Smuzhiyun 
1951*4882a593Smuzhiyun void
si_ercx_init(si_t * sih,uint32 ltecx_mux,uint32 ltecx_padnum,uint32 ltecx_fnsel,uint32 ltecx_gcigpio)1952*4882a593Smuzhiyun si_ercx_init(si_t *sih, uint32 ltecx_mux, uint32 ltecx_padnum,
1953*4882a593Smuzhiyun 	uint32 ltecx_fnsel, uint32 ltecx_gcigpio)
1954*4882a593Smuzhiyun {
1955*4882a593Smuzhiyun 	uint8 fsync_padnum, lterx_padnum, ltetx_padnum, wlprio_padnum;
1956*4882a593Smuzhiyun 	uint8 fsync_fnsel, lterx_fnsel, ltetx_fnsel, wlprio_fnsel;
1957*4882a593Smuzhiyun 	uint8 fsync_gcigpio, lterx_gcigpio, ltetx_gcigpio, wlprio_gcigpio;
1958*4882a593Smuzhiyun 
1959*4882a593Smuzhiyun 	/* reset GCI block */
1960*4882a593Smuzhiyun 	si_gci_reset(sih);
1961*4882a593Smuzhiyun 
1962*4882a593Smuzhiyun 	/* enable ERCX (pure gpio) mode, Keep SECI in Reset Mode Only */
1963*4882a593Smuzhiyun 	/* Hopefully, keeping SECI in Reset Mode will draw lesser current */
1964*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl),
1965*4882a593Smuzhiyun 		((GCI_MODE_MASK << GCI_CCTL_SMODE_OFFSET)
1966*4882a593Smuzhiyun 		|(1 << GCI_CCTL_SECIEN_OFFSET)
1967*4882a593Smuzhiyun 		|(1 << GCI_CCTL_RSTSL_OFFSET)
1968*4882a593Smuzhiyun 		|(1 << GCI_CCTL_SECIRST_OFFSET)),
1969*4882a593Smuzhiyun 		((GCI_MODE_GPIO << GCI_CCTL_SMODE_OFFSET)
1970*4882a593Smuzhiyun 		|(0 << GCI_CCTL_SECIEN_OFFSET)
1971*4882a593Smuzhiyun 		|(1 << GCI_CCTL_RSTSL_OFFSET)
1972*4882a593Smuzhiyun 		|(1 << GCI_CCTL_SECIRST_OFFSET)));
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun 	/* Extract Interface Configuration */
1975*4882a593Smuzhiyun 	fsync_padnum	= LTECX_EXTRACT_PADNUM(ltecx_padnum, LTECX_NVRAM_FSYNC_IDX);
1976*4882a593Smuzhiyun 	lterx_padnum	= LTECX_EXTRACT_PADNUM(ltecx_padnum, LTECX_NVRAM_LTERX_IDX);
1977*4882a593Smuzhiyun 	ltetx_padnum	= LTECX_EXTRACT_PADNUM(ltecx_padnum, LTECX_NVRAM_LTETX_IDX);
1978*4882a593Smuzhiyun 	wlprio_padnum	= LTECX_EXTRACT_PADNUM(ltecx_padnum, LTECX_NVRAM_WLPRIO_IDX);
1979*4882a593Smuzhiyun 
1980*4882a593Smuzhiyun 	fsync_fnsel	= LTECX_EXTRACT_FNSEL(ltecx_fnsel, LTECX_NVRAM_FSYNC_IDX);
1981*4882a593Smuzhiyun 	lterx_fnsel	= LTECX_EXTRACT_FNSEL(ltecx_fnsel, LTECX_NVRAM_LTERX_IDX);
1982*4882a593Smuzhiyun 	ltetx_fnsel	= LTECX_EXTRACT_FNSEL(ltecx_fnsel, LTECX_NVRAM_LTETX_IDX);
1983*4882a593Smuzhiyun 	wlprio_fnsel	= LTECX_EXTRACT_FNSEL(ltecx_fnsel, LTECX_NVRAM_WLPRIO_IDX);
1984*4882a593Smuzhiyun 
1985*4882a593Smuzhiyun 	fsync_gcigpio	= LTECX_EXTRACT_GCIGPIO(ltecx_gcigpio, LTECX_NVRAM_FSYNC_IDX);
1986*4882a593Smuzhiyun 	lterx_gcigpio	= LTECX_EXTRACT_GCIGPIO(ltecx_gcigpio, LTECX_NVRAM_LTERX_IDX);
1987*4882a593Smuzhiyun 	ltetx_gcigpio	= LTECX_EXTRACT_GCIGPIO(ltecx_gcigpio, LTECX_NVRAM_LTETX_IDX);
1988*4882a593Smuzhiyun 	wlprio_gcigpio	= LTECX_EXTRACT_GCIGPIO(ltecx_gcigpio, LTECX_NVRAM_WLPRIO_IDX);
1989*4882a593Smuzhiyun 
1990*4882a593Smuzhiyun 	/* Clear this Function Select for all GPIOs if programmed by default */
1991*4882a593Smuzhiyun 	si_gci_clear_functionsel(sih, fsync_fnsel);
1992*4882a593Smuzhiyun 	si_gci_clear_functionsel(sih, lterx_fnsel);
1993*4882a593Smuzhiyun 	si_gci_clear_functionsel(sih, ltetx_fnsel);
1994*4882a593Smuzhiyun 	si_gci_clear_functionsel(sih, wlprio_fnsel);
1995*4882a593Smuzhiyun 
1996*4882a593Smuzhiyun 	/* Program Function select for selected GPIOs */
1997*4882a593Smuzhiyun 	si_gci_set_functionsel(sih, fsync_padnum, fsync_fnsel);
1998*4882a593Smuzhiyun 	si_gci_set_functionsel(sih, lterx_padnum, lterx_fnsel);
1999*4882a593Smuzhiyun 	si_gci_set_functionsel(sih, ltetx_padnum, ltetx_fnsel);
2000*4882a593Smuzhiyun 	si_gci_set_functionsel(sih, wlprio_padnum, wlprio_fnsel);
2001*4882a593Smuzhiyun 
2002*4882a593Smuzhiyun 	/* NOTE: We are keeping Input PADs in Pull Down Mode to take care of the case
2003*4882a593Smuzhiyun 	 * when LTE Modem doesn't drive these lines for any reason.
2004*4882a593Smuzhiyun 	 * We should consider alternate ways to identify this situation and dynamically
2005*4882a593Smuzhiyun 	 * enable Pull Down PAD only when LTE Modem doesn't drive these lines.
2006*4882a593Smuzhiyun 	 */
2007*4882a593Smuzhiyun 
2008*4882a593Smuzhiyun 	/* Configure Frame Sync as input */
2009*4882a593Smuzhiyun 	si_config_gcigpio(sih, GCI_LTE_FRAMESYNC_POS, fsync_gcigpio, 0xFF,
2010*4882a593Smuzhiyun 		((1 << GCI_GPIOCTL_INEN_OFFSET)|(1 << GCI_GPIOCTL_PDN_OFFSET)));
2011*4882a593Smuzhiyun 
2012*4882a593Smuzhiyun 	/* Configure LTE Rx as input */
2013*4882a593Smuzhiyun 	si_config_gcigpio(sih, GCI_LTE_RX_POS, lterx_gcigpio, 0xFF,
2014*4882a593Smuzhiyun 		((1 << GCI_GPIOCTL_INEN_OFFSET)|(1 << GCI_GPIOCTL_PDN_OFFSET)));
2015*4882a593Smuzhiyun 
2016*4882a593Smuzhiyun 	/* Configure LTE Tx as input */
2017*4882a593Smuzhiyun 	si_config_gcigpio(sih, GCI_LTE_TX_POS, ltetx_gcigpio, 0xFF,
2018*4882a593Smuzhiyun 		((1 << GCI_GPIOCTL_INEN_OFFSET)|(1 << GCI_GPIOCTL_PDN_OFFSET)));
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun 	/* Configure WLAN Prio as output. BT Need to configure its ISM Prio separately
2021*4882a593Smuzhiyun 	 * NOTE: LTE chip has to enable its internal pull-down whenever WL goes down
2022*4882a593Smuzhiyun 	 */
2023*4882a593Smuzhiyun 	si_config_gcigpio(sih, GCI_WLAN_PRIO_POS, wlprio_gcigpio, 0xFF,
2024*4882a593Smuzhiyun 		(1 << GCI_GPIOCTL_OUTEN_OFFSET));
2025*4882a593Smuzhiyun 
2026*4882a593Smuzhiyun 	/* Enable inbandIntMask for FrmSync only, disable LTE_Rx and LTE_Tx
2027*4882a593Smuzhiyun 	  * Note: FrameSync, LTE Rx & LTE Tx happen to share the same REGIDX
2028*4882a593Smuzhiyun 	  * Hence a single Access is sufficient
2029*4882a593Smuzhiyun 	  */
2030*4882a593Smuzhiyun 	si_gci_indirect(sih, GCI_REGIDX(GCI_LTE_FRAMESYNC_POS),
2031*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_inbandeventintmask),
2032*4882a593Smuzhiyun 		((1 << GCI_BITOFFSET(GCI_LTE_FRAMESYNC_POS))
2033*4882a593Smuzhiyun 		|(1 << GCI_BITOFFSET(GCI_LTE_RX_POS))
2034*4882a593Smuzhiyun 		|(1 << GCI_BITOFFSET(GCI_LTE_TX_POS))),
2035*4882a593Smuzhiyun 		((1 << GCI_BITOFFSET(GCI_LTE_FRAMESYNC_POS))
2036*4882a593Smuzhiyun 		|(0 << GCI_BITOFFSET(GCI_LTE_RX_POS))
2037*4882a593Smuzhiyun 		|(0 << GCI_BITOFFSET(GCI_LTE_TX_POS))));
2038*4882a593Smuzhiyun 
2039*4882a593Smuzhiyun 	/* Enable Inband interrupt polarity for LTE_FRMSYNC */
2040*4882a593Smuzhiyun 	si_gci_indirect(sih, GCI_REGIDX(GCI_LTE_FRAMESYNC_POS),
2041*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_intpolreg),
2042*4882a593Smuzhiyun 		(1 << GCI_BITOFFSET(GCI_LTE_FRAMESYNC_POS)),
2043*4882a593Smuzhiyun 		(1 << GCI_BITOFFSET(GCI_LTE_FRAMESYNC_POS)));
2044*4882a593Smuzhiyun }
2045*4882a593Smuzhiyun 
2046*4882a593Smuzhiyun void
si_wci2_init(si_t * sih,uint8 baudrate,uint32 ltecx_mux,uint32 ltecx_padnum,uint32 ltecx_fnsel,uint32 ltecx_gcigpio,uint32 xtalfreq)2047*4882a593Smuzhiyun si_wci2_init(si_t *sih, uint8 baudrate, uint32 ltecx_mux, uint32 ltecx_padnum,
2048*4882a593Smuzhiyun 	uint32 ltecx_fnsel, uint32 ltecx_gcigpio, uint32 xtalfreq)
2049*4882a593Smuzhiyun {
2050*4882a593Smuzhiyun 	/* BCMLTECOEXGCI_ENAB should be checked before calling si_wci2_init() */
2051*4882a593Smuzhiyun 	uint8 baud = baudrate;
2052*4882a593Smuzhiyun 	uint8 seciin, seciout, fnselin, fnselout, gcigpioin, gcigpioout;
2053*4882a593Smuzhiyun 
2054*4882a593Smuzhiyun 	/* Extract PAD GPIO number (1-byte) from "ltecx_padnum" for each LTECX pin */
2055*4882a593Smuzhiyun 	seciin =	LTECX_EXTRACT_PADNUM(ltecx_padnum, LTECX_NVRAM_WCI2IN_IDX);
2056*4882a593Smuzhiyun 	seciout =	LTECX_EXTRACT_PADNUM(ltecx_padnum, LTECX_NVRAM_WCI2OUT_IDX);
2057*4882a593Smuzhiyun 	/* Extract FunctionSel (1-nibble) from "ltecx_fnsel" for each LTECX pin */
2058*4882a593Smuzhiyun 	fnselin =	LTECX_EXTRACT_FNSEL(ltecx_fnsel, LTECX_NVRAM_WCI2IN_IDX);
2059*4882a593Smuzhiyun 	fnselout =	LTECX_EXTRACT_FNSEL(ltecx_fnsel, LTECX_NVRAM_WCI2OUT_IDX);
2060*4882a593Smuzhiyun 	/* Extract GCI-GPIO number (1-nibble) from "ltecx_gcigpio" for each LTECX pin */
2061*4882a593Smuzhiyun 	gcigpioin =	LTECX_EXTRACT_GCIGPIO(ltecx_gcigpio, LTECX_NVRAM_WCI2IN_IDX);
2062*4882a593Smuzhiyun 	gcigpioout =	LTECX_EXTRACT_GCIGPIO(ltecx_gcigpio, LTECX_NVRAM_WCI2OUT_IDX);
2063*4882a593Smuzhiyun 
2064*4882a593Smuzhiyun 	/* reset GCI block */
2065*4882a593Smuzhiyun 	si_gci_reset(sih);
2066*4882a593Smuzhiyun 
2067*4882a593Smuzhiyun 	/* NOTE: Writing Reserved bits of older GCI Revs is OK */
2068*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl),
2069*4882a593Smuzhiyun 		((GCI_CCTL_SCS_MASK << GCI_CCTL_SCS_OFFSET)
2070*4882a593Smuzhiyun 		|(GCI_CCTL_LOWTOUT_MASK << GCI_CCTL_SILOWTOUT_OFFSET)
2071*4882a593Smuzhiyun 		|(1 << GCI_CCTL_BRKONSLP_OFFSET)
2072*4882a593Smuzhiyun 		|(1 << GCI_CCTL_US_OFFSET)
2073*4882a593Smuzhiyun 		|(GCI_MODE_MASK << GCI_CCTL_SMODE_OFFSET)
2074*4882a593Smuzhiyun 		|(1 << GCI_CCTL_FSL_OFFSET)
2075*4882a593Smuzhiyun 		|(1 << GCI_CCTL_SECIEN_OFFSET)),
2076*4882a593Smuzhiyun 		((GCI_CCTL_SCS_DEF << GCI_CCTL_SCS_OFFSET)
2077*4882a593Smuzhiyun 		|(GCI_CCTL_LOWTOUT_30BIT << GCI_CCTL_SILOWTOUT_OFFSET)
2078*4882a593Smuzhiyun 		|(0 << GCI_CCTL_BRKONSLP_OFFSET)
2079*4882a593Smuzhiyun 		|(0 << GCI_CCTL_US_OFFSET)
2080*4882a593Smuzhiyun 		|(GCI_MODE_BTSIG << GCI_CCTL_SMODE_OFFSET)
2081*4882a593Smuzhiyun 		|(0 << GCI_CCTL_FSL_OFFSET)
2082*4882a593Smuzhiyun 		|(1 << GCI_CCTL_SECIEN_OFFSET))); /* 19000024 */
2083*4882a593Smuzhiyun 
2084*4882a593Smuzhiyun 	/* Program Function select for selected GPIOs */
2085*4882a593Smuzhiyun 	si_gci_set_functionsel(sih, seciin, fnselin);
2086*4882a593Smuzhiyun 	si_gci_set_functionsel(sih, seciout, fnselout);
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun 	/* Enable inbandIntMask for FrmSync only; disable LTE_Rx and LTE_Tx
2089*4882a593Smuzhiyun 	  * Note: FrameSync, LTE Rx & LTE Tx happen to share the same REGIDX
2090*4882a593Smuzhiyun 	  * Hence a single Access is sufficient
2091*4882a593Smuzhiyun 	  */
2092*4882a593Smuzhiyun 	si_gci_indirect(sih,
2093*4882a593Smuzhiyun 		GCI_REGIDX(GCI_LTE_FRAMESYNC_POS),
2094*4882a593Smuzhiyun 		GCI_OFFSETOF(sih, gci_inbandeventintmask),
2095*4882a593Smuzhiyun 		((1 << GCI_BITOFFSET(GCI_LTE_FRAMESYNC_POS))
2096*4882a593Smuzhiyun 		|(1 << GCI_BITOFFSET(GCI_LTE_RX_POS))
2097*4882a593Smuzhiyun 		|(1 << GCI_BITOFFSET(GCI_LTE_TX_POS))),
2098*4882a593Smuzhiyun 		((1 << GCI_BITOFFSET(GCI_LTE_FRAMESYNC_POS))
2099*4882a593Smuzhiyun 		|(0 << GCI_BITOFFSET(GCI_LTE_RX_POS))
2100*4882a593Smuzhiyun 		|(0 << GCI_BITOFFSET(GCI_LTE_TX_POS))));
2101*4882a593Smuzhiyun 
2102*4882a593Smuzhiyun 	if (GCIREV(sih->gcirev) >= 1) {
2103*4882a593Smuzhiyun 		/* Program inband interrupt polarity as posedge for FrameSync */
2104*4882a593Smuzhiyun 		si_gci_indirect(sih, GCI_REGIDX(GCI_LTE_FRAMESYNC_POS),
2105*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_intpolreg),
2106*4882a593Smuzhiyun 			(1 << GCI_BITOFFSET(GCI_LTE_FRAMESYNC_POS)),
2107*4882a593Smuzhiyun 			(1 << GCI_BITOFFSET(GCI_LTE_FRAMESYNC_POS)));
2108*4882a593Smuzhiyun 	}
2109*4882a593Smuzhiyun 	if (GCIREV(sih->gcirev) >= 4) {
2110*4882a593Smuzhiyun 		/* Program SECI_IN Control Register */
2111*4882a593Smuzhiyun 		si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2112*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_seciin_ctrl), ALLONES_32,
2113*4882a593Smuzhiyun 			((GCI_MODE_BTSIG << GCI_SECIIN_MODE_OFFSET)
2114*4882a593Smuzhiyun 			 |(gcigpioin << GCI_SECIIN_GCIGPIO_OFFSET)
2115*4882a593Smuzhiyun 			 |(GCI_LTE_IP_ID << GCI_SECIIN_RXID2IP_OFFSET)));
2116*4882a593Smuzhiyun 
2117*4882a593Smuzhiyun 		/* Program GPIO Control Register for SECI_IN GCI GPIO */
2118*4882a593Smuzhiyun 		si_gci_indirect(sih, gcigpioin/4, GCI_OFFSETOF(sih, gci_gpioctl),
2119*4882a593Smuzhiyun 			(0xFF << (gcigpioin%4)*8),
2120*4882a593Smuzhiyun 			(((1 << GCI_GPIOCTL_INEN_OFFSET)
2121*4882a593Smuzhiyun 			 |(1 << GCI_GPIOCTL_PDN_OFFSET)) << (gcigpioin%4)*8));
2122*4882a593Smuzhiyun 
2123*4882a593Smuzhiyun 		/* Program SECI_OUT Control Register */
2124*4882a593Smuzhiyun 		si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2125*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_seciout_ctrl), ALLONES_32,
2126*4882a593Smuzhiyun 			((GCI_MODE_BTSIG << GCI_SECIOUT_MODE_OFFSET)
2127*4882a593Smuzhiyun 			 |(gcigpioout << GCI_SECIOUT_GCIGPIO_OFFSET)
2128*4882a593Smuzhiyun 			 |((1 << GCI_LTECX_SECI_ID) << GCI_SECIOUT_SECIINRELATED_OFFSET)));
2129*4882a593Smuzhiyun 
2130*4882a593Smuzhiyun 		/* Program GPIO Control Register for SECI_OUT GCI GPIO */
2131*4882a593Smuzhiyun 		si_gci_indirect(sih, gcigpioout/4, GCI_OFFSETOF(sih, gci_gpioctl),
2132*4882a593Smuzhiyun 			(0xFF << (gcigpioout%4)*8),
2133*4882a593Smuzhiyun 			(((1 << GCI_GPIOCTL_OUTEN_OFFSET)) << (gcigpioout%4)*8));
2134*4882a593Smuzhiyun 
2135*4882a593Smuzhiyun 		/* Program SECI_IN Aux FIFO enable for LTECX SECI_IN Port */
2136*4882a593Smuzhiyun 		if (GCIREV(sih->gcirev) >= 16) {
2137*4882a593Smuzhiyun 			si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2138*4882a593Smuzhiyun 				GCI_OFFSETOF(sih, gci_seciin_auxfifo_en),
2139*4882a593Smuzhiyun 				(((1 << GCI_LTECX_SECI_ID) << GCI_SECIAUX_RXENABLE_OFFSET)
2140*4882a593Smuzhiyun 				|((1 << GCI_LTECX_SECI_ID) << GCI_SECIFIFO_RXENABLE_OFFSET)),
2141*4882a593Smuzhiyun 				(((1 << GCI_LTECX_SECI_ID) << GCI_SECIAUX_RXENABLE_OFFSET)
2142*4882a593Smuzhiyun 				|((1 << GCI_LTECX_SECI_ID) << GCI_SECIFIFO_RXENABLE_OFFSET)));
2143*4882a593Smuzhiyun 		} else {
2144*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_seciin_auxfifo_en),
2145*4882a593Smuzhiyun 				(((1 << GCI_LTECX_SECI_ID) << GCI_SECIAUX_RXENABLE_OFFSET)
2146*4882a593Smuzhiyun 				|((1 << GCI_LTECX_SECI_ID) << GCI_SECIFIFO_RXENABLE_OFFSET)),
2147*4882a593Smuzhiyun 				(((1 << GCI_LTECX_SECI_ID) << GCI_SECIAUX_RXENABLE_OFFSET)
2148*4882a593Smuzhiyun 				|((1 << GCI_LTECX_SECI_ID) << GCI_SECIFIFO_RXENABLE_OFFSET)));
2149*4882a593Smuzhiyun 		}
2150*4882a593Smuzhiyun 		/* Program SECI_OUT Tx Enable for LTECX SECI_OUT Port */
2151*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_seciout_txen_txbr), ALLONES_32,
2152*4882a593Smuzhiyun 			((1 << GCI_LTECX_SECI_ID) << GCI_SECITX_ENABLE_OFFSET));
2153*4882a593Smuzhiyun 	}
2154*4882a593Smuzhiyun 	if (GCIREV(sih->gcirev) >= 5) {
2155*4882a593Smuzhiyun 		/* enable WlPrio/TxOn override from D11 */
2156*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_miscctl),
2157*4882a593Smuzhiyun 			(1 << GCI_LTECX_TXCONF_EN_OFFSET | 1 << GCI_LTECX_PRISEL_EN_OFFSET),
2158*4882a593Smuzhiyun 			(1 << GCI_LTECX_TXCONF_EN_OFFSET | 1 << GCI_LTECX_PRISEL_EN_OFFSET));
2159*4882a593Smuzhiyun 	} else {
2160*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_miscctl),
2161*4882a593Smuzhiyun 			(1 << GCI_LTECX_TXCONF_EN_OFFSET | 1 << GCI_LTECX_PRISEL_EN_OFFSET),
2162*4882a593Smuzhiyun 			0x0000);
2163*4882a593Smuzhiyun 	}
2164*4882a593Smuzhiyun 	/* baudrate: 1/2/3/4mbps, escseq:0xdb, high baudrate, enable seci_tx/rx */
2165*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secifcr), ALLONES_32, 0x00);
2166*4882a593Smuzhiyun 	if (GCIREV(sih->gcirev) >= 15) {
2167*4882a593Smuzhiyun 		si_gci_indirect(sih, GCI_LTECX_SECI_ID, GCI_OFFSETOF(sih, gci_secilcr),
2168*4882a593Smuzhiyun 			ALLONES_32, 0x00);
2169*4882a593Smuzhiyun 	} else if (GCIREV(sih->gcirev) >= 4) {
2170*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secilcr), ALLONES_32, 0x00);
2171*4882a593Smuzhiyun 	} else {
2172*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secilcr), ALLONES_32, 0x28);
2173*4882a593Smuzhiyun 	}
2174*4882a593Smuzhiyun 	si_gci_direct(sih, GCI_OFFSETOF(sih, gci_seciuartescval), ALLONES_32, 0xDB);
2175*4882a593Smuzhiyun 
2176*4882a593Smuzhiyun 	switch (baud) {
2177*4882a593Smuzhiyun 	case 1:
2178*4882a593Smuzhiyun 		/* baudrate:1mbps */
2179*4882a593Smuzhiyun 		if (GCIREV(sih->gcirev) >= 15) {
2180*4882a593Smuzhiyun 			si_gci_indirect(sih, GCI_LTECX_SECI_ID, GCI_OFFSETOF(sih, gci_secibauddiv),
2181*4882a593Smuzhiyun 				ALLONES_32, 0xFE);
2182*4882a593Smuzhiyun 		} else {
2183*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv),
2184*4882a593Smuzhiyun 				ALLONES_32, 0xFE);
2185*4882a593Smuzhiyun 		}
2186*4882a593Smuzhiyun 		if (GCIREV(sih->gcirev) >= 15) {
2187*4882a593Smuzhiyun 			si_gci_indirect(sih, GCI_LTECX_SECI_ID, GCI_OFFSETOF(sih, gci_secimcr),
2188*4882a593Smuzhiyun 				ALLONES_32, 0x80);
2189*4882a593Smuzhiyun 		} else if (GCIREV(sih->gcirev) >= 4) {
2190*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2191*4882a593Smuzhiyun 				ALLONES_32, 0x80);
2192*4882a593Smuzhiyun 		} else {
2193*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2194*4882a593Smuzhiyun 				ALLONES_32, 0x81);
2195*4882a593Smuzhiyun 		}
2196*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_baudadj),
2197*4882a593Smuzhiyun 			ALLONES_32, 0x23);
2198*4882a593Smuzhiyun 		break;
2199*4882a593Smuzhiyun 
2200*4882a593Smuzhiyun 	case 2:
2201*4882a593Smuzhiyun 		/* baudrate:2mbps */
2202*4882a593Smuzhiyun 		if (xtalfreq == XTAL_FREQ_26000KHZ) {
2203*4882a593Smuzhiyun 			/* 43430 A0 uses 26 MHz crystal.
2204*4882a593Smuzhiyun 			 * Baudrate settings for crystel freq 26 MHz
2205*4882a593Smuzhiyun 			 */
2206*4882a593Smuzhiyun 			if (GCIREV(sih->gcirev) >= 15) {
2207*4882a593Smuzhiyun 				si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2208*4882a593Smuzhiyun 					GCI_OFFSETOF(sih, gci_secibauddiv), ALLONES_32, 0xFF);
2209*4882a593Smuzhiyun 			} else {
2210*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv),
2211*4882a593Smuzhiyun 					ALLONES_32, 0xFF);
2212*4882a593Smuzhiyun 			}
2213*4882a593Smuzhiyun 			if (GCIREV(sih->gcirev) >= 15) {
2214*4882a593Smuzhiyun 				si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2215*4882a593Smuzhiyun 					GCI_OFFSETOF(sih, gci_secimcr), ALLONES_32, 0x80);
2216*4882a593Smuzhiyun 			} else {
2217*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2218*4882a593Smuzhiyun 					ALLONES_32, 0x80);
2219*4882a593Smuzhiyun 			}
2220*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_baudadj),
2221*4882a593Smuzhiyun 					ALLONES_32, 0x0);
2222*4882a593Smuzhiyun 		}
2223*4882a593Smuzhiyun 		else {
2224*4882a593Smuzhiyun 			if (GCIREV(sih->gcirev) >= 15) {
2225*4882a593Smuzhiyun 				si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2226*4882a593Smuzhiyun 					GCI_OFFSETOF(sih, gci_secibauddiv), ALLONES_32, 0xFF);
2227*4882a593Smuzhiyun 			} else {
2228*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv),
2229*4882a593Smuzhiyun 					ALLONES_32, 0xFF);
2230*4882a593Smuzhiyun 			}
2231*4882a593Smuzhiyun 			if (GCIREV(sih->gcirev) >= 15) {
2232*4882a593Smuzhiyun 				si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2233*4882a593Smuzhiyun 					GCI_OFFSETOF(sih, gci_secimcr), ALLONES_32, 0x80);
2234*4882a593Smuzhiyun 			} else if (GCIREV(sih->gcirev) >= 4) {
2235*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2236*4882a593Smuzhiyun 						ALLONES_32, 0x80);
2237*4882a593Smuzhiyun 			} else {
2238*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2239*4882a593Smuzhiyun 						ALLONES_32, 0x81);
2240*4882a593Smuzhiyun 			}
2241*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_baudadj),
2242*4882a593Smuzhiyun 					ALLONES_32, 0x11);
2243*4882a593Smuzhiyun 		}
2244*4882a593Smuzhiyun 		break;
2245*4882a593Smuzhiyun 
2246*4882a593Smuzhiyun 	case 4:
2247*4882a593Smuzhiyun 		/* baudrate:4mbps */
2248*4882a593Smuzhiyun 		if (GCIREV(sih->gcirev) >= 15) {
2249*4882a593Smuzhiyun 			si_gci_indirect(sih, GCI_LTECX_SECI_ID, GCI_OFFSETOF(sih, gci_secibauddiv),
2250*4882a593Smuzhiyun 				ALLONES_32, 0xF7);
2251*4882a593Smuzhiyun 		} else {
2252*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv),
2253*4882a593Smuzhiyun 				ALLONES_32, 0xF7);
2254*4882a593Smuzhiyun 		}
2255*4882a593Smuzhiyun 		if (GCIREV(sih->gcirev) >= 15) {
2256*4882a593Smuzhiyun 			si_gci_indirect(sih, GCI_LTECX_SECI_ID, GCI_OFFSETOF(sih, gci_secimcr),
2257*4882a593Smuzhiyun 				ALLONES_32, 0x8);
2258*4882a593Smuzhiyun 		} else if (GCIREV(sih->gcirev) >= 4) {
2259*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2260*4882a593Smuzhiyun 				ALLONES_32, 0x8);
2261*4882a593Smuzhiyun 		} else {
2262*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2263*4882a593Smuzhiyun 				ALLONES_32, 0x9);
2264*4882a593Smuzhiyun 		}
2265*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_baudadj),
2266*4882a593Smuzhiyun 			ALLONES_32, 0x0);
2267*4882a593Smuzhiyun 		break;
2268*4882a593Smuzhiyun 
2269*4882a593Smuzhiyun 	case 25:
2270*4882a593Smuzhiyun 		/* baudrate:2.5mbps */
2271*4882a593Smuzhiyun 		if (xtalfreq == XTAL_FREQ_26000KHZ) {
2272*4882a593Smuzhiyun 			/* 43430 A0 uses 26 MHz crystal.
2273*4882a593Smuzhiyun 			  * Baudrate settings for crystel freq 26 MHz
2274*4882a593Smuzhiyun 			  */
2275*4882a593Smuzhiyun 			if (GCIREV(sih->gcirev) >= 15) {
2276*4882a593Smuzhiyun 				si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2277*4882a593Smuzhiyun 					GCI_OFFSETOF(sih, gci_secibauddiv), ALLONES_32, 0xF6);
2278*4882a593Smuzhiyun 			} else {
2279*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv),
2280*4882a593Smuzhiyun 					ALLONES_32, 0xF6);
2281*4882a593Smuzhiyun 			}
2282*4882a593Smuzhiyun 		} else if (xtalfreq == XTAL_FREQ_59970KHZ) {
2283*4882a593Smuzhiyun 			/* 4387 uses 60M MHz crystal.
2284*4882a593Smuzhiyun 			  * Baudrate settings for crystel freq/2 29.9 MHz
2285*4882a593Smuzhiyun 			  * set bauddiv to 0xF4 to achieve 2.5M for Xtal/2 @ 29.9MHz
2286*4882a593Smuzhiyun 			  * bauddiv = 256-Integer Part of (GCI clk freq/baudrate)
2287*4882a593Smuzhiyun 			  */
2288*4882a593Smuzhiyun 			if (GCIREV(sih->gcirev) >= 15) {
2289*4882a593Smuzhiyun 				si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2290*4882a593Smuzhiyun 					GCI_OFFSETOF(sih, gci_secibauddiv), ALLONES_32, 0xF4);
2291*4882a593Smuzhiyun 			} else {
2292*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv),
2293*4882a593Smuzhiyun 					ALLONES_32, 0xF4);
2294*4882a593Smuzhiyun 			}
2295*4882a593Smuzhiyun 		} else {
2296*4882a593Smuzhiyun 			if (GCIREV(sih->gcirev) >= 15) {
2297*4882a593Smuzhiyun 				si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2298*4882a593Smuzhiyun 					GCI_OFFSETOF(sih, gci_secibauddiv), ALLONES_32, 0xF1);
2299*4882a593Smuzhiyun 			} else {
2300*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv),
2301*4882a593Smuzhiyun 					ALLONES_32, 0xF1);
2302*4882a593Smuzhiyun 			}
2303*4882a593Smuzhiyun 		}
2304*4882a593Smuzhiyun 		if (GCIREV(sih->gcirev) >= 15) {
2305*4882a593Smuzhiyun 			si_gci_indirect(sih, GCI_LTECX_SECI_ID, GCI_OFFSETOF(sih, gci_secimcr),
2306*4882a593Smuzhiyun 				ALLONES_32, 0x8);
2307*4882a593Smuzhiyun 		} else if (GCIREV(sih->gcirev) >= 4) {
2308*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2309*4882a593Smuzhiyun 				ALLONES_32, 0x8);
2310*4882a593Smuzhiyun 		} else {
2311*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2312*4882a593Smuzhiyun 				ALLONES_32, 0x9);
2313*4882a593Smuzhiyun 		}
2314*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_baudadj),
2315*4882a593Smuzhiyun 			ALLONES_32, 0x0);
2316*4882a593Smuzhiyun 		break;
2317*4882a593Smuzhiyun 
2318*4882a593Smuzhiyun 	case 3:
2319*4882a593Smuzhiyun 	default:
2320*4882a593Smuzhiyun 		/* baudrate:3mbps */
2321*4882a593Smuzhiyun 		if (xtalfreq == XTAL_FREQ_26000KHZ) {
2322*4882a593Smuzhiyun 			/* 43430 A0 uses 26 MHz crystal.
2323*4882a593Smuzhiyun 			  * Baudrate settings for crystel freq 26 MHz
2324*4882a593Smuzhiyun 			  */
2325*4882a593Smuzhiyun 			if (GCIREV(sih->gcirev) >= 15) {
2326*4882a593Smuzhiyun 				si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2327*4882a593Smuzhiyun 					GCI_OFFSETOF(sih, gci_secibauddiv), ALLONES_32, 0xF7);
2328*4882a593Smuzhiyun 			} else {
2329*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv),
2330*4882a593Smuzhiyun 					ALLONES_32, 0xF7);
2331*4882a593Smuzhiyun 			}
2332*4882a593Smuzhiyun 		} else {
2333*4882a593Smuzhiyun 			if (GCIREV(sih->gcirev) >= 15) {
2334*4882a593Smuzhiyun 				si_gci_indirect(sih, GCI_LTECX_SECI_ID,
2335*4882a593Smuzhiyun 					GCI_OFFSETOF(sih, gci_secibauddiv), ALLONES_32, 0xF4);
2336*4882a593Smuzhiyun 			} else {
2337*4882a593Smuzhiyun 				si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secibauddiv),
2338*4882a593Smuzhiyun 					ALLONES_32, 0xF4);
2339*4882a593Smuzhiyun 			}
2340*4882a593Smuzhiyun 		}
2341*4882a593Smuzhiyun 		if (GCIREV(sih->gcirev) >= 15) {
2342*4882a593Smuzhiyun 			si_gci_indirect(sih, GCI_LTECX_SECI_ID, GCI_OFFSETOF(sih, gci_secimcr),
2343*4882a593Smuzhiyun 				ALLONES_32, 0x8);
2344*4882a593Smuzhiyun 		} else if (GCIREV(sih->gcirev) >= 4) {
2345*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2346*4882a593Smuzhiyun 				ALLONES_32, 0x8);
2347*4882a593Smuzhiyun 		} else {
2348*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_secimcr),
2349*4882a593Smuzhiyun 				ALLONES_32, 0x9);
2350*4882a593Smuzhiyun 		}
2351*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_baudadj),
2352*4882a593Smuzhiyun 			ALLONES_32, 0x0);
2353*4882a593Smuzhiyun 		break;
2354*4882a593Smuzhiyun 	}
2355*4882a593Smuzhiyun 	/* GCI Rev >= 1 */
2356*4882a593Smuzhiyun 	if (GCIREV(sih->gcirev) >= 1) {
2357*4882a593Smuzhiyun 		/* Route Rx-data through AUX register */
2358*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_rxfifo_common_ctrl),
2359*4882a593Smuzhiyun 			GCI_RXFIFO_CTRL_AUX_EN, GCI_RXFIFO_CTRL_AUX_EN);
2360*4882a593Smuzhiyun #if !defined(WLTEST)
2361*4882a593Smuzhiyun 		/* Route RX Type 2 data through RX FIFO */
2362*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_rxfifo_common_ctrl),
2363*4882a593Smuzhiyun 			GCI_RXFIFO_CTRL_FIFO_TYPE2_EN, GCI_RXFIFO_CTRL_FIFO_TYPE2_EN);
2364*4882a593Smuzhiyun 		/* Enable Inband interrupt for RX FIFO status */
2365*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_intmask),
2366*4882a593Smuzhiyun 			(GCI_INTSTATUS_SRFNE | GCI_INTSTATUS_SRFOF),
2367*4882a593Smuzhiyun 			(GCI_INTSTATUS_SRFNE | GCI_INTSTATUS_SRFOF));
2368*4882a593Smuzhiyun #endif /* !WLTEST */
2369*4882a593Smuzhiyun 	} else {
2370*4882a593Smuzhiyun 		/* GPIO 3-7 as BT_SIG complaint */
2371*4882a593Smuzhiyun 		/* config GPIO pins 3-7 as input */
2372*4882a593Smuzhiyun 		si_gci_indirect(sih, 0,
2373*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_gpioctl), 0x20000000, 0x20000010);
2374*4882a593Smuzhiyun 		si_gci_indirect(sih, 1,
2375*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_gpioctl), 0x20202020, 0x20202020);
2376*4882a593Smuzhiyun 		/* gpio mapping: frmsync-gpio7, mws_rx-gpio6, mws_tx-gpio5,
2377*4882a593Smuzhiyun 		 * pat[0]-gpio4, pat[1]-gpio3
2378*4882a593Smuzhiyun 		 */
2379*4882a593Smuzhiyun 		si_gci_indirect(sih, 0x70010,
2380*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_gpiomask), 0x00000001, 0x00000001);
2381*4882a593Smuzhiyun 		si_gci_indirect(sih, 0x60010,
2382*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_gpiomask), 0x00000002, 0x00000002);
2383*4882a593Smuzhiyun 		si_gci_indirect(sih, 0x50010,
2384*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_gpiomask), 0x00000004, 0x00000004);
2385*4882a593Smuzhiyun 		si_gci_indirect(sih, 0x40010,
2386*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_gpiomask), 0x02000000, 0x00000008);
2387*4882a593Smuzhiyun 		si_gci_indirect(sih, 0x30010,
2388*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_gpiomask), 0x04000000, 0x04000010);
2389*4882a593Smuzhiyun 		/* gpio mapping: wlan_rx_prio-gpio5, wlan_tx_on-gpio4 */
2390*4882a593Smuzhiyun 		si_gci_indirect(sih, 0x50000,
2391*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_gpiomask), 0x00000010, 0x00000010);
2392*4882a593Smuzhiyun 		si_gci_indirect(sih, 0x40000,
2393*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_gpiomask), 0x00000020, 0x00000020);
2394*4882a593Smuzhiyun 		/* enable gpio out on gpio4(wlanrxprio), gpio5(wlantxon) */
2395*4882a593Smuzhiyun 		si_gci_direct(sih,
2396*4882a593Smuzhiyun 			GCI_OFFSETOF(sih, gci_control_0), 0x00000030, 0x00000000);
2397*4882a593Smuzhiyun 	}
2398*4882a593Smuzhiyun }
2399*4882a593Smuzhiyun #endif /* BCMLTECOEX */
2400*4882a593Smuzhiyun 
2401*4882a593Smuzhiyun /* This function is used in AIBSS mode by BTCX to enable strobing to BT */
2402*4882a593Smuzhiyun bool
si_btcx_wci2_init(si_t * sih)2403*4882a593Smuzhiyun si_btcx_wci2_init(si_t *sih)
2404*4882a593Smuzhiyun {
2405*4882a593Smuzhiyun 	/* reset GCI block */
2406*4882a593Smuzhiyun 	si_gci_reset(sih);
2407*4882a593Smuzhiyun 
2408*4882a593Smuzhiyun 	if (GCIREV(sih->gcirev) >= 1) {
2409*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_corectrl),
2410*4882a593Smuzhiyun 			((GCI_CCTL_SCS_MASK << GCI_CCTL_SCS_OFFSET)
2411*4882a593Smuzhiyun 			|(GCI_CCTL_LOWTOUT_MASK << GCI_CCTL_SILOWTOUT_OFFSET)
2412*4882a593Smuzhiyun 			|(1 << GCI_CCTL_BRKONSLP_OFFSET)
2413*4882a593Smuzhiyun 			|(1 << GCI_CCTL_US_OFFSET)
2414*4882a593Smuzhiyun 			|(GCI_MODE_MASK << GCI_CCTL_SMODE_OFFSET)
2415*4882a593Smuzhiyun 			|(1 << GCI_CCTL_FSL_OFFSET)
2416*4882a593Smuzhiyun 			|(1 << GCI_CCTL_SECIEN_OFFSET)),
2417*4882a593Smuzhiyun 			((GCI_CCTL_SCS_DEF << GCI_CCTL_SCS_OFFSET)
2418*4882a593Smuzhiyun 			|(GCI_CCTL_LOWTOUT_30BIT << GCI_CCTL_SILOWTOUT_OFFSET)
2419*4882a593Smuzhiyun 			|(0 << GCI_CCTL_BRKONSLP_OFFSET)
2420*4882a593Smuzhiyun 			|(0 << GCI_CCTL_US_OFFSET)
2421*4882a593Smuzhiyun 			|(GCI_MODE_BTSIG << GCI_CCTL_SMODE_OFFSET)
2422*4882a593Smuzhiyun 			|(0 << GCI_CCTL_FSL_OFFSET)
2423*4882a593Smuzhiyun 			|(1 << GCI_CCTL_SECIEN_OFFSET))); /* 19000024 */
2424*4882a593Smuzhiyun 		return TRUE;
2425*4882a593Smuzhiyun 	}
2426*4882a593Smuzhiyun 	return FALSE;
2427*4882a593Smuzhiyun }
2428*4882a593Smuzhiyun 
2429*4882a593Smuzhiyun void
si_gci_uart_init(si_t * sih,osl_t * osh,uint8 seci_mode)2430*4882a593Smuzhiyun si_gci_uart_init(si_t *sih, osl_t *osh, uint8 seci_mode)
2431*4882a593Smuzhiyun {
2432*4882a593Smuzhiyun #ifdef	HNDGCI
2433*4882a593Smuzhiyun 	hndgci_init(sih, osh, HND_GCI_PLAIN_UART_MODE,
2434*4882a593Smuzhiyun 		GCI_UART_BR_115200);
2435*4882a593Smuzhiyun 
2436*4882a593Smuzhiyun 	/* specify rx callback */
2437*4882a593Smuzhiyun 	hndgci_uart_config_rx_complete(-1, -1, 0, NULL, NULL);
2438*4882a593Smuzhiyun #else
2439*4882a593Smuzhiyun 	BCM_REFERENCE(sih);
2440*4882a593Smuzhiyun 	BCM_REFERENCE(osh);
2441*4882a593Smuzhiyun 	BCM_REFERENCE(seci_mode);
2442*4882a593Smuzhiyun #endif	/* HNDGCI */
2443*4882a593Smuzhiyun }
2444*4882a593Smuzhiyun 
2445*4882a593Smuzhiyun /**
2446*4882a593Smuzhiyun  * A given GCI pin needs to be converted to a GCI FunctionSel register offset and the bit position
2447*4882a593Smuzhiyun  * in this register.
2448*4882a593Smuzhiyun  * @param[in]  input   pin number, see respective chip Toplevel Arch page, GCI chipstatus regs
2449*4882a593Smuzhiyun  * @param[out] regidx  chipcontrol reg(ring_index base) and
2450*4882a593Smuzhiyun  * @param[out] pos     bits to shift for pin first regbit
2451*4882a593Smuzhiyun  *
2452*4882a593Smuzhiyun  * eg: gpio9 will give regidx: 1 and pos 4
2453*4882a593Smuzhiyun  */
2454*4882a593Smuzhiyun static void
BCMPOSTTRAPFN(si_gci_get_chipctrlreg_ringidx_base4)2455*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_get_chipctrlreg_ringidx_base4)(uint32 pin, uint32 *regidx, uint32 *pos)
2456*4882a593Smuzhiyun {
2457*4882a593Smuzhiyun 	*regidx = (pin / 8);
2458*4882a593Smuzhiyun 	*pos = (pin % 8) * 4; // each pin occupies 4 FunctionSel register bits
2459*4882a593Smuzhiyun 
2460*4882a593Smuzhiyun 	SI_MSG(("si_gci_get_chipctrlreg_ringidx_base4:%d:%d:%d\n", pin, *regidx, *pos));
2461*4882a593Smuzhiyun }
2462*4882a593Smuzhiyun 
2463*4882a593Smuzhiyun /* input: pin number
2464*4882a593Smuzhiyun * output: chipcontrol reg(ring_index base) and
2465*4882a593Smuzhiyun * bits to shift for pin first regbit.
2466*4882a593Smuzhiyun * eg: gpio9 will give regidx: 2 and pos 16
2467*4882a593Smuzhiyun */
2468*4882a593Smuzhiyun static uint8
BCMPOSTTRAPFN(si_gci_get_chipctrlreg_ringidx_base8)2469*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_get_chipctrlreg_ringidx_base8)(uint32 pin, uint32 *regidx, uint32 *pos)
2470*4882a593Smuzhiyun {
2471*4882a593Smuzhiyun 	*regidx = (pin / 4);
2472*4882a593Smuzhiyun 	*pos = (pin % 4)*8;
2473*4882a593Smuzhiyun 
2474*4882a593Smuzhiyun 	SI_MSG(("si_gci_get_chipctrlreg_ringidx_base8:%d:%d:%d\n", pin, *regidx, *pos));
2475*4882a593Smuzhiyun 
2476*4882a593Smuzhiyun 	return 0;
2477*4882a593Smuzhiyun }
2478*4882a593Smuzhiyun 
2479*4882a593Smuzhiyun /** setup a given pin for fnsel function */
2480*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_gci_set_functionsel)2481*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_set_functionsel)(si_t *sih, uint32 pin, uint8 fnsel)
2482*4882a593Smuzhiyun {
2483*4882a593Smuzhiyun 	uint32 reg = 0, pos = 0;
2484*4882a593Smuzhiyun 
2485*4882a593Smuzhiyun 	SI_MSG(("si_gci_set_functionsel:%d\n", pin));
2486*4882a593Smuzhiyun 
2487*4882a593Smuzhiyun 	si_gci_get_chipctrlreg_ringidx_base4(pin, &reg, &pos);
2488*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, reg, GCIMASK_4B(pos), GCIPOSVAL_4B(fnsel, pos));
2489*4882a593Smuzhiyun }
2490*4882a593Smuzhiyun 
2491*4882a593Smuzhiyun /* Returns a given pin's fnsel value */
2492*4882a593Smuzhiyun uint32
si_gci_get_functionsel(si_t * sih,uint32 pin)2493*4882a593Smuzhiyun si_gci_get_functionsel(si_t *sih, uint32 pin)
2494*4882a593Smuzhiyun {
2495*4882a593Smuzhiyun 	uint32 reg = 0, pos = 0, temp;
2496*4882a593Smuzhiyun 
2497*4882a593Smuzhiyun 	SI_MSG(("si_gci_get_functionsel: %d\n", pin));
2498*4882a593Smuzhiyun 
2499*4882a593Smuzhiyun 	si_gci_get_chipctrlreg_ringidx_base4(pin, &reg, &pos);
2500*4882a593Smuzhiyun 	temp = si_gci_chipstatus(sih, reg);
2501*4882a593Smuzhiyun 	return GCIGETNBL(temp, pos);
2502*4882a593Smuzhiyun }
2503*4882a593Smuzhiyun 
2504*4882a593Smuzhiyun /* Sets fnsel value to IND for all the GPIO pads that have fnsel set to given argument */
2505*4882a593Smuzhiyun void
si_gci_clear_functionsel(si_t * sih,uint8 fnsel)2506*4882a593Smuzhiyun si_gci_clear_functionsel(si_t *sih, uint8 fnsel)
2507*4882a593Smuzhiyun {
2508*4882a593Smuzhiyun 	uint32 i;
2509*4882a593Smuzhiyun 	SI_MSG(("si_gci_clear_functionsel: %d\n", fnsel));
2510*4882a593Smuzhiyun 	for (i = 0; i <= CC_PIN_GPIO_LAST; i++)	{
2511*4882a593Smuzhiyun 		if (si_gci_get_functionsel(sih, i) == fnsel)
2512*4882a593Smuzhiyun 			si_gci_set_functionsel(sih, i, CC_FNSEL_IND);
2513*4882a593Smuzhiyun 	}
2514*4882a593Smuzhiyun }
2515*4882a593Smuzhiyun 
2516*4882a593Smuzhiyun /** write 'val' to the gci chip control register indexed by 'reg' */
2517*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_gci_chipcontrol)2518*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_chipcontrol)(si_t *sih, uint reg, uint32 mask, uint32 val)
2519*4882a593Smuzhiyun {
2520*4882a593Smuzhiyun 	/* because NFLASH and GCI clashes in 0xC00 */
2521*4882a593Smuzhiyun 	if ((CCREV(sih->ccrev) == 38) && ((sih->chipst & (1 << 4)) != 0)) {
2522*4882a593Smuzhiyun 		/* CC NFLASH exist, prohibit to manipulate gci register */
2523*4882a593Smuzhiyun 		ASSERT(0);
2524*4882a593Smuzhiyun 		return ALLONES_32;
2525*4882a593Smuzhiyun 	}
2526*4882a593Smuzhiyun 
2527*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_indirect_addr), ~0, reg);
2528*4882a593Smuzhiyun 	return si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_chipctrl), mask, val);
2529*4882a593Smuzhiyun }
2530*4882a593Smuzhiyun 
2531*4882a593Smuzhiyun /* Read the gci chip status register indexed by 'reg' */
2532*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_gci_chipstatus)2533*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gci_chipstatus)(si_t *sih, uint reg)
2534*4882a593Smuzhiyun {
2535*4882a593Smuzhiyun 	/* because NFLASH and GCI clashes in 0xC00 */
2536*4882a593Smuzhiyun 	if ((CCREV(sih->ccrev) == 38) && ((sih->chipst & (1 << 4)) != 0)) {
2537*4882a593Smuzhiyun 		/* CC NFLASH exist, prohibit to manipulate gci register */
2538*4882a593Smuzhiyun 		ASSERT(0);
2539*4882a593Smuzhiyun 		return ALLONES_32;
2540*4882a593Smuzhiyun 	}
2541*4882a593Smuzhiyun 
2542*4882a593Smuzhiyun 	si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_indirect_addr), ~0, reg);
2543*4882a593Smuzhiyun 	/* setting mask and value to '0' to use si_corereg for read only purpose */
2544*4882a593Smuzhiyun 	return si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_chipsts), 0, 0);
2545*4882a593Smuzhiyun }
2546*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
2547*4882a593Smuzhiyun 
2548*4882a593Smuzhiyun uint16
BCMINITFN(si_chipid)2549*4882a593Smuzhiyun BCMINITFN(si_chipid)(const si_t *sih)
2550*4882a593Smuzhiyun {
2551*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
2552*4882a593Smuzhiyun 
2553*4882a593Smuzhiyun 	return (sii->chipnew) ? sii->chipnew : sih->chip;
2554*4882a593Smuzhiyun }
2555*4882a593Smuzhiyun 
2556*4882a593Smuzhiyun /* CHIP_ID's being mapped here should not be used anywhere else in the code */
2557*4882a593Smuzhiyun static void
BCMATTACHFN(si_chipid_fixup)2558*4882a593Smuzhiyun BCMATTACHFN(si_chipid_fixup)(si_t *sih)
2559*4882a593Smuzhiyun {
2560*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
2561*4882a593Smuzhiyun 
2562*4882a593Smuzhiyun 	ASSERT(sii->chipnew == 0);
2563*4882a593Smuzhiyun 	switch (sih->chip) {
2564*4882a593Smuzhiyun 		case BCM4377_CHIP_ID:
2565*4882a593Smuzhiyun 			sii->chipnew = sih->chip; /* save it */
2566*4882a593Smuzhiyun 			sii->pub.chip = BCM4369_CHIP_ID; /* chip class */
2567*4882a593Smuzhiyun 		break;
2568*4882a593Smuzhiyun 		case BCM4375_CHIP_ID:
2569*4882a593Smuzhiyun 			sii->chipnew = sih->chip; /* save it */
2570*4882a593Smuzhiyun 			sii->pub.chip = BCM4375_CHIP_ID; /* chip class */
2571*4882a593Smuzhiyun 		break;
2572*4882a593Smuzhiyun 		case BCM4362_CHIP_ID:
2573*4882a593Smuzhiyun 			sii->chipnew = sih->chip; /* save it */
2574*4882a593Smuzhiyun 			sii->pub.chip = BCM4362_CHIP_ID; /* chip class */
2575*4882a593Smuzhiyun 		break;
2576*4882a593Smuzhiyun 		case BCM4356_CHIP_ID:
2577*4882a593Smuzhiyun 		case BCM4371_CHIP_ID:
2578*4882a593Smuzhiyun 			sii->chipnew = sih->chip; /* save it */
2579*4882a593Smuzhiyun 			sii->pub.chip = BCM4354_CHIP_ID; /* chip class */
2580*4882a593Smuzhiyun 			break;
2581*4882a593Smuzhiyun 		default:
2582*4882a593Smuzhiyun 		break;
2583*4882a593Smuzhiyun 	}
2584*4882a593Smuzhiyun }
2585*4882a593Smuzhiyun 
2586*4882a593Smuzhiyun #ifdef AXI_TIMEOUTS_NIC
2587*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_clear_backplane_to_fast)2588*4882a593Smuzhiyun BCMPOSTTRAPFN(si_clear_backplane_to_fast)(void *sih, void *addr)
2589*4882a593Smuzhiyun {
2590*4882a593Smuzhiyun 	si_t *_sih = DISCARD_QUAL(sih, si_t);
2591*4882a593Smuzhiyun 
2592*4882a593Smuzhiyun 	if (CHIPTYPE(_sih->socitype) == SOCI_AI) {
2593*4882a593Smuzhiyun 		return ai_clear_backplane_to_fast(_sih, addr);
2594*4882a593Smuzhiyun 	}
2595*4882a593Smuzhiyun 
2596*4882a593Smuzhiyun 	return 0;
2597*4882a593Smuzhiyun }
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun const si_axi_error_info_t *
si_get_axi_errlog_info(const si_t * sih)2600*4882a593Smuzhiyun si_get_axi_errlog_info(const si_t *sih)
2601*4882a593Smuzhiyun {
2602*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI) {
2603*4882a593Smuzhiyun 		return (const si_axi_error_info_t *)sih->err_info;
2604*4882a593Smuzhiyun 	}
2605*4882a593Smuzhiyun 
2606*4882a593Smuzhiyun 	return NULL;
2607*4882a593Smuzhiyun }
2608*4882a593Smuzhiyun 
2609*4882a593Smuzhiyun void
si_reset_axi_errlog_info(const si_t * sih)2610*4882a593Smuzhiyun si_reset_axi_errlog_info(const si_t *sih)
2611*4882a593Smuzhiyun {
2612*4882a593Smuzhiyun 	if (sih->err_info) {
2613*4882a593Smuzhiyun 		sih->err_info->count = 0;
2614*4882a593Smuzhiyun 	}
2615*4882a593Smuzhiyun }
2616*4882a593Smuzhiyun #endif /* AXI_TIMEOUTS_NIC */
2617*4882a593Smuzhiyun 
2618*4882a593Smuzhiyun /* TODO: Can we allocate only one instance? */
2619*4882a593Smuzhiyun static int32
BCMATTACHFN(si_alloc_wrapper)2620*4882a593Smuzhiyun BCMATTACHFN(si_alloc_wrapper)(si_info_t *sii)
2621*4882a593Smuzhiyun {
2622*4882a593Smuzhiyun 	if (sii->osh) {
2623*4882a593Smuzhiyun 		sii->axi_wrapper = (axi_wrapper_t *)MALLOCZ(sii->osh,
2624*4882a593Smuzhiyun 			(sizeof(axi_wrapper_t) * SI_MAX_AXI_WRAPPERS));
2625*4882a593Smuzhiyun 
2626*4882a593Smuzhiyun 		if (sii->axi_wrapper == NULL) {
2627*4882a593Smuzhiyun 			return BCME_NOMEM;
2628*4882a593Smuzhiyun 		}
2629*4882a593Smuzhiyun 	} else {
2630*4882a593Smuzhiyun 		sii->axi_wrapper = NULL;
2631*4882a593Smuzhiyun 		return BCME_ERROR;
2632*4882a593Smuzhiyun 	}
2633*4882a593Smuzhiyun 	return BCME_OK;
2634*4882a593Smuzhiyun }
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun static void
BCMATTACHFN(si_free_wrapper)2637*4882a593Smuzhiyun BCMATTACHFN(si_free_wrapper)(si_info_t *sii)
2638*4882a593Smuzhiyun {
2639*4882a593Smuzhiyun 	if (sii->axi_wrapper) {
2640*4882a593Smuzhiyun 
2641*4882a593Smuzhiyun 		MFREE(sii->osh, sii->axi_wrapper, (sizeof(axi_wrapper_t) * SI_MAX_AXI_WRAPPERS));
2642*4882a593Smuzhiyun 	}
2643*4882a593Smuzhiyun }
2644*4882a593Smuzhiyun 
2645*4882a593Smuzhiyun static void *
BCMATTACHFN(si_alloc_coresinfo)2646*4882a593Smuzhiyun BCMATTACHFN(si_alloc_coresinfo)(si_info_t *sii, osl_t *osh, chipcregs_t *cc)
2647*4882a593Smuzhiyun {
2648*4882a593Smuzhiyun 	if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) {
2649*4882a593Smuzhiyun 		sii->nci_info = nci_init(&sii->pub, (void*)(uintptr)cc, sii->pub.bustype);
2650*4882a593Smuzhiyun 
2651*4882a593Smuzhiyun 		return sii->nci_info;
2652*4882a593Smuzhiyun 
2653*4882a593Smuzhiyun 	} else {
2654*4882a593Smuzhiyun 
2655*4882a593Smuzhiyun #ifdef _RTE_
2656*4882a593Smuzhiyun 		sii->cores_info = (si_cores_info_t *)&ksii_cores_info;
2657*4882a593Smuzhiyun #else
2658*4882a593Smuzhiyun 		if (sii->cores_info == NULL) {
2659*4882a593Smuzhiyun 			/* alloc si_cores_info_t */
2660*4882a593Smuzhiyun 			if ((sii->cores_info = (si_cores_info_t *)MALLOCZ(osh,
2661*4882a593Smuzhiyun 				sizeof(si_cores_info_t))) == NULL) {
2662*4882a593Smuzhiyun 				SI_ERROR(("si_attach: malloc failed for cores_info! malloced"
2663*4882a593Smuzhiyun 					" %d bytes\n", MALLOCED(osh)));
2664*4882a593Smuzhiyun 				return (NULL);
2665*4882a593Smuzhiyun 			}
2666*4882a593Smuzhiyun 		} else {
2667*4882a593Smuzhiyun 			ASSERT(sii->cores_info == &ksii_cores_info);
2668*4882a593Smuzhiyun 
2669*4882a593Smuzhiyun 		}
2670*4882a593Smuzhiyun #endif /* _RTE_ */
2671*4882a593Smuzhiyun 		return sii->cores_info;
2672*4882a593Smuzhiyun 	}
2673*4882a593Smuzhiyun 
2674*4882a593Smuzhiyun }
2675*4882a593Smuzhiyun 
2676*4882a593Smuzhiyun static void
BCMATTACHFN(si_free_coresinfo)2677*4882a593Smuzhiyun BCMATTACHFN(si_free_coresinfo)(si_info_t *sii, osl_t *osh)
2678*4882a593Smuzhiyun {
2679*4882a593Smuzhiyun 
2680*4882a593Smuzhiyun 	if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) {
2681*4882a593Smuzhiyun 		if (sii->nci_info) {
2682*4882a593Smuzhiyun 			nci_uninit(sii->nci_info);
2683*4882a593Smuzhiyun 			sii->nci_info = NULL;
2684*4882a593Smuzhiyun 		}
2685*4882a593Smuzhiyun 	} else {
2686*4882a593Smuzhiyun 		if (sii->cores_info && (sii->cores_info != &ksii_cores_info)) {
2687*4882a593Smuzhiyun 			MFREE(osh, sii->cores_info, sizeof(si_cores_info_t));
2688*4882a593Smuzhiyun 		}
2689*4882a593Smuzhiyun 	}
2690*4882a593Smuzhiyun }
2691*4882a593Smuzhiyun 
2692*4882a593Smuzhiyun /**
2693*4882a593Smuzhiyun  * Allocate an si handle. This function may be called multiple times. This function is called by
2694*4882a593Smuzhiyun  * both si_attach() and si_kattach().
2695*4882a593Smuzhiyun  *
2696*4882a593Smuzhiyun  * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this
2697*4882a593Smuzhiyun  *        function set 'vars' to NULL.
2698*4882a593Smuzhiyun  */
2699*4882a593Smuzhiyun static si_info_t *
BCMATTACHFN(si_doattach)2700*4882a593Smuzhiyun BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs,
2701*4882a593Smuzhiyun                        uint bustype, void *sdh, char **vars, uint *varsz)
2702*4882a593Smuzhiyun {
2703*4882a593Smuzhiyun 	struct si_pub *sih = &sii->pub;
2704*4882a593Smuzhiyun 	uint32 w, savewin;
2705*4882a593Smuzhiyun 	chipcregs_t *cc;
2706*4882a593Smuzhiyun 	char *pvars = NULL;
2707*4882a593Smuzhiyun 	uint origidx;
2708*4882a593Smuzhiyun #if defined(NVSRCX)
2709*4882a593Smuzhiyun 	char *sromvars;
2710*4882a593Smuzhiyun #endif
2711*4882a593Smuzhiyun 	uint err_at = 0;
2712*4882a593Smuzhiyun 
2713*4882a593Smuzhiyun 	ASSERT(GOODREGS(regs));
2714*4882a593Smuzhiyun 
2715*4882a593Smuzhiyun 	savewin = 0;
2716*4882a593Smuzhiyun 
2717*4882a593Smuzhiyun 	sih->buscoreidx = BADIDX;
2718*4882a593Smuzhiyun 	sii->device_removed = FALSE;
2719*4882a593Smuzhiyun 
2720*4882a593Smuzhiyun 	sii->curmap = regs;
2721*4882a593Smuzhiyun 	sii->sdh = sdh;
2722*4882a593Smuzhiyun 	sii->osh = osh;
2723*4882a593Smuzhiyun 	sii->second_bar0win = ~0x0;
2724*4882a593Smuzhiyun 	sih->enum_base = si_enum_base(devid);
2725*4882a593Smuzhiyun 
2726*4882a593Smuzhiyun #if defined(AXI_TIMEOUTS_NIC)
2727*4882a593Smuzhiyun 	sih->err_info = MALLOCZ(osh, sizeof(si_axi_error_info_t));
2728*4882a593Smuzhiyun 	if (sih->err_info == NULL) {
2729*4882a593Smuzhiyun 		SI_ERROR(("si_doattach: %zu bytes MALLOC FAILED",
2730*4882a593Smuzhiyun 			sizeof(si_axi_error_info_t)));
2731*4882a593Smuzhiyun 	}
2732*4882a593Smuzhiyun #endif /* AXI_TIMEOUTS_NIC */
2733*4882a593Smuzhiyun 
2734*4882a593Smuzhiyun #if defined(AXI_TIMEOUTS_NIC) && defined(__linux__)
2735*4882a593Smuzhiyun 	osl_set_bpt_cb(osh, (void *)si_clear_backplane_to_fast, (void *)sih);
2736*4882a593Smuzhiyun #endif	/* AXI_TIMEOUTS_NIC && linux */
2737*4882a593Smuzhiyun 
2738*4882a593Smuzhiyun 	/* check to see if we are a si core mimic'ing a pci core */
2739*4882a593Smuzhiyun 	if ((bustype == PCI_BUS) &&
2740*4882a593Smuzhiyun 	    (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(uint32)) == 0xffffffff)) {
2741*4882a593Smuzhiyun 		SI_ERROR(("si_doattach: incoming bus is PCI but it's a lie, switching to SI "
2742*4882a593Smuzhiyun 		          "devid:0x%x\n", devid));
2743*4882a593Smuzhiyun 		bustype = SI_BUS;
2744*4882a593Smuzhiyun 	}
2745*4882a593Smuzhiyun 
2746*4882a593Smuzhiyun 	/* find Chipcommon address */
2747*4882a593Smuzhiyun 	if (bustype == PCI_BUS) {
2748*4882a593Smuzhiyun 		savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32));
2749*4882a593Smuzhiyun 		/* PR 29857: init to core0 if bar0window is not programmed properly */
2750*4882a593Smuzhiyun 		if (!GOODCOREADDR(savewin, SI_ENUM_BASE(sih)))
2751*4882a593Smuzhiyun 			savewin = SI_ENUM_BASE(sih);
2752*4882a593Smuzhiyun 		OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE(sih));
2753*4882a593Smuzhiyun 		if (!regs) {
2754*4882a593Smuzhiyun 			err_at = 1;
2755*4882a593Smuzhiyun 			goto exit;
2756*4882a593Smuzhiyun 		}
2757*4882a593Smuzhiyun 		cc = (chipcregs_t *)regs;
2758*4882a593Smuzhiyun #ifdef BCMSDIO
2759*4882a593Smuzhiyun 	} else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) {
2760*4882a593Smuzhiyun 		cc = (chipcregs_t *)sii->curmap;
2761*4882a593Smuzhiyun #endif
2762*4882a593Smuzhiyun 	} else {
2763*4882a593Smuzhiyun 		cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE(sih), SI_CORE_SIZE);
2764*4882a593Smuzhiyun 	}
2765*4882a593Smuzhiyun 
2766*4882a593Smuzhiyun 	sih->bustype = (uint16)bustype;
2767*4882a593Smuzhiyun #ifdef BCMBUSTYPE
2768*4882a593Smuzhiyun 	if (bustype != BUSTYPE(bustype)) {
2769*4882a593Smuzhiyun 		SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n",
2770*4882a593Smuzhiyun 			bustype, BUSTYPE(bustype)));
2771*4882a593Smuzhiyun 		err_at = 2;
2772*4882a593Smuzhiyun 		goto exit;
2773*4882a593Smuzhiyun 	}
2774*4882a593Smuzhiyun #endif
2775*4882a593Smuzhiyun 
2776*4882a593Smuzhiyun 	/* bus/core/clk setup for register access */
2777*4882a593Smuzhiyun 	if (!si_buscore_prep(sii, bustype, devid, sdh)) {
2778*4882a593Smuzhiyun 		SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype));
2779*4882a593Smuzhiyun 		err_at = 3;
2780*4882a593Smuzhiyun 		goto exit;
2781*4882a593Smuzhiyun 	}
2782*4882a593Smuzhiyun 
2783*4882a593Smuzhiyun 	/* ChipID recognition.
2784*4882a593Smuzhiyun 	*   We assume we can read chipid at offset 0 from the regs arg.
2785*4882a593Smuzhiyun 	*   If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon),
2786*4882a593Smuzhiyun 	*   some way of recognizing them needs to be added here.
2787*4882a593Smuzhiyun 	*/
2788*4882a593Smuzhiyun 	if (!cc) {
2789*4882a593Smuzhiyun 		err_at = 3;
2790*4882a593Smuzhiyun 		goto exit;
2791*4882a593Smuzhiyun 	}
2792*4882a593Smuzhiyun 	w = R_REG(osh, &cc->chipid);
2793*4882a593Smuzhiyun #if defined(BCMDONGLEHOST)
2794*4882a593Smuzhiyun 	/* plz refer to RB:13157 */
2795*4882a593Smuzhiyun 	if ((w & 0xfffff) == 148277) w -= 65532;
2796*4882a593Smuzhiyun #endif /* defined(BCMDONGLEHOST) */
2797*4882a593Smuzhiyun 	sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
2798*4882a593Smuzhiyun 	/* Might as wll fill in chip id rev & pkg */
2799*4882a593Smuzhiyun 	sih->chip = w & CID_ID_MASK;
2800*4882a593Smuzhiyun 	sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
2801*4882a593Smuzhiyun 	sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
2802*4882a593Smuzhiyun 
2803*4882a593Smuzhiyun #if defined(BCMSDIO) && (defined(HW_OOB) || defined(FORCE_WOWLAN))
2804*4882a593Smuzhiyun 	dhd_conf_set_hw_oob_intr(sdh, sih);
2805*4882a593Smuzhiyun #endif
2806*4882a593Smuzhiyun 
2807*4882a593Smuzhiyun 	si_chipid_fixup(sih);
2808*4882a593Smuzhiyun 
2809*4882a593Smuzhiyun 	sih->issim = IS_SIM(sih->chippkg);
2810*4882a593Smuzhiyun 
2811*4882a593Smuzhiyun 	if (MULTIBP_CAP(sih)) {
2812*4882a593Smuzhiyun 		sih->_multibp_enable = TRUE;
2813*4882a593Smuzhiyun 	}
2814*4882a593Smuzhiyun 
2815*4882a593Smuzhiyun 	/* scan for cores */
2816*4882a593Smuzhiyun 	 if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) {
2817*4882a593Smuzhiyun 
2818*4882a593Smuzhiyun 		if (si_alloc_coresinfo(sii, osh, cc) == NULL) {
2819*4882a593Smuzhiyun 			err_at = 4;
2820*4882a593Smuzhiyun 			goto exit;
2821*4882a593Smuzhiyun 		}
2822*4882a593Smuzhiyun 		ASSERT(sii->nci_info);
2823*4882a593Smuzhiyun 
2824*4882a593Smuzhiyun 		if (!FWSIGN_ENAB()) {
2825*4882a593Smuzhiyun 			if ((si_alloc_wrapper(sii)) != BCME_OK) {
2826*4882a593Smuzhiyun 				err_at = 5;
2827*4882a593Smuzhiyun 				goto exit;
2828*4882a593Smuzhiyun 			}
2829*4882a593Smuzhiyun 		}
2830*4882a593Smuzhiyun 
2831*4882a593Smuzhiyun 		if ((sii->numcores = nci_scan(sih)) == 0u) {
2832*4882a593Smuzhiyun 			err_at = 6;
2833*4882a593Smuzhiyun 			goto exit;
2834*4882a593Smuzhiyun 		} else {
2835*4882a593Smuzhiyun 			if (!FWSIGN_ENAB()) {
2836*4882a593Smuzhiyun 				nci_dump_erom(sii->nci_info);
2837*4882a593Smuzhiyun 			}
2838*4882a593Smuzhiyun 		}
2839*4882a593Smuzhiyun 	} else {
2840*4882a593Smuzhiyun 
2841*4882a593Smuzhiyun 		if (si_alloc_coresinfo(sii, osh, cc) == NULL) {
2842*4882a593Smuzhiyun 			err_at = 7;
2843*4882a593Smuzhiyun 			goto exit;
2844*4882a593Smuzhiyun 		}
2845*4882a593Smuzhiyun 
2846*4882a593Smuzhiyun 		if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) {
2847*4882a593Smuzhiyun 			SI_MSG(("Found chip type SB (0x%08x)\n", w));
2848*4882a593Smuzhiyun 			sb_scan(&sii->pub, regs, devid);
2849*4882a593Smuzhiyun 		} else if ((CHIPTYPE(sii->pub.socitype) == SOCI_AI) ||
2850*4882a593Smuzhiyun 			(CHIPTYPE(sii->pub.socitype) == SOCI_NAI) ||
2851*4882a593Smuzhiyun 			(CHIPTYPE(sii->pub.socitype) == SOCI_DVTBUS)) {
2852*4882a593Smuzhiyun 
2853*4882a593Smuzhiyun 			if (CHIPTYPE(sii->pub.socitype) == SOCI_AI)
2854*4882a593Smuzhiyun 				SI_MSG(("Found chip type AI (0x%08x)\n", w));
2855*4882a593Smuzhiyun 			else if (CHIPTYPE(sii->pub.socitype) == SOCI_NAI)
2856*4882a593Smuzhiyun 				SI_MSG(("Found chip type NAI (0x%08x)\n", w));
2857*4882a593Smuzhiyun 			else
2858*4882a593Smuzhiyun 				SI_MSG(("Found chip type DVT (0x%08x)\n", w));
2859*4882a593Smuzhiyun 			/* pass chipc address instead of original core base */
2860*4882a593Smuzhiyun 			if ((si_alloc_wrapper(sii)) != BCME_OK) {
2861*4882a593Smuzhiyun 				err_at = 8;
2862*4882a593Smuzhiyun 				goto exit;
2863*4882a593Smuzhiyun 			}
2864*4882a593Smuzhiyun 			ai_scan(&sii->pub, (void *)(uintptr)cc, devid);
2865*4882a593Smuzhiyun 			/* make sure the wrappers are properly accounted for */
2866*4882a593Smuzhiyun 			if (sii->axi_num_wrappers == 0) {
2867*4882a593Smuzhiyun 				SI_ERROR(("FATAL: Wrapper count 0\n"));
2868*4882a593Smuzhiyun 				err_at = 16;
2869*4882a593Smuzhiyun 				goto exit;
2870*4882a593Smuzhiyun 			}
2871*4882a593Smuzhiyun 		}
2872*4882a593Smuzhiyun 		 else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) {
2873*4882a593Smuzhiyun 			SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip));
2874*4882a593Smuzhiyun 			/* pass chipc address instead of original core base */
2875*4882a593Smuzhiyun 			ub_scan(&sii->pub, (void *)(uintptr)cc, devid);
2876*4882a593Smuzhiyun 		} else {
2877*4882a593Smuzhiyun 			SI_ERROR(("Found chip of unknown type (0x%08x)\n", w));
2878*4882a593Smuzhiyun 			err_at = 9;
2879*4882a593Smuzhiyun 			goto exit;
2880*4882a593Smuzhiyun 		}
2881*4882a593Smuzhiyun 	}
2882*4882a593Smuzhiyun 	/* no cores found, bail out */
2883*4882a593Smuzhiyun 	if (sii->numcores == 0) {
2884*4882a593Smuzhiyun 		err_at = 10;
2885*4882a593Smuzhiyun 		goto exit;
2886*4882a593Smuzhiyun 	}
2887*4882a593Smuzhiyun 	/* bus/core/clk setup */
2888*4882a593Smuzhiyun 	origidx = SI_CC_IDX;
2889*4882a593Smuzhiyun 	if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) {
2890*4882a593Smuzhiyun 		err_at = 11;
2891*4882a593Smuzhiyun 		goto exit;
2892*4882a593Smuzhiyun 	}
2893*4882a593Smuzhiyun 
2894*4882a593Smuzhiyun 	/* JIRA: SWWLAN-98321: SPROM read showing wrong values */
2895*4882a593Smuzhiyun 	/* Set the clkdiv2 divisor bits (2:0) to 0x4 if srom is present */
2896*4882a593Smuzhiyun 	if (bustype == SI_BUS) {
2897*4882a593Smuzhiyun 		uint32 clkdiv2, sromprsnt, capabilities, srom_supported;
2898*4882a593Smuzhiyun 		capabilities =	R_REG(osh, &cc->capabilities);
2899*4882a593Smuzhiyun 		srom_supported = capabilities & SROM_SUPPORTED;
2900*4882a593Smuzhiyun 		if (srom_supported) {
2901*4882a593Smuzhiyun 			sromprsnt = R_REG(osh, &cc->sromcontrol);
2902*4882a593Smuzhiyun 			sromprsnt = sromprsnt & SROM_PRSNT_MASK;
2903*4882a593Smuzhiyun 			if (sromprsnt) {
2904*4882a593Smuzhiyun 				/* SROM clock come from backplane clock/div2. Must <= 1Mhz */
2905*4882a593Smuzhiyun 				clkdiv2 = (R_REG(osh, &cc->clkdiv2) & ~CLKD2_SROM);
2906*4882a593Smuzhiyun 				clkdiv2 |= CLKD2_SROMDIV_192;
2907*4882a593Smuzhiyun 				W_REG(osh, &cc->clkdiv2, clkdiv2);
2908*4882a593Smuzhiyun 			}
2909*4882a593Smuzhiyun 		}
2910*4882a593Smuzhiyun 	}
2911*4882a593Smuzhiyun 
2912*4882a593Smuzhiyun 	if (bustype == PCI_BUS) {
2913*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
2914*4882a593Smuzhiyun 		/* JIRA:SWWLAN-18243: SPROM access taking too long */
2915*4882a593Smuzhiyun 		/* not required for 43602 */
2916*4882a593Smuzhiyun 		if (((CHIPID(sih->chip) == BCM4360_CHIP_ID) ||
2917*4882a593Smuzhiyun 		     (CHIPID(sih->chip) == BCM43460_CHIP_ID) ||
2918*4882a593Smuzhiyun 		     (CHIPID(sih->chip) == BCM4352_CHIP_ID)) &&
2919*4882a593Smuzhiyun 		    (CHIPREV(sih->chiprev) <= 2)) {
2920*4882a593Smuzhiyun 			pcie_disable_TL_clk_gating(sii->pch);
2921*4882a593Smuzhiyun 			pcie_set_L1_entry_time(sii->pch, 0x40);
2922*4882a593Smuzhiyun 		}
2923*4882a593Smuzhiyun #endif /* BCMDONGLEHOST */
2924*4882a593Smuzhiyun 
2925*4882a593Smuzhiyun 	}
2926*4882a593Smuzhiyun #ifdef BCM_SDRBL
2927*4882a593Smuzhiyun 	/* 4360 rom bootloader in PCIE case, if the SDR is enabled, But preotection is
2928*4882a593Smuzhiyun 	 * not turned on, then we want to hold arm in reset.
2929*4882a593Smuzhiyun 	 * Bottomline: In sdrenable case, we allow arm to boot only when protection is
2930*4882a593Smuzhiyun 	 * turned on.
2931*4882a593Smuzhiyun 	 */
2932*4882a593Smuzhiyun 	if (CHIP_HOSTIF_PCIE(&(sii->pub))) {
2933*4882a593Smuzhiyun 		uint32 sflags = si_arm_sflags(&(sii->pub));
2934*4882a593Smuzhiyun 
2935*4882a593Smuzhiyun 		/* If SDR is enabled but protection is not turned on
2936*4882a593Smuzhiyun 		* then we want to force arm to WFI.
2937*4882a593Smuzhiyun 		*/
2938*4882a593Smuzhiyun 		if ((sflags & (SISF_SDRENABLE | SISF_TCMPROT)) == SISF_SDRENABLE) {
2939*4882a593Smuzhiyun 			disable_arm_irq();
2940*4882a593Smuzhiyun 			while (1) {
2941*4882a593Smuzhiyun 				hnd_cpu_wait(sih);
2942*4882a593Smuzhiyun 			}
2943*4882a593Smuzhiyun 		}
2944*4882a593Smuzhiyun 	}
2945*4882a593Smuzhiyun #endif /* BCM_SDRBL */
2946*4882a593Smuzhiyun #ifdef SI_SPROM_PROBE
2947*4882a593Smuzhiyun 	si_sprom_init(sih);
2948*4882a593Smuzhiyun #endif /* SI_SPROM_PROBE */
2949*4882a593Smuzhiyun 
2950*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
2951*4882a593Smuzhiyun 	if (!FWSIGN_ENAB()) {
2952*4882a593Smuzhiyun 		/* Init nvram from flash if it exists */
2953*4882a593Smuzhiyun 		if (nvram_init(&(sii->pub)) != BCME_OK) {
2954*4882a593Smuzhiyun 			SI_ERROR(("si_doattach: nvram_init failed \n"));
2955*4882a593Smuzhiyun 			goto exit;
2956*4882a593Smuzhiyun 		}
2957*4882a593Smuzhiyun 	}
2958*4882a593Smuzhiyun 
2959*4882a593Smuzhiyun 	/* Init nvram from sprom/otp if they exist */
2960*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2961*4882a593Smuzhiyun 
2962*4882a593Smuzhiyun #ifdef DONGLEBUILD
2963*4882a593Smuzhiyun #if	!defined(NVSRCX)
2964*4882a593Smuzhiyun 	/* Init nvram from sprom/otp if they exist and not inited */
2965*4882a593Smuzhiyun 	if (!FWSIGN_ENAB() && si_getkvars()) {
2966*4882a593Smuzhiyun 		*vars = si_getkvars();
2967*4882a593Smuzhiyun 		*varsz = si_getkvarsz();
2968*4882a593Smuzhiyun 	}
2969*4882a593Smuzhiyun 	else
2970*4882a593Smuzhiyun #endif
2971*4882a593Smuzhiyun #endif /* DONGLEBUILD */
2972*4882a593Smuzhiyun 	{
2973*4882a593Smuzhiyun #if defined(NVSRCX)
2974*4882a593Smuzhiyun 	sromvars = srom_get_sromvars();
2975*4882a593Smuzhiyun 	if (sromvars == NULL) {
2976*4882a593Smuzhiyun 		if (srom_var_init(&sii->pub, BUSTYPE(bustype), (void *)regs,
2977*4882a593Smuzhiyun 				sii->osh, &sromvars, varsz)) {
2978*4882a593Smuzhiyun 			err_at = 12;
2979*4882a593Smuzhiyun 			goto exit;
2980*4882a593Smuzhiyun 		}
2981*4882a593Smuzhiyun 	}
2982*4882a593Smuzhiyun #else
2983*4882a593Smuzhiyun 	if (!FWSIGN_ENAB()) {
2984*4882a593Smuzhiyun 		if (srom_var_init(&sii->pub, BUSTYPE(bustype), (void *)regs,
2985*4882a593Smuzhiyun 				sii->osh, vars, varsz)) {
2986*4882a593Smuzhiyun 			err_at = 13;
2987*4882a593Smuzhiyun 			goto exit;
2988*4882a593Smuzhiyun 		}
2989*4882a593Smuzhiyun 	}
2990*4882a593Smuzhiyun #endif /* NVSRCX */
2991*4882a593Smuzhiyun 	}
2992*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_POP();
2993*4882a593Smuzhiyun 
2994*4882a593Smuzhiyun 	pvars = vars ? *vars : NULL;
2995*4882a593Smuzhiyun 
2996*4882a593Smuzhiyun 	si_nvram_process(sii, pvars);
2997*4882a593Smuzhiyun 
2998*4882a593Smuzhiyun 	/* xtalfreq is required for programming open loop calibration support changes */
2999*4882a593Smuzhiyun 	sii->xtalfreq = getintvar(NULL, rstr_xtalfreq);
3000*4882a593Smuzhiyun 	/* === NVRAM, clock is ready === */
3001*4882a593Smuzhiyun #else
3002*4882a593Smuzhiyun 	pvars = NULL;
3003*4882a593Smuzhiyun 	BCM_REFERENCE(pvars);
3004*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
3005*4882a593Smuzhiyun 
3006*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
3007*4882a593Smuzhiyun #if defined(BCMSRTOPOFF) && !defined(BCMSRTOPOFF_DISABLED)
3008*4882a593Smuzhiyun 	_srtopoff_enab = (bool)getintvar(NULL, rstr_srtopoff_enab);
3009*4882a593Smuzhiyun #endif
3010*4882a593Smuzhiyun 
3011*4882a593Smuzhiyun 	if (!FWSIGN_ENAB()) {
3012*4882a593Smuzhiyun 		if (HIB_EXT_WAKEUP_CAP(sih)) {
3013*4882a593Smuzhiyun 			sii->lhl_ps_mode = (uint8)getintvar(NULL, rstr_lhl_ps_mode);
3014*4882a593Smuzhiyun 
3015*4882a593Smuzhiyun 			if (getintvar(NULL, rstr_ext_wakeup_dis)) {
3016*4882a593Smuzhiyun 				sii->hib_ext_wakeup_enab = FALSE;
3017*4882a593Smuzhiyun 			} else if (BCMSRTOPOFF_ENAB()) {
3018*4882a593Smuzhiyun 				/*  Has GPIO false wakeup issue on 4387, needs resolve  */
3019*4882a593Smuzhiyun 				sii->hib_ext_wakeup_enab = TRUE;
3020*4882a593Smuzhiyun 			} else if (LHL_IS_PSMODE_1(sih)) {
3021*4882a593Smuzhiyun 				sii->hib_ext_wakeup_enab = TRUE;
3022*4882a593Smuzhiyun 			} else {
3023*4882a593Smuzhiyun 				sii->hib_ext_wakeup_enab = FALSE;
3024*4882a593Smuzhiyun 			}
3025*4882a593Smuzhiyun 		}
3026*4882a593Smuzhiyun 
3027*4882a593Smuzhiyun 		sii->rfldo3p3_war = (bool)getintvar(NULL, rstr_rfldo3p3_cap_war);
3028*4882a593Smuzhiyun 	}
3029*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
3030*4882a593Smuzhiyun 
3031*4882a593Smuzhiyun 	if (!si_onetimeinit) {
3032*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
3033*4882a593Smuzhiyun 		char *val;
3034*4882a593Smuzhiyun 
3035*4882a593Smuzhiyun 		(void) val;
3036*4882a593Smuzhiyun 		if (!FWSIGN_ENAB()) {
3037*4882a593Smuzhiyun 			/* Cache nvram override to min mask */
3038*4882a593Smuzhiyun 			if ((val = getvar(NULL, rstr_rmin)) != NULL) {
3039*4882a593Smuzhiyun 				sii->min_mask_valid = TRUE;
3040*4882a593Smuzhiyun 				sii->nvram_min_mask = (uint32)bcm_strtoul(val, NULL, 0);
3041*4882a593Smuzhiyun 			} else {
3042*4882a593Smuzhiyun 				sii->min_mask_valid = FALSE;
3043*4882a593Smuzhiyun 			}
3044*4882a593Smuzhiyun 			/* Cache nvram override to max mask */
3045*4882a593Smuzhiyun 			if ((val = getvar(NULL, rstr_rmax)) != NULL) {
3046*4882a593Smuzhiyun 				sii->max_mask_valid = TRUE;
3047*4882a593Smuzhiyun 				sii->nvram_max_mask = (uint32)bcm_strtoul(val, NULL, 0);
3048*4882a593Smuzhiyun 			} else {
3049*4882a593Smuzhiyun 				sii->max_mask_valid = FALSE;
3050*4882a593Smuzhiyun 			}
3051*4882a593Smuzhiyun 
3052*4882a593Smuzhiyun #ifdef DONGLEBUILD
3053*4882a593Smuzhiyun 			/* Handle armclk frequency setting from NVRAM file */
3054*4882a593Smuzhiyun 			if (BCM4369_CHIP(sih->chip) || BCM4362_CHIP(sih->chip) ||
3055*4882a593Smuzhiyun 				BCM4389_CHIP(sih->chip) ||
3056*4882a593Smuzhiyun 				BCM4388_CHIP(sih->chip) || BCM4397_CHIP(sih->chip) || FALSE) {
3057*4882a593Smuzhiyun 				if ((val = getvar(NULL, rstr_armclk)) != NULL) {
3058*4882a593Smuzhiyun 					sii->armpllclkfreq = (uint32)bcm_strtoul(val, NULL, 0);
3059*4882a593Smuzhiyun 					ASSERT(sii->armpllclkfreq > 0);
3060*4882a593Smuzhiyun 				} else {
3061*4882a593Smuzhiyun 					sii->armpllclkfreq = 0;
3062*4882a593Smuzhiyun 				}
3063*4882a593Smuzhiyun 			}
3064*4882a593Smuzhiyun 
3065*4882a593Smuzhiyun #endif /* DONGLEBUILD */
3066*4882a593Smuzhiyun 		}
3067*4882a593Smuzhiyun 
3068*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
3069*4882a593Smuzhiyun 
3070*4882a593Smuzhiyun #if defined(CONFIG_XIP) && defined(BCMTCAM)
3071*4882a593Smuzhiyun 		/* patch the ROM if there are any patch pairs from OTP/SPROM */
3072*4882a593Smuzhiyun 		if (patch_pair) {
3073*4882a593Smuzhiyun 
3074*4882a593Smuzhiyun #if defined(__ARM_ARCH_7R__)
3075*4882a593Smuzhiyun 			hnd_tcam_bootloader_load(si_setcore(sih, ARMCR4_CORE_ID, 0), pvars);
3076*4882a593Smuzhiyun #elif defined(__ARM_ARCH_7A__)
3077*4882a593Smuzhiyun 			hnd_tcam_bootloader_load(si_setcore(sih, SYSMEM_CORE_ID, 0), pvars);
3078*4882a593Smuzhiyun #else
3079*4882a593Smuzhiyun 			hnd_tcam_bootloader_load(si_setcore(sih, SOCRAM_CORE_ID, 0), pvars);
3080*4882a593Smuzhiyun #endif
3081*4882a593Smuzhiyun 			si_setcoreidx(sih, origidx);
3082*4882a593Smuzhiyun 		}
3083*4882a593Smuzhiyun #endif /* CONFIG_XIP && BCMTCAM */
3084*4882a593Smuzhiyun 
3085*4882a593Smuzhiyun 		if (CCREV(sii->pub.ccrev) >= 20) {
3086*4882a593Smuzhiyun 			uint32 gpiopullup = 0, gpiopulldown = 0;
3087*4882a593Smuzhiyun 			cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
3088*4882a593Smuzhiyun 			ASSERT(cc != NULL);
3089*4882a593Smuzhiyun 
3090*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST) /* if not a DHD build */
3091*4882a593Smuzhiyun 			if (getvar(pvars, rstr_gpiopulldown) != NULL) {
3092*4882a593Smuzhiyun 				uint32 value;
3093*4882a593Smuzhiyun 				value = getintvar(pvars, rstr_gpiopulldown);
3094*4882a593Smuzhiyun 				if (value != 0xFFFFFFFF) { /* non populated SROM fields are ffff */
3095*4882a593Smuzhiyun 					gpiopulldown |= value;
3096*4882a593Smuzhiyun 				}
3097*4882a593Smuzhiyun 			}
3098*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
3099*4882a593Smuzhiyun 
3100*4882a593Smuzhiyun 			W_REG(osh, &cc->gpiopullup, gpiopullup);
3101*4882a593Smuzhiyun 			W_REG(osh, &cc->gpiopulldown, gpiopulldown);
3102*4882a593Smuzhiyun 			si_setcoreidx(sih, origidx);
3103*4882a593Smuzhiyun 		}
3104*4882a593Smuzhiyun 
3105*4882a593Smuzhiyun #ifdef DONGLEBUILD
3106*4882a593Smuzhiyun 		/* Ensure gci is initialized before PMU as PLL init needs to aquire gci semaphore */
3107*4882a593Smuzhiyun 		hnd_gci_init(sih);
3108*4882a593Smuzhiyun #endif /* DONGLEBUILD */
3109*4882a593Smuzhiyun 
3110*4882a593Smuzhiyun #if defined(BT_WLAN_REG_ON_WAR)
3111*4882a593Smuzhiyun 	/*
3112*4882a593Smuzhiyun 	 * 4389B0/C0 - WLAN and BT turn on WAR - synchronize WLAN and BT firmware using GCI
3113*4882a593Smuzhiyun 	 * semaphore - THREAD_0_GCI_SEM_3_ID to ensure that simultaneous register accesses
3114*4882a593Smuzhiyun 	 * does not occur. The WLAN firmware will acquire the semaphore just to ensure that
3115*4882a593Smuzhiyun 	 * if BT firmware is already executing the WAR, then wait until it finishes.
3116*4882a593Smuzhiyun 	 * In BT firmware checking for WL_REG_ON status is sufficient to decide whether
3117*4882a593Smuzhiyun 	 * to apply the WAR or not (i.e, WLAN is turned ON/OFF).
3118*4882a593Smuzhiyun 	 */
3119*4882a593Smuzhiyun 	if ((hnd_gcisem_acquire(GCI_BT_WLAN_REG_ON_WAR_SEM, TRUE,
3120*4882a593Smuzhiyun 			GCI_BT_WLAN_REG_ON_WAR_SEM_TIMEOUT) != BCME_OK)) {
3121*4882a593Smuzhiyun 		err_at = 14;
3122*4882a593Smuzhiyun 		hnd_gcisem_set_err(GCI_BT_WLAN_REG_ON_WAR_SEM);
3123*4882a593Smuzhiyun 		goto exit;
3124*4882a593Smuzhiyun 	}
3125*4882a593Smuzhiyun 
3126*4882a593Smuzhiyun 	/* WLAN/BT turn On WAR - Remove wlsc_btsc_prisel override after semaphore acquire
3127*4882a593Smuzhiyun 	 * BT sets the override at power up when WL_REG_ON is low - wlsc_btsc_prisel is in
3128*4882a593Smuzhiyun 	 * undefined state when wlan_reg_on is low
3129*4882a593Smuzhiyun 	 */
3130*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_23,
3131*4882a593Smuzhiyun 		(CC_GCI_CHIPCTRL_23_WLSC_BTSC_PRISEL_FORCE_MASK |
3132*4882a593Smuzhiyun 		CC_GCI_CHIPCTRL_23_WLSC_BTSC_PRISEL_VAL_MASK), 0u);
3133*4882a593Smuzhiyun 
3134*4882a593Smuzhiyun 	if ((hnd_gcisem_release(GCI_BT_WLAN_REG_ON_WAR_SEM) != BCME_OK)) {
3135*4882a593Smuzhiyun 		hnd_gcisem_set_err(GCI_BT_WLAN_REG_ON_WAR_SEM);
3136*4882a593Smuzhiyun 		err_at = 15;
3137*4882a593Smuzhiyun 		goto exit;
3138*4882a593Smuzhiyun 	}
3139*4882a593Smuzhiyun #endif /* BT_WLAN_REG_ON_WAR */
3140*4882a593Smuzhiyun 
3141*4882a593Smuzhiyun 		/* Skip PMU initialization from the Dongle Host.
3142*4882a593Smuzhiyun 		 * Firmware will take care of it when it comes up.
3143*4882a593Smuzhiyun 		 */
3144*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
3145*4882a593Smuzhiyun 		/* PMU specific initializations */
3146*4882a593Smuzhiyun 		if (PMUCTL_ENAB(sih)) {
3147*4882a593Smuzhiyun 			uint32 xtalfreq;
3148*4882a593Smuzhiyun 			si_pmu_init(sih, sii->osh);
3149*4882a593Smuzhiyun 			si_pmu_chip_init(sih, sii->osh);
3150*4882a593Smuzhiyun 			xtalfreq = getintvar(pvars, rstr_xtalfreq);
3151*4882a593Smuzhiyun #if defined(WL_FWSIGN)
3152*4882a593Smuzhiyun 			if (FWSIGN_ENAB()) {
3153*4882a593Smuzhiyun 				xtalfreq = XTALFREQ_KHZ;
3154*4882a593Smuzhiyun 			}
3155*4882a593Smuzhiyun #endif /* WL_FWSIGN */
3156*4882a593Smuzhiyun 
3157*4882a593Smuzhiyun 			/*
3158*4882a593Smuzhiyun 			 * workaround for chips that don't support external LPO, thus ALP clock
3159*4882a593Smuzhiyun 			 * can not be measured accurately:
3160*4882a593Smuzhiyun 			 */
3161*4882a593Smuzhiyun 			switch (CHIPID(sih->chip)) {
3162*4882a593Smuzhiyun 			CASE_BCM43602_CHIP:
3163*4882a593Smuzhiyun 				xtalfreq = 40000;
3164*4882a593Smuzhiyun 				break;
3165*4882a593Smuzhiyun 			case BCM4369_CHIP_GRPID:
3166*4882a593Smuzhiyun 				if (xtalfreq == 0)
3167*4882a593Smuzhiyun 					xtalfreq = 37400;
3168*4882a593Smuzhiyun 				break;
3169*4882a593Smuzhiyun 			default:
3170*4882a593Smuzhiyun 				break;
3171*4882a593Smuzhiyun 			}
3172*4882a593Smuzhiyun 
3173*4882a593Smuzhiyun 			/* If xtalfreq var not available, try to measure it */
3174*4882a593Smuzhiyun 			if (xtalfreq == 0)
3175*4882a593Smuzhiyun 				xtalfreq = si_pmu_measure_alpclk(sih, sii->osh);
3176*4882a593Smuzhiyun 
3177*4882a593Smuzhiyun 			sii->xtalfreq = xtalfreq;
3178*4882a593Smuzhiyun 			si_pmu_pll_init(sih, sii->osh, xtalfreq);
3179*4882a593Smuzhiyun 
3180*4882a593Smuzhiyun 			if (!FWSIGN_ENAB()) {
3181*4882a593Smuzhiyun 				/* configure default spurmode  */
3182*4882a593Smuzhiyun 				sii->spurmode = getintvar(pvars, rstr_spurconfig) & 0xf;
3183*4882a593Smuzhiyun 
3184*4882a593Smuzhiyun #if defined(SAVERESTORE)
3185*4882a593Smuzhiyun 				/* Only needs to be done once.
3186*4882a593Smuzhiyun 				 * Needs this before si_pmu_res_init() to use sr_isenab()
3187*4882a593Smuzhiyun 				 */
3188*4882a593Smuzhiyun 				if (SR_ENAB()) {
3189*4882a593Smuzhiyun 					sr_save_restore_init(sih);
3190*4882a593Smuzhiyun 				}
3191*4882a593Smuzhiyun #endif
3192*4882a593Smuzhiyun 
3193*4882a593Smuzhiyun 				/* TODO: should move the per core srpwr out of
3194*4882a593Smuzhiyun 				 * si_doattach() to a function where it knows
3195*4882a593Smuzhiyun 				 * which core it should enable the power domain
3196*4882a593Smuzhiyun 				 * request for...
3197*4882a593Smuzhiyun 				 */
3198*4882a593Smuzhiyun 				if (SRPWR_CAP(sih) && !SRPWR_ENAB()) {
3199*4882a593Smuzhiyun 					uint32 domain = SRPWR_DMN3_MACMAIN_MASK;
3200*4882a593Smuzhiyun 
3201*4882a593Smuzhiyun #if defined(WLRSDB) && !defined(WLRSDB_DISABLED)
3202*4882a593Smuzhiyun 					domain |= SRPWR_DMN2_MACAUX_MASK;
3203*4882a593Smuzhiyun #endif /* WLRSDB && !WLRSDB_DISABLED */
3204*4882a593Smuzhiyun 
3205*4882a593Smuzhiyun 					if (si_scan_core_present(sih)) {
3206*4882a593Smuzhiyun 						domain |= SRPWR_DMN4_MACSCAN_MASK;
3207*4882a593Smuzhiyun 					}
3208*4882a593Smuzhiyun 
3209*4882a593Smuzhiyun 					si_srpwr_request(sih, domain, domain);
3210*4882a593Smuzhiyun 				}
3211*4882a593Smuzhiyun 			}
3212*4882a593Smuzhiyun 
3213*4882a593Smuzhiyun 			si_pmu_res_init(sih, sii->osh);
3214*4882a593Smuzhiyun 			si_pmu_swreg_init(sih, sii->osh);
3215*4882a593Smuzhiyun #ifdef BCMGCISHM
3216*4882a593Smuzhiyun 			hnd_gcishm_init(sih);
3217*4882a593Smuzhiyun #endif
3218*4882a593Smuzhiyun 		}
3219*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
3220*4882a593Smuzhiyun #ifdef _RTE_
3221*4882a593Smuzhiyun 		si_onetimeinit = TRUE;
3222*4882a593Smuzhiyun #endif
3223*4882a593Smuzhiyun 	}
3224*4882a593Smuzhiyun 
3225*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
3226*4882a593Smuzhiyun 
3227*4882a593Smuzhiyun 	si_lowpwr_opt(sih);
3228*4882a593Smuzhiyun 
3229*4882a593Smuzhiyun 	if (!FWSIGN_ENAB()) {
3230*4882a593Smuzhiyun 		if (PCIE(sii)) {
3231*4882a593Smuzhiyun 			ASSERT(sii->pch != NULL);
3232*4882a593Smuzhiyun 			pcicore_attach(sii->pch, pvars, SI_DOATTACH);
3233*4882a593Smuzhiyun 		}
3234*4882a593Smuzhiyun 	}
3235*4882a593Smuzhiyun 
3236*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
3237*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
3238*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID) ||
3239*4882a593Smuzhiyun 		(CCREV(sih->ccrev) >= 62)) {
3240*4882a593Smuzhiyun 		/* Clear SFlash clock request */
3241*4882a593Smuzhiyun 		CHIPC_REG(sih, clk_ctl_st, CCS_SFLASH_CLKREQ, 0);
3242*4882a593Smuzhiyun 	}
3243*4882a593Smuzhiyun 
3244*4882a593Smuzhiyun #ifdef SECI_UART
3245*4882a593Smuzhiyun 	/* Enable pull up on fast_uart_rx and fast_uart_cts_in
3246*4882a593Smuzhiyun 	* when fast uart is disabled.
3247*4882a593Smuzhiyun 	*/
3248*4882a593Smuzhiyun 	if (getvar(pvars, rstr_fuart_pup_rx_cts) != NULL) {
3249*4882a593Smuzhiyun 		w = getintvar(pvars, rstr_fuart_pup_rx_cts);
3250*4882a593Smuzhiyun 		if (w)
3251*4882a593Smuzhiyun 			fuart_pullup_rx_cts_enab = TRUE;
3252*4882a593Smuzhiyun 	}
3253*4882a593Smuzhiyun #endif
3254*4882a593Smuzhiyun 
3255*4882a593Smuzhiyun 	/* configure default pinmux enables for the chip */
3256*4882a593Smuzhiyun 	if (getvar(pvars, rstr_muxenab) != NULL) {
3257*4882a593Smuzhiyun 		w = getintvar(pvars, rstr_muxenab);
3258*4882a593Smuzhiyun 		si_muxenab((si_t *)sii, w);
3259*4882a593Smuzhiyun 	}
3260*4882a593Smuzhiyun 
3261*4882a593Smuzhiyun 	/* configure default swd enables for the chip */
3262*4882a593Smuzhiyun 	if (getvar(pvars, rstr_swdenab) != NULL) {
3263*4882a593Smuzhiyun 		w = getintvar(pvars, rstr_swdenab);
3264*4882a593Smuzhiyun 		si_swdenable((si_t *)sii, w);
3265*4882a593Smuzhiyun 	}
3266*4882a593Smuzhiyun 
3267*4882a593Smuzhiyun 	sii->device_wake_opt = CC_GCI_GPIO_INVALID;
3268*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
3269*4882a593Smuzhiyun 	/* clear any previous epidiag-induced target abort */
3270*4882a593Smuzhiyun 	ASSERT(!si_taclear(sih, FALSE));
3271*4882a593Smuzhiyun 
3272*4882a593Smuzhiyun #if defined(BCMPMU_STATS) && !defined(BCMPMU_STATS_DISABLED)
3273*4882a593Smuzhiyun 	si_pmustatstimer_init(sih);
3274*4882a593Smuzhiyun #endif /* BCMPMU_STATS */
3275*4882a593Smuzhiyun 
3276*4882a593Smuzhiyun #ifdef BOOTLOADER_CONSOLE_OUTPUT
3277*4882a593Smuzhiyun 	/* Enable console prints */
3278*4882a593Smuzhiyun 	si_muxenab(sii, 3);
3279*4882a593Smuzhiyun #endif
3280*4882a593Smuzhiyun 
3281*4882a593Smuzhiyun 	if (((PCIECOREREV(sih->buscorerev) == 66) || (PCIECOREREV(sih->buscorerev) == 68)) &&
3282*4882a593Smuzhiyun 		CST4378_CHIPMODE_BTOP(sih->chipst)) {
3283*4882a593Smuzhiyun 		/*
3284*4882a593Smuzhiyun 		 * HW4378-413 :
3285*4882a593Smuzhiyun 		 * BT oob connections for pcie function 1 seen at oob_ain[5] instead of oob_ain[1]
3286*4882a593Smuzhiyun 		 */
3287*4882a593Smuzhiyun 		si_oob_war_BT_F1(sih);
3288*4882a593Smuzhiyun 	}
3289*4882a593Smuzhiyun 
3290*4882a593Smuzhiyun 	return (sii);
3291*4882a593Smuzhiyun 
3292*4882a593Smuzhiyun exit:
3293*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
3294*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == PCI_BUS) {
3295*4882a593Smuzhiyun 		if (sii->pch)
3296*4882a593Smuzhiyun 			pcicore_deinit(sii->pch);
3297*4882a593Smuzhiyun 		sii->pch = NULL;
3298*4882a593Smuzhiyun 	}
3299*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
3300*4882a593Smuzhiyun 
3301*4882a593Smuzhiyun 	if (err_at) {
3302*4882a593Smuzhiyun 		SI_ERROR(("si_doattach Failed. Error at %d\n", err_at));
3303*4882a593Smuzhiyun 		si_free_coresinfo(sii, osh);
3304*4882a593Smuzhiyun 		si_free_wrapper(sii);
3305*4882a593Smuzhiyun 	}
3306*4882a593Smuzhiyun 	return NULL;
3307*4882a593Smuzhiyun }
3308*4882a593Smuzhiyun 
3309*4882a593Smuzhiyun /** may be called with core in reset */
3310*4882a593Smuzhiyun void
BCMATTACHFN(si_detach)3311*4882a593Smuzhiyun BCMATTACHFN(si_detach)(si_t *sih)
3312*4882a593Smuzhiyun {
3313*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
3314*4882a593Smuzhiyun 	si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
3315*4882a593Smuzhiyun 	uint idx;
3316*4882a593Smuzhiyun 
3317*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
3318*4882a593Smuzhiyun 	struct si_pub *si_local = NULL;
3319*4882a593Smuzhiyun 	bcopy(&sih, &si_local, sizeof(si_t*));
3320*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
3321*4882a593Smuzhiyun 
3322*4882a593Smuzhiyun #ifdef BCM_SH_SFLASH
3323*4882a593Smuzhiyun 	if (BCM_SH_SFLASH_ENAB()) {
3324*4882a593Smuzhiyun 		sh_sflash_detach(sii->osh, sih);
3325*4882a593Smuzhiyun 	}
3326*4882a593Smuzhiyun #endif
3327*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == SI_BUS) {
3328*4882a593Smuzhiyun 		if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) {
3329*4882a593Smuzhiyun 			if (sii->nci_info) {
3330*4882a593Smuzhiyun 				nci_uninit(sii->nci_info);
3331*4882a593Smuzhiyun 				sii->nci_info = NULL;
3332*4882a593Smuzhiyun 
3333*4882a593Smuzhiyun 				/* TODO: REG_UNMAP */
3334*4882a593Smuzhiyun 			}
3335*4882a593Smuzhiyun 		} else {
3336*4882a593Smuzhiyun 			for (idx = 0; idx < SI_MAXCORES; idx++) {
3337*4882a593Smuzhiyun 				if (cores_info->regs[idx]) {
3338*4882a593Smuzhiyun 					REG_UNMAP(cores_info->regs[idx]);
3339*4882a593Smuzhiyun 					cores_info->regs[idx] = NULL;
3340*4882a593Smuzhiyun 				}
3341*4882a593Smuzhiyun 			}
3342*4882a593Smuzhiyun 		}
3343*4882a593Smuzhiyun 	}
3344*4882a593Smuzhiyun 
3345*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
3346*4882a593Smuzhiyun 	srom_var_deinit(si_local);
3347*4882a593Smuzhiyun 	nvram_exit(si_local); /* free up nvram buffers */
3348*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
3349*4882a593Smuzhiyun 
3350*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
3351*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == PCI_BUS) {
3352*4882a593Smuzhiyun 		if (sii->pch)
3353*4882a593Smuzhiyun 			pcicore_deinit(sii->pch);
3354*4882a593Smuzhiyun 		sii->pch = NULL;
3355*4882a593Smuzhiyun 	}
3356*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
3357*4882a593Smuzhiyun 
3358*4882a593Smuzhiyun 	si_free_coresinfo(sii, sii->osh);
3359*4882a593Smuzhiyun 
3360*4882a593Smuzhiyun #if defined(AXI_TIMEOUTS_NIC)
3361*4882a593Smuzhiyun 	if (sih->err_info) {
3362*4882a593Smuzhiyun 		MFREE(sii->osh, sih->err_info, sizeof(si_axi_error_info_t));
3363*4882a593Smuzhiyun 		sii->pub.err_info = NULL;
3364*4882a593Smuzhiyun 	}
3365*4882a593Smuzhiyun #endif /* AXI_TIMEOUTS_NIC */
3366*4882a593Smuzhiyun 
3367*4882a593Smuzhiyun 	si_free_wrapper(sii);
3368*4882a593Smuzhiyun 
3369*4882a593Smuzhiyun #ifdef BCMDVFS
3370*4882a593Smuzhiyun 	if (BCMDVFS_ENAB()) {
3371*4882a593Smuzhiyun 		si_dvfs_info_deinit(sih, sii->osh);
3372*4882a593Smuzhiyun 	}
3373*4882a593Smuzhiyun #endif /* BCMDVFS */
3374*4882a593Smuzhiyun 
3375*4882a593Smuzhiyun 	if (sii != &ksii) {
3376*4882a593Smuzhiyun 		MFREE(sii->osh, sii, sizeof(si_info_t));
3377*4882a593Smuzhiyun 	}
3378*4882a593Smuzhiyun }
3379*4882a593Smuzhiyun 
3380*4882a593Smuzhiyun void *
BCMPOSTTRAPFN(si_osh)3381*4882a593Smuzhiyun BCMPOSTTRAPFN(si_osh)(si_t *sih)
3382*4882a593Smuzhiyun {
3383*4882a593Smuzhiyun 	const si_info_t *sii;
3384*4882a593Smuzhiyun 
3385*4882a593Smuzhiyun 	sii = SI_INFO(sih);
3386*4882a593Smuzhiyun 	return sii->osh;
3387*4882a593Smuzhiyun }
3388*4882a593Smuzhiyun 
3389*4882a593Smuzhiyun void
si_setosh(si_t * sih,osl_t * osh)3390*4882a593Smuzhiyun si_setosh(si_t *sih, osl_t *osh)
3391*4882a593Smuzhiyun {
3392*4882a593Smuzhiyun 	si_info_t *sii;
3393*4882a593Smuzhiyun 
3394*4882a593Smuzhiyun 	sii = SI_INFO(sih);
3395*4882a593Smuzhiyun 	if (sii->osh != NULL) {
3396*4882a593Smuzhiyun 		SI_ERROR(("osh is already set....\n"));
3397*4882a593Smuzhiyun 		ASSERT(!sii->osh);
3398*4882a593Smuzhiyun 	}
3399*4882a593Smuzhiyun 	sii->osh = osh;
3400*4882a593Smuzhiyun }
3401*4882a593Smuzhiyun 
3402*4882a593Smuzhiyun /** register driver interrupt disabling and restoring callback functions */
3403*4882a593Smuzhiyun void
BCMATTACHFN(si_register_intr_callback)3404*4882a593Smuzhiyun BCMATTACHFN(si_register_intr_callback)(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn,
3405*4882a593Smuzhiyun                           void *intrsenabled_fn, void *intr_arg)
3406*4882a593Smuzhiyun {
3407*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
3408*4882a593Smuzhiyun 	sii->intr_arg = intr_arg;
3409*4882a593Smuzhiyun 	sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn;
3410*4882a593Smuzhiyun 	sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn;
3411*4882a593Smuzhiyun 	sii->intrsenabled_fn = (si_intrsenabled_t)intrsenabled_fn;
3412*4882a593Smuzhiyun 	/* save current core id.  when this function called, the current core
3413*4882a593Smuzhiyun 	 * must be the core which provides driver functions(il, et, wl, etc.)
3414*4882a593Smuzhiyun 	 */
3415*4882a593Smuzhiyun 	sii->dev_coreid = si_coreid(sih);
3416*4882a593Smuzhiyun }
3417*4882a593Smuzhiyun 
3418*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_deregister_intr_callback)3419*4882a593Smuzhiyun BCMPOSTTRAPFN(si_deregister_intr_callback)(si_t *sih)
3420*4882a593Smuzhiyun {
3421*4882a593Smuzhiyun 	si_info_t *sii;
3422*4882a593Smuzhiyun 
3423*4882a593Smuzhiyun 	sii = SI_INFO(sih);
3424*4882a593Smuzhiyun 	sii->intrsoff_fn = NULL;
3425*4882a593Smuzhiyun 	sii->intrsrestore_fn = NULL;
3426*4882a593Smuzhiyun 	sii->intrsenabled_fn = NULL;
3427*4882a593Smuzhiyun }
3428*4882a593Smuzhiyun 
3429*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_intflag)3430*4882a593Smuzhiyun BCMPOSTTRAPFN(si_intflag)(si_t *sih)
3431*4882a593Smuzhiyun {
3432*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3433*4882a593Smuzhiyun 
3434*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3435*4882a593Smuzhiyun 		return sb_intflag(sih);
3436*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3437*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3438*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3439*4882a593Smuzhiyun 		return R_REG(sii->osh, ((uint32 *)(uintptr)
3440*4882a593Smuzhiyun 			    (sii->oob_router + OOB_STATUSA)));
3441*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3442*4882a593Smuzhiyun 		return nci_intflag(sih);
3443*4882a593Smuzhiyun 	else {
3444*4882a593Smuzhiyun 		ASSERT(0);
3445*4882a593Smuzhiyun 		return 0;
3446*4882a593Smuzhiyun 	}
3447*4882a593Smuzhiyun }
3448*4882a593Smuzhiyun 
3449*4882a593Smuzhiyun uint
si_flag(si_t * sih)3450*4882a593Smuzhiyun si_flag(si_t *sih)
3451*4882a593Smuzhiyun {
3452*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3453*4882a593Smuzhiyun 		return sb_flag(sih);
3454*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3455*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3456*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3457*4882a593Smuzhiyun 		return ai_flag(sih);
3458*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3459*4882a593Smuzhiyun 		return ub_flag(sih);
3460*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3461*4882a593Smuzhiyun 		return nci_flag(sih);
3462*4882a593Smuzhiyun 	else {
3463*4882a593Smuzhiyun 		ASSERT(0);
3464*4882a593Smuzhiyun 		return 0;
3465*4882a593Smuzhiyun 	}
3466*4882a593Smuzhiyun }
3467*4882a593Smuzhiyun 
3468*4882a593Smuzhiyun uint
si_flag_alt(const si_t * sih)3469*4882a593Smuzhiyun si_flag_alt(const si_t *sih)
3470*4882a593Smuzhiyun {
3471*4882a593Smuzhiyun 	if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3472*4882a593Smuzhiyun 	(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3473*4882a593Smuzhiyun 	(CHIPTYPE(sih->socitype) == SOCI_NAI))
3474*4882a593Smuzhiyun 		return ai_flag_alt(sih);
3475*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3476*4882a593Smuzhiyun 		return nci_flag_alt(sih);
3477*4882a593Smuzhiyun 	else {
3478*4882a593Smuzhiyun 		ASSERT(0);
3479*4882a593Smuzhiyun 		return 0;
3480*4882a593Smuzhiyun 	}
3481*4882a593Smuzhiyun }
3482*4882a593Smuzhiyun 
3483*4882a593Smuzhiyun void
BCMATTACHFN(si_setint)3484*4882a593Smuzhiyun BCMATTACHFN(si_setint)(const si_t *sih, int siflag)
3485*4882a593Smuzhiyun {
3486*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3487*4882a593Smuzhiyun 		sb_setint(sih, siflag);
3488*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3489*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3490*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3491*4882a593Smuzhiyun 		ai_setint(sih, siflag);
3492*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3493*4882a593Smuzhiyun 		ub_setint(sih, siflag);
3494*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3495*4882a593Smuzhiyun 		nci_setint(sih, siflag);
3496*4882a593Smuzhiyun 	else
3497*4882a593Smuzhiyun 		ASSERT(0);
3498*4882a593Smuzhiyun }
3499*4882a593Smuzhiyun 
3500*4882a593Smuzhiyun uint32
si_oobr_baseaddr(const si_t * sih,bool second)3501*4882a593Smuzhiyun si_oobr_baseaddr(const si_t *sih, bool second)
3502*4882a593Smuzhiyun {
3503*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3504*4882a593Smuzhiyun 
3505*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3506*4882a593Smuzhiyun 		return 0;
3507*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3508*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3509*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3510*4882a593Smuzhiyun 		return (second ? sii->oob_router1 : sii->oob_router);
3511*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3512*4882a593Smuzhiyun 		return nci_oobr_baseaddr(sih, second);
3513*4882a593Smuzhiyun 	else {
3514*4882a593Smuzhiyun 		ASSERT(0);
3515*4882a593Smuzhiyun 		return 0;
3516*4882a593Smuzhiyun 	}
3517*4882a593Smuzhiyun }
3518*4882a593Smuzhiyun 
3519*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_coreid)3520*4882a593Smuzhiyun BCMPOSTTRAPFN(si_coreid)(const si_t *sih)
3521*4882a593Smuzhiyun {
3522*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3523*4882a593Smuzhiyun 	const si_cores_info_t *cores_info = (const si_cores_info_t *)sii->cores_info;
3524*4882a593Smuzhiyun 	if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) {
3525*4882a593Smuzhiyun 		return nci_coreid(sih, sii->curidx);
3526*4882a593Smuzhiyun 	} else
3527*4882a593Smuzhiyun 	{
3528*4882a593Smuzhiyun 		return cores_info->coreid[sii->curidx];
3529*4882a593Smuzhiyun 	}
3530*4882a593Smuzhiyun }
3531*4882a593Smuzhiyun 
3532*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_coreidx)3533*4882a593Smuzhiyun BCMPOSTTRAPFN(si_coreidx)(const si_t *sih)
3534*4882a593Smuzhiyun {
3535*4882a593Smuzhiyun 	const si_info_t *sii;
3536*4882a593Smuzhiyun 
3537*4882a593Smuzhiyun 	sii = SI_INFO(sih);
3538*4882a593Smuzhiyun 	return sii->curidx;
3539*4882a593Smuzhiyun }
3540*4882a593Smuzhiyun 
3541*4882a593Smuzhiyun uint
si_get_num_cores(const si_t * sih)3542*4882a593Smuzhiyun si_get_num_cores(const si_t *sih)
3543*4882a593Smuzhiyun {
3544*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3545*4882a593Smuzhiyun 	return sii->numcores;
3546*4882a593Smuzhiyun }
3547*4882a593Smuzhiyun 
3548*4882a593Smuzhiyun volatile void *
si_d11_switch_addrbase(si_t * sih,uint coreunit)3549*4882a593Smuzhiyun si_d11_switch_addrbase(si_t *sih, uint coreunit)
3550*4882a593Smuzhiyun {
3551*4882a593Smuzhiyun 	return si_setcore(sih,  D11_CORE_ID, coreunit);
3552*4882a593Smuzhiyun }
3553*4882a593Smuzhiyun 
3554*4882a593Smuzhiyun /** return the core-type instantiation # of the current core */
3555*4882a593Smuzhiyun uint
si_coreunit(const si_t * sih)3556*4882a593Smuzhiyun si_coreunit(const si_t *sih)
3557*4882a593Smuzhiyun {
3558*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3559*4882a593Smuzhiyun 	const si_cores_info_t *cores_info = (const si_cores_info_t *)sii->cores_info;
3560*4882a593Smuzhiyun 	uint idx;
3561*4882a593Smuzhiyun 	uint coreid;
3562*4882a593Smuzhiyun 	uint coreunit;
3563*4882a593Smuzhiyun 	uint i;
3564*4882a593Smuzhiyun 
3565*4882a593Smuzhiyun 	if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) {
3566*4882a593Smuzhiyun 		return nci_coreunit(sih);
3567*4882a593Smuzhiyun 	}
3568*4882a593Smuzhiyun 
3569*4882a593Smuzhiyun 	coreunit = 0;
3570*4882a593Smuzhiyun 
3571*4882a593Smuzhiyun 	idx = sii->curidx;
3572*4882a593Smuzhiyun 
3573*4882a593Smuzhiyun 	ASSERT(GOODREGS(sii->curmap));
3574*4882a593Smuzhiyun 	coreid = si_coreid(sih);
3575*4882a593Smuzhiyun 
3576*4882a593Smuzhiyun 	/* count the cores of our type */
3577*4882a593Smuzhiyun 	for (i = 0; i < idx; i++)
3578*4882a593Smuzhiyun 		if (cores_info->coreid[i] == coreid)
3579*4882a593Smuzhiyun 			coreunit++;
3580*4882a593Smuzhiyun 
3581*4882a593Smuzhiyun 	return (coreunit);
3582*4882a593Smuzhiyun }
3583*4882a593Smuzhiyun 
3584*4882a593Smuzhiyun uint
BCMATTACHFN(si_corevendor)3585*4882a593Smuzhiyun BCMATTACHFN(si_corevendor)(const si_t *sih)
3586*4882a593Smuzhiyun {
3587*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3588*4882a593Smuzhiyun 		return sb_corevendor(sih);
3589*4882a593Smuzhiyun 		else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3590*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3591*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3592*4882a593Smuzhiyun 		return ai_corevendor(sih);
3593*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3594*4882a593Smuzhiyun 		return ub_corevendor(sih);
3595*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3596*4882a593Smuzhiyun 		return nci_corevendor(sih);
3597*4882a593Smuzhiyun 	else {
3598*4882a593Smuzhiyun 		ASSERT(0);
3599*4882a593Smuzhiyun 		return 0;
3600*4882a593Smuzhiyun 	}
3601*4882a593Smuzhiyun }
3602*4882a593Smuzhiyun 
3603*4882a593Smuzhiyun bool
BCMINITFN(si_backplane64)3604*4882a593Smuzhiyun BCMINITFN(si_backplane64)(const si_t *sih)
3605*4882a593Smuzhiyun {
3606*4882a593Smuzhiyun 	return ((sih->cccaps & CC_CAP_BKPLN64) != 0);
3607*4882a593Smuzhiyun }
3608*4882a593Smuzhiyun 
3609*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_corerev)3610*4882a593Smuzhiyun BCMPOSTTRAPFN(si_corerev)(const si_t *sih)
3611*4882a593Smuzhiyun {
3612*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3613*4882a593Smuzhiyun 		return sb_corerev(sih);
3614*4882a593Smuzhiyun 		else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3615*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3616*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3617*4882a593Smuzhiyun 		return ai_corerev(sih);
3618*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3619*4882a593Smuzhiyun 		return ub_corerev(sih);
3620*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3621*4882a593Smuzhiyun 		return nci_corerev(sih);
3622*4882a593Smuzhiyun 	else {
3623*4882a593Smuzhiyun 		ASSERT(0);
3624*4882a593Smuzhiyun 		return 0;
3625*4882a593Smuzhiyun 	}
3626*4882a593Smuzhiyun }
3627*4882a593Smuzhiyun 
3628*4882a593Smuzhiyun uint
si_corerev_minor(const si_t * sih)3629*4882a593Smuzhiyun si_corerev_minor(const si_t *sih)
3630*4882a593Smuzhiyun {
3631*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI) {
3632*4882a593Smuzhiyun 		return ai_corerev_minor(sih);
3633*4882a593Smuzhiyun 	}
3634*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3635*4882a593Smuzhiyun 		return nci_corerev_minor(sih);
3636*4882a593Smuzhiyun 	else {
3637*4882a593Smuzhiyun 		return 0;
3638*4882a593Smuzhiyun 	}
3639*4882a593Smuzhiyun }
3640*4882a593Smuzhiyun 
3641*4882a593Smuzhiyun /* return index of coreid or BADIDX if not found */
3642*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_findcoreidx)3643*4882a593Smuzhiyun BCMPOSTTRAPFN(si_findcoreidx)(const si_t *sih, uint coreid, uint coreunit)
3644*4882a593Smuzhiyun {
3645*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3646*4882a593Smuzhiyun 	const si_cores_info_t *cores_info = (const si_cores_info_t *)sii->cores_info;
3647*4882a593Smuzhiyun 	uint found;
3648*4882a593Smuzhiyun 	uint i;
3649*4882a593Smuzhiyun 
3650*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_NCI) {
3651*4882a593Smuzhiyun 		return nci_findcoreidx(sih, coreid, coreunit);
3652*4882a593Smuzhiyun 	}
3653*4882a593Smuzhiyun 
3654*4882a593Smuzhiyun 	found = 0;
3655*4882a593Smuzhiyun 
3656*4882a593Smuzhiyun 	for (i = 0; i < sii->numcores; i++) {
3657*4882a593Smuzhiyun 		if (cores_info->coreid[i] == coreid) {
3658*4882a593Smuzhiyun 			if (found == coreunit)
3659*4882a593Smuzhiyun 				return (i);
3660*4882a593Smuzhiyun 			found++;
3661*4882a593Smuzhiyun 		}
3662*4882a593Smuzhiyun 	}
3663*4882a593Smuzhiyun 
3664*4882a593Smuzhiyun 	return (BADIDX);
3665*4882a593Smuzhiyun }
3666*4882a593Smuzhiyun 
3667*4882a593Smuzhiyun bool
BCMPOSTTRAPFN(si_hwa_present)3668*4882a593Smuzhiyun BCMPOSTTRAPFN(si_hwa_present)(const si_t *sih)
3669*4882a593Smuzhiyun {
3670*4882a593Smuzhiyun 	if (si_findcoreidx(sih, HWA_CORE_ID, 0) != BADIDX) {
3671*4882a593Smuzhiyun 		return TRUE;
3672*4882a593Smuzhiyun 	}
3673*4882a593Smuzhiyun 	return FALSE;
3674*4882a593Smuzhiyun }
3675*4882a593Smuzhiyun 
3676*4882a593Smuzhiyun bool
BCMPOSTTRAPFN(si_sysmem_present)3677*4882a593Smuzhiyun BCMPOSTTRAPFN(si_sysmem_present)(const si_t *sih)
3678*4882a593Smuzhiyun {
3679*4882a593Smuzhiyun 	if (si_findcoreidx(sih, SYSMEM_CORE_ID, 0) != BADIDX) {
3680*4882a593Smuzhiyun 		return TRUE;
3681*4882a593Smuzhiyun 	}
3682*4882a593Smuzhiyun 	return FALSE;
3683*4882a593Smuzhiyun }
3684*4882a593Smuzhiyun 
3685*4882a593Smuzhiyun /* return the coreid of the core at index */
3686*4882a593Smuzhiyun uint
si_findcoreid(const si_t * sih,uint coreidx)3687*4882a593Smuzhiyun si_findcoreid(const si_t *sih, uint coreidx)
3688*4882a593Smuzhiyun {
3689*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3690*4882a593Smuzhiyun 	const si_cores_info_t *cores_info = sii->cores_info;
3691*4882a593Smuzhiyun 
3692*4882a593Smuzhiyun 	if (coreidx >= sii->numcores) {
3693*4882a593Smuzhiyun 		return NODEV_CORE_ID;
3694*4882a593Smuzhiyun 	}
3695*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_NCI) {
3696*4882a593Smuzhiyun 		return nci_coreid(sih, coreidx);
3697*4882a593Smuzhiyun 	}
3698*4882a593Smuzhiyun 	return cores_info->coreid[coreidx];
3699*4882a593Smuzhiyun }
3700*4882a593Smuzhiyun 
3701*4882a593Smuzhiyun /** return total coreunit of coreid or zero if not found */
3702*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_numcoreunits)3703*4882a593Smuzhiyun BCMPOSTTRAPFN(si_numcoreunits)(const si_t *sih, uint coreid)
3704*4882a593Smuzhiyun {
3705*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3706*4882a593Smuzhiyun 	const si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
3707*4882a593Smuzhiyun 	uint found = 0;
3708*4882a593Smuzhiyun 	uint i;
3709*4882a593Smuzhiyun 
3710*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_NCI) {
3711*4882a593Smuzhiyun 		return nci_numcoreunits(sih, coreid);
3712*4882a593Smuzhiyun 	}
3713*4882a593Smuzhiyun 	for (i = 0; i < sii->numcores; i++) {
3714*4882a593Smuzhiyun 		if (cores_info->coreid[i] == coreid) {
3715*4882a593Smuzhiyun 			found++;
3716*4882a593Smuzhiyun 		}
3717*4882a593Smuzhiyun 	}
3718*4882a593Smuzhiyun 
3719*4882a593Smuzhiyun 	return found;
3720*4882a593Smuzhiyun }
3721*4882a593Smuzhiyun 
3722*4882a593Smuzhiyun /** return total D11 coreunits */
3723*4882a593Smuzhiyun uint
BCMPOSTTRAPRAMFN(si_numd11coreunits)3724*4882a593Smuzhiyun BCMPOSTTRAPRAMFN(si_numd11coreunits)(const si_t *sih)
3725*4882a593Smuzhiyun {
3726*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_NCI) {
3727*4882a593Smuzhiyun 		return nci_numcoreunits(sih, D11_CORE_ID);
3728*4882a593Smuzhiyun 	}
3729*4882a593Smuzhiyun 	return si_numcoreunits(sih, D11_CORE_ID);
3730*4882a593Smuzhiyun }
3731*4882a593Smuzhiyun 
3732*4882a593Smuzhiyun /** return list of found cores */
3733*4882a593Smuzhiyun uint
si_corelist(const si_t * sih,uint coreid[])3734*4882a593Smuzhiyun si_corelist(const si_t *sih, uint coreid[])
3735*4882a593Smuzhiyun {
3736*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3737*4882a593Smuzhiyun 	const si_cores_info_t *cores_info = (const si_cores_info_t *)sii->cores_info;
3738*4882a593Smuzhiyun 
3739*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_NCI) {
3740*4882a593Smuzhiyun 		return nci_corelist(sih, coreid);
3741*4882a593Smuzhiyun 	}
3742*4882a593Smuzhiyun 	(void)memcpy_s(coreid, (sii->numcores * sizeof(uint)), cores_info->coreid,
3743*4882a593Smuzhiyun 		(sii->numcores * sizeof(uint)));
3744*4882a593Smuzhiyun 	return (sii->numcores);
3745*4882a593Smuzhiyun }
3746*4882a593Smuzhiyun 
3747*4882a593Smuzhiyun /** return current wrapper mapping */
3748*4882a593Smuzhiyun void *
BCMPOSTTRAPFN(si_wrapperregs)3749*4882a593Smuzhiyun BCMPOSTTRAPFN(si_wrapperregs)(const si_t *sih)
3750*4882a593Smuzhiyun {
3751*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3752*4882a593Smuzhiyun 
3753*4882a593Smuzhiyun 	ASSERT(GOODREGS(sii->curwrap));
3754*4882a593Smuzhiyun 
3755*4882a593Smuzhiyun 	return (sii->curwrap);
3756*4882a593Smuzhiyun }
3757*4882a593Smuzhiyun 
3758*4882a593Smuzhiyun /** return current register mapping */
3759*4882a593Smuzhiyun volatile void *
BCMPOSTTRAPFN(si_coreregs)3760*4882a593Smuzhiyun BCMPOSTTRAPFN(si_coreregs)(const si_t *sih)
3761*4882a593Smuzhiyun {
3762*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
3763*4882a593Smuzhiyun 
3764*4882a593Smuzhiyun 	ASSERT(GOODREGS(sii->curmap));
3765*4882a593Smuzhiyun 
3766*4882a593Smuzhiyun 	return (sii->curmap);
3767*4882a593Smuzhiyun }
3768*4882a593Smuzhiyun 
3769*4882a593Smuzhiyun /**
3770*4882a593Smuzhiyun  * This function changes logical "focus" to the indicated core;
3771*4882a593Smuzhiyun  * must be called with interrupts off.
3772*4882a593Smuzhiyun  * Moreover, callers should keep interrupts off during switching out of and back to d11 core
3773*4882a593Smuzhiyun  */
3774*4882a593Smuzhiyun volatile void *
BCMPOSTTRAPFN(si_setcore)3775*4882a593Smuzhiyun BCMPOSTTRAPFN(si_setcore)(si_t *sih, uint coreid, uint coreunit)
3776*4882a593Smuzhiyun {
3777*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
3778*4882a593Smuzhiyun 	uint idx;
3779*4882a593Smuzhiyun 
3780*4882a593Smuzhiyun 	idx = si_findcoreidx(sih, coreid, coreunit);
3781*4882a593Smuzhiyun 	if (!GOODIDX(idx, sii->numcores)) {
3782*4882a593Smuzhiyun 		return (NULL);
3783*4882a593Smuzhiyun 	}
3784*4882a593Smuzhiyun 
3785*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3786*4882a593Smuzhiyun 		return sb_setcoreidx(sih, idx);
3787*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3788*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3789*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3790*4882a593Smuzhiyun 		return ai_setcoreidx(sih, idx);
3791*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3792*4882a593Smuzhiyun 		return ub_setcoreidx(sih, idx);
3793*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3794*4882a593Smuzhiyun 		return nci_setcoreidx(sih, idx);
3795*4882a593Smuzhiyun 	else {
3796*4882a593Smuzhiyun 		ASSERT(0);
3797*4882a593Smuzhiyun 		return NULL;
3798*4882a593Smuzhiyun 	}
3799*4882a593Smuzhiyun }
3800*4882a593Smuzhiyun 
3801*4882a593Smuzhiyun volatile void *
BCMPOSTTRAPFN(si_setcoreidx)3802*4882a593Smuzhiyun BCMPOSTTRAPFN(si_setcoreidx)(si_t *sih, uint coreidx)
3803*4882a593Smuzhiyun {
3804*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3805*4882a593Smuzhiyun 		return sb_setcoreidx(sih, coreidx);
3806*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3807*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3808*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3809*4882a593Smuzhiyun 		return ai_setcoreidx(sih, coreidx);
3810*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3811*4882a593Smuzhiyun 		return ub_setcoreidx(sih, coreidx);
3812*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3813*4882a593Smuzhiyun 		return nci_setcoreidx(sih, coreidx);
3814*4882a593Smuzhiyun 	else {
3815*4882a593Smuzhiyun 		ASSERT(0);
3816*4882a593Smuzhiyun 		return NULL;
3817*4882a593Smuzhiyun 	}
3818*4882a593Smuzhiyun }
3819*4882a593Smuzhiyun 
3820*4882a593Smuzhiyun /** Turn off interrupt as required by sb_setcore, before switch core */
3821*4882a593Smuzhiyun volatile void *
BCMPOSTTRAPFN(si_switch_core)3822*4882a593Smuzhiyun BCMPOSTTRAPFN(si_switch_core)(si_t *sih, uint coreid, uint *origidx, bcm_int_bitmask_t *intr_val)
3823*4882a593Smuzhiyun {
3824*4882a593Smuzhiyun 	volatile void *cc;
3825*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
3826*4882a593Smuzhiyun 
3827*4882a593Smuzhiyun 	if (SI_FAST(sii)) {
3828*4882a593Smuzhiyun 		/* Overloading the origidx variable to remember the coreid,
3829*4882a593Smuzhiyun 		 * this works because the core ids cannot be confused with
3830*4882a593Smuzhiyun 		 * core indices.
3831*4882a593Smuzhiyun 		 */
3832*4882a593Smuzhiyun 		*origidx = coreid;
3833*4882a593Smuzhiyun 		if (coreid == CC_CORE_ID)
3834*4882a593Smuzhiyun 			return (volatile void *)CCREGS_FAST(sii);
3835*4882a593Smuzhiyun 		else if (coreid == BUSCORETYPE(sih->buscoretype))
3836*4882a593Smuzhiyun 			return (volatile void *)PCIEREGS(sii);
3837*4882a593Smuzhiyun 	}
3838*4882a593Smuzhiyun 	INTR_OFF(sii, intr_val);
3839*4882a593Smuzhiyun 	*origidx = sii->curidx;
3840*4882a593Smuzhiyun 	cc = si_setcore(sih, coreid, 0);
3841*4882a593Smuzhiyun 	ASSERT(cc != NULL);
3842*4882a593Smuzhiyun 
3843*4882a593Smuzhiyun 	return cc;
3844*4882a593Smuzhiyun }
3845*4882a593Smuzhiyun 
3846*4882a593Smuzhiyun /* restore coreidx and restore interrupt */
3847*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_restore_core)3848*4882a593Smuzhiyun 	BCMPOSTTRAPFN(si_restore_core)(si_t *sih, uint coreid, bcm_int_bitmask_t *intr_val)
3849*4882a593Smuzhiyun {
3850*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
3851*4882a593Smuzhiyun 
3852*4882a593Smuzhiyun 	if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == BUSCORETYPE(sih->buscoretype))))
3853*4882a593Smuzhiyun 		return;
3854*4882a593Smuzhiyun 
3855*4882a593Smuzhiyun 	si_setcoreidx(sih, coreid);
3856*4882a593Smuzhiyun 	INTR_RESTORE(sii, intr_val);
3857*4882a593Smuzhiyun }
3858*4882a593Smuzhiyun 
3859*4882a593Smuzhiyun /* Switch to particular core and get corerev */
3860*4882a593Smuzhiyun #ifdef USE_NEW_COREREV_API
3861*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_corerev_ext)3862*4882a593Smuzhiyun BCMPOSTTRAPFN(si_corerev_ext)(si_t *sih, uint coreid, uint coreunit)
3863*4882a593Smuzhiyun {
3864*4882a593Smuzhiyun 	uint coreidx;
3865*4882a593Smuzhiyun 	uint corerev;
3866*4882a593Smuzhiyun 
3867*4882a593Smuzhiyun 	coreidx = si_coreidx(sih);
3868*4882a593Smuzhiyun 	(void)si_setcore(sih, coreid, coreunit);
3869*4882a593Smuzhiyun 
3870*4882a593Smuzhiyun 	corerev = si_corerev(sih);
3871*4882a593Smuzhiyun 
3872*4882a593Smuzhiyun 	si_setcoreidx(sih, coreidx);
3873*4882a593Smuzhiyun 	return corerev;
3874*4882a593Smuzhiyun }
3875*4882a593Smuzhiyun #else
si_get_corerev(si_t * sih,uint core_id)3876*4882a593Smuzhiyun uint si_get_corerev(si_t *sih, uint core_id)
3877*4882a593Smuzhiyun {
3878*4882a593Smuzhiyun 	uint corerev, orig_coreid;
3879*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
3880*4882a593Smuzhiyun 
3881*4882a593Smuzhiyun 	si_switch_core(sih, core_id, &orig_coreid, &intr_val);
3882*4882a593Smuzhiyun 	corerev = si_corerev(sih);
3883*4882a593Smuzhiyun 	si_restore_core(sih, orig_coreid, &intr_val);
3884*4882a593Smuzhiyun 	return corerev;
3885*4882a593Smuzhiyun }
3886*4882a593Smuzhiyun #endif /* !USE_NEW_COREREV_API */
3887*4882a593Smuzhiyun 
3888*4882a593Smuzhiyun int
BCMATTACHFN(si_numaddrspaces)3889*4882a593Smuzhiyun BCMATTACHFN(si_numaddrspaces)(const si_t *sih)
3890*4882a593Smuzhiyun {
3891*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3892*4882a593Smuzhiyun 		return sb_numaddrspaces(sih);
3893*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3894*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3895*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3896*4882a593Smuzhiyun 		return ai_numaddrspaces(sih);
3897*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3898*4882a593Smuzhiyun 		return ub_numaddrspaces(sih);
3899*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3900*4882a593Smuzhiyun 		return nci_numaddrspaces(sih);
3901*4882a593Smuzhiyun 	else {
3902*4882a593Smuzhiyun 		ASSERT(0);
3903*4882a593Smuzhiyun 		return 0;
3904*4882a593Smuzhiyun 	}
3905*4882a593Smuzhiyun }
3906*4882a593Smuzhiyun 
3907*4882a593Smuzhiyun /* Return the address of the nth address space in the current core
3908*4882a593Smuzhiyun  * Arguments:
3909*4882a593Smuzhiyun  * sih : Pointer to struct si_t
3910*4882a593Smuzhiyun  * spidx : slave port index
3911*4882a593Smuzhiyun  * baidx : base address index
3912*4882a593Smuzhiyun  */
3913*4882a593Smuzhiyun 
3914*4882a593Smuzhiyun uint32
si_addrspace(const si_t * sih,uint spidx,uint baidx)3915*4882a593Smuzhiyun si_addrspace(const si_t *sih, uint spidx, uint baidx)
3916*4882a593Smuzhiyun {
3917*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3918*4882a593Smuzhiyun 		return sb_addrspace(sih, baidx);
3919*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3920*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3921*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3922*4882a593Smuzhiyun 		return ai_addrspace(sih, spidx, baidx);
3923*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3924*4882a593Smuzhiyun 		return ub_addrspace(sih, baidx);
3925*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3926*4882a593Smuzhiyun 		return nci_addrspace(sih, spidx, baidx);
3927*4882a593Smuzhiyun 	else {
3928*4882a593Smuzhiyun 		ASSERT(0);
3929*4882a593Smuzhiyun 		return 0;
3930*4882a593Smuzhiyun 	}
3931*4882a593Smuzhiyun }
3932*4882a593Smuzhiyun 
3933*4882a593Smuzhiyun /* Return the size of the nth address space in the current core
3934*4882a593Smuzhiyun  * Arguments:
3935*4882a593Smuzhiyun  * sih : Pointer to struct si_t
3936*4882a593Smuzhiyun  * spidx : slave port index
3937*4882a593Smuzhiyun  * baidx : base address index
3938*4882a593Smuzhiyun  */
3939*4882a593Smuzhiyun uint32
BCMATTACHFN(si_addrspacesize)3940*4882a593Smuzhiyun BCMATTACHFN(si_addrspacesize)(const si_t *sih, uint spidx, uint baidx)
3941*4882a593Smuzhiyun {
3942*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3943*4882a593Smuzhiyun 		return sb_addrspacesize(sih, baidx);
3944*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3945*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3946*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3947*4882a593Smuzhiyun 		return ai_addrspacesize(sih, spidx, baidx);
3948*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3949*4882a593Smuzhiyun 		return ub_addrspacesize(sih, baidx);
3950*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3951*4882a593Smuzhiyun 		return nci_addrspacesize(sih, spidx, baidx);
3952*4882a593Smuzhiyun 	else {
3953*4882a593Smuzhiyun 		ASSERT(0);
3954*4882a593Smuzhiyun 		return 0;
3955*4882a593Smuzhiyun 	}
3956*4882a593Smuzhiyun }
3957*4882a593Smuzhiyun 
3958*4882a593Smuzhiyun void
si_coreaddrspaceX(const si_t * sih,uint asidx,uint32 * addr,uint32 * size)3959*4882a593Smuzhiyun si_coreaddrspaceX(const si_t *sih, uint asidx, uint32 *addr, uint32 *size)
3960*4882a593Smuzhiyun {
3961*4882a593Smuzhiyun 	/* Only supported for SOCI_AI */
3962*4882a593Smuzhiyun 	if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3963*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3964*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3965*4882a593Smuzhiyun 		ai_coreaddrspaceX(sih, asidx, addr, size);
3966*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3967*4882a593Smuzhiyun 		nci_coreaddrspaceX(sih, asidx, addr, size);
3968*4882a593Smuzhiyun 	else
3969*4882a593Smuzhiyun 		*size = 0;
3970*4882a593Smuzhiyun }
3971*4882a593Smuzhiyun 
3972*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_core_cflags)3973*4882a593Smuzhiyun BCMPOSTTRAPFN(si_core_cflags)(const si_t *sih, uint32 mask, uint32 val)
3974*4882a593Smuzhiyun {
3975*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3976*4882a593Smuzhiyun 		return sb_core_cflags(sih, mask, val);
3977*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3978*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3979*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3980*4882a593Smuzhiyun 		return ai_core_cflags(sih, mask, val);
3981*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
3982*4882a593Smuzhiyun 		return ub_core_cflags(sih, mask, val);
3983*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
3984*4882a593Smuzhiyun 		return nci_core_cflags(sih, mask, val);
3985*4882a593Smuzhiyun 	else {
3986*4882a593Smuzhiyun 		ASSERT(0);
3987*4882a593Smuzhiyun 		return 0;
3988*4882a593Smuzhiyun 	}
3989*4882a593Smuzhiyun }
3990*4882a593Smuzhiyun 
3991*4882a593Smuzhiyun void
si_core_cflags_wo(const si_t * sih,uint32 mask,uint32 val)3992*4882a593Smuzhiyun si_core_cflags_wo(const si_t *sih, uint32 mask, uint32 val)
3993*4882a593Smuzhiyun {
3994*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
3995*4882a593Smuzhiyun 		sb_core_cflags_wo(sih, mask, val);
3996*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
3997*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
3998*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
3999*4882a593Smuzhiyun 		ai_core_cflags_wo(sih, mask, val);
4000*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4001*4882a593Smuzhiyun 		ub_core_cflags_wo(sih, mask, val);
4002*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4003*4882a593Smuzhiyun 		nci_core_cflags_wo(sih, mask, val);
4004*4882a593Smuzhiyun 	else
4005*4882a593Smuzhiyun 		ASSERT(0);
4006*4882a593Smuzhiyun }
4007*4882a593Smuzhiyun 
4008*4882a593Smuzhiyun uint32
si_core_sflags(const si_t * sih,uint32 mask,uint32 val)4009*4882a593Smuzhiyun si_core_sflags(const si_t *sih, uint32 mask, uint32 val)
4010*4882a593Smuzhiyun {
4011*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4012*4882a593Smuzhiyun 		return sb_core_sflags(sih, mask, val);
4013*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4014*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4015*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4016*4882a593Smuzhiyun 		return ai_core_sflags(sih, mask, val);
4017*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4018*4882a593Smuzhiyun 		return ub_core_sflags(sih, mask, val);
4019*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4020*4882a593Smuzhiyun 		return nci_core_sflags(sih, mask, val);
4021*4882a593Smuzhiyun 	else {
4022*4882a593Smuzhiyun 		ASSERT(0);
4023*4882a593Smuzhiyun 		return 0;
4024*4882a593Smuzhiyun 	}
4025*4882a593Smuzhiyun }
4026*4882a593Smuzhiyun 
4027*4882a593Smuzhiyun void
si_commit(si_t * sih)4028*4882a593Smuzhiyun si_commit(si_t *sih)
4029*4882a593Smuzhiyun {
4030*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4031*4882a593Smuzhiyun 		sb_commit(sih);
4032*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4033*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4034*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4035*4882a593Smuzhiyun 		;
4036*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4037*4882a593Smuzhiyun 		;
4038*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4039*4882a593Smuzhiyun 		;
4040*4882a593Smuzhiyun 	else {
4041*4882a593Smuzhiyun 		ASSERT(0);
4042*4882a593Smuzhiyun 	}
4043*4882a593Smuzhiyun }
4044*4882a593Smuzhiyun 
4045*4882a593Smuzhiyun bool
BCMPOSTTRAPFN(si_iscoreup)4046*4882a593Smuzhiyun BCMPOSTTRAPFN(si_iscoreup)(const si_t *sih)
4047*4882a593Smuzhiyun {
4048*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4049*4882a593Smuzhiyun 		return sb_iscoreup(sih);
4050*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4051*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4052*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4053*4882a593Smuzhiyun 		return ai_iscoreup(sih);
4054*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4055*4882a593Smuzhiyun 		return ub_iscoreup(sih);
4056*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4057*4882a593Smuzhiyun 		return nci_iscoreup(sih);
4058*4882a593Smuzhiyun 	else {
4059*4882a593Smuzhiyun 		ASSERT(0);
4060*4882a593Smuzhiyun 		return FALSE;
4061*4882a593Smuzhiyun 	}
4062*4882a593Smuzhiyun }
4063*4882a593Smuzhiyun 
4064*4882a593Smuzhiyun /** Caller should make sure it is on the right core, before calling this routine */
4065*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_wrapperreg)4066*4882a593Smuzhiyun BCMPOSTTRAPFN(si_wrapperreg)(const si_t *sih, uint32 offset, uint32 mask, uint32 val)
4067*4882a593Smuzhiyun {
4068*4882a593Smuzhiyun 	/* only for AI back plane chips */
4069*4882a593Smuzhiyun 	if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4070*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4071*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4072*4882a593Smuzhiyun 		return (ai_wrap_reg(sih, offset, mask, val));
4073*4882a593Smuzhiyun 	else if	(CHIPTYPE(sih->socitype) == SOCI_NCI)
4074*4882a593Smuzhiyun 		return (nci_get_wrap_reg(sih, offset, mask, val));
4075*4882a593Smuzhiyun 	return 0;
4076*4882a593Smuzhiyun }
4077*4882a593Smuzhiyun /* si_backplane_access is used to read full backplane address from host for PCIE FD
4078*4882a593Smuzhiyun  * it uses secondary bar-0 window which lies at an offset of 16K from primary bar-0
4079*4882a593Smuzhiyun  * Provides support for read/write of 1/2/4 bytes of backplane address
4080*4882a593Smuzhiyun  * Can be used to read/write
4081*4882a593Smuzhiyun  *	1. core regs
4082*4882a593Smuzhiyun  *	2. Wrapper regs
4083*4882a593Smuzhiyun  *	3. memory
4084*4882a593Smuzhiyun  *	4. BT area
4085*4882a593Smuzhiyun  * For accessing any 32 bit backplane address, [31 : 12] of backplane should be given in "region"
4086*4882a593Smuzhiyun  * [11 : 0] should be the "regoff"
4087*4882a593Smuzhiyun  * for reading  4 bytes from reg 0x200 of d11 core use it like below
4088*4882a593Smuzhiyun  * : si_backplane_access(sih, 0x18001000, 0x200, 4, 0, TRUE)
4089*4882a593Smuzhiyun  */
si_backplane_addr_sane(uint addr,uint size)4090*4882a593Smuzhiyun static int si_backplane_addr_sane(uint addr, uint size)
4091*4882a593Smuzhiyun {
4092*4882a593Smuzhiyun 	int bcmerror = BCME_OK;
4093*4882a593Smuzhiyun 
4094*4882a593Smuzhiyun 	/* For 2 byte access, address has to be 2 byte aligned */
4095*4882a593Smuzhiyun 	if (size == 2) {
4096*4882a593Smuzhiyun 		if (addr & 0x1) {
4097*4882a593Smuzhiyun 			bcmerror = BCME_ERROR;
4098*4882a593Smuzhiyun 		}
4099*4882a593Smuzhiyun 	}
4100*4882a593Smuzhiyun 	/* For 4 byte access, address has to be 4 byte aligned */
4101*4882a593Smuzhiyun 	if (size == 4) {
4102*4882a593Smuzhiyun 		if (addr & 0x3) {
4103*4882a593Smuzhiyun 			bcmerror = BCME_ERROR;
4104*4882a593Smuzhiyun 		}
4105*4882a593Smuzhiyun 	}
4106*4882a593Smuzhiyun 
4107*4882a593Smuzhiyun 	return bcmerror;
4108*4882a593Smuzhiyun }
4109*4882a593Smuzhiyun 
4110*4882a593Smuzhiyun void
si_invalidate_second_bar0win(si_t * sih)4111*4882a593Smuzhiyun si_invalidate_second_bar0win(si_t *sih)
4112*4882a593Smuzhiyun {
4113*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
4114*4882a593Smuzhiyun 	sii->second_bar0win = ~0x0;
4115*4882a593Smuzhiyun }
4116*4882a593Smuzhiyun 
4117*4882a593Smuzhiyun int
si_backplane_access(si_t * sih,uint addr,uint size,uint * val,bool read)4118*4882a593Smuzhiyun si_backplane_access(si_t *sih, uint addr, uint size, uint *val, bool read)
4119*4882a593Smuzhiyun {
4120*4882a593Smuzhiyun 	volatile uint32 *r = NULL;
4121*4882a593Smuzhiyun 	uint32 region = 0;
4122*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
4123*4882a593Smuzhiyun 
4124*4882a593Smuzhiyun 	/* Valid only for pcie bus */
4125*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) != PCI_BUS) {
4126*4882a593Smuzhiyun 		SI_ERROR(("Valid only for pcie bus \n"));
4127*4882a593Smuzhiyun 		return BCME_ERROR;
4128*4882a593Smuzhiyun 	}
4129*4882a593Smuzhiyun 
4130*4882a593Smuzhiyun 	/* Split adrr into region and address offset */
4131*4882a593Smuzhiyun 	region = (addr & (0xFFFFF << 12));
4132*4882a593Smuzhiyun 	addr = addr & 0xFFF;
4133*4882a593Smuzhiyun 
4134*4882a593Smuzhiyun 	/* check for address and size sanity */
4135*4882a593Smuzhiyun 	if (si_backplane_addr_sane(addr, size) != BCME_OK)
4136*4882a593Smuzhiyun 		return BCME_ERROR;
4137*4882a593Smuzhiyun 
4138*4882a593Smuzhiyun 	/* Update window if required */
4139*4882a593Smuzhiyun 	if (sii->second_bar0win != region) {
4140*4882a593Smuzhiyun 		OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_CORE2_WIN, 4, region);
4141*4882a593Smuzhiyun 		sii->second_bar0win = region;
4142*4882a593Smuzhiyun 	}
4143*4882a593Smuzhiyun 
4144*4882a593Smuzhiyun 	/* Estimate effective address
4145*4882a593Smuzhiyun 	 * sii->curmap   : bar-0 virtual address
4146*4882a593Smuzhiyun 	 * PCI_SECOND_BAR0_OFFSET  : secondar bar-0 offset
4147*4882a593Smuzhiyun 	 * regoff : actual reg offset
4148*4882a593Smuzhiyun 	 */
4149*4882a593Smuzhiyun 	r = (volatile uint32 *)((volatile char *)sii->curmap + PCI_SECOND_BAR0_OFFSET + addr);
4150*4882a593Smuzhiyun 
4151*4882a593Smuzhiyun 	SI_VMSG(("si curmap %p  region %x regaddr %x effective addr %p READ %d\n",
4152*4882a593Smuzhiyun 		(volatile char*)sii->curmap, region, addr, r, read));
4153*4882a593Smuzhiyun 
4154*4882a593Smuzhiyun 	switch (size) {
4155*4882a593Smuzhiyun 		case sizeof(uint8) :
4156*4882a593Smuzhiyun 			if (read)
4157*4882a593Smuzhiyun 				*val = R_REG(sii->osh, (volatile uint8*)r);
4158*4882a593Smuzhiyun 			else
4159*4882a593Smuzhiyun 				W_REG(sii->osh, (volatile uint8*)r, *val);
4160*4882a593Smuzhiyun 			break;
4161*4882a593Smuzhiyun 		case sizeof(uint16) :
4162*4882a593Smuzhiyun 			if (read)
4163*4882a593Smuzhiyun 				*val = R_REG(sii->osh, (volatile uint16*)r);
4164*4882a593Smuzhiyun 			else
4165*4882a593Smuzhiyun 				W_REG(sii->osh, (volatile uint16*)r, *val);
4166*4882a593Smuzhiyun 			break;
4167*4882a593Smuzhiyun 		case sizeof(uint32) :
4168*4882a593Smuzhiyun 			if (read)
4169*4882a593Smuzhiyun 				*val = R_REG(sii->osh, (volatile uint32*)r);
4170*4882a593Smuzhiyun 			else
4171*4882a593Smuzhiyun 				W_REG(sii->osh, (volatile uint32*)r, *val);
4172*4882a593Smuzhiyun 			break;
4173*4882a593Smuzhiyun 		default :
4174*4882a593Smuzhiyun 			SI_ERROR(("Invalid  size %d \n", size));
4175*4882a593Smuzhiyun 			return (BCME_ERROR);
4176*4882a593Smuzhiyun 			break;
4177*4882a593Smuzhiyun 	}
4178*4882a593Smuzhiyun 
4179*4882a593Smuzhiyun 	return (BCME_OK);
4180*4882a593Smuzhiyun }
4181*4882a593Smuzhiyun 
4182*4882a593Smuzhiyun /* precommit failed when this is removed */
4183*4882a593Smuzhiyun /* BLAZAR_BRANCH_101_10_DHD_002/build/dhd/linux-fc30/brix-brcm */
4184*4882a593Smuzhiyun /* TBD: Revisit later */
4185*4882a593Smuzhiyun #ifdef BCMINTERNAL
4186*4882a593Smuzhiyun int
si_backplane_access_64(si_t * sih,uint addr,uint size,uint64 * val,bool read)4187*4882a593Smuzhiyun si_backplane_access_64(si_t *sih, uint addr, uint size, uint64 *val, bool read)
4188*4882a593Smuzhiyun {
4189*4882a593Smuzhiyun #if defined(NDIS) || defined(EFI)
4190*4882a593Smuzhiyun 	SI_ERROR(("NDIS/EFI won't support 64 bit access\n"));
4191*4882a593Smuzhiyun 	return (BCME_ERROR);
4192*4882a593Smuzhiyun #else
4193*4882a593Smuzhiyun 	volatile uint64 *r = NULL;
4194*4882a593Smuzhiyun 	uint32 region = 0;
4195*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
4196*4882a593Smuzhiyun 
4197*4882a593Smuzhiyun 	/* Valid only for pcie bus */
4198*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) != PCI_BUS) {
4199*4882a593Smuzhiyun 		SI_ERROR(("Valid only for pcie bus \n"));
4200*4882a593Smuzhiyun 		return BCME_ERROR;
4201*4882a593Smuzhiyun 	}
4202*4882a593Smuzhiyun 
4203*4882a593Smuzhiyun 	/* Split adrr into region and address offset */
4204*4882a593Smuzhiyun 	region = (addr & (0xFFFFF << 12));
4205*4882a593Smuzhiyun 	addr = addr & 0xFFF;
4206*4882a593Smuzhiyun 
4207*4882a593Smuzhiyun 	/* check for address and size sanity */
4208*4882a593Smuzhiyun 	if (si_backplane_addr_sane(addr, size) != BCME_OK) {
4209*4882a593Smuzhiyun 		SI_ERROR(("Address is not aligned\n"));
4210*4882a593Smuzhiyun 		return BCME_ERROR;
4211*4882a593Smuzhiyun 	}
4212*4882a593Smuzhiyun 
4213*4882a593Smuzhiyun 	/* Update window if required */
4214*4882a593Smuzhiyun 	if (sii->second_bar0win != region) {
4215*4882a593Smuzhiyun 		OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_CORE2_WIN, 4, region);
4216*4882a593Smuzhiyun 		sii->second_bar0win = region;
4217*4882a593Smuzhiyun 	}
4218*4882a593Smuzhiyun 
4219*4882a593Smuzhiyun 	/* Estimate effective address
4220*4882a593Smuzhiyun 	 * sii->curmap   : bar-0 virtual address
4221*4882a593Smuzhiyun 	 * PCI_SECOND_BAR0_OFFSET  : secondar bar-0 offset
4222*4882a593Smuzhiyun 	 * regoff : actual reg offset
4223*4882a593Smuzhiyun 	 */
4224*4882a593Smuzhiyun 	r = (volatile uint64 *)((volatile char *)sii->curmap + PCI_SECOND_BAR0_OFFSET + addr);
4225*4882a593Smuzhiyun 
4226*4882a593Smuzhiyun 	switch (size) {
4227*4882a593Smuzhiyun 		case sizeof(uint64) :
4228*4882a593Smuzhiyun 			if (read) {
4229*4882a593Smuzhiyun 				*val = R_REG(sii->osh, (volatile uint64*)r);
4230*4882a593Smuzhiyun 			} else {
4231*4882a593Smuzhiyun 				W_REG(sii->osh, (volatile uint64*)r, *val);
4232*4882a593Smuzhiyun 			}
4233*4882a593Smuzhiyun 			break;
4234*4882a593Smuzhiyun 		default :
4235*4882a593Smuzhiyun 			SI_ERROR(("Invalid  size %d \n", size));
4236*4882a593Smuzhiyun 			return (BCME_ERROR);
4237*4882a593Smuzhiyun 			break;
4238*4882a593Smuzhiyun 	}
4239*4882a593Smuzhiyun 
4240*4882a593Smuzhiyun 	return (BCME_OK);
4241*4882a593Smuzhiyun #endif /* NDIS */
4242*4882a593Smuzhiyun }
4243*4882a593Smuzhiyun #endif /* BCMINTERNAL */
4244*4882a593Smuzhiyun 
4245*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_corereg)4246*4882a593Smuzhiyun BCMPOSTTRAPFN(si_corereg)(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
4247*4882a593Smuzhiyun {
4248*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4249*4882a593Smuzhiyun 		return sb_corereg(sih, coreidx, regoff, mask, val);
4250*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4251*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4252*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4253*4882a593Smuzhiyun 		return ai_corereg(sih, coreidx, regoff, mask, val);
4254*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4255*4882a593Smuzhiyun 		return ub_corereg(sih, coreidx, regoff, mask, val);
4256*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4257*4882a593Smuzhiyun 		return nci_corereg(sih, coreidx, regoff, mask, val);
4258*4882a593Smuzhiyun 	else {
4259*4882a593Smuzhiyun 		ASSERT(0);
4260*4882a593Smuzhiyun 		return 0;
4261*4882a593Smuzhiyun 	}
4262*4882a593Smuzhiyun }
4263*4882a593Smuzhiyun 
4264*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_corereg_writeonly)4265*4882a593Smuzhiyun BCMPOSTTRAPFN(si_corereg_writeonly)(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
4266*4882a593Smuzhiyun {
4267*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_NCI) {
4268*4882a593Smuzhiyun 		return nci_corereg_writeonly(sih, coreidx, regoff, mask, val);
4269*4882a593Smuzhiyun 	} else
4270*4882a593Smuzhiyun 	{
4271*4882a593Smuzhiyun 		return ai_corereg_writeonly(sih, coreidx, regoff, mask, val);
4272*4882a593Smuzhiyun 	}
4273*4882a593Smuzhiyun }
4274*4882a593Smuzhiyun 
4275*4882a593Smuzhiyun /** ILP sensitive register access needs special treatment to avoid backplane stalls */
4276*4882a593Smuzhiyun bool
BCMPOSTTRAPFN(si_pmu_is_ilp_sensitive)4277*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_is_ilp_sensitive)(uint32 idx, uint regoff)
4278*4882a593Smuzhiyun {
4279*4882a593Smuzhiyun 	if (idx == SI_CC_IDX) {
4280*4882a593Smuzhiyun 		if (CHIPCREGS_ILP_SENSITIVE(regoff))
4281*4882a593Smuzhiyun 			return TRUE;
4282*4882a593Smuzhiyun 	} else if (PMUREGS_ILP_SENSITIVE(regoff)) {
4283*4882a593Smuzhiyun 		return TRUE;
4284*4882a593Smuzhiyun 	}
4285*4882a593Smuzhiyun 
4286*4882a593Smuzhiyun 	return FALSE;
4287*4882a593Smuzhiyun }
4288*4882a593Smuzhiyun 
4289*4882a593Smuzhiyun /** 'idx' should refer either to the chipcommon core or the PMU core */
4290*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_pmu_corereg)4291*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_corereg)(si_t *sih, uint32 idx, uint regoff, uint mask, uint val)
4292*4882a593Smuzhiyun {
4293*4882a593Smuzhiyun 	int pmustatus_offset;
4294*4882a593Smuzhiyun 
4295*4882a593Smuzhiyun 	/* prevent backplane stall on double write to 'ILP domain' registers in the PMU */
4296*4882a593Smuzhiyun 	if (mask != 0 && PMUREV(sih->pmurev) >= 22 &&
4297*4882a593Smuzhiyun 	    si_pmu_is_ilp_sensitive(idx, regoff)) {
4298*4882a593Smuzhiyun 		pmustatus_offset = AOB_ENAB(sih) ? OFFSETOF(pmuregs_t, pmustatus) :
4299*4882a593Smuzhiyun 			OFFSETOF(chipcregs_t, pmustatus);
4300*4882a593Smuzhiyun 
4301*4882a593Smuzhiyun 		while (si_corereg(sih, idx, pmustatus_offset, 0, 0) & PST_SLOW_WR_PENDING)
4302*4882a593Smuzhiyun 			{};
4303*4882a593Smuzhiyun 	}
4304*4882a593Smuzhiyun 
4305*4882a593Smuzhiyun 	return si_corereg(sih, idx, regoff, mask, val);
4306*4882a593Smuzhiyun }
4307*4882a593Smuzhiyun 
4308*4882a593Smuzhiyun /*
4309*4882a593Smuzhiyun  * If there is no need for fiddling with interrupts or core switches (typically silicon
4310*4882a593Smuzhiyun  * back plane registers, pci registers and chipcommon registers), this function
4311*4882a593Smuzhiyun  * returns the register offset on this core to a mapped address. This address can
4312*4882a593Smuzhiyun  * be used for W_REG/R_REG directly.
4313*4882a593Smuzhiyun  *
4314*4882a593Smuzhiyun  * For accessing registers that would need a core switch, this function will return
4315*4882a593Smuzhiyun  * NULL.
4316*4882a593Smuzhiyun  */
4317*4882a593Smuzhiyun volatile uint32 *
BCMPOSTTRAPFN(si_corereg_addr)4318*4882a593Smuzhiyun BCMPOSTTRAPFN(si_corereg_addr)(si_t *sih, uint coreidx, uint regoff)
4319*4882a593Smuzhiyun {
4320*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4321*4882a593Smuzhiyun 		return sb_corereg_addr(sih, coreidx, regoff);
4322*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4323*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4324*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4325*4882a593Smuzhiyun 		return ai_corereg_addr(sih, coreidx, regoff);
4326*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4327*4882a593Smuzhiyun 		return nci_corereg_addr(sih, coreidx, regoff);
4328*4882a593Smuzhiyun 	else {
4329*4882a593Smuzhiyun 		return 0;
4330*4882a593Smuzhiyun 	}
4331*4882a593Smuzhiyun }
4332*4882a593Smuzhiyun 
4333*4882a593Smuzhiyun void
si_core_disable(const si_t * sih,uint32 bits)4334*4882a593Smuzhiyun si_core_disable(const si_t *sih, uint32 bits)
4335*4882a593Smuzhiyun {
4336*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4337*4882a593Smuzhiyun 		sb_core_disable(sih, bits);
4338*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4339*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4340*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4341*4882a593Smuzhiyun 		ai_core_disable(sih, bits);
4342*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4343*4882a593Smuzhiyun 		nci_core_disable(sih, bits);
4344*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4345*4882a593Smuzhiyun 		ub_core_disable(sih, bits);
4346*4882a593Smuzhiyun }
4347*4882a593Smuzhiyun 
4348*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_core_reset)4349*4882a593Smuzhiyun BCMPOSTTRAPFN(si_core_reset)(si_t *sih, uint32 bits, uint32 resetbits)
4350*4882a593Smuzhiyun {
4351*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4352*4882a593Smuzhiyun 		sb_core_reset(sih, bits, resetbits);
4353*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4354*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4355*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4356*4882a593Smuzhiyun 		ai_core_reset(sih, bits, resetbits);
4357*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4358*4882a593Smuzhiyun 		nci_core_reset(sih, bits, resetbits);
4359*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4360*4882a593Smuzhiyun 		ub_core_reset(sih, bits, resetbits);
4361*4882a593Smuzhiyun }
4362*4882a593Smuzhiyun 
4363*4882a593Smuzhiyun /** Run bist on current core. Caller needs to take care of core-specific bist hazards */
4364*4882a593Smuzhiyun int
si_corebist(const si_t * sih)4365*4882a593Smuzhiyun si_corebist(const si_t *sih)
4366*4882a593Smuzhiyun {
4367*4882a593Smuzhiyun 	uint32 cflags;
4368*4882a593Smuzhiyun 	int result = 0;
4369*4882a593Smuzhiyun 
4370*4882a593Smuzhiyun 	/* Read core control flags */
4371*4882a593Smuzhiyun 	cflags = si_core_cflags(sih, 0, 0);
4372*4882a593Smuzhiyun 
4373*4882a593Smuzhiyun 	/* Set bist & fgc */
4374*4882a593Smuzhiyun 	si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC));
4375*4882a593Smuzhiyun 
4376*4882a593Smuzhiyun 	/* Wait for bist done */
4377*4882a593Smuzhiyun 	SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000);
4378*4882a593Smuzhiyun 
4379*4882a593Smuzhiyun 	if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR)
4380*4882a593Smuzhiyun 		result = BCME_ERROR;
4381*4882a593Smuzhiyun 
4382*4882a593Smuzhiyun 	/* Reset core control flags */
4383*4882a593Smuzhiyun 	si_core_cflags(sih, 0xffff, cflags);
4384*4882a593Smuzhiyun 
4385*4882a593Smuzhiyun 	return result;
4386*4882a593Smuzhiyun }
4387*4882a593Smuzhiyun 
4388*4882a593Smuzhiyun uint
si_num_slaveports(const si_t * sih,uint coreid)4389*4882a593Smuzhiyun si_num_slaveports(const si_t *sih, uint coreid)
4390*4882a593Smuzhiyun {
4391*4882a593Smuzhiyun 	uint idx = si_findcoreidx(sih, coreid, 0);
4392*4882a593Smuzhiyun 	uint num = 0;
4393*4882a593Smuzhiyun 
4394*4882a593Smuzhiyun 	if (idx != BADIDX) {
4395*4882a593Smuzhiyun 		if (CHIPTYPE(sih->socitype) == SOCI_AI) {
4396*4882a593Smuzhiyun 			num = ai_num_slaveports(sih, idx);
4397*4882a593Smuzhiyun 		}
4398*4882a593Smuzhiyun 		else if (CHIPTYPE(sih->socitype) == SOCI_NCI) {
4399*4882a593Smuzhiyun 			num = nci_num_slaveports(sih, idx);
4400*4882a593Smuzhiyun 		}
4401*4882a593Smuzhiyun 	}
4402*4882a593Smuzhiyun 	return num;
4403*4882a593Smuzhiyun }
4404*4882a593Smuzhiyun 
4405*4882a593Smuzhiyun /* TODO: Check if NCI has a slave port address */
4406*4882a593Smuzhiyun uint32
si_get_slaveport_addr(si_t * sih,uint spidx,uint baidx,uint core_id,uint coreunit)4407*4882a593Smuzhiyun si_get_slaveport_addr(si_t *sih, uint spidx, uint baidx, uint core_id, uint coreunit)
4408*4882a593Smuzhiyun {
4409*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
4410*4882a593Smuzhiyun 	uint origidx = sii->curidx;
4411*4882a593Smuzhiyun 	uint32 addr = 0x0;
4412*4882a593Smuzhiyun 
4413*4882a593Smuzhiyun 	if (!((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4414*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4415*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI) ||
4416*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NCI)))
4417*4882a593Smuzhiyun 		goto done;
4418*4882a593Smuzhiyun 
4419*4882a593Smuzhiyun 	si_setcore(sih, core_id, coreunit);
4420*4882a593Smuzhiyun 
4421*4882a593Smuzhiyun 	addr = si_addrspace(sih, spidx, baidx);
4422*4882a593Smuzhiyun 
4423*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
4424*4882a593Smuzhiyun 
4425*4882a593Smuzhiyun done:
4426*4882a593Smuzhiyun 	return addr;
4427*4882a593Smuzhiyun }
4428*4882a593Smuzhiyun 
4429*4882a593Smuzhiyun /* TODO: Check if NCI has a d11 slave port address */
4430*4882a593Smuzhiyun uint32
si_get_d11_slaveport_addr(si_t * sih,uint spidx,uint baidx,uint coreunit)4431*4882a593Smuzhiyun si_get_d11_slaveport_addr(si_t *sih, uint spidx, uint baidx, uint coreunit)
4432*4882a593Smuzhiyun {
4433*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
4434*4882a593Smuzhiyun 	uint origidx = sii->curidx;
4435*4882a593Smuzhiyun 	uint32 addr = 0x0;
4436*4882a593Smuzhiyun 
4437*4882a593Smuzhiyun 	if (!((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4438*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4439*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI) ||
4440*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NCI)))
4441*4882a593Smuzhiyun 		goto done;
4442*4882a593Smuzhiyun 
4443*4882a593Smuzhiyun 	si_setcore(sih, D11_CORE_ID, coreunit);
4444*4882a593Smuzhiyun 
4445*4882a593Smuzhiyun 	addr = si_addrspace(sih, spidx, baidx);
4446*4882a593Smuzhiyun 
4447*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
4448*4882a593Smuzhiyun 
4449*4882a593Smuzhiyun done:
4450*4882a593Smuzhiyun 	return addr;
4451*4882a593Smuzhiyun }
4452*4882a593Smuzhiyun 
4453*4882a593Smuzhiyun static uint32
BCMINITFN(factor6)4454*4882a593Smuzhiyun BCMINITFN(factor6)(uint32 x)
4455*4882a593Smuzhiyun {
4456*4882a593Smuzhiyun 	switch (x) {
4457*4882a593Smuzhiyun 	case CC_F6_2:	return 2;
4458*4882a593Smuzhiyun 	case CC_F6_3:	return 3;
4459*4882a593Smuzhiyun 	case CC_F6_4:	return 4;
4460*4882a593Smuzhiyun 	case CC_F6_5:	return 5;
4461*4882a593Smuzhiyun 	case CC_F6_6:	return 6;
4462*4882a593Smuzhiyun 	case CC_F6_7:	return 7;
4463*4882a593Smuzhiyun 	default:	return 0;
4464*4882a593Smuzhiyun 	}
4465*4882a593Smuzhiyun }
4466*4882a593Smuzhiyun 
4467*4882a593Smuzhiyun /*
4468*4882a593Smuzhiyun  * Divide the clock by the divisor with protection for
4469*4882a593Smuzhiyun  * a zero divisor.
4470*4882a593Smuzhiyun  */
4471*4882a593Smuzhiyun static uint32
divide_clock(uint32 clock,uint32 div)4472*4882a593Smuzhiyun divide_clock(uint32 clock, uint32 div)
4473*4882a593Smuzhiyun {
4474*4882a593Smuzhiyun 	return div ? clock / div : 0;
4475*4882a593Smuzhiyun }
4476*4882a593Smuzhiyun 
4477*4882a593Smuzhiyun /** calculate the speed the SI would run at given a set of clockcontrol values */
4478*4882a593Smuzhiyun uint32
BCMINITFN(si_clock_rate)4479*4882a593Smuzhiyun BCMINITFN(si_clock_rate)(uint32 pll_type, uint32 n, uint32 m)
4480*4882a593Smuzhiyun {
4481*4882a593Smuzhiyun 	uint32 n1, n2, clock, m1, m2, m3, mc;
4482*4882a593Smuzhiyun 
4483*4882a593Smuzhiyun 	n1 = n & CN_N1_MASK;
4484*4882a593Smuzhiyun 	n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT;
4485*4882a593Smuzhiyun 
4486*4882a593Smuzhiyun 	if (pll_type == PLL_TYPE6) {
4487*4882a593Smuzhiyun 		if (m & CC_T6_MMASK)
4488*4882a593Smuzhiyun 			return CC_T6_M1;
4489*4882a593Smuzhiyun 		else
4490*4882a593Smuzhiyun 			return CC_T6_M0;
4491*4882a593Smuzhiyun 	} else if ((pll_type == PLL_TYPE1) ||
4492*4882a593Smuzhiyun 	           (pll_type == PLL_TYPE3) ||
4493*4882a593Smuzhiyun 	           (pll_type == PLL_TYPE4) ||
4494*4882a593Smuzhiyun 	           (pll_type == PLL_TYPE7)) {
4495*4882a593Smuzhiyun 		n1 = factor6(n1);
4496*4882a593Smuzhiyun 		n2 += CC_F5_BIAS;
4497*4882a593Smuzhiyun 	} else if (pll_type == PLL_TYPE2) {
4498*4882a593Smuzhiyun 		n1 += CC_T2_BIAS;
4499*4882a593Smuzhiyun 		n2 += CC_T2_BIAS;
4500*4882a593Smuzhiyun 		ASSERT((n1 >= 2) && (n1 <= 7));
4501*4882a593Smuzhiyun 		ASSERT((n2 >= 5) && (n2 <= 23));
4502*4882a593Smuzhiyun 	} else if (pll_type == PLL_TYPE5) {
4503*4882a593Smuzhiyun 		/* 5365 */
4504*4882a593Smuzhiyun 		return (100000000);
4505*4882a593Smuzhiyun 	} else
4506*4882a593Smuzhiyun 		ASSERT(0);
4507*4882a593Smuzhiyun 	/* PLL types 3 and 7 use BASE2 (25Mhz) */
4508*4882a593Smuzhiyun 	if ((pll_type == PLL_TYPE3) ||
4509*4882a593Smuzhiyun 	    (pll_type == PLL_TYPE7)) {
4510*4882a593Smuzhiyun 		clock = CC_CLOCK_BASE2 * n1 * n2;
4511*4882a593Smuzhiyun 	} else
4512*4882a593Smuzhiyun 		clock = CC_CLOCK_BASE1 * n1 * n2;
4513*4882a593Smuzhiyun 
4514*4882a593Smuzhiyun 	if (clock == 0)
4515*4882a593Smuzhiyun 		return 0;
4516*4882a593Smuzhiyun 
4517*4882a593Smuzhiyun 	m1 = m & CC_M1_MASK;
4518*4882a593Smuzhiyun 	m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT;
4519*4882a593Smuzhiyun 	m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT;
4520*4882a593Smuzhiyun 	mc = (m & CC_MC_MASK) >> CC_MC_SHIFT;
4521*4882a593Smuzhiyun 
4522*4882a593Smuzhiyun 	if ((pll_type == PLL_TYPE1) ||
4523*4882a593Smuzhiyun 	    (pll_type == PLL_TYPE3) ||
4524*4882a593Smuzhiyun 	    (pll_type == PLL_TYPE4) ||
4525*4882a593Smuzhiyun 	    (pll_type == PLL_TYPE7)) {
4526*4882a593Smuzhiyun 		m1 = factor6(m1);
4527*4882a593Smuzhiyun 		if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3))
4528*4882a593Smuzhiyun 			m2 += CC_F5_BIAS;
4529*4882a593Smuzhiyun 		else
4530*4882a593Smuzhiyun 			m2 = factor6(m2);
4531*4882a593Smuzhiyun 		m3 = factor6(m3);
4532*4882a593Smuzhiyun 
4533*4882a593Smuzhiyun 		switch (mc) {
4534*4882a593Smuzhiyun 		case CC_MC_BYPASS:	return (clock);
4535*4882a593Smuzhiyun 		case CC_MC_M1:		return divide_clock(clock, m1);
4536*4882a593Smuzhiyun 		case CC_MC_M1M2:	return divide_clock(clock, m1 * m2);
4537*4882a593Smuzhiyun 		case CC_MC_M1M2M3:	return divide_clock(clock, m1 * m2 * m3);
4538*4882a593Smuzhiyun 		case CC_MC_M1M3:	return divide_clock(clock, m1 * m3);
4539*4882a593Smuzhiyun 		default:		return (0);
4540*4882a593Smuzhiyun 		}
4541*4882a593Smuzhiyun 	} else {
4542*4882a593Smuzhiyun 		ASSERT(pll_type == PLL_TYPE2);
4543*4882a593Smuzhiyun 
4544*4882a593Smuzhiyun 		m1 += CC_T2_BIAS;
4545*4882a593Smuzhiyun 		m2 += CC_T2M2_BIAS;
4546*4882a593Smuzhiyun 		m3 += CC_T2_BIAS;
4547*4882a593Smuzhiyun 		ASSERT((m1 >= 2) && (m1 <= 7));
4548*4882a593Smuzhiyun 		ASSERT((m2 >= 3) && (m2 <= 10));
4549*4882a593Smuzhiyun 		ASSERT((m3 >= 2) && (m3 <= 7));
4550*4882a593Smuzhiyun 
4551*4882a593Smuzhiyun 		if ((mc & CC_T2MC_M1BYP) == 0)
4552*4882a593Smuzhiyun 			clock /= m1;
4553*4882a593Smuzhiyun 		if ((mc & CC_T2MC_M2BYP) == 0)
4554*4882a593Smuzhiyun 			clock /= m2;
4555*4882a593Smuzhiyun 		if ((mc & CC_T2MC_M3BYP) == 0)
4556*4882a593Smuzhiyun 			clock /= m3;
4557*4882a593Smuzhiyun 
4558*4882a593Smuzhiyun 		return (clock);
4559*4882a593Smuzhiyun 	}
4560*4882a593Smuzhiyun }
4561*4882a593Smuzhiyun 
4562*4882a593Smuzhiyun /**
4563*4882a593Smuzhiyun  * Some chips could have multiple host interfaces, however only one will be active.
4564*4882a593Smuzhiyun  * For a given chip. Depending pkgopt and cc_chipst return the active host interface.
4565*4882a593Smuzhiyun  */
4566*4882a593Smuzhiyun uint
si_chip_hostif(const si_t * sih)4567*4882a593Smuzhiyun si_chip_hostif(const si_t *sih)
4568*4882a593Smuzhiyun {
4569*4882a593Smuzhiyun 	uint hosti = 0;
4570*4882a593Smuzhiyun 
4571*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
4572*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
4573*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
4574*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
4575*4882a593Smuzhiyun 		hosti = CHIP_HOSTIF_SDIOMODE;
4576*4882a593Smuzhiyun 		break;
4577*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
4578*4882a593Smuzhiyun 		hosti = CHIP_HOSTIF_PCIEMODE;
4579*4882a593Smuzhiyun 		break;
4580*4882a593Smuzhiyun 
4581*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
4582*4882a593Smuzhiyun 		/* chippkg bit-0 == 0 is PCIE only pkgs
4583*4882a593Smuzhiyun 		 * chippkg bit-0 == 1 has both PCIE and USB cores enabled
4584*4882a593Smuzhiyun 		 */
4585*4882a593Smuzhiyun 		if ((sih->chippkg & 0x1) && (sih->chipst & CST4360_MODE_USB))
4586*4882a593Smuzhiyun 			hosti = CHIP_HOSTIF_USBMODE;
4587*4882a593Smuzhiyun 		else
4588*4882a593Smuzhiyun 			hosti = CHIP_HOSTIF_PCIEMODE;
4589*4882a593Smuzhiyun 
4590*4882a593Smuzhiyun 		break;
4591*4882a593Smuzhiyun 
4592*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
4593*4882a593Smuzhiyun 		 if (CST4369_CHIPMODE_SDIOD(sih->chipst))
4594*4882a593Smuzhiyun 			 hosti = CHIP_HOSTIF_SDIOMODE;
4595*4882a593Smuzhiyun 		 else if (CST4369_CHIPMODE_PCIE(sih->chipst))
4596*4882a593Smuzhiyun 			 hosti = CHIP_HOSTIF_PCIEMODE;
4597*4882a593Smuzhiyun 		 break;
4598*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
4599*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
4600*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
4601*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
4602*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
4603*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
4604*4882a593Smuzhiyun 		 hosti = CHIP_HOSTIF_PCIEMODE;
4605*4882a593Smuzhiyun 		 break;
4606*4882a593Smuzhiyun 	 case BCM4362_CHIP_GRPID:
4607*4882a593Smuzhiyun 		if (CST4362_CHIPMODE_SDIOD(sih->chipst)) {
4608*4882a593Smuzhiyun 			hosti = CHIP_HOSTIF_SDIOMODE;
4609*4882a593Smuzhiyun 		} else if (CST4362_CHIPMODE_PCIE(sih->chipst)) {
4610*4882a593Smuzhiyun 			hosti = CHIP_HOSTIF_PCIEMODE;
4611*4882a593Smuzhiyun 		}
4612*4882a593Smuzhiyun 		break;
4613*4882a593Smuzhiyun 
4614*4882a593Smuzhiyun 	default:
4615*4882a593Smuzhiyun 		break;
4616*4882a593Smuzhiyun 	}
4617*4882a593Smuzhiyun 
4618*4882a593Smuzhiyun 	return hosti;
4619*4882a593Smuzhiyun }
4620*4882a593Smuzhiyun 
4621*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
4622*4882a593Smuzhiyun uint32
BCMINITFN(si_clock)4623*4882a593Smuzhiyun BCMINITFN(si_clock)(si_t *sih)
4624*4882a593Smuzhiyun {
4625*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
4626*4882a593Smuzhiyun 	chipcregs_t *cc;
4627*4882a593Smuzhiyun 	uint32 n, m;
4628*4882a593Smuzhiyun 	uint idx;
4629*4882a593Smuzhiyun 	uint32 pll_type, rate;
4630*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
4631*4882a593Smuzhiyun 
4632*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
4633*4882a593Smuzhiyun 	if (PMUCTL_ENAB(sih)) {
4634*4882a593Smuzhiyun 		rate = si_pmu_si_clock(sih, sii->osh);
4635*4882a593Smuzhiyun 		goto exit;
4636*4882a593Smuzhiyun 	}
4637*4882a593Smuzhiyun 
4638*4882a593Smuzhiyun 	idx = sii->curidx;
4639*4882a593Smuzhiyun 	cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
4640*4882a593Smuzhiyun 	ASSERT(cc != NULL);
4641*4882a593Smuzhiyun 
4642*4882a593Smuzhiyun 	n = R_REG(sii->osh, &cc->clockcontrol_n);
4643*4882a593Smuzhiyun 	pll_type = sih->cccaps & CC_CAP_PLL_MASK;
4644*4882a593Smuzhiyun 	if (pll_type == PLL_TYPE6)
4645*4882a593Smuzhiyun 		m = R_REG(sii->osh, &cc->clockcontrol_m3);
4646*4882a593Smuzhiyun 	else if (pll_type == PLL_TYPE3)
4647*4882a593Smuzhiyun 		m = R_REG(sii->osh, &cc->clockcontrol_m2);
4648*4882a593Smuzhiyun 	else
4649*4882a593Smuzhiyun 		m = R_REG(sii->osh, &cc->clockcontrol_sb);
4650*4882a593Smuzhiyun 
4651*4882a593Smuzhiyun 	/* calculate rate */
4652*4882a593Smuzhiyun 	rate = si_clock_rate(pll_type, n, m);
4653*4882a593Smuzhiyun 
4654*4882a593Smuzhiyun 	if (pll_type == PLL_TYPE3)
4655*4882a593Smuzhiyun 		rate = rate / 2;
4656*4882a593Smuzhiyun 
4657*4882a593Smuzhiyun 	/* switch back to previous core */
4658*4882a593Smuzhiyun 	si_setcoreidx(sih, idx);
4659*4882a593Smuzhiyun exit:
4660*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
4661*4882a593Smuzhiyun 
4662*4882a593Smuzhiyun 	return rate;
4663*4882a593Smuzhiyun }
4664*4882a593Smuzhiyun 
4665*4882a593Smuzhiyun /** returns value in [Hz] units */
4666*4882a593Smuzhiyun uint32
BCMINITFN(si_alp_clock)4667*4882a593Smuzhiyun BCMINITFN(si_alp_clock)(si_t *sih)
4668*4882a593Smuzhiyun {
4669*4882a593Smuzhiyun 	if (PMUCTL_ENAB(sih)) {
4670*4882a593Smuzhiyun 		return si_pmu_alp_clock(sih, si_osh(sih));
4671*4882a593Smuzhiyun 	}
4672*4882a593Smuzhiyun 
4673*4882a593Smuzhiyun 	return ALP_CLOCK;
4674*4882a593Smuzhiyun }
4675*4882a593Smuzhiyun 
4676*4882a593Smuzhiyun /** returns value in [Hz] units */
4677*4882a593Smuzhiyun uint32
BCMINITFN(si_ilp_clock)4678*4882a593Smuzhiyun BCMINITFN(si_ilp_clock)(si_t *sih)
4679*4882a593Smuzhiyun {
4680*4882a593Smuzhiyun 	if (PMUCTL_ENAB(sih))
4681*4882a593Smuzhiyun 		return si_pmu_ilp_clock(sih, si_osh(sih));
4682*4882a593Smuzhiyun 
4683*4882a593Smuzhiyun 	return ILP_CLOCK;
4684*4882a593Smuzhiyun }
4685*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
4686*4882a593Smuzhiyun 
4687*4882a593Smuzhiyun /** set chip watchdog reset timer to fire in 'ticks' */
4688*4882a593Smuzhiyun void
si_watchdog(si_t * sih,uint ticks)4689*4882a593Smuzhiyun si_watchdog(si_t *sih, uint ticks)
4690*4882a593Smuzhiyun {
4691*4882a593Smuzhiyun 	uint nb, maxt;
4692*4882a593Smuzhiyun 	uint pmu_wdt = 1;
4693*4882a593Smuzhiyun 
4694*4882a593Smuzhiyun 	if (PMUCTL_ENAB(sih) && pmu_wdt) {
4695*4882a593Smuzhiyun 		nb = (CCREV(sih->ccrev) < 26) ? 16 : ((CCREV(sih->ccrev) >= 37) ? 32 : 24);
4696*4882a593Smuzhiyun 		/* The mips compiler uses the sllv instruction,
4697*4882a593Smuzhiyun 		 * so we specially handle the 32-bit case.
4698*4882a593Smuzhiyun 		 */
4699*4882a593Smuzhiyun 		if (nb == 32)
4700*4882a593Smuzhiyun 			maxt = 0xffffffff;
4701*4882a593Smuzhiyun 		else
4702*4882a593Smuzhiyun 			maxt = ((1 << nb) - 1);
4703*4882a593Smuzhiyun 
4704*4882a593Smuzhiyun 		/* PR43821: PMU watchdog timer needs min. of 2 ticks */
4705*4882a593Smuzhiyun 		if (ticks == 1)
4706*4882a593Smuzhiyun 			ticks = 2;
4707*4882a593Smuzhiyun 		else if (ticks > maxt)
4708*4882a593Smuzhiyun 			ticks = maxt;
4709*4882a593Smuzhiyun #ifndef DONGLEBUILD
4710*4882a593Smuzhiyun 		if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
4711*4882a593Smuzhiyun 			(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
4712*4882a593Smuzhiyun 			(CHIPID(sih->chip) == BCM43014_CHIP_ID)) {
4713*4882a593Smuzhiyun 			PMU_REG_NEW(sih, min_res_mask, ~0, DEFAULT_43012_MIN_RES_MASK);
4714*4882a593Smuzhiyun 			PMU_REG_NEW(sih, watchdog_res_mask, ~0, DEFAULT_43012_MIN_RES_MASK);
4715*4882a593Smuzhiyun 			PMU_REG_NEW(sih, pmustatus, PST_WDRESET, PST_WDRESET);
4716*4882a593Smuzhiyun 			PMU_REG_NEW(sih, pmucontrol_ext, PCTL_EXT_FASTLPO_SWENAB, 0);
4717*4882a593Smuzhiyun 			SPINWAIT((PMU_REG(sih, pmustatus, 0, 0) & PST_ILPFASTLPO),
4718*4882a593Smuzhiyun 				PMU_MAX_TRANSITION_DLY);
4719*4882a593Smuzhiyun 		}
4720*4882a593Smuzhiyun #endif /* DONGLEBUILD */
4721*4882a593Smuzhiyun 		pmu_corereg(sih, SI_CC_IDX, pmuwatchdog, ~0, ticks);
4722*4882a593Smuzhiyun 	} else {
4723*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
4724*4882a593Smuzhiyun 		/* make sure we come up in fast clock mode; or if clearing, clear clock */
4725*4882a593Smuzhiyun 		si_clkctl_cc(sih, ticks ? CLK_FAST : CLK_DYNAMIC);
4726*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
4727*4882a593Smuzhiyun 		maxt = (1 << 28) - 1;
4728*4882a593Smuzhiyun 		if (ticks > maxt)
4729*4882a593Smuzhiyun 			ticks = maxt;
4730*4882a593Smuzhiyun 
4731*4882a593Smuzhiyun 		if (CCREV(sih->ccrev) >= 65) {
4732*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0,
4733*4882a593Smuzhiyun 				(ticks & WD_COUNTER_MASK) | WD_SSRESET_PCIE_F0_EN |
4734*4882a593Smuzhiyun 					WD_SSRESET_PCIE_ALL_FN_EN);
4735*4882a593Smuzhiyun 		} else {
4736*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks);
4737*4882a593Smuzhiyun 		}
4738*4882a593Smuzhiyun 	}
4739*4882a593Smuzhiyun }
4740*4882a593Smuzhiyun 
4741*4882a593Smuzhiyun /** trigger watchdog reset after ms milliseconds */
4742*4882a593Smuzhiyun void
si_watchdog_ms(si_t * sih,uint32 ms)4743*4882a593Smuzhiyun si_watchdog_ms(si_t *sih, uint32 ms)
4744*4882a593Smuzhiyun {
4745*4882a593Smuzhiyun 	si_watchdog(sih, wd_msticks * ms);
4746*4882a593Smuzhiyun }
4747*4882a593Smuzhiyun 
si_watchdog_msticks(void)4748*4882a593Smuzhiyun uint32 si_watchdog_msticks(void)
4749*4882a593Smuzhiyun {
4750*4882a593Smuzhiyun 	return wd_msticks;
4751*4882a593Smuzhiyun }
4752*4882a593Smuzhiyun 
4753*4882a593Smuzhiyun bool
si_taclear(si_t * sih,bool details)4754*4882a593Smuzhiyun si_taclear(si_t *sih, bool details)
4755*4882a593Smuzhiyun {
4756*4882a593Smuzhiyun #if defined(BCMDBG_ERR) || defined(BCMASSERT_SUPPORT) || \
4757*4882a593Smuzhiyun 	defined(BCMDBG_DUMP)
4758*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4759*4882a593Smuzhiyun 		return sb_taclear(sih, details);
4760*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4761*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4762*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NCI) ||
4763*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4764*4882a593Smuzhiyun 		return FALSE;
4765*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4766*4882a593Smuzhiyun 		return FALSE;
4767*4882a593Smuzhiyun 	else {
4768*4882a593Smuzhiyun 		ASSERT(0);
4769*4882a593Smuzhiyun 		return FALSE;
4770*4882a593Smuzhiyun 	}
4771*4882a593Smuzhiyun #else
4772*4882a593Smuzhiyun 	return FALSE;
4773*4882a593Smuzhiyun #endif /* BCMDBG_ERR || BCMASSERT_SUPPORT || BCMDBG_DUMP */
4774*4882a593Smuzhiyun }
4775*4882a593Smuzhiyun 
4776*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
4777*4882a593Smuzhiyun /**
4778*4882a593Smuzhiyun  * Map sb core id to pci device id.
4779*4882a593Smuzhiyun  */
4780*4882a593Smuzhiyun uint16
BCMATTACHFN(si_d11_devid)4781*4882a593Smuzhiyun BCMATTACHFN(si_d11_devid)(si_t *sih)
4782*4882a593Smuzhiyun {
4783*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
4784*4882a593Smuzhiyun 	uint16 device;
4785*4882a593Smuzhiyun 
4786*4882a593Smuzhiyun 	(void) sii;
4787*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
4788*4882a593Smuzhiyun 		return 0xffff;
4789*4882a593Smuzhiyun 	}
4790*4882a593Smuzhiyun 
4791*4882a593Smuzhiyun 	/* normal case: nvram variable with devpath->devid->wl0id */
4792*4882a593Smuzhiyun 	if ((device = (uint16)si_getdevpathintvar(sih, rstr_devid)) != 0)
4793*4882a593Smuzhiyun 		;
4794*4882a593Smuzhiyun 	/* Get devid from OTP/SPROM depending on where the SROM is read */
4795*4882a593Smuzhiyun 	else if ((device = (uint16)getintvar(sii->vars, rstr_devid)) != 0)
4796*4882a593Smuzhiyun 		;
4797*4882a593Smuzhiyun 	/* no longer support wl0id, but keep the code here for backward compatibility. */
4798*4882a593Smuzhiyun 	else if ((device = (uint16)getintvar(sii->vars, rstr_wl0id)) != 0)
4799*4882a593Smuzhiyun 		;
4800*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4801*4882a593Smuzhiyun 		;
4802*4882a593Smuzhiyun 	else {
4803*4882a593Smuzhiyun 		/* ignore it */
4804*4882a593Smuzhiyun 		device = 0xffff;
4805*4882a593Smuzhiyun 	}
4806*4882a593Smuzhiyun 	return device;
4807*4882a593Smuzhiyun }
4808*4882a593Smuzhiyun 
4809*4882a593Smuzhiyun int
BCMATTACHFN(si_corepciid)4810*4882a593Smuzhiyun BCMATTACHFN(si_corepciid)(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice,
4811*4882a593Smuzhiyun                           uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif,
4812*4882a593Smuzhiyun                           uint8 *pciheader)
4813*4882a593Smuzhiyun {
4814*4882a593Smuzhiyun 	uint16 vendor = 0xffff, device = 0xffff;
4815*4882a593Smuzhiyun 	uint8 class, subclass, progif = 0;
4816*4882a593Smuzhiyun 	uint8 header = PCI_HEADER_NORMAL;
4817*4882a593Smuzhiyun 	uint32 core = si_coreid(sih);
4818*4882a593Smuzhiyun 
4819*4882a593Smuzhiyun 	/* Verify whether the function exists for the core */
4820*4882a593Smuzhiyun 	if (func >= (uint)((core == USB20H_CORE_ID) || (core == NS_USB20_CORE_ID) ? 2 : 1))
4821*4882a593Smuzhiyun 		return BCME_ERROR;
4822*4882a593Smuzhiyun 
4823*4882a593Smuzhiyun 	/* Known vendor translations */
4824*4882a593Smuzhiyun 	switch (si_corevendor(sih)) {
4825*4882a593Smuzhiyun 	case SB_VEND_BCM:
4826*4882a593Smuzhiyun 	case MFGID_BRCM:
4827*4882a593Smuzhiyun 		vendor = VENDOR_BROADCOM;
4828*4882a593Smuzhiyun 		break;
4829*4882a593Smuzhiyun 	default:
4830*4882a593Smuzhiyun 		return BCME_ERROR;
4831*4882a593Smuzhiyun 	}
4832*4882a593Smuzhiyun 
4833*4882a593Smuzhiyun 	/* Determine class based on known core codes */
4834*4882a593Smuzhiyun 	switch (core) {
4835*4882a593Smuzhiyun 	case ENET_CORE_ID:
4836*4882a593Smuzhiyun 		class = PCI_CLASS_NET;
4837*4882a593Smuzhiyun 		subclass = PCI_NET_ETHER;
4838*4882a593Smuzhiyun 		device = BCM47XX_ENET_ID;
4839*4882a593Smuzhiyun 		break;
4840*4882a593Smuzhiyun 	case GIGETH_CORE_ID:
4841*4882a593Smuzhiyun 		class = PCI_CLASS_NET;
4842*4882a593Smuzhiyun 		subclass = PCI_NET_ETHER;
4843*4882a593Smuzhiyun 		device = BCM47XX_GIGETH_ID;
4844*4882a593Smuzhiyun 		break;
4845*4882a593Smuzhiyun 	case GMAC_CORE_ID:
4846*4882a593Smuzhiyun 		class = PCI_CLASS_NET;
4847*4882a593Smuzhiyun 		subclass = PCI_NET_ETHER;
4848*4882a593Smuzhiyun 		device = BCM47XX_GMAC_ID;
4849*4882a593Smuzhiyun 		break;
4850*4882a593Smuzhiyun 	case SDRAM_CORE_ID:
4851*4882a593Smuzhiyun 	case MEMC_CORE_ID:
4852*4882a593Smuzhiyun 	case DMEMC_CORE_ID:
4853*4882a593Smuzhiyun 	case SOCRAM_CORE_ID:
4854*4882a593Smuzhiyun 		class = PCI_CLASS_MEMORY;
4855*4882a593Smuzhiyun 		subclass = PCI_MEMORY_RAM;
4856*4882a593Smuzhiyun 		device = (uint16)core;
4857*4882a593Smuzhiyun 		break;
4858*4882a593Smuzhiyun 	case PCI_CORE_ID:
4859*4882a593Smuzhiyun 	case PCIE_CORE_ID:
4860*4882a593Smuzhiyun 	case PCIE2_CORE_ID:
4861*4882a593Smuzhiyun 		class = PCI_CLASS_BRIDGE;
4862*4882a593Smuzhiyun 		subclass = PCI_BRIDGE_PCI;
4863*4882a593Smuzhiyun 		device = (uint16)core;
4864*4882a593Smuzhiyun 		header = PCI_HEADER_BRIDGE;
4865*4882a593Smuzhiyun 		break;
4866*4882a593Smuzhiyun 	case CODEC_CORE_ID:
4867*4882a593Smuzhiyun 		class = PCI_CLASS_COMM;
4868*4882a593Smuzhiyun 		subclass = PCI_COMM_MODEM;
4869*4882a593Smuzhiyun 		device = BCM47XX_V90_ID;
4870*4882a593Smuzhiyun 		break;
4871*4882a593Smuzhiyun 	case I2S_CORE_ID:
4872*4882a593Smuzhiyun 		class = PCI_CLASS_MMEDIA;
4873*4882a593Smuzhiyun 		subclass = PCI_MMEDIA_AUDIO;
4874*4882a593Smuzhiyun 		device = BCM47XX_AUDIO_ID;
4875*4882a593Smuzhiyun 		break;
4876*4882a593Smuzhiyun 	case USB_CORE_ID:
4877*4882a593Smuzhiyun 	case USB11H_CORE_ID:
4878*4882a593Smuzhiyun 		class = PCI_CLASS_SERIAL;
4879*4882a593Smuzhiyun 		subclass = PCI_SERIAL_USB;
4880*4882a593Smuzhiyun 		progif = 0x10; /* OHCI */
4881*4882a593Smuzhiyun 		device = BCM47XX_USBH_ID;
4882*4882a593Smuzhiyun 		break;
4883*4882a593Smuzhiyun 	case USB20H_CORE_ID:
4884*4882a593Smuzhiyun 	case NS_USB20_CORE_ID:
4885*4882a593Smuzhiyun 		class = PCI_CLASS_SERIAL;
4886*4882a593Smuzhiyun 		subclass = PCI_SERIAL_USB;
4887*4882a593Smuzhiyun 		progif = func == 0 ? 0x10 : 0x20; /* OHCI/EHCI value defined in spec */
4888*4882a593Smuzhiyun 		device = BCM47XX_USB20H_ID;
4889*4882a593Smuzhiyun 		header = PCI_HEADER_MULTI; /* multifunction */
4890*4882a593Smuzhiyun 		break;
4891*4882a593Smuzhiyun 	case IPSEC_CORE_ID:
4892*4882a593Smuzhiyun 		class = PCI_CLASS_CRYPT;
4893*4882a593Smuzhiyun 		subclass = PCI_CRYPT_NETWORK;
4894*4882a593Smuzhiyun 		device = BCM47XX_IPSEC_ID;
4895*4882a593Smuzhiyun 		break;
4896*4882a593Smuzhiyun 	case NS_USB30_CORE_ID:
4897*4882a593Smuzhiyun 		class = PCI_CLASS_SERIAL;
4898*4882a593Smuzhiyun 		subclass = PCI_SERIAL_USB;
4899*4882a593Smuzhiyun 		progif = 0x30; /* XHCI */
4900*4882a593Smuzhiyun 		device = BCM47XX_USB30H_ID;
4901*4882a593Smuzhiyun 		break;
4902*4882a593Smuzhiyun 	case ROBO_CORE_ID:
4903*4882a593Smuzhiyun 		/* Don't use class NETWORK, so wl/et won't attempt to recognize it */
4904*4882a593Smuzhiyun 		class = PCI_CLASS_COMM;
4905*4882a593Smuzhiyun 		subclass = PCI_COMM_OTHER;
4906*4882a593Smuzhiyun 		device = BCM47XX_ROBO_ID;
4907*4882a593Smuzhiyun 		break;
4908*4882a593Smuzhiyun 	case CC_CORE_ID:
4909*4882a593Smuzhiyun 		class = PCI_CLASS_MEMORY;
4910*4882a593Smuzhiyun 		subclass = PCI_MEMORY_FLASH;
4911*4882a593Smuzhiyun 		device = (uint16)core;
4912*4882a593Smuzhiyun 		break;
4913*4882a593Smuzhiyun 	case SATAXOR_CORE_ID:
4914*4882a593Smuzhiyun 		class = PCI_CLASS_XOR;
4915*4882a593Smuzhiyun 		subclass = PCI_XOR_QDMA;
4916*4882a593Smuzhiyun 		device = BCM47XX_SATAXOR_ID;
4917*4882a593Smuzhiyun 		break;
4918*4882a593Smuzhiyun 	case ATA100_CORE_ID:
4919*4882a593Smuzhiyun 		class = PCI_CLASS_DASDI;
4920*4882a593Smuzhiyun 		subclass = PCI_DASDI_IDE;
4921*4882a593Smuzhiyun 		device = BCM47XX_ATA100_ID;
4922*4882a593Smuzhiyun 		break;
4923*4882a593Smuzhiyun 	case USB11D_CORE_ID:
4924*4882a593Smuzhiyun 		class = PCI_CLASS_SERIAL;
4925*4882a593Smuzhiyun 		subclass = PCI_SERIAL_USB;
4926*4882a593Smuzhiyun 		device = BCM47XX_USBD_ID;
4927*4882a593Smuzhiyun 		break;
4928*4882a593Smuzhiyun 	case USB20D_CORE_ID:
4929*4882a593Smuzhiyun 		class = PCI_CLASS_SERIAL;
4930*4882a593Smuzhiyun 		subclass = PCI_SERIAL_USB;
4931*4882a593Smuzhiyun 		device = BCM47XX_USB20D_ID;
4932*4882a593Smuzhiyun 		break;
4933*4882a593Smuzhiyun 	case D11_CORE_ID:
4934*4882a593Smuzhiyun 		class = PCI_CLASS_NET;
4935*4882a593Smuzhiyun 		subclass = PCI_NET_OTHER;
4936*4882a593Smuzhiyun 		device = si_d11_devid(sih);
4937*4882a593Smuzhiyun 		break;
4938*4882a593Smuzhiyun 
4939*4882a593Smuzhiyun 	default:
4940*4882a593Smuzhiyun 		class = subclass = progif = 0xff;
4941*4882a593Smuzhiyun 		device = (uint16)core;
4942*4882a593Smuzhiyun 		break;
4943*4882a593Smuzhiyun 	}
4944*4882a593Smuzhiyun 
4945*4882a593Smuzhiyun 	*pcivendor = vendor;
4946*4882a593Smuzhiyun 	*pcidevice = device;
4947*4882a593Smuzhiyun 	*pciclass = class;
4948*4882a593Smuzhiyun 	*pcisubclass = subclass;
4949*4882a593Smuzhiyun 	*pciprogif = progif;
4950*4882a593Smuzhiyun 	*pciheader = header;
4951*4882a593Smuzhiyun 
4952*4882a593Smuzhiyun 	return 0;
4953*4882a593Smuzhiyun }
4954*4882a593Smuzhiyun 
4955*4882a593Smuzhiyun #if defined(BCMDBG) || defined(BCMDBG_DUMP) || defined(BCMDBG_PHYDUMP)
4956*4882a593Smuzhiyun /** print interesting sbconfig registers */
4957*4882a593Smuzhiyun void
si_dumpregs(si_t * sih,struct bcmstrbuf * b)4958*4882a593Smuzhiyun si_dumpregs(si_t *sih, struct bcmstrbuf *b)
4959*4882a593Smuzhiyun {
4960*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
4961*4882a593Smuzhiyun 	uint origidx;
4962*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
4963*4882a593Smuzhiyun 
4964*4882a593Smuzhiyun 	origidx = sii->curidx;
4965*4882a593Smuzhiyun 
4966*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
4967*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4968*4882a593Smuzhiyun 		sb_dumpregs(sih, b);
4969*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4970*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4971*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4972*4882a593Smuzhiyun 		ai_dumpregs(sih, b);
4973*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4974*4882a593Smuzhiyun 		ub_dumpregs(sih, b);
4975*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4976*4882a593Smuzhiyun 		nci_dumpregs(sih, b);
4977*4882a593Smuzhiyun 	else
4978*4882a593Smuzhiyun 		ASSERT(0);
4979*4882a593Smuzhiyun 
4980*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
4981*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
4982*4882a593Smuzhiyun }
4983*4882a593Smuzhiyun #endif	/* BCMDBG || BCMDBG_DUMP || BCMDBG_PHYDUMP */
4984*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
4985*4882a593Smuzhiyun 
4986*4882a593Smuzhiyun #ifdef BCMDBG
4987*4882a593Smuzhiyun void
si_view(si_t * sih,bool verbose)4988*4882a593Smuzhiyun si_view(si_t *sih, bool verbose)
4989*4882a593Smuzhiyun {
4990*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
4991*4882a593Smuzhiyun 		sb_view(sih, verbose);
4992*4882a593Smuzhiyun 	else if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
4993*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
4994*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
4995*4882a593Smuzhiyun 		ai_view(sih, verbose);
4996*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
4997*4882a593Smuzhiyun 		ub_view(sih, verbose);
4998*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
4999*4882a593Smuzhiyun 		nci_view(sih, verbose);
5000*4882a593Smuzhiyun 	else
5001*4882a593Smuzhiyun 		ASSERT(0);
5002*4882a593Smuzhiyun }
5003*4882a593Smuzhiyun 
5004*4882a593Smuzhiyun void
si_viewall(si_t * sih,bool verbose)5005*4882a593Smuzhiyun si_viewall(si_t *sih, bool verbose)
5006*4882a593Smuzhiyun {
5007*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
5008*4882a593Smuzhiyun 	uint curidx, i;
5009*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
5010*4882a593Smuzhiyun 
5011*4882a593Smuzhiyun 	curidx = sii->curidx;
5012*4882a593Smuzhiyun 
5013*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
5014*4882a593Smuzhiyun 	if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
5015*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS) ||
5016*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_NAI))
5017*4882a593Smuzhiyun 		ai_viewall(sih, verbose);
5018*4882a593Smuzhiyun 	else if (CHIPTYPE(sih->socitype) == SOCI_NCI)
5019*4882a593Smuzhiyun 		nci_viewall(sih, verbose);
5020*4882a593Smuzhiyun 	else {
5021*4882a593Smuzhiyun 		SI_ERROR(("si_viewall: num_cores %d\n", sii->numcores));
5022*4882a593Smuzhiyun 		for (i = 0; i < sii->numcores; i++) {
5023*4882a593Smuzhiyun 			si_setcoreidx(sih, i);
5024*4882a593Smuzhiyun 			si_view(sih, verbose);
5025*4882a593Smuzhiyun 		}
5026*4882a593Smuzhiyun 	}
5027*4882a593Smuzhiyun 	si_setcoreidx(sih, curidx);
5028*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
5029*4882a593Smuzhiyun }
5030*4882a593Smuzhiyun #endif	/* BCMDBG */
5031*4882a593Smuzhiyun 
5032*4882a593Smuzhiyun /** return the slow clock source - LPO, XTAL, or PCI */
5033*4882a593Smuzhiyun static uint
si_slowclk_src(si_info_t * sii)5034*4882a593Smuzhiyun si_slowclk_src(si_info_t *sii)
5035*4882a593Smuzhiyun {
5036*4882a593Smuzhiyun 	chipcregs_t *cc;
5037*4882a593Smuzhiyun 
5038*4882a593Smuzhiyun 	ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
5039*4882a593Smuzhiyun 
5040*4882a593Smuzhiyun 	if (CCREV(sii->pub.ccrev) < 6) {
5041*4882a593Smuzhiyun 		if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) &&
5042*4882a593Smuzhiyun 		    (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) &
5043*4882a593Smuzhiyun 		     PCI_CFG_GPIO_SCS))
5044*4882a593Smuzhiyun 			return (SCC_SS_PCI);
5045*4882a593Smuzhiyun 		else
5046*4882a593Smuzhiyun 			return (SCC_SS_XTAL);
5047*4882a593Smuzhiyun 	} else if (CCREV(sii->pub.ccrev) < 10) {
5048*4882a593Smuzhiyun 		cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx);
5049*4882a593Smuzhiyun 		ASSERT(cc);
5050*4882a593Smuzhiyun 		return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK);
5051*4882a593Smuzhiyun 	} else	/* Insta-clock */
5052*4882a593Smuzhiyun 		return (SCC_SS_XTAL);
5053*4882a593Smuzhiyun }
5054*4882a593Smuzhiyun 
5055*4882a593Smuzhiyun /** return the ILP (slowclock) min or max frequency */
5056*4882a593Smuzhiyun static uint
si_slowclk_freq(si_info_t * sii,bool max_freq,chipcregs_t * cc)5057*4882a593Smuzhiyun si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc)
5058*4882a593Smuzhiyun {
5059*4882a593Smuzhiyun 	uint32 slowclk;
5060*4882a593Smuzhiyun 	uint div;
5061*4882a593Smuzhiyun 
5062*4882a593Smuzhiyun 	ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
5063*4882a593Smuzhiyun 
5064*4882a593Smuzhiyun 	/* shouldn't be here unless we've established the chip has dynamic clk control */
5065*4882a593Smuzhiyun 	ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL);
5066*4882a593Smuzhiyun 
5067*4882a593Smuzhiyun 	slowclk = si_slowclk_src(sii);
5068*4882a593Smuzhiyun 	if (CCREV(sii->pub.ccrev) < 6) {
5069*4882a593Smuzhiyun 		if (slowclk == SCC_SS_PCI)
5070*4882a593Smuzhiyun 			return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64));
5071*4882a593Smuzhiyun 		else
5072*4882a593Smuzhiyun 			return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32));
5073*4882a593Smuzhiyun 	} else if (CCREV(sii->pub.ccrev) < 10) {
5074*4882a593Smuzhiyun 		div = 4 *
5075*4882a593Smuzhiyun 		        (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
5076*4882a593Smuzhiyun 		if (slowclk == SCC_SS_LPO)
5077*4882a593Smuzhiyun 			return (max_freq ? LPOMAXFREQ : LPOMINFREQ);
5078*4882a593Smuzhiyun 		else if (slowclk == SCC_SS_XTAL)
5079*4882a593Smuzhiyun 			return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div));
5080*4882a593Smuzhiyun 		else if (slowclk == SCC_SS_PCI)
5081*4882a593Smuzhiyun 			return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div));
5082*4882a593Smuzhiyun 		else
5083*4882a593Smuzhiyun 			ASSERT(0);
5084*4882a593Smuzhiyun 	} else {
5085*4882a593Smuzhiyun 		/* Chipc rev 10 is InstaClock */
5086*4882a593Smuzhiyun 		div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT;
5087*4882a593Smuzhiyun 		div = 4 * (div + 1);
5088*4882a593Smuzhiyun 		return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div));
5089*4882a593Smuzhiyun 	}
5090*4882a593Smuzhiyun 	return (0);
5091*4882a593Smuzhiyun }
5092*4882a593Smuzhiyun 
5093*4882a593Smuzhiyun static void
BCMINITFN(si_clkctl_setdelay)5094*4882a593Smuzhiyun BCMINITFN(si_clkctl_setdelay)(si_info_t *sii, void *chipcregs)
5095*4882a593Smuzhiyun {
5096*4882a593Smuzhiyun 	chipcregs_t *cc = (chipcregs_t *)chipcregs;
5097*4882a593Smuzhiyun 	uint slowmaxfreq, pll_delay, slowclk;
5098*4882a593Smuzhiyun 	uint pll_on_delay, fref_sel_delay;
5099*4882a593Smuzhiyun 
5100*4882a593Smuzhiyun 	pll_delay = PLL_DELAY;
5101*4882a593Smuzhiyun 
5102*4882a593Smuzhiyun 	/* If the slow clock is not sourced by the xtal then add the xtal_on_delay
5103*4882a593Smuzhiyun 	 * since the xtal will also be powered down by dynamic clk control logic.
5104*4882a593Smuzhiyun 	 */
5105*4882a593Smuzhiyun 
5106*4882a593Smuzhiyun 	slowclk = si_slowclk_src(sii);
5107*4882a593Smuzhiyun 	if (slowclk != SCC_SS_XTAL)
5108*4882a593Smuzhiyun 		pll_delay += XTAL_ON_DELAY;
5109*4882a593Smuzhiyun 
5110*4882a593Smuzhiyun 	/* Starting with 4318 it is ILP that is used for the delays */
5111*4882a593Smuzhiyun 	slowmaxfreq = si_slowclk_freq(sii, (CCREV(sii->pub.ccrev) >= 10) ? FALSE : TRUE, cc);
5112*4882a593Smuzhiyun 
5113*4882a593Smuzhiyun 	pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
5114*4882a593Smuzhiyun 	fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
5115*4882a593Smuzhiyun 
5116*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay);
5117*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay);
5118*4882a593Smuzhiyun }
5119*4882a593Smuzhiyun 
5120*4882a593Smuzhiyun /** initialize power control delay registers */
5121*4882a593Smuzhiyun void
BCMINITFN(si_clkctl_init)5122*4882a593Smuzhiyun BCMINITFN(si_clkctl_init)(si_t *sih)
5123*4882a593Smuzhiyun {
5124*4882a593Smuzhiyun 	si_info_t *sii;
5125*4882a593Smuzhiyun 	uint origidx = 0;
5126*4882a593Smuzhiyun 	chipcregs_t *cc;
5127*4882a593Smuzhiyun 	bool fast;
5128*4882a593Smuzhiyun 
5129*4882a593Smuzhiyun 	if (!CCCTL_ENAB(sih))
5130*4882a593Smuzhiyun 		return;
5131*4882a593Smuzhiyun 
5132*4882a593Smuzhiyun 	sii = SI_INFO(sih);
5133*4882a593Smuzhiyun 	fast = SI_FAST(sii);
5134*4882a593Smuzhiyun 	if (!fast) {
5135*4882a593Smuzhiyun 		origidx = sii->curidx;
5136*4882a593Smuzhiyun 		if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL)
5137*4882a593Smuzhiyun 			return;
5138*4882a593Smuzhiyun 	} else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL)
5139*4882a593Smuzhiyun 		return;
5140*4882a593Smuzhiyun 	ASSERT(cc != NULL);
5141*4882a593Smuzhiyun 
5142*4882a593Smuzhiyun 	/* set all Instaclk chip ILP to 1 MHz */
5143*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) >= 10)
5144*4882a593Smuzhiyun 		SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK,
5145*4882a593Smuzhiyun 		        (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
5146*4882a593Smuzhiyun 
5147*4882a593Smuzhiyun 	si_clkctl_setdelay(sii, (void *)(uintptr)cc);
5148*4882a593Smuzhiyun 
5149*4882a593Smuzhiyun 	/* PR 110294 */
5150*4882a593Smuzhiyun 	OSL_DELAY(20000);
5151*4882a593Smuzhiyun 
5152*4882a593Smuzhiyun 	if (!fast)
5153*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
5154*4882a593Smuzhiyun }
5155*4882a593Smuzhiyun 
5156*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
5157*4882a593Smuzhiyun /** return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */
5158*4882a593Smuzhiyun uint16
BCMINITFN(si_clkctl_fast_pwrup_delay)5159*4882a593Smuzhiyun BCMINITFN(si_clkctl_fast_pwrup_delay)(si_t *sih)
5160*4882a593Smuzhiyun {
5161*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
5162*4882a593Smuzhiyun 	uint origidx = 0;
5163*4882a593Smuzhiyun 	chipcregs_t *cc;
5164*4882a593Smuzhiyun 	uint slowminfreq;
5165*4882a593Smuzhiyun 	uint16 fpdelay;
5166*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
5167*4882a593Smuzhiyun 	bool fast;
5168*4882a593Smuzhiyun 
5169*4882a593Smuzhiyun 	if (PMUCTL_ENAB(sih)) {
5170*4882a593Smuzhiyun 		INTR_OFF(sii, &intr_val);
5171*4882a593Smuzhiyun 		fpdelay = si_pmu_fast_pwrup_delay(sih, sii->osh);
5172*4882a593Smuzhiyun 		INTR_RESTORE(sii, &intr_val);
5173*4882a593Smuzhiyun 		return fpdelay;
5174*4882a593Smuzhiyun 	}
5175*4882a593Smuzhiyun 
5176*4882a593Smuzhiyun 	if (!CCCTL_ENAB(sih))
5177*4882a593Smuzhiyun 		return 0;
5178*4882a593Smuzhiyun 
5179*4882a593Smuzhiyun 	fast = SI_FAST(sii);
5180*4882a593Smuzhiyun 	fpdelay = 0;
5181*4882a593Smuzhiyun 	if (!fast) {
5182*4882a593Smuzhiyun 		origidx = sii->curidx;
5183*4882a593Smuzhiyun 		INTR_OFF(sii, &intr_val);
5184*4882a593Smuzhiyun 		if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL)
5185*4882a593Smuzhiyun 			goto done;
5186*4882a593Smuzhiyun 	} else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) {
5187*4882a593Smuzhiyun 		goto done;
5188*4882a593Smuzhiyun 	}
5189*4882a593Smuzhiyun 
5190*4882a593Smuzhiyun 	ASSERT(cc != NULL);
5191*4882a593Smuzhiyun 
5192*4882a593Smuzhiyun 	slowminfreq = si_slowclk_freq(sii, FALSE, cc);
5193*4882a593Smuzhiyun 	if (slowminfreq > 0)
5194*4882a593Smuzhiyun 		fpdelay = (((R_REG(sii->osh, &cc->pll_on_delay) + 2) * 1000000) +
5195*4882a593Smuzhiyun 		(slowminfreq - 1)) / slowminfreq;
5196*4882a593Smuzhiyun 
5197*4882a593Smuzhiyun done:
5198*4882a593Smuzhiyun 	if (!fast) {
5199*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
5200*4882a593Smuzhiyun 		INTR_RESTORE(sii, &intr_val);
5201*4882a593Smuzhiyun 	}
5202*4882a593Smuzhiyun 	return fpdelay;
5203*4882a593Smuzhiyun }
5204*4882a593Smuzhiyun 
5205*4882a593Smuzhiyun /** turn primary xtal and/or pll off/on */
5206*4882a593Smuzhiyun int
si_clkctl_xtal(si_t * sih,uint what,bool on)5207*4882a593Smuzhiyun si_clkctl_xtal(si_t *sih, uint what, bool on)
5208*4882a593Smuzhiyun {
5209*4882a593Smuzhiyun 	si_info_t *sii;
5210*4882a593Smuzhiyun 	uint32 in, out, outen;
5211*4882a593Smuzhiyun 
5212*4882a593Smuzhiyun 	sii = SI_INFO(sih);
5213*4882a593Smuzhiyun 
5214*4882a593Smuzhiyun 	switch (BUSTYPE(sih->bustype)) {
5215*4882a593Smuzhiyun 
5216*4882a593Smuzhiyun #ifdef BCMSDIO
5217*4882a593Smuzhiyun 	case SDIO_BUS:
5218*4882a593Smuzhiyun 		return (-1);
5219*4882a593Smuzhiyun #endif	/* BCMSDIO */
5220*4882a593Smuzhiyun 
5221*4882a593Smuzhiyun 	case PCI_BUS:
5222*4882a593Smuzhiyun 		/* pcie core doesn't have any mapping to control the xtal pu */
5223*4882a593Smuzhiyun 		if (PCIE(sii) || PCIE_GEN2(sii))
5224*4882a593Smuzhiyun 			return -1;
5225*4882a593Smuzhiyun 
5226*4882a593Smuzhiyun 		in = OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_IN, sizeof(uint32));
5227*4882a593Smuzhiyun 		out = OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32));
5228*4882a593Smuzhiyun 		outen = OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUTEN, sizeof(uint32));
5229*4882a593Smuzhiyun 
5230*4882a593Smuzhiyun 		/*
5231*4882a593Smuzhiyun 		 * Avoid glitching the clock if GPRS is already using it.
5232*4882a593Smuzhiyun 		 * We can't actually read the state of the PLLPD so we infer it
5233*4882a593Smuzhiyun 		 * by the value of XTAL_PU which *is* readable via gpioin.
5234*4882a593Smuzhiyun 		 */
5235*4882a593Smuzhiyun 		if (on && (in & PCI_CFG_GPIO_XTAL))
5236*4882a593Smuzhiyun 			return (0);
5237*4882a593Smuzhiyun 
5238*4882a593Smuzhiyun 		if (what & XTAL)
5239*4882a593Smuzhiyun 			outen |= PCI_CFG_GPIO_XTAL;
5240*4882a593Smuzhiyun 		if (what & PLL)
5241*4882a593Smuzhiyun 			outen |= PCI_CFG_GPIO_PLL;
5242*4882a593Smuzhiyun 
5243*4882a593Smuzhiyun 		if (on) {
5244*4882a593Smuzhiyun 			/* turn primary xtal on */
5245*4882a593Smuzhiyun 			if (what & XTAL) {
5246*4882a593Smuzhiyun 				out |= PCI_CFG_GPIO_XTAL;
5247*4882a593Smuzhiyun 				if (what & PLL)
5248*4882a593Smuzhiyun 					out |= PCI_CFG_GPIO_PLL;
5249*4882a593Smuzhiyun 				OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT,
5250*4882a593Smuzhiyun 				                     sizeof(uint32), out);
5251*4882a593Smuzhiyun 				OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUTEN,
5252*4882a593Smuzhiyun 				                     sizeof(uint32), outen);
5253*4882a593Smuzhiyun 				OSL_DELAY(XTAL_ON_DELAY);
5254*4882a593Smuzhiyun 			}
5255*4882a593Smuzhiyun 
5256*4882a593Smuzhiyun 			/* turn pll on */
5257*4882a593Smuzhiyun 			if (what & PLL) {
5258*4882a593Smuzhiyun 				out &= ~PCI_CFG_GPIO_PLL;
5259*4882a593Smuzhiyun 				OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT,
5260*4882a593Smuzhiyun 				                     sizeof(uint32), out);
5261*4882a593Smuzhiyun 				OSL_DELAY(2000);
5262*4882a593Smuzhiyun 			}
5263*4882a593Smuzhiyun 		} else {
5264*4882a593Smuzhiyun 			if (what & XTAL)
5265*4882a593Smuzhiyun 				out &= ~PCI_CFG_GPIO_XTAL;
5266*4882a593Smuzhiyun 			if (what & PLL)
5267*4882a593Smuzhiyun 				out |= PCI_CFG_GPIO_PLL;
5268*4882a593Smuzhiyun 			OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32), out);
5269*4882a593Smuzhiyun 			OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUTEN, sizeof(uint32),
5270*4882a593Smuzhiyun 			                     outen);
5271*4882a593Smuzhiyun 		}
5272*4882a593Smuzhiyun 		return 0;
5273*4882a593Smuzhiyun 
5274*4882a593Smuzhiyun 	default:
5275*4882a593Smuzhiyun 		return (-1);
5276*4882a593Smuzhiyun 	}
5277*4882a593Smuzhiyun 
5278*4882a593Smuzhiyun 	return (0);
5279*4882a593Smuzhiyun }
5280*4882a593Smuzhiyun 
5281*4882a593Smuzhiyun /**
5282*4882a593Smuzhiyun  *  clock control policy function throught chipcommon
5283*4882a593Smuzhiyun  *
5284*4882a593Smuzhiyun  *    set dynamic clk control mode (forceslow, forcefast, dynamic)
5285*4882a593Smuzhiyun  *    returns true if we are forcing fast clock
5286*4882a593Smuzhiyun  *    this is a wrapper over the next internal function
5287*4882a593Smuzhiyun  *      to allow flexible policy settings for outside caller
5288*4882a593Smuzhiyun  */
5289*4882a593Smuzhiyun bool
si_clkctl_cc(si_t * sih,uint mode)5290*4882a593Smuzhiyun si_clkctl_cc(si_t *sih, uint mode)
5291*4882a593Smuzhiyun {
5292*4882a593Smuzhiyun 	si_info_t *sii;
5293*4882a593Smuzhiyun 
5294*4882a593Smuzhiyun 	sii = SI_INFO(sih);
5295*4882a593Smuzhiyun 
5296*4882a593Smuzhiyun 	/* chipcommon cores prior to rev6 don't support dynamic clock control */
5297*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) < 6)
5298*4882a593Smuzhiyun 		return FALSE;
5299*4882a593Smuzhiyun 
5300*4882a593Smuzhiyun 	return _si_clkctl_cc(sii, mode);
5301*4882a593Smuzhiyun }
5302*4882a593Smuzhiyun 
5303*4882a593Smuzhiyun /* clk control mechanism through chipcommon, no policy checking */
5304*4882a593Smuzhiyun static bool
_si_clkctl_cc(si_info_t * sii,uint mode)5305*4882a593Smuzhiyun _si_clkctl_cc(si_info_t *sii, uint mode)
5306*4882a593Smuzhiyun {
5307*4882a593Smuzhiyun 	uint origidx = 0;
5308*4882a593Smuzhiyun 	chipcregs_t *cc;
5309*4882a593Smuzhiyun 	uint32 scc;
5310*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
5311*4882a593Smuzhiyun 	bool fast = SI_FAST(sii);
5312*4882a593Smuzhiyun 
5313*4882a593Smuzhiyun 	/* chipcommon cores prior to rev6 don't support dynamic clock control */
5314*4882a593Smuzhiyun 	if (CCREV(sii->pub.ccrev) < 6)
5315*4882a593Smuzhiyun 		return (FALSE);
5316*4882a593Smuzhiyun 
5317*4882a593Smuzhiyun 	/* Chips with ccrev 10 are EOL and they don't have SYCC_HR which we use below */
5318*4882a593Smuzhiyun 	ASSERT(CCREV(sii->pub.ccrev) != 10);
5319*4882a593Smuzhiyun 
5320*4882a593Smuzhiyun 	if (!fast) {
5321*4882a593Smuzhiyun 		INTR_OFF(sii, &intr_val);
5322*4882a593Smuzhiyun 		origidx = sii->curidx;
5323*4882a593Smuzhiyun 		cc = (chipcregs_t *) si_setcore(&sii->pub, CC_CORE_ID, 0);
5324*4882a593Smuzhiyun 	} else if ((cc = (chipcregs_t *) CCREGS_FAST(sii)) == NULL)
5325*4882a593Smuzhiyun 		goto done;
5326*4882a593Smuzhiyun 	ASSERT(cc != NULL);
5327*4882a593Smuzhiyun 
5328*4882a593Smuzhiyun 	if (!CCCTL_ENAB(&sii->pub) && (CCREV(sii->pub.ccrev) < 20))
5329*4882a593Smuzhiyun 		goto done;
5330*4882a593Smuzhiyun 
5331*4882a593Smuzhiyun 	switch (mode) {
5332*4882a593Smuzhiyun 	case CLK_FAST:	/* FORCEHT, fast (pll) clock */
5333*4882a593Smuzhiyun 		if (CCREV(sii->pub.ccrev) < 10) {
5334*4882a593Smuzhiyun 			/* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */
5335*4882a593Smuzhiyun 			si_clkctl_xtal(&sii->pub, XTAL, ON);
5336*4882a593Smuzhiyun 			SET_REG(sii->osh, &cc->slow_clk_ctl, (SCC_XC | SCC_FS | SCC_IP), SCC_IP);
5337*4882a593Smuzhiyun 		} else if (CCREV(sii->pub.ccrev) < 20) {
5338*4882a593Smuzhiyun 			OR_REG(sii->osh, &cc->system_clk_ctl, SYCC_HR);
5339*4882a593Smuzhiyun 		} else {
5340*4882a593Smuzhiyun 			OR_REG(sii->osh, &cc->clk_ctl_st, CCS_FORCEHT);
5341*4882a593Smuzhiyun 		}
5342*4882a593Smuzhiyun 
5343*4882a593Smuzhiyun 		/* wait for the PLL */
5344*4882a593Smuzhiyun 		if (PMUCTL_ENAB(&sii->pub)) {
5345*4882a593Smuzhiyun 			uint32 htavail = CCS_HTAVAIL;
5346*4882a593Smuzhiyun 			SPINWAIT(((R_REG(sii->osh, &cc->clk_ctl_st) & htavail) == 0),
5347*4882a593Smuzhiyun 			         PMU_MAX_TRANSITION_DLY);
5348*4882a593Smuzhiyun 			ASSERT(R_REG(sii->osh, &cc->clk_ctl_st) & htavail);
5349*4882a593Smuzhiyun 		} else {
5350*4882a593Smuzhiyun 			OSL_DELAY(PLL_DELAY);
5351*4882a593Smuzhiyun 		}
5352*4882a593Smuzhiyun 		break;
5353*4882a593Smuzhiyun 
5354*4882a593Smuzhiyun 	case CLK_DYNAMIC:	/* enable dynamic clock control */
5355*4882a593Smuzhiyun 		if (CCREV(sii->pub.ccrev) < 10) {
5356*4882a593Smuzhiyun 			scc = R_REG(sii->osh, &cc->slow_clk_ctl);
5357*4882a593Smuzhiyun 			scc &= ~(SCC_FS | SCC_IP | SCC_XC);
5358*4882a593Smuzhiyun 			if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
5359*4882a593Smuzhiyun 				scc |= SCC_XC;
5360*4882a593Smuzhiyun 			W_REG(sii->osh, &cc->slow_clk_ctl, scc);
5361*4882a593Smuzhiyun 
5362*4882a593Smuzhiyun 			/* for dynamic control, we have to release our xtal_pu "force on" */
5363*4882a593Smuzhiyun 			if (scc & SCC_XC)
5364*4882a593Smuzhiyun 				si_clkctl_xtal(&sii->pub, XTAL, OFF);
5365*4882a593Smuzhiyun 		} else if (CCREV(sii->pub.ccrev) < 20) {
5366*4882a593Smuzhiyun 			/* Instaclock */
5367*4882a593Smuzhiyun 			AND_REG(sii->osh, &cc->system_clk_ctl, ~SYCC_HR);
5368*4882a593Smuzhiyun 		} else {
5369*4882a593Smuzhiyun 			AND_REG(sii->osh, &cc->clk_ctl_st, ~CCS_FORCEHT);
5370*4882a593Smuzhiyun 		}
5371*4882a593Smuzhiyun 
5372*4882a593Smuzhiyun 		/* wait for the PLL */
5373*4882a593Smuzhiyun 		if (PMUCTL_ENAB(&sii->pub)) {
5374*4882a593Smuzhiyun 			uint32 htavail = CCS_HTAVAIL;
5375*4882a593Smuzhiyun 			SPINWAIT(((R_REG(sii->osh, &cc->clk_ctl_st) & htavail) != 0),
5376*4882a593Smuzhiyun 			         PMU_MAX_TRANSITION_DLY);
5377*4882a593Smuzhiyun 			ASSERT(!(R_REG(sii->osh, &cc->clk_ctl_st) & htavail));
5378*4882a593Smuzhiyun 		} else {
5379*4882a593Smuzhiyun 			OSL_DELAY(PLL_DELAY);
5380*4882a593Smuzhiyun 		}
5381*4882a593Smuzhiyun 
5382*4882a593Smuzhiyun 		break;
5383*4882a593Smuzhiyun 
5384*4882a593Smuzhiyun 	default:
5385*4882a593Smuzhiyun 		ASSERT(0);
5386*4882a593Smuzhiyun 	}
5387*4882a593Smuzhiyun 
5388*4882a593Smuzhiyun done:
5389*4882a593Smuzhiyun 	if (!fast) {
5390*4882a593Smuzhiyun 		si_setcoreidx(&sii->pub, origidx);
5391*4882a593Smuzhiyun 		INTR_RESTORE(sii, &intr_val);
5392*4882a593Smuzhiyun 	}
5393*4882a593Smuzhiyun 	return (mode == CLK_FAST);
5394*4882a593Smuzhiyun }
5395*4882a593Smuzhiyun 
5396*4882a593Smuzhiyun /** Build device path. Support SI, PCI for now. */
5397*4882a593Smuzhiyun int
BCMNMIATTACHFN(si_devpath)5398*4882a593Smuzhiyun BCMNMIATTACHFN(si_devpath)(const si_t *sih, char *path, int size)
5399*4882a593Smuzhiyun {
5400*4882a593Smuzhiyun 	int slen;
5401*4882a593Smuzhiyun 
5402*4882a593Smuzhiyun 	ASSERT(path != NULL);
5403*4882a593Smuzhiyun 	ASSERT(size >= SI_DEVPATH_BUFSZ);
5404*4882a593Smuzhiyun 
5405*4882a593Smuzhiyun 	if (!path || size <= 0)
5406*4882a593Smuzhiyun 		return -1;
5407*4882a593Smuzhiyun 
5408*4882a593Smuzhiyun 	switch (BUSTYPE(sih->bustype)) {
5409*4882a593Smuzhiyun 	case SI_BUS:
5410*4882a593Smuzhiyun 		slen = snprintf(path, (size_t)size, "sb/%u/", si_coreidx(sih));
5411*4882a593Smuzhiyun 		break;
5412*4882a593Smuzhiyun 	case PCI_BUS:
5413*4882a593Smuzhiyun 		ASSERT((SI_INFO(sih))->osh != NULL);
5414*4882a593Smuzhiyun 		slen = snprintf(path, (size_t)size, "pci/%u/%u/",
5415*4882a593Smuzhiyun 		                OSL_PCI_BUS((SI_INFO(sih))->osh),
5416*4882a593Smuzhiyun 		                OSL_PCI_SLOT((SI_INFO(sih))->osh));
5417*4882a593Smuzhiyun 		break;
5418*4882a593Smuzhiyun #ifdef BCMSDIO
5419*4882a593Smuzhiyun 	case SDIO_BUS:
5420*4882a593Smuzhiyun 		SI_ERROR(("si_devpath: device 0 assumed\n"));
5421*4882a593Smuzhiyun 		slen = snprintf(path, (size_t)size, "sd/%u/", si_coreidx(sih));
5422*4882a593Smuzhiyun 		break;
5423*4882a593Smuzhiyun #endif
5424*4882a593Smuzhiyun 	default:
5425*4882a593Smuzhiyun 		slen = -1;
5426*4882a593Smuzhiyun 		ASSERT(0);
5427*4882a593Smuzhiyun 		break;
5428*4882a593Smuzhiyun 	}
5429*4882a593Smuzhiyun 
5430*4882a593Smuzhiyun 	if (slen < 0 || slen >= size) {
5431*4882a593Smuzhiyun 		path[0] = '\0';
5432*4882a593Smuzhiyun 		return -1;
5433*4882a593Smuzhiyun 	}
5434*4882a593Smuzhiyun 
5435*4882a593Smuzhiyun 	return 0;
5436*4882a593Smuzhiyun }
5437*4882a593Smuzhiyun 
5438*4882a593Smuzhiyun int
BCMNMIATTACHFN(si_devpath_pcie)5439*4882a593Smuzhiyun BCMNMIATTACHFN(si_devpath_pcie)(const si_t *sih, char *path, int size)
5440*4882a593Smuzhiyun {
5441*4882a593Smuzhiyun 	ASSERT(path != NULL);
5442*4882a593Smuzhiyun 	ASSERT(size >= SI_DEVPATH_BUFSZ);
5443*4882a593Smuzhiyun 
5444*4882a593Smuzhiyun 	if (!path || size <= 0)
5445*4882a593Smuzhiyun 		return -1;
5446*4882a593Smuzhiyun 
5447*4882a593Smuzhiyun 	ASSERT((SI_INFO(sih))->osh != NULL);
5448*4882a593Smuzhiyun 	snprintf(path, (size_t)size, "pcie/%u/%u/",
5449*4882a593Smuzhiyun 		OSL_PCIE_DOMAIN((SI_INFO(sih))->osh),
5450*4882a593Smuzhiyun 		OSL_PCIE_BUS((SI_INFO(sih))->osh));
5451*4882a593Smuzhiyun 
5452*4882a593Smuzhiyun 	return 0;
5453*4882a593Smuzhiyun }
5454*4882a593Smuzhiyun 
5455*4882a593Smuzhiyun char *
BCMATTACHFN(si_coded_devpathvar)5456*4882a593Smuzhiyun BCMATTACHFN(si_coded_devpathvar)(const si_t *sih, char *varname, int var_len, const char *name)
5457*4882a593Smuzhiyun {
5458*4882a593Smuzhiyun 	char pathname[SI_DEVPATH_BUFSZ + 32];
5459*4882a593Smuzhiyun 	char devpath[SI_DEVPATH_BUFSZ + 32];
5460*4882a593Smuzhiyun 	char devpath_pcie[SI_DEVPATH_BUFSZ + 32];
5461*4882a593Smuzhiyun 	char *p;
5462*4882a593Smuzhiyun 	int idx;
5463*4882a593Smuzhiyun 	int len1;
5464*4882a593Smuzhiyun 	int len2;
5465*4882a593Smuzhiyun 	int len3 = 0;
5466*4882a593Smuzhiyun 
5467*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
5468*4882a593Smuzhiyun 		return NULL;
5469*4882a593Smuzhiyun 	}
5470*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == PCI_BUS) {
5471*4882a593Smuzhiyun 		snprintf(devpath_pcie, SI_DEVPATH_BUFSZ, "pcie/%u/%u",
5472*4882a593Smuzhiyun 			OSL_PCIE_DOMAIN((SI_INFO(sih))->osh),
5473*4882a593Smuzhiyun 			OSL_PCIE_BUS((SI_INFO(sih))->osh));
5474*4882a593Smuzhiyun 		len3 = strlen(devpath_pcie);
5475*4882a593Smuzhiyun 	}
5476*4882a593Smuzhiyun 
5477*4882a593Smuzhiyun 	/* try to get compact devpath if it exist */
5478*4882a593Smuzhiyun 	if (si_devpath(sih, devpath, SI_DEVPATH_BUFSZ) == 0) {
5479*4882a593Smuzhiyun 		/* devpath now is 'zzz/zz/', adjust length to */
5480*4882a593Smuzhiyun 		/* eliminate ending '/' (if present) */
5481*4882a593Smuzhiyun 		len1 = strlen(devpath);
5482*4882a593Smuzhiyun 		if (devpath[len1 - 1] == '/')
5483*4882a593Smuzhiyun 			len1--;
5484*4882a593Smuzhiyun 
5485*4882a593Smuzhiyun 		for (idx = 0; idx < SI_MAXCORES; idx++) {
5486*4882a593Smuzhiyun 			snprintf(pathname, SI_DEVPATH_BUFSZ, rstr_devpathD, idx);
5487*4882a593Smuzhiyun 			if ((p = getvar(NULL, pathname)) == NULL)
5488*4882a593Smuzhiyun 				continue;
5489*4882a593Smuzhiyun 
5490*4882a593Smuzhiyun 			/* eliminate ending '/' (if present) */
5491*4882a593Smuzhiyun 			len2 = strlen(p);
5492*4882a593Smuzhiyun 			if (p[len2 - 1] == '/')
5493*4882a593Smuzhiyun 				len2--;
5494*4882a593Smuzhiyun 
5495*4882a593Smuzhiyun 			/* check that both lengths match and if so compare */
5496*4882a593Smuzhiyun 			/* the strings (minus trailing '/'s if present */
5497*4882a593Smuzhiyun 			if ((len1 == len2) && (memcmp(p, devpath, len1) == 0)) {
5498*4882a593Smuzhiyun 				snprintf(varname, var_len, rstr_D_S, idx, name);
5499*4882a593Smuzhiyun 				return varname;
5500*4882a593Smuzhiyun 			}
5501*4882a593Smuzhiyun 
5502*4882a593Smuzhiyun 			/* try the new PCIe devpath format if it exists */
5503*4882a593Smuzhiyun 			if (len3 && (len3 == len2) && (memcmp(p, devpath_pcie, len3) == 0)) {
5504*4882a593Smuzhiyun 				snprintf(varname, var_len, rstr_D_S, idx, name);
5505*4882a593Smuzhiyun 				return varname;
5506*4882a593Smuzhiyun 			}
5507*4882a593Smuzhiyun 		}
5508*4882a593Smuzhiyun 	}
5509*4882a593Smuzhiyun 
5510*4882a593Smuzhiyun 	return NULL;
5511*4882a593Smuzhiyun }
5512*4882a593Smuzhiyun 
5513*4882a593Smuzhiyun /** Get a variable, but only if it has a devpath prefix */
5514*4882a593Smuzhiyun char *
BCMATTACHFN(si_getdevpathvar)5515*4882a593Smuzhiyun BCMATTACHFN(si_getdevpathvar)(const si_t *sih, const char *name)
5516*4882a593Smuzhiyun {
5517*4882a593Smuzhiyun 	char varname[SI_DEVPATH_BUFSZ + 32];
5518*4882a593Smuzhiyun 	char *val;
5519*4882a593Smuzhiyun 
5520*4882a593Smuzhiyun 	si_devpathvar(sih, varname, sizeof(varname), name);
5521*4882a593Smuzhiyun 
5522*4882a593Smuzhiyun 	if ((val = getvar(NULL, varname)) != NULL)
5523*4882a593Smuzhiyun 		return val;
5524*4882a593Smuzhiyun 
5525*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == PCI_BUS) {
5526*4882a593Smuzhiyun 		si_pcie_devpathvar(sih, varname, sizeof(varname), name);
5527*4882a593Smuzhiyun 		if ((val = getvar(NULL, varname)) != NULL)
5528*4882a593Smuzhiyun 			return val;
5529*4882a593Smuzhiyun 	}
5530*4882a593Smuzhiyun 
5531*4882a593Smuzhiyun 	/* try to get compact devpath if it exist */
5532*4882a593Smuzhiyun 	if (si_coded_devpathvar(sih, varname, sizeof(varname), name) == NULL)
5533*4882a593Smuzhiyun 		return NULL;
5534*4882a593Smuzhiyun 
5535*4882a593Smuzhiyun 	return (getvar(NULL, varname));
5536*4882a593Smuzhiyun }
5537*4882a593Smuzhiyun 
5538*4882a593Smuzhiyun /** Get a variable, but only if it has a devpath prefix */
5539*4882a593Smuzhiyun int
BCMATTACHFN(si_getdevpathintvar)5540*4882a593Smuzhiyun BCMATTACHFN(si_getdevpathintvar)(const si_t *sih, const char *name)
5541*4882a593Smuzhiyun {
5542*4882a593Smuzhiyun #if defined(BCMBUSTYPE) && (BCMBUSTYPE == SI_BUS)
5543*4882a593Smuzhiyun 	BCM_REFERENCE(sih);
5544*4882a593Smuzhiyun 	return (getintvar(NULL, name));
5545*4882a593Smuzhiyun #else
5546*4882a593Smuzhiyun 	char varname[SI_DEVPATH_BUFSZ + 32];
5547*4882a593Smuzhiyun 	int val;
5548*4882a593Smuzhiyun 
5549*4882a593Smuzhiyun 	si_devpathvar(sih, varname, sizeof(varname), name);
5550*4882a593Smuzhiyun 
5551*4882a593Smuzhiyun 	if ((val = getintvar(NULL, varname)) != 0)
5552*4882a593Smuzhiyun 		return val;
5553*4882a593Smuzhiyun 
5554*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == PCI_BUS) {
5555*4882a593Smuzhiyun 		si_pcie_devpathvar(sih, varname, sizeof(varname), name);
5556*4882a593Smuzhiyun 		if ((val = getintvar(NULL, varname)) != 0)
5557*4882a593Smuzhiyun 			return val;
5558*4882a593Smuzhiyun 	}
5559*4882a593Smuzhiyun 
5560*4882a593Smuzhiyun 	/* try to get compact devpath if it exist */
5561*4882a593Smuzhiyun 	if (si_coded_devpathvar(sih, varname, sizeof(varname), name) == NULL)
5562*4882a593Smuzhiyun 		return 0;
5563*4882a593Smuzhiyun 
5564*4882a593Smuzhiyun 	return (getintvar(NULL, varname));
5565*4882a593Smuzhiyun #endif /* BCMBUSTYPE && BCMBUSTYPE == SI_BUS */
5566*4882a593Smuzhiyun }
5567*4882a593Smuzhiyun 
5568*4882a593Smuzhiyun /**
5569*4882a593Smuzhiyun  * Concatenate the dev path with a varname into the given 'var' buffer
5570*4882a593Smuzhiyun  * and return the 'var' pointer.
5571*4882a593Smuzhiyun  * Nothing is done to the arguments if len == 0 or var is NULL, var is still returned.
5572*4882a593Smuzhiyun  * On overflow, the first char will be set to '\0'.
5573*4882a593Smuzhiyun  */
5574*4882a593Smuzhiyun static char *
BCMATTACHFN(si_devpathvar)5575*4882a593Smuzhiyun BCMATTACHFN(si_devpathvar)(const si_t *sih, char *var, int len, const char *name)
5576*4882a593Smuzhiyun {
5577*4882a593Smuzhiyun 	uint path_len;
5578*4882a593Smuzhiyun 
5579*4882a593Smuzhiyun 	if (!var || len <= 0)
5580*4882a593Smuzhiyun 		return var;
5581*4882a593Smuzhiyun 
5582*4882a593Smuzhiyun 	if (si_devpath(sih, var, len) == 0) {
5583*4882a593Smuzhiyun 		path_len = strlen(var);
5584*4882a593Smuzhiyun 
5585*4882a593Smuzhiyun 		if (strlen(name) + 1 > (uint)(len - path_len))
5586*4882a593Smuzhiyun 			var[0] = '\0';
5587*4882a593Smuzhiyun 		else
5588*4882a593Smuzhiyun 			strlcpy(var + path_len, name, len - path_len);
5589*4882a593Smuzhiyun 	}
5590*4882a593Smuzhiyun 
5591*4882a593Smuzhiyun 	return var;
5592*4882a593Smuzhiyun }
5593*4882a593Smuzhiyun 
5594*4882a593Smuzhiyun static char *
BCMATTACHFN(si_pcie_devpathvar)5595*4882a593Smuzhiyun BCMATTACHFN(si_pcie_devpathvar)(const si_t *sih, char *var, int len, const char *name)
5596*4882a593Smuzhiyun {
5597*4882a593Smuzhiyun 	uint path_len;
5598*4882a593Smuzhiyun 
5599*4882a593Smuzhiyun 	if (!var || len <= 0)
5600*4882a593Smuzhiyun 		return var;
5601*4882a593Smuzhiyun 
5602*4882a593Smuzhiyun 	if (si_devpath_pcie(sih, var, len) == 0) {
5603*4882a593Smuzhiyun 		path_len = strlen(var);
5604*4882a593Smuzhiyun 
5605*4882a593Smuzhiyun 		if (strlen(name) + 1 > (uint)(len - path_len))
5606*4882a593Smuzhiyun 			var[0] = '\0';
5607*4882a593Smuzhiyun 		else
5608*4882a593Smuzhiyun 			strlcpy(var + path_len, name, len - path_len);
5609*4882a593Smuzhiyun 	}
5610*4882a593Smuzhiyun 
5611*4882a593Smuzhiyun 	return var;
5612*4882a593Smuzhiyun }
5613*4882a593Smuzhiyun 
5614*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_ccreg)5615*4882a593Smuzhiyun BCMPOSTTRAPFN(si_ccreg)(si_t *sih, uint32 offset, uint32 mask, uint32 val)
5616*4882a593Smuzhiyun {
5617*4882a593Smuzhiyun 	si_info_t *sii;
5618*4882a593Smuzhiyun 	uint32 reg_val = 0;
5619*4882a593Smuzhiyun 
5620*4882a593Smuzhiyun 	sii = SI_INFO(sih);
5621*4882a593Smuzhiyun 
5622*4882a593Smuzhiyun 	/* abort for invalid offset */
5623*4882a593Smuzhiyun 	if (offset > sizeof(chipcregs_t))
5624*4882a593Smuzhiyun 		return 0;
5625*4882a593Smuzhiyun 
5626*4882a593Smuzhiyun 	reg_val = si_corereg(&sii->pub, SI_CC_IDX, offset, mask, val);
5627*4882a593Smuzhiyun 
5628*4882a593Smuzhiyun 	return reg_val;
5629*4882a593Smuzhiyun }
5630*4882a593Smuzhiyun 
5631*4882a593Smuzhiyun void
sih_write_sraon(si_t * sih,int offset,int len,const uint32 * data)5632*4882a593Smuzhiyun sih_write_sraon(si_t *sih, int offset, int len, const uint32* data)
5633*4882a593Smuzhiyun {
5634*4882a593Smuzhiyun 	chipcregs_t *cc;
5635*4882a593Smuzhiyun 	cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
5636*4882a593Smuzhiyun 	W_REG(si_osh(sih), &cc->sr_memrw_addr, offset);
5637*4882a593Smuzhiyun 	while (len > 0) {
5638*4882a593Smuzhiyun 		W_REG(si_osh(sih), &cc->sr_memrw_data, *data);
5639*4882a593Smuzhiyun 		data++;
5640*4882a593Smuzhiyun 		len -= sizeof(uint32);
5641*4882a593Smuzhiyun 	}
5642*4882a593Smuzhiyun }
5643*4882a593Smuzhiyun 
5644*4882a593Smuzhiyun #ifdef SR_DEBUG
5645*4882a593Smuzhiyun void
si_dump_pmu(si_t * sih,void * arg)5646*4882a593Smuzhiyun si_dump_pmu(si_t *sih, void *arg)
5647*4882a593Smuzhiyun {
5648*4882a593Smuzhiyun 	uint i;
5649*4882a593Smuzhiyun 	uint32 pmu_chip_ctl_reg;
5650*4882a593Smuzhiyun 	uint32 pmu_chip_reg_reg;
5651*4882a593Smuzhiyun 	uint32 pmu_chip_pll_reg;
5652*4882a593Smuzhiyun 	uint32 pmu_chip_res_reg;
5653*4882a593Smuzhiyun 	pmu_reg_t *pmu_var = (pmu_reg_t*)arg;
5654*4882a593Smuzhiyun 	pmu_var->pmu_control = si_ccreg(sih, PMU_CTL, 0, 0);
5655*4882a593Smuzhiyun 	pmu_var->pmu_capabilities = si_ccreg(sih, PMU_CAP, 0, 0);
5656*4882a593Smuzhiyun 	pmu_var->pmu_status = si_ccreg(sih, PMU_ST, 0, 0);
5657*4882a593Smuzhiyun 	pmu_var->res_state = si_ccreg(sih, PMU_RES_STATE, 0, 0);
5658*4882a593Smuzhiyun 	pmu_var->res_pending = si_ccreg(sih, PMU_RES_PENDING, 0, 0);
5659*4882a593Smuzhiyun 	pmu_var->pmu_timer1 = si_ccreg(sih, PMU_TIMER, 0, 0);
5660*4882a593Smuzhiyun 	pmu_var->min_res_mask = si_ccreg(sih, MINRESMASKREG, 0, 0);
5661*4882a593Smuzhiyun 	pmu_var->max_res_mask = si_ccreg(sih, MAXRESMASKREG, 0, 0);
5662*4882a593Smuzhiyun 	pmu_chip_ctl_reg = (pmu_var->pmu_capabilities & 0xf8000000);
5663*4882a593Smuzhiyun 	pmu_chip_ctl_reg = pmu_chip_ctl_reg >> 27;
5664*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_ctl_reg; i++) {
5665*4882a593Smuzhiyun 		pmu_var->pmu_chipcontrol1[i] = si_pmu_chipcontrol(sih, i, 0, 0);
5666*4882a593Smuzhiyun 	}
5667*4882a593Smuzhiyun 	pmu_chip_reg_reg = (pmu_var->pmu_capabilities & 0x07c00000);
5668*4882a593Smuzhiyun 	pmu_chip_reg_reg = pmu_chip_reg_reg >> 22;
5669*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_reg_reg; i++) {
5670*4882a593Smuzhiyun 		pmu_var->pmu_regcontrol[i] = si_pmu_vreg_control(sih, i, 0, 0);
5671*4882a593Smuzhiyun 	}
5672*4882a593Smuzhiyun 	pmu_chip_pll_reg = (pmu_var->pmu_capabilities & 0x003e0000);
5673*4882a593Smuzhiyun 	pmu_chip_pll_reg = pmu_chip_pll_reg >> 17;
5674*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_pll_reg; i++) {
5675*4882a593Smuzhiyun 		pmu_var->pmu_pllcontrol[i] = si_pmu_pllcontrol(sih, i, 0, 0);
5676*4882a593Smuzhiyun 	}
5677*4882a593Smuzhiyun 	pmu_chip_res_reg = (pmu_var->pmu_capabilities & 0x00001f00);
5678*4882a593Smuzhiyun 	pmu_chip_res_reg = pmu_chip_res_reg >> 8;
5679*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_res_reg; i++) {
5680*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, RSRCTABLEADDR, ~0, i);
5681*4882a593Smuzhiyun 		pmu_var->pmu_rsrc_up_down_timer[i] = si_corereg(sih, SI_CC_IDX,
5682*4882a593Smuzhiyun 			RSRCUPDWNTIME, 0, 0);
5683*4882a593Smuzhiyun 	}
5684*4882a593Smuzhiyun 	pmu_chip_res_reg = (pmu_var->pmu_capabilities & 0x00001f00);
5685*4882a593Smuzhiyun 	pmu_chip_res_reg = pmu_chip_res_reg >> 8;
5686*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_res_reg; i++) {
5687*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, RSRCTABLEADDR, ~0, i);
5688*4882a593Smuzhiyun 		pmu_var->rsrc_dep_mask[i] = si_corereg(sih, SI_CC_IDX, PMU_RES_DEP_MASK, 0, 0);
5689*4882a593Smuzhiyun 	}
5690*4882a593Smuzhiyun }
5691*4882a593Smuzhiyun 
5692*4882a593Smuzhiyun void
si_pmu_keep_on(const si_t * sih,int32 int_val)5693*4882a593Smuzhiyun si_pmu_keep_on(const si_t *sih, int32 int_val)
5694*4882a593Smuzhiyun {
5695*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5696*4882a593Smuzhiyun 	chipcregs_t *cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
5697*4882a593Smuzhiyun 	uint32 res_dep_mask;
5698*4882a593Smuzhiyun 	uint32 min_res_mask;
5699*4882a593Smuzhiyun 	uint32 max_res_mask;
5700*4882a593Smuzhiyun 
5701*4882a593Smuzhiyun 	/* Corresponding Resource Dependancy Mask */
5702*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->res_table_sel, int_val);
5703*4882a593Smuzhiyun 	res_dep_mask = R_REG(sii->osh, &cc->res_dep_mask);
5704*4882a593Smuzhiyun 	/* Local change of minimum resource mask */
5705*4882a593Smuzhiyun 	min_res_mask = res_dep_mask | 1 << int_val;
5706*4882a593Smuzhiyun 	/* Corresponding change of Maximum Resource Mask */
5707*4882a593Smuzhiyun 	max_res_mask = R_REG(sii->osh, &cc->max_res_mask);
5708*4882a593Smuzhiyun 	max_res_mask  = max_res_mask | min_res_mask;
5709*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->max_res_mask, max_res_mask);
5710*4882a593Smuzhiyun 	/* Corresponding change of Minimum Resource Mask */
5711*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->min_res_mask, min_res_mask);
5712*4882a593Smuzhiyun }
5713*4882a593Smuzhiyun 
5714*4882a593Smuzhiyun uint32
si_pmu_keep_on_get(const si_t * sih)5715*4882a593Smuzhiyun si_pmu_keep_on_get(const si_t *sih)
5716*4882a593Smuzhiyun {
5717*4882a593Smuzhiyun 	uint i;
5718*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5719*4882a593Smuzhiyun 	chipcregs_t *cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
5720*4882a593Smuzhiyun 	uint32 res_dep_mask;
5721*4882a593Smuzhiyun 	uint32 min_res_mask;
5722*4882a593Smuzhiyun 
5723*4882a593Smuzhiyun 	/* Read min res mask */
5724*4882a593Smuzhiyun 	min_res_mask = R_REG(sii->osh, &cc->min_res_mask);
5725*4882a593Smuzhiyun 	/* Get corresponding Resource Dependancy Mask  */
5726*4882a593Smuzhiyun 	for (i = 0; i < PMU_RES; i++) {
5727*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->res_table_sel, i);
5728*4882a593Smuzhiyun 		res_dep_mask = R_REG(sii->osh, &cc->res_dep_mask);
5729*4882a593Smuzhiyun 		res_dep_mask = res_dep_mask | 1 << i;
5730*4882a593Smuzhiyun 		/* Compare with the present min res mask */
5731*4882a593Smuzhiyun 		if (res_dep_mask == min_res_mask) {
5732*4882a593Smuzhiyun 			return i;
5733*4882a593Smuzhiyun 		}
5734*4882a593Smuzhiyun 	}
5735*4882a593Smuzhiyun 	return 0;
5736*4882a593Smuzhiyun }
5737*4882a593Smuzhiyun 
5738*4882a593Smuzhiyun uint32
si_power_island_set(si_t * sih,uint32 int_val)5739*4882a593Smuzhiyun si_power_island_set(si_t *sih, uint32 int_val)
5740*4882a593Smuzhiyun {
5741*4882a593Smuzhiyun 	uint32 i = 0x0;
5742*4882a593Smuzhiyun 	uint32 j;
5743*4882a593Smuzhiyun 	uint32 k;
5744*4882a593Smuzhiyun 	int cnt = 0;
5745*4882a593Smuzhiyun 	for (k = 0; k < ARRAYSIZE(si_power_island_test_array); k++) {
5746*4882a593Smuzhiyun 		if (int_val == si_power_island_test_array[k]) {
5747*4882a593Smuzhiyun 			cnt = cnt + 1;
5748*4882a593Smuzhiyun 		}
5749*4882a593Smuzhiyun 	}
5750*4882a593Smuzhiyun 	if (cnt > 0) {
5751*4882a593Smuzhiyun 		if (int_val & SUBCORE_POWER_ON) {
5752*4882a593Smuzhiyun 			i = i | 0x1;
5753*4882a593Smuzhiyun 		}
5754*4882a593Smuzhiyun 		if (int_val & PHY_POWER_ON) {
5755*4882a593Smuzhiyun 			i = i | 0x2;
5756*4882a593Smuzhiyun 		}
5757*4882a593Smuzhiyun 		if (int_val & VDDM_POWER_ON) {
5758*4882a593Smuzhiyun 			i = i | 0x4;
5759*4882a593Smuzhiyun 		}
5760*4882a593Smuzhiyun 		if (int_val & MEMLPLDO_POWER_ON) {
5761*4882a593Smuzhiyun 			i = i | 0x8;
5762*4882a593Smuzhiyun 		}
5763*4882a593Smuzhiyun 		j = (i << 18) & 0x003c0000;
5764*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, CHIPCTRLREG2, 0x003c0000, j);
5765*4882a593Smuzhiyun 	} else {
5766*4882a593Smuzhiyun 		return 0;
5767*4882a593Smuzhiyun 	}
5768*4882a593Smuzhiyun 
5769*4882a593Smuzhiyun 	return 1;
5770*4882a593Smuzhiyun }
5771*4882a593Smuzhiyun 
5772*4882a593Smuzhiyun uint32
si_power_island_get(si_t * sih)5773*4882a593Smuzhiyun si_power_island_get(si_t *sih)
5774*4882a593Smuzhiyun {
5775*4882a593Smuzhiyun 	uint32 sc_on = 0x0;
5776*4882a593Smuzhiyun 	uint32 phy_on = 0x0;
5777*4882a593Smuzhiyun 	uint32 vddm_on = 0x0;
5778*4882a593Smuzhiyun 	uint32 memlpldo_on = 0x0;
5779*4882a593Smuzhiyun 	uint32 res;
5780*4882a593Smuzhiyun 	uint32 reg_val;
5781*4882a593Smuzhiyun 	reg_val = si_pmu_chipcontrol(sih, CHIPCTRLREG2, 0, 0);
5782*4882a593Smuzhiyun 	if (reg_val & SUBCORE_POWER_ON_CHK) {
5783*4882a593Smuzhiyun 		sc_on = SUBCORE_POWER_ON;
5784*4882a593Smuzhiyun 	}
5785*4882a593Smuzhiyun 	if (reg_val & PHY_POWER_ON_CHK) {
5786*4882a593Smuzhiyun 		phy_on = PHY_POWER_ON;
5787*4882a593Smuzhiyun 	}
5788*4882a593Smuzhiyun 	if (reg_val & VDDM_POWER_ON_CHK) {
5789*4882a593Smuzhiyun 		vddm_on = VDDM_POWER_ON;
5790*4882a593Smuzhiyun 	}
5791*4882a593Smuzhiyun 	if (reg_val & MEMLPLDO_POWER_ON_CHK) {
5792*4882a593Smuzhiyun 		memlpldo_on = MEMLPLDO_POWER_ON;
5793*4882a593Smuzhiyun 	}
5794*4882a593Smuzhiyun 	res = (sc_on | phy_on | vddm_on | memlpldo_on);
5795*4882a593Smuzhiyun 	return res;
5796*4882a593Smuzhiyun }
5797*4882a593Smuzhiyun #endif /* SR_DEBUG */
5798*4882a593Smuzhiyun 
5799*4882a593Smuzhiyun uint32
si_pciereg(const si_t * sih,uint32 offset,uint32 mask,uint32 val,uint type)5800*4882a593Smuzhiyun si_pciereg(const si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type)
5801*4882a593Smuzhiyun {
5802*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5803*4882a593Smuzhiyun 
5804*4882a593Smuzhiyun 	if (!PCIE(sii)) {
5805*4882a593Smuzhiyun 		SI_ERROR(("si_pciereg: Not a PCIE device\n"));
5806*4882a593Smuzhiyun 		return 0;
5807*4882a593Smuzhiyun 	}
5808*4882a593Smuzhiyun 
5809*4882a593Smuzhiyun 	return pcicore_pciereg(sii->pch, offset, mask, val, type);
5810*4882a593Smuzhiyun }
5811*4882a593Smuzhiyun 
5812*4882a593Smuzhiyun uint32
si_pcieserdesreg(const si_t * sih,uint32 mdioslave,uint32 offset,uint32 mask,uint32 val)5813*4882a593Smuzhiyun si_pcieserdesreg(const si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val)
5814*4882a593Smuzhiyun {
5815*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5816*4882a593Smuzhiyun 
5817*4882a593Smuzhiyun 	if (!PCIE(sii)) {
5818*4882a593Smuzhiyun 		SI_ERROR(("si_pcieserdesreg: Not a PCIE device\n"));
5819*4882a593Smuzhiyun 		return 0;
5820*4882a593Smuzhiyun 	}
5821*4882a593Smuzhiyun 
5822*4882a593Smuzhiyun 	return pcicore_pcieserdesreg(sii->pch, mdioslave, offset, mask, val);
5823*4882a593Smuzhiyun 
5824*4882a593Smuzhiyun }
5825*4882a593Smuzhiyun 
5826*4882a593Smuzhiyun /** return TRUE if PCIE capability exists in the pci config space */
5827*4882a593Smuzhiyun static bool
BCMATTACHFN(si_ispcie)5828*4882a593Smuzhiyun BCMATTACHFN(si_ispcie)(const si_info_t *sii)
5829*4882a593Smuzhiyun {
5830*4882a593Smuzhiyun 	uint8 cap_ptr;
5831*4882a593Smuzhiyun 
5832*4882a593Smuzhiyun 	if (BUSTYPE(sii->pub.bustype) != PCI_BUS)
5833*4882a593Smuzhiyun 		return FALSE;
5834*4882a593Smuzhiyun 
5835*4882a593Smuzhiyun 	cap_ptr = pcicore_find_pci_capability(sii->osh, PCI_CAP_PCIECAP_ID, NULL, NULL);
5836*4882a593Smuzhiyun 	if (!cap_ptr)
5837*4882a593Smuzhiyun 		return FALSE;
5838*4882a593Smuzhiyun 
5839*4882a593Smuzhiyun 	return TRUE;
5840*4882a593Smuzhiyun }
5841*4882a593Smuzhiyun 
5842*4882a593Smuzhiyun /* Wake-on-wireless-LAN (WOWL) support functions */
5843*4882a593Smuzhiyun /** Enable PME generation and disable clkreq */
5844*4882a593Smuzhiyun void
si_pci_pmeen(const si_t * sih)5845*4882a593Smuzhiyun si_pci_pmeen(const si_t *sih)
5846*4882a593Smuzhiyun {
5847*4882a593Smuzhiyun 	pcicore_pmeen(SI_INFO(sih)->pch);
5848*4882a593Smuzhiyun }
5849*4882a593Smuzhiyun 
5850*4882a593Smuzhiyun /** Return TRUE if PME status is set */
5851*4882a593Smuzhiyun bool
si_pci_pmestat(const si_t * sih)5852*4882a593Smuzhiyun si_pci_pmestat(const si_t *sih)
5853*4882a593Smuzhiyun {
5854*4882a593Smuzhiyun 	return pcicore_pmestat(SI_INFO(sih)->pch);
5855*4882a593Smuzhiyun }
5856*4882a593Smuzhiyun 
5857*4882a593Smuzhiyun /** Disable PME generation, clear the PME status bit if set */
5858*4882a593Smuzhiyun void
si_pci_pmeclr(const si_t * sih)5859*4882a593Smuzhiyun si_pci_pmeclr(const si_t *sih)
5860*4882a593Smuzhiyun {
5861*4882a593Smuzhiyun 	pcicore_pmeclr(SI_INFO(sih)->pch);
5862*4882a593Smuzhiyun }
5863*4882a593Smuzhiyun 
5864*4882a593Smuzhiyun void
si_pci_pmestatclr(const si_t * sih)5865*4882a593Smuzhiyun si_pci_pmestatclr(const si_t *sih)
5866*4882a593Smuzhiyun {
5867*4882a593Smuzhiyun 	pcicore_pmestatclr(SI_INFO(sih)->pch);
5868*4882a593Smuzhiyun }
5869*4882a593Smuzhiyun 
5870*4882a593Smuzhiyun #ifdef BCMSDIO
5871*4882a593Smuzhiyun /** initialize the sdio core */
5872*4882a593Smuzhiyun void
si_sdio_init(si_t * sih)5873*4882a593Smuzhiyun si_sdio_init(si_t *sih)
5874*4882a593Smuzhiyun {
5875*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5876*4882a593Smuzhiyun 
5877*4882a593Smuzhiyun 	if (BUSCORETYPE(sih->buscoretype) == SDIOD_CORE_ID) {
5878*4882a593Smuzhiyun 		uint idx;
5879*4882a593Smuzhiyun 		sdpcmd_regs_t *sdpregs;
5880*4882a593Smuzhiyun 
5881*4882a593Smuzhiyun 		/* get the current core index */
5882*4882a593Smuzhiyun 		/* could do stuff like tcpflag in pci, but why? */
5883*4882a593Smuzhiyun 		idx = sii->curidx;
5884*4882a593Smuzhiyun 		ASSERT(idx == si_findcoreidx(sih, D11_CORE_ID, 0));
5885*4882a593Smuzhiyun 
5886*4882a593Smuzhiyun 		/* switch to sdio core */
5887*4882a593Smuzhiyun 		/* could use buscoreidx? */
5888*4882a593Smuzhiyun 		sdpregs = (sdpcmd_regs_t *)si_setcore(sih, SDIOD_CORE_ID, 0);
5889*4882a593Smuzhiyun 		ASSERT(sdpregs);
5890*4882a593Smuzhiyun 
5891*4882a593Smuzhiyun 		SI_MSG(("si_sdio_init: For SDIO Corerev %d, enable ints from core %d "
5892*4882a593Smuzhiyun 		        "through SD core %d (%p)\n",
5893*4882a593Smuzhiyun 		        sih->buscorerev, idx, sii->curidx, OSL_OBFUSCATE_BUF(sdpregs)));
5894*4882a593Smuzhiyun 
5895*4882a593Smuzhiyun 		/* enable backplane error and core interrupts */
5896*4882a593Smuzhiyun 		W_REG(sii->osh, &sdpregs->hostintmask, I_SBINT);
5897*4882a593Smuzhiyun 		W_REG(sii->osh, &sdpregs->sbintmask, (I_SB_SERR | I_SB_RESPERR | (1 << idx)));
5898*4882a593Smuzhiyun 
5899*4882a593Smuzhiyun 		/* switch back to previous core */
5900*4882a593Smuzhiyun 		si_setcoreidx(sih, idx);
5901*4882a593Smuzhiyun 	}
5902*4882a593Smuzhiyun 
5903*4882a593Smuzhiyun 	/* enable interrupts */
5904*4882a593Smuzhiyun 	bcmsdh_intr_enable(sii->sdh);
5905*4882a593Smuzhiyun 
5906*4882a593Smuzhiyun 	/* What else */
5907*4882a593Smuzhiyun }
5908*4882a593Smuzhiyun #endif	/* BCMSDIO */
5909*4882a593Smuzhiyun 
5910*4882a593Smuzhiyun /**
5911*4882a593Smuzhiyun  * Disable pcie_war_ovr for some platforms (sigh!)
5912*4882a593Smuzhiyun  * This is for boards that have BFL2_PCIEWAR_OVR set
5913*4882a593Smuzhiyun  * but are in systems that still want the benefits of ASPM
5914*4882a593Smuzhiyun  * Note that this should be done AFTER si_doattach
5915*4882a593Smuzhiyun  */
5916*4882a593Smuzhiyun void
si_pcie_war_ovr_update(const si_t * sih,uint8 aspm)5917*4882a593Smuzhiyun si_pcie_war_ovr_update(const si_t *sih, uint8 aspm)
5918*4882a593Smuzhiyun {
5919*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5920*4882a593Smuzhiyun 
5921*4882a593Smuzhiyun 	if (!PCIE_GEN1(sii))
5922*4882a593Smuzhiyun 		return;
5923*4882a593Smuzhiyun 
5924*4882a593Smuzhiyun 	pcie_war_ovr_aspm_update(sii->pch, aspm);
5925*4882a593Smuzhiyun }
5926*4882a593Smuzhiyun 
5927*4882a593Smuzhiyun void
si_pcie_power_save_enable(const si_t * sih,bool enable)5928*4882a593Smuzhiyun si_pcie_power_save_enable(const si_t *sih, bool enable)
5929*4882a593Smuzhiyun {
5930*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5931*4882a593Smuzhiyun 
5932*4882a593Smuzhiyun 	if (!PCIE_GEN1(sii))
5933*4882a593Smuzhiyun 		return;
5934*4882a593Smuzhiyun 
5935*4882a593Smuzhiyun 	pcie_power_save_enable(sii->pch, enable);
5936*4882a593Smuzhiyun }
5937*4882a593Smuzhiyun 
5938*4882a593Smuzhiyun void
si_pcie_set_maxpayload_size(const si_t * sih,uint16 size)5939*4882a593Smuzhiyun si_pcie_set_maxpayload_size(const si_t *sih, uint16 size)
5940*4882a593Smuzhiyun {
5941*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5942*4882a593Smuzhiyun 
5943*4882a593Smuzhiyun 	if (!PCIE(sii))
5944*4882a593Smuzhiyun 		return;
5945*4882a593Smuzhiyun 
5946*4882a593Smuzhiyun 	pcie_set_maxpayload_size(sii->pch, size);
5947*4882a593Smuzhiyun }
5948*4882a593Smuzhiyun 
5949*4882a593Smuzhiyun uint16
si_pcie_get_maxpayload_size(const si_t * sih)5950*4882a593Smuzhiyun si_pcie_get_maxpayload_size(const si_t *sih)
5951*4882a593Smuzhiyun {
5952*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5953*4882a593Smuzhiyun 
5954*4882a593Smuzhiyun 	if (!PCIE(sii))
5955*4882a593Smuzhiyun 		return (0);
5956*4882a593Smuzhiyun 
5957*4882a593Smuzhiyun 	return pcie_get_maxpayload_size(sii->pch);
5958*4882a593Smuzhiyun }
5959*4882a593Smuzhiyun 
5960*4882a593Smuzhiyun void
si_pcie_set_request_size(const si_t * sih,uint16 size)5961*4882a593Smuzhiyun si_pcie_set_request_size(const si_t *sih, uint16 size)
5962*4882a593Smuzhiyun {
5963*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5964*4882a593Smuzhiyun 
5965*4882a593Smuzhiyun 	if (!PCIE(sii))
5966*4882a593Smuzhiyun 		return;
5967*4882a593Smuzhiyun 
5968*4882a593Smuzhiyun 	pcie_set_request_size(sii->pch, size);
5969*4882a593Smuzhiyun }
5970*4882a593Smuzhiyun 
5971*4882a593Smuzhiyun uint16
BCMATTACHFN(si_pcie_get_request_size)5972*4882a593Smuzhiyun BCMATTACHFN(si_pcie_get_request_size)(const si_t *sih)
5973*4882a593Smuzhiyun {
5974*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5975*4882a593Smuzhiyun 
5976*4882a593Smuzhiyun 	if (!PCIE_GEN1(sii))
5977*4882a593Smuzhiyun 		return (0);
5978*4882a593Smuzhiyun 
5979*4882a593Smuzhiyun 	return pcie_get_request_size(sii->pch);
5980*4882a593Smuzhiyun }
5981*4882a593Smuzhiyun 
5982*4882a593Smuzhiyun uint16
si_pcie_get_ssid(const si_t * sih)5983*4882a593Smuzhiyun si_pcie_get_ssid(const si_t *sih)
5984*4882a593Smuzhiyun {
5985*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5986*4882a593Smuzhiyun 
5987*4882a593Smuzhiyun 	if (!PCIE_GEN1(sii))
5988*4882a593Smuzhiyun 		return (0);
5989*4882a593Smuzhiyun 
5990*4882a593Smuzhiyun 	return pcie_get_ssid(sii->pch);
5991*4882a593Smuzhiyun }
5992*4882a593Smuzhiyun 
5993*4882a593Smuzhiyun uint32
si_pcie_get_bar0(const si_t * sih)5994*4882a593Smuzhiyun si_pcie_get_bar0(const si_t *sih)
5995*4882a593Smuzhiyun {
5996*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
5997*4882a593Smuzhiyun 
5998*4882a593Smuzhiyun 	if (!PCIE(sii))
5999*4882a593Smuzhiyun 		return (0);
6000*4882a593Smuzhiyun 
6001*4882a593Smuzhiyun 	return pcie_get_bar0(sii->pch);
6002*4882a593Smuzhiyun }
6003*4882a593Smuzhiyun 
6004*4882a593Smuzhiyun int
si_pcie_configspace_cache(const si_t * sih)6005*4882a593Smuzhiyun si_pcie_configspace_cache(const si_t *sih)
6006*4882a593Smuzhiyun {
6007*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6008*4882a593Smuzhiyun 
6009*4882a593Smuzhiyun 	if (!PCIE(sii))
6010*4882a593Smuzhiyun 		return BCME_UNSUPPORTED;
6011*4882a593Smuzhiyun 
6012*4882a593Smuzhiyun 	return pcie_configspace_cache(sii->pch);
6013*4882a593Smuzhiyun }
6014*4882a593Smuzhiyun 
6015*4882a593Smuzhiyun int
si_pcie_configspace_restore(const si_t * sih)6016*4882a593Smuzhiyun si_pcie_configspace_restore(const si_t *sih)
6017*4882a593Smuzhiyun {
6018*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6019*4882a593Smuzhiyun 
6020*4882a593Smuzhiyun 	if (!PCIE(sii))
6021*4882a593Smuzhiyun 		return BCME_UNSUPPORTED;
6022*4882a593Smuzhiyun 
6023*4882a593Smuzhiyun 	return pcie_configspace_restore(sii->pch);
6024*4882a593Smuzhiyun }
6025*4882a593Smuzhiyun 
6026*4882a593Smuzhiyun int
si_pcie_configspace_get(const si_t * sih,uint8 * buf,uint size)6027*4882a593Smuzhiyun si_pcie_configspace_get(const si_t *sih, uint8 *buf, uint size)
6028*4882a593Smuzhiyun {
6029*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6030*4882a593Smuzhiyun 
6031*4882a593Smuzhiyun 	if (!PCIE(sii) || size > PCI_CONFIG_SPACE_SIZE)
6032*4882a593Smuzhiyun 		return -1;
6033*4882a593Smuzhiyun 
6034*4882a593Smuzhiyun 	return pcie_configspace_get(sii->pch, buf, size);
6035*4882a593Smuzhiyun }
6036*4882a593Smuzhiyun 
6037*4882a593Smuzhiyun void
si_pcie_hw_L1SS_war(const si_t * sih)6038*4882a593Smuzhiyun si_pcie_hw_L1SS_war(const si_t *sih)
6039*4882a593Smuzhiyun {
6040*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6041*4882a593Smuzhiyun 
6042*4882a593Smuzhiyun 	/* SWWLAN-41753: WAR intermittent issue with D3Cold and L1.2 exit,
6043*4882a593Smuzhiyun 	 * need to update PMU rsrc dependency
6044*4882a593Smuzhiyun 	 */
6045*4882a593Smuzhiyun 	if (PCIE_GEN2(sii))
6046*4882a593Smuzhiyun 		pcie_hw_L1SS_war(sii->pch);
6047*4882a593Smuzhiyun }
6048*4882a593Smuzhiyun 
6049*4882a593Smuzhiyun void
BCMINITFN(si_pci_up)6050*4882a593Smuzhiyun BCMINITFN(si_pci_up)(const si_t *sih)
6051*4882a593Smuzhiyun {
6052*4882a593Smuzhiyun 	const si_info_t *sii;
6053*4882a593Smuzhiyun 
6054*4882a593Smuzhiyun 	/* if not pci bus, we're done */
6055*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) != PCI_BUS)
6056*4882a593Smuzhiyun 		return;
6057*4882a593Smuzhiyun 
6058*4882a593Smuzhiyun 	sii = SI_INFO(sih);
6059*4882a593Smuzhiyun 
6060*4882a593Smuzhiyun 	if (PCIE(sii)) {
6061*4882a593Smuzhiyun 		pcicore_up(sii->pch, SI_PCIUP);
6062*4882a593Smuzhiyun 	}
6063*4882a593Smuzhiyun }
6064*4882a593Smuzhiyun 
6065*4882a593Smuzhiyun /** Unconfigure and/or apply various WARs when system is going to sleep mode */
6066*4882a593Smuzhiyun void
BCMUNINITFN(si_pci_sleep)6067*4882a593Smuzhiyun BCMUNINITFN(si_pci_sleep)(const si_t *sih)
6068*4882a593Smuzhiyun {
6069*4882a593Smuzhiyun 	/* 4360 pcie2 WAR */
6070*4882a593Smuzhiyun 	do_4360_pcie2_war = 0;
6071*4882a593Smuzhiyun 
6072*4882a593Smuzhiyun 	pcicore_sleep(SI_INFO(sih)->pch);
6073*4882a593Smuzhiyun }
6074*4882a593Smuzhiyun 
6075*4882a593Smuzhiyun /** Unconfigure and/or apply various WARs when the wireless interface is going down */
6076*4882a593Smuzhiyun void
BCMINITFN(si_pci_down)6077*4882a593Smuzhiyun BCMINITFN(si_pci_down)(const si_t *sih)
6078*4882a593Smuzhiyun {
6079*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6080*4882a593Smuzhiyun 	BCM_REFERENCE(sii);
6081*4882a593Smuzhiyun 
6082*4882a593Smuzhiyun 	/* if not pci bus, we're done */
6083*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) != PCI_BUS)
6084*4882a593Smuzhiyun 		return;
6085*4882a593Smuzhiyun 
6086*4882a593Smuzhiyun 	pcicore_down(sii->pch, SI_PCIDOWN);
6087*4882a593Smuzhiyun }
6088*4882a593Smuzhiyun 
6089*4882a593Smuzhiyun /**
6090*4882a593Smuzhiyun  * Configure the pci core for pci client (NIC) action
6091*4882a593Smuzhiyun  * coremask is the bitvec of cores by index to be enabled.
6092*4882a593Smuzhiyun  */
6093*4882a593Smuzhiyun void
BCMATTACHFN(si_pci_setup)6094*4882a593Smuzhiyun BCMATTACHFN(si_pci_setup)(si_t *sih, uint coremask)
6095*4882a593Smuzhiyun {
6096*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6097*4882a593Smuzhiyun 	sbpciregs_t *pciregs = NULL;
6098*4882a593Smuzhiyun 	uint32 siflag = 0, w;
6099*4882a593Smuzhiyun 	uint idx = 0;
6100*4882a593Smuzhiyun 
6101*4882a593Smuzhiyun 	if (BUSTYPE(sii->pub.bustype) != PCI_BUS)
6102*4882a593Smuzhiyun 		return;
6103*4882a593Smuzhiyun 
6104*4882a593Smuzhiyun 	ASSERT(PCI(sii) || PCIE(sii));
6105*4882a593Smuzhiyun 	ASSERT(sii->pub.buscoreidx != BADIDX);
6106*4882a593Smuzhiyun 
6107*4882a593Smuzhiyun 	if (PCI(sii)) {
6108*4882a593Smuzhiyun 		/* get current core index */
6109*4882a593Smuzhiyun 		idx = sii->curidx;
6110*4882a593Smuzhiyun 
6111*4882a593Smuzhiyun 		/* we interrupt on this backplane flag number */
6112*4882a593Smuzhiyun 		siflag = si_flag(sih);
6113*4882a593Smuzhiyun 
6114*4882a593Smuzhiyun 		/* switch over to pci core */
6115*4882a593Smuzhiyun 		pciregs = (sbpciregs_t *)si_setcoreidx(sih, sii->pub.buscoreidx);
6116*4882a593Smuzhiyun 	}
6117*4882a593Smuzhiyun 
6118*4882a593Smuzhiyun 	/*
6119*4882a593Smuzhiyun 	 * Enable sb->pci interrupts.  Assume
6120*4882a593Smuzhiyun 	 * PCI rev 2.3 support was added in pci core rev 6 and things changed..
6121*4882a593Smuzhiyun 	 */
6122*4882a593Smuzhiyun 	if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) {
6123*4882a593Smuzhiyun 		/* pci config write to set this core bit in PCIIntMask */
6124*4882a593Smuzhiyun 		w = OSL_PCI_READ_CONFIG(sii->osh, PCI_INT_MASK, sizeof(uint32));
6125*4882a593Smuzhiyun 		w |= (coremask << PCI_SBIM_SHIFT);
6126*4882a593Smuzhiyun #ifdef USER_MODE
6127*4882a593Smuzhiyun 		/* User mode operate with interrupt disabled */
6128*4882a593Smuzhiyun 		w &= !(coremask << PCI_SBIM_SHIFT);
6129*4882a593Smuzhiyun #endif
6130*4882a593Smuzhiyun 		OSL_PCI_WRITE_CONFIG(sii->osh, PCI_INT_MASK, sizeof(uint32), w);
6131*4882a593Smuzhiyun 	} else {
6132*4882a593Smuzhiyun 		/* set sbintvec bit for our flag number */
6133*4882a593Smuzhiyun 		si_setint(sih, siflag);
6134*4882a593Smuzhiyun 	}
6135*4882a593Smuzhiyun 
6136*4882a593Smuzhiyun 	/*
6137*4882a593Smuzhiyun 	 * enable prefetch and bursts for dma big window
6138*4882a593Smuzhiyun 	 * enable read multiple for dma big window corerev >= 11
6139*4882a593Smuzhiyun 	 * PR 9962/4708: Set initiator timeouts. corerev < 5
6140*4882a593Smuzhiyun 	 */
6141*4882a593Smuzhiyun 	if (PCI(sii)) {
6142*4882a593Smuzhiyun 		OR_REG(sii->osh, &pciregs->sbtopci2, (SBTOPCI_PREF | SBTOPCI_BURST));
6143*4882a593Smuzhiyun 		if (sii->pub.buscorerev >= 11) {
6144*4882a593Smuzhiyun 			OR_REG(sii->osh, &pciregs->sbtopci2, SBTOPCI_RC_READMULTI);
6145*4882a593Smuzhiyun 			/* PR50531: On some Laptops, the 4321 CB shows bad
6146*4882a593Smuzhiyun 			 * UDP performance on one direction
6147*4882a593Smuzhiyun 			 */
6148*4882a593Smuzhiyun 			w = R_REG(sii->osh, &pciregs->clkrun);
6149*4882a593Smuzhiyun 			W_REG(sii->osh, &pciregs->clkrun, (w | PCI_CLKRUN_DSBL));
6150*4882a593Smuzhiyun 			w = R_REG(sii->osh, &pciregs->clkrun);
6151*4882a593Smuzhiyun 		}
6152*4882a593Smuzhiyun 
6153*4882a593Smuzhiyun 		/* switch back to previous core */
6154*4882a593Smuzhiyun 		si_setcoreidx(sih, idx);
6155*4882a593Smuzhiyun 	}
6156*4882a593Smuzhiyun }
6157*4882a593Smuzhiyun 
6158*4882a593Smuzhiyun /* In NIC mode is there any better way to find out what ARM core is there? */
6159*4882a593Smuzhiyun static uint
BCMATTACHFN(si_get_armcoreidx)6160*4882a593Smuzhiyun BCMATTACHFN(si_get_armcoreidx)(si_t *sih)
6161*4882a593Smuzhiyun {
6162*4882a593Smuzhiyun 	uint saveidx = si_coreidx(sih);
6163*4882a593Smuzhiyun 	uint coreidx = BADIDX;
6164*4882a593Smuzhiyun 
6165*4882a593Smuzhiyun 	if (si_setcore(sih, ARMCR4_CORE_ID, 0) != NULL ||
6166*4882a593Smuzhiyun 	    si_setcore(sih, ARMCA7_CORE_ID, 0) != NULL) {
6167*4882a593Smuzhiyun 		coreidx = si_coreidx(sih);
6168*4882a593Smuzhiyun 	}
6169*4882a593Smuzhiyun 
6170*4882a593Smuzhiyun 	si_setcoreidx(sih, saveidx);
6171*4882a593Smuzhiyun 
6172*4882a593Smuzhiyun 	return coreidx;
6173*4882a593Smuzhiyun }
6174*4882a593Smuzhiyun 
6175*4882a593Smuzhiyun /**
6176*4882a593Smuzhiyun  * Configure the pcie core for pcie client (NIC) action
6177*4882a593Smuzhiyun  * coreidx is the index of the core to be enabled.
6178*4882a593Smuzhiyun  */
6179*4882a593Smuzhiyun int
BCMATTACHFN(si_pcie_setup)6180*4882a593Smuzhiyun BCMATTACHFN(si_pcie_setup)(si_t *sih, uint coreidx)
6181*4882a593Smuzhiyun {
6182*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
6183*4882a593Smuzhiyun 	int main_intr, alt_intr;
6184*4882a593Smuzhiyun 	uint pciepidx;
6185*4882a593Smuzhiyun 	uint32 w;
6186*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
6187*4882a593Smuzhiyun 	uint saveidx = si_coreidx(sih);
6188*4882a593Smuzhiyun 	volatile void *oobrregs;
6189*4882a593Smuzhiyun 	uint armcidx, armpidx;
6190*4882a593Smuzhiyun 	int ret = BCME_OK;
6191*4882a593Smuzhiyun 
6192*4882a593Smuzhiyun 	/* try the new hnd oobr first */
6193*4882a593Smuzhiyun 	if ((oobrregs = si_setcore(sih, HND_OOBR_CORE_ID, 0)) == NULL) {
6194*4882a593Smuzhiyun 		goto exit;
6195*4882a593Smuzhiyun 	}
6196*4882a593Smuzhiyun 
6197*4882a593Smuzhiyun 	ASSERT(BUSTYPE(sih->bustype) == PCI_BUS);
6198*4882a593Smuzhiyun 	ASSERT(BUSTYPE(sih->buscoretype) == PCIE2_CORE_ID);
6199*4882a593Smuzhiyun 
6200*4882a593Smuzhiyun 	/* ==== Enable sb->pci interrupts ==== */
6201*4882a593Smuzhiyun 
6202*4882a593Smuzhiyun 	/* 1) query the pcie interrupt port index and
6203*4882a593Smuzhiyun 	 *    re-route the main interrupt to pcie (from ARM) if necessary
6204*4882a593Smuzhiyun 	 */
6205*4882a593Smuzhiyun 	main_intr = hnd_oobr_get_intr_config(sih, coreidx,
6206*4882a593Smuzhiyun 			HND_CORE_MAIN_INTR, sih->buscoreidx, &pciepidx);
6207*4882a593Smuzhiyun 	if (main_intr < 0) {
6208*4882a593Smuzhiyun 		/* query failure means the main interrupt is not routed
6209*4882a593Smuzhiyun 		 * to the pcie core... re-route!
6210*4882a593Smuzhiyun 		 */
6211*4882a593Smuzhiyun 		armcidx = si_get_armcoreidx(sih);
6212*4882a593Smuzhiyun 		if (!GOODIDX(armcidx, sii->numcores)) {
6213*4882a593Smuzhiyun 			SI_MSG(("si_pcie_setup: arm core not found\n"));
6214*4882a593Smuzhiyun 			ret = BCME_NOTFOUND;
6215*4882a593Smuzhiyun 			goto exit;
6216*4882a593Smuzhiyun 		}
6217*4882a593Smuzhiyun 
6218*4882a593Smuzhiyun 		/* query main and alt interrupt info */
6219*4882a593Smuzhiyun 		main_intr = hnd_oobr_get_intr_config(sih, coreidx,
6220*4882a593Smuzhiyun 				HND_CORE_MAIN_INTR, armcidx, &armpidx);
6221*4882a593Smuzhiyun 		alt_intr = hnd_oobr_get_intr_config(sih, coreidx,
6222*4882a593Smuzhiyun 				HND_CORE_ALT_INTR, sih->buscoreidx, &pciepidx);
6223*4882a593Smuzhiyun 		if ((ret = main_intr) < 0 || (ret = alt_intr) < 0) {
6224*4882a593Smuzhiyun 			SI_MSG(("si_pcie_setup: coreidx %u main (=%d) or "
6225*4882a593Smuzhiyun 			        "alt (=%d) interrupt query failed\n",
6226*4882a593Smuzhiyun 			        coreidx, main_intr, alt_intr));
6227*4882a593Smuzhiyun 			goto exit;
6228*4882a593Smuzhiyun 		}
6229*4882a593Smuzhiyun 
6230*4882a593Smuzhiyun 		/* swap main and alt interrupts at pcie input interrupts */
6231*4882a593Smuzhiyun 		hnd_oobr_set_intr_src(sih, sih->buscoreidx, pciepidx, main_intr);
6232*4882a593Smuzhiyun 		/* TODO: route the alternate interrupt to arm */
6233*4882a593Smuzhiyun 		/* hnd_oobr_set_intr_src(sih, armcidx, armppidx, alt_intr); */
6234*4882a593Smuzhiyun 		BCM_REFERENCE(armpidx);
6235*4882a593Smuzhiyun 
6236*4882a593Smuzhiyun 		/* query main interrupt info again.
6237*4882a593Smuzhiyun 		 * is it really necessary?
6238*4882a593Smuzhiyun 		 * it can't fail as we just set it up...
6239*4882a593Smuzhiyun 		 */
6240*4882a593Smuzhiyun 		main_intr = hnd_oobr_get_intr_config(sih, coreidx,
6241*4882a593Smuzhiyun 				HND_CORE_MAIN_INTR, sih->buscoreidx, &pciepidx);
6242*4882a593Smuzhiyun 		ASSERT(main_intr >= 0);
6243*4882a593Smuzhiyun 	}
6244*4882a593Smuzhiyun 	/* hnd_oobr_dump(sih); */
6245*4882a593Smuzhiyun 
6246*4882a593Smuzhiyun 	/* 2) pcie config write to set this core bit in PCIIntMask */
6247*4882a593Smuzhiyun 	w = OSL_PCI_READ_CONFIG(osh, PCI_INT_MASK, sizeof(w));
6248*4882a593Smuzhiyun 	w |= ((1 << pciepidx) << PCI_SBIM_SHIFT);
6249*4882a593Smuzhiyun 	OSL_PCI_WRITE_CONFIG(osh, PCI_INT_MASK, sizeof(w), w);
6250*4882a593Smuzhiyun 
6251*4882a593Smuzhiyun 	/* ==== other setups ==== */
6252*4882a593Smuzhiyun 
6253*4882a593Smuzhiyun 	/* reset the return value */
6254*4882a593Smuzhiyun 	ret = BCME_OK;
6255*4882a593Smuzhiyun exit:
6256*4882a593Smuzhiyun 	/* return to the original core */
6257*4882a593Smuzhiyun 	si_setcoreidx(sih, saveidx);
6258*4882a593Smuzhiyun 	if (ret != BCME_OK) {
6259*4882a593Smuzhiyun 		return ret;
6260*4882a593Smuzhiyun 	}
6261*4882a593Smuzhiyun 
6262*4882a593Smuzhiyun 	/* fall back to the old way... */
6263*4882a593Smuzhiyun 	if (oobrregs == NULL) {
6264*4882a593Smuzhiyun 		uint coremask = (1 << coreidx);
6265*4882a593Smuzhiyun 		si_pci_setup(sih, coremask);
6266*4882a593Smuzhiyun 	}
6267*4882a593Smuzhiyun 
6268*4882a593Smuzhiyun 	return ret;
6269*4882a593Smuzhiyun }
6270*4882a593Smuzhiyun 
6271*4882a593Smuzhiyun uint8
si_pcieclkreq(const si_t * sih,uint32 mask,uint32 val)6272*4882a593Smuzhiyun si_pcieclkreq(const si_t *sih, uint32 mask, uint32 val)
6273*4882a593Smuzhiyun {
6274*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6275*4882a593Smuzhiyun 
6276*4882a593Smuzhiyun 	if (!PCIE(sii))
6277*4882a593Smuzhiyun 		return 0;
6278*4882a593Smuzhiyun 
6279*4882a593Smuzhiyun 	return pcie_clkreq(sii->pch, mask, val);
6280*4882a593Smuzhiyun }
6281*4882a593Smuzhiyun 
6282*4882a593Smuzhiyun uint32
si_pcielcreg(const si_t * sih,uint32 mask,uint32 val)6283*4882a593Smuzhiyun si_pcielcreg(const si_t *sih, uint32 mask, uint32 val)
6284*4882a593Smuzhiyun {
6285*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6286*4882a593Smuzhiyun 
6287*4882a593Smuzhiyun 	if (!PCIE(sii))
6288*4882a593Smuzhiyun 		return 0;
6289*4882a593Smuzhiyun 
6290*4882a593Smuzhiyun 	return pcie_lcreg(sii->pch, mask, val);
6291*4882a593Smuzhiyun }
6292*4882a593Smuzhiyun 
6293*4882a593Smuzhiyun uint8
si_pcieltrenable(const si_t * sih,uint32 mask,uint32 val)6294*4882a593Smuzhiyun si_pcieltrenable(const si_t *sih, uint32 mask, uint32 val)
6295*4882a593Smuzhiyun {
6296*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6297*4882a593Smuzhiyun 
6298*4882a593Smuzhiyun 	if (!(PCIE(sii)))
6299*4882a593Smuzhiyun 		return 0;
6300*4882a593Smuzhiyun 
6301*4882a593Smuzhiyun 	return pcie_ltrenable(sii->pch, mask, val);
6302*4882a593Smuzhiyun }
6303*4882a593Smuzhiyun 
6304*4882a593Smuzhiyun uint8
BCMATTACHFN(si_pcieobffenable)6305*4882a593Smuzhiyun BCMATTACHFN(si_pcieobffenable)(const si_t *sih, uint32 mask, uint32 val)
6306*4882a593Smuzhiyun {
6307*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6308*4882a593Smuzhiyun 
6309*4882a593Smuzhiyun 	if (!(PCIE(sii)))
6310*4882a593Smuzhiyun 		return 0;
6311*4882a593Smuzhiyun 
6312*4882a593Smuzhiyun 	return pcie_obffenable(sii->pch, mask, val);
6313*4882a593Smuzhiyun }
6314*4882a593Smuzhiyun 
6315*4882a593Smuzhiyun uint32
si_pcieltr_reg(const si_t * sih,uint32 reg,uint32 mask,uint32 val)6316*4882a593Smuzhiyun si_pcieltr_reg(const si_t *sih, uint32 reg, uint32 mask, uint32 val)
6317*4882a593Smuzhiyun {
6318*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6319*4882a593Smuzhiyun 
6320*4882a593Smuzhiyun 	if (!(PCIE(sii)))
6321*4882a593Smuzhiyun 		return 0;
6322*4882a593Smuzhiyun 
6323*4882a593Smuzhiyun 	return pcie_ltr_reg(sii->pch, reg, mask, val);
6324*4882a593Smuzhiyun }
6325*4882a593Smuzhiyun 
6326*4882a593Smuzhiyun uint32
si_pcieltrspacing_reg(const si_t * sih,uint32 mask,uint32 val)6327*4882a593Smuzhiyun si_pcieltrspacing_reg(const si_t *sih, uint32 mask, uint32 val)
6328*4882a593Smuzhiyun {
6329*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6330*4882a593Smuzhiyun 
6331*4882a593Smuzhiyun 	if (!(PCIE(sii)))
6332*4882a593Smuzhiyun 		return 0;
6333*4882a593Smuzhiyun 
6334*4882a593Smuzhiyun 	return pcieltrspacing_reg(sii->pch, mask, val);
6335*4882a593Smuzhiyun }
6336*4882a593Smuzhiyun 
6337*4882a593Smuzhiyun uint32
si_pcieltrhysteresiscnt_reg(const si_t * sih,uint32 mask,uint32 val)6338*4882a593Smuzhiyun si_pcieltrhysteresiscnt_reg(const si_t *sih, uint32 mask, uint32 val)
6339*4882a593Smuzhiyun {
6340*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6341*4882a593Smuzhiyun 
6342*4882a593Smuzhiyun 	if (!(PCIE(sii)))
6343*4882a593Smuzhiyun 		return 0;
6344*4882a593Smuzhiyun 
6345*4882a593Smuzhiyun 	return pcieltrhysteresiscnt_reg(sii->pch, mask, val);
6346*4882a593Smuzhiyun }
6347*4882a593Smuzhiyun 
6348*4882a593Smuzhiyun void
si_pcie_set_error_injection(const si_t * sih,uint32 mode)6349*4882a593Smuzhiyun si_pcie_set_error_injection(const si_t *sih, uint32 mode)
6350*4882a593Smuzhiyun {
6351*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6352*4882a593Smuzhiyun 
6353*4882a593Smuzhiyun 	if (!PCIE(sii))
6354*4882a593Smuzhiyun 		return;
6355*4882a593Smuzhiyun 
6356*4882a593Smuzhiyun 	pcie_set_error_injection(sii->pch, mode);
6357*4882a593Smuzhiyun }
6358*4882a593Smuzhiyun 
6359*4882a593Smuzhiyun void
si_pcie_set_L1substate(const si_t * sih,uint32 substate)6360*4882a593Smuzhiyun si_pcie_set_L1substate(const si_t *sih, uint32 substate)
6361*4882a593Smuzhiyun {
6362*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6363*4882a593Smuzhiyun 
6364*4882a593Smuzhiyun 	if (PCIE_GEN2(sii))
6365*4882a593Smuzhiyun 		pcie_set_L1substate(sii->pch, substate);
6366*4882a593Smuzhiyun }
6367*4882a593Smuzhiyun #ifndef BCM_BOOTLOADER
6368*4882a593Smuzhiyun uint32
si_pcie_get_L1substate(const si_t * sih)6369*4882a593Smuzhiyun si_pcie_get_L1substate(const si_t *sih)
6370*4882a593Smuzhiyun {
6371*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6372*4882a593Smuzhiyun 
6373*4882a593Smuzhiyun 	if (PCIE_GEN2(sii))
6374*4882a593Smuzhiyun 		return pcie_get_L1substate(sii->pch);
6375*4882a593Smuzhiyun 
6376*4882a593Smuzhiyun 	return 0;
6377*4882a593Smuzhiyun }
6378*4882a593Smuzhiyun #endif /* BCM_BOOTLOADER */
6379*4882a593Smuzhiyun /** indirect way to read pcie config regs */
6380*4882a593Smuzhiyun uint
si_pcie_readreg(void * sih,uint addrtype,uint offset)6381*4882a593Smuzhiyun si_pcie_readreg(void *sih, uint addrtype, uint offset)
6382*4882a593Smuzhiyun {
6383*4882a593Smuzhiyun 	return pcie_readreg(sih, (sbpcieregs_t *)PCIEREGS(((si_info_t *)sih)),
6384*4882a593Smuzhiyun 	                    addrtype, offset);
6385*4882a593Smuzhiyun }
6386*4882a593Smuzhiyun 
6387*4882a593Smuzhiyun /* indirect way to write pcie config regs */
6388*4882a593Smuzhiyun uint
si_pcie_writereg(void * sih,uint addrtype,uint offset,uint val)6389*4882a593Smuzhiyun si_pcie_writereg(void *sih, uint addrtype, uint offset, uint val)
6390*4882a593Smuzhiyun {
6391*4882a593Smuzhiyun 	return pcie_writereg(sih, (sbpcieregs_t *)PCIEREGS(((si_info_t *)sih)),
6392*4882a593Smuzhiyun 	                    addrtype, offset, val);
6393*4882a593Smuzhiyun }
6394*4882a593Smuzhiyun 
6395*4882a593Smuzhiyun /**
6396*4882a593Smuzhiyun  * PCI(e) core requires additional software initialization in an SROMless system. In such a system,
6397*4882a593Smuzhiyun  * the PCIe core will assume POR defaults, which are mostly ok, with the exception of the mapping of
6398*4882a593Smuzhiyun  * two address subwindows within the BAR0 window.
6399*4882a593Smuzhiyun  * Note: the current core may be changed upon return.
6400*4882a593Smuzhiyun  */
6401*4882a593Smuzhiyun int
si_pci_fixcfg(si_t * sih)6402*4882a593Smuzhiyun si_pci_fixcfg(si_t *sih)
6403*4882a593Smuzhiyun {
6404*4882a593Smuzhiyun #ifndef DONGLEBUILD
6405*4882a593Smuzhiyun 
6406*4882a593Smuzhiyun 	uint origidx, pciidx;
6407*4882a593Smuzhiyun 	sbpciregs_t *pciregs = NULL;
6408*4882a593Smuzhiyun 	sbpcieregs_t *pcieregs = NULL;
6409*4882a593Smuzhiyun 	uint16 val16;
6410*4882a593Smuzhiyun 	volatile uint16 *reg16 = NULL;
6411*4882a593Smuzhiyun 
6412*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
6413*4882a593Smuzhiyun 
6414*4882a593Smuzhiyun 	ASSERT(BUSTYPE(sii->pub.bustype) == PCI_BUS);
6415*4882a593Smuzhiyun 
6416*4882a593Smuzhiyun 	/* Fixup PI in SROM shadow area to enable the correct PCI core access */
6417*4882a593Smuzhiyun 	origidx = si_coreidx(&sii->pub);
6418*4882a593Smuzhiyun 
6419*4882a593Smuzhiyun 	/* check 'pi' is correct and fix it if not. */
6420*4882a593Smuzhiyun 	if (BUSCORETYPE(sii->pub.buscoretype) == PCIE2_CORE_ID) {
6421*4882a593Smuzhiyun 		pcieregs = (sbpcieregs_t *)si_setcore(&sii->pub, PCIE2_CORE_ID, 0);
6422*4882a593Smuzhiyun 		ASSERT(pcieregs != NULL);
6423*4882a593Smuzhiyun 		reg16 = &pcieregs->sprom[SRSH_PI_OFFSET];
6424*4882a593Smuzhiyun 	} else if (BUSCORETYPE(sii->pub.buscoretype) == PCIE_CORE_ID) {
6425*4882a593Smuzhiyun 		pcieregs = (sbpcieregs_t *)si_setcore(&sii->pub, PCIE_CORE_ID, 0);
6426*4882a593Smuzhiyun 		ASSERT(pcieregs != NULL);
6427*4882a593Smuzhiyun 		reg16 = &pcieregs->sprom[SRSH_PI_OFFSET];
6428*4882a593Smuzhiyun 	} else if (BUSCORETYPE(sii->pub.buscoretype) == PCI_CORE_ID) {
6429*4882a593Smuzhiyun 		pciregs = (sbpciregs_t *)si_setcore(&sii->pub, PCI_CORE_ID, 0);
6430*4882a593Smuzhiyun 		ASSERT(pciregs != NULL);
6431*4882a593Smuzhiyun 		reg16 = &pciregs->sprom[SRSH_PI_OFFSET];
6432*4882a593Smuzhiyun 	}
6433*4882a593Smuzhiyun 	pciidx = si_coreidx(&sii->pub);
6434*4882a593Smuzhiyun 
6435*4882a593Smuzhiyun 	if (!reg16) return -1;
6436*4882a593Smuzhiyun 
6437*4882a593Smuzhiyun 	val16 = R_REG(sii->osh, reg16);
6438*4882a593Smuzhiyun 	if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (uint16)pciidx) {
6439*4882a593Smuzhiyun 		/* write bitfield used to translate 3rd and 7th 4K chunk in the Bar0 space. */
6440*4882a593Smuzhiyun 		val16 = (uint16)(pciidx << SRSH_PI_SHIFT) | (val16 & ~SRSH_PI_MASK);
6441*4882a593Smuzhiyun 		W_REG(sii->osh, reg16, val16);
6442*4882a593Smuzhiyun 	}
6443*4882a593Smuzhiyun 
6444*4882a593Smuzhiyun 	/* restore the original index */
6445*4882a593Smuzhiyun 	si_setcoreidx(&sii->pub, origidx);
6446*4882a593Smuzhiyun 
6447*4882a593Smuzhiyun 	pcicore_hwup(sii->pch);
6448*4882a593Smuzhiyun #endif /* DONGLEBUILD */
6449*4882a593Smuzhiyun 	return 0;
6450*4882a593Smuzhiyun } /* si_pci_fixcfg */
6451*4882a593Smuzhiyun 
6452*4882a593Smuzhiyun #if defined(BCMDBG) || defined(BCMDBG_DUMP) || defined(WLTEST)
6453*4882a593Smuzhiyun int
si_dump_pcieinfo(const si_t * sih,struct bcmstrbuf * b)6454*4882a593Smuzhiyun si_dump_pcieinfo(const si_t *sih, struct bcmstrbuf *b)
6455*4882a593Smuzhiyun {
6456*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6457*4882a593Smuzhiyun 
6458*4882a593Smuzhiyun 	if (!PCIE_GEN1(sii) && !PCIE_GEN2(sii))
6459*4882a593Smuzhiyun 		return BCME_ERROR;
6460*4882a593Smuzhiyun 
6461*4882a593Smuzhiyun 	return pcicore_dump_pcieinfo(sii->pch, b);
6462*4882a593Smuzhiyun }
6463*4882a593Smuzhiyun 
6464*4882a593Smuzhiyun void
si_dump_pmuregs(si_t * sih,struct bcmstrbuf * b)6465*4882a593Smuzhiyun si_dump_pmuregs(si_t *sih, struct bcmstrbuf *b)
6466*4882a593Smuzhiyun {
6467*4882a593Smuzhiyun 	uint i;
6468*4882a593Smuzhiyun 	uint32 pmu_cap;
6469*4882a593Smuzhiyun 	uint32 pmu_chip_reg;
6470*4882a593Smuzhiyun 
6471*4882a593Smuzhiyun 	bcm_bprintf(b, "===pmu(rev %d)===\n", sih->pmurev);
6472*4882a593Smuzhiyun 	if (!(sih->pmurev == 0x11 || (sih->pmurev >= 0x15 && sih->pmurev <= 0x19))) {
6473*4882a593Smuzhiyun 		bcm_bprintf(b, "PMU dump not supported\n");
6474*4882a593Smuzhiyun 		return;
6475*4882a593Smuzhiyun 	}
6476*4882a593Smuzhiyun 	pmu_cap = si_ccreg(sih, PMU_CAP, 0, 0);
6477*4882a593Smuzhiyun 	bcm_bprintf(b, "pmu_control 0x%x\n", si_ccreg(sih, PMU_CTL, 0, 0));
6478*4882a593Smuzhiyun 	bcm_bprintf(b, "pmu_capabilities 0x%x\n", pmu_cap);
6479*4882a593Smuzhiyun 	bcm_bprintf(b, "pmu_status 0x%x\n", si_ccreg(sih, PMU_ST, 0, 0));
6480*4882a593Smuzhiyun 	bcm_bprintf(b, "res_state 0x%x\n", si_ccreg(sih, PMU_RES_STATE, 0, 0));
6481*4882a593Smuzhiyun 	bcm_bprintf(b, "res_pending 0x%x\n", si_ccreg(sih, PMU_RES_PENDING, 0, 0));
6482*4882a593Smuzhiyun 	bcm_bprintf(b, "pmu_timer1 %d\n", si_ccreg(sih, PMU_TIMER, 0, 0));
6483*4882a593Smuzhiyun 	bcm_bprintf(b, "min_res_mask 0x%x\n", si_ccreg(sih, MINRESMASKREG, 0, 0));
6484*4882a593Smuzhiyun 	bcm_bprintf(b, "max_res_mask 0x%x\n", si_ccreg(sih, MAXRESMASKREG, 0, 0));
6485*4882a593Smuzhiyun 
6486*4882a593Smuzhiyun 	pmu_chip_reg = (pmu_cap & 0xf8000000);
6487*4882a593Smuzhiyun 	pmu_chip_reg = pmu_chip_reg >> 27;
6488*4882a593Smuzhiyun 	bcm_bprintf(b, "si_pmu_chipcontrol: ");
6489*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_reg; i++) {
6490*4882a593Smuzhiyun 		bcm_bprintf(b, "[%d]=0x%x ", i, si_pmu_chipcontrol(sih, i, 0, 0));
6491*4882a593Smuzhiyun 	}
6492*4882a593Smuzhiyun 
6493*4882a593Smuzhiyun 	pmu_chip_reg = (pmu_cap & 0x07c00000);
6494*4882a593Smuzhiyun 	pmu_chip_reg = pmu_chip_reg >> 22;
6495*4882a593Smuzhiyun 	bcm_bprintf(b, "\nsi_pmu_vregcontrol: ");
6496*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_reg; i++) {
6497*4882a593Smuzhiyun 		bcm_bprintf(b, "[%d]=0x%x ", i, si_pmu_vreg_control(sih, i, 0, 0));
6498*4882a593Smuzhiyun 	}
6499*4882a593Smuzhiyun 	pmu_chip_reg = (pmu_cap & 0x003e0000);
6500*4882a593Smuzhiyun 	pmu_chip_reg = pmu_chip_reg >> 17;
6501*4882a593Smuzhiyun 	bcm_bprintf(b, "\nsi_pmu_pllcontrol: ");
6502*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_reg; i++) {
6503*4882a593Smuzhiyun 		bcm_bprintf(b, "[%d]=0x%x ", i, si_pmu_pllcontrol(sih, i, 0, 0));
6504*4882a593Smuzhiyun 	}
6505*4882a593Smuzhiyun 	pmu_chip_reg = (pmu_cap & 0x0001e000);
6506*4882a593Smuzhiyun 	pmu_chip_reg = pmu_chip_reg >> 13;
6507*4882a593Smuzhiyun 	bcm_bprintf(b, "\nsi_pmu_res u/d timer: ");
6508*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_reg; i++) {
6509*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, RSRCTABLEADDR, ~0, i);
6510*4882a593Smuzhiyun 		bcm_bprintf(b, "[%d]=0x%x ", i, si_corereg(sih, SI_CC_IDX, RSRCUPDWNTIME, 0, 0));
6511*4882a593Smuzhiyun 	}
6512*4882a593Smuzhiyun 	pmu_chip_reg = (pmu_cap & 0x00001f00);
6513*4882a593Smuzhiyun 	pmu_chip_reg = pmu_chip_reg >> 8;
6514*4882a593Smuzhiyun 	bcm_bprintf(b, "\nsi_pmu_res dep_mask: ");
6515*4882a593Smuzhiyun 	for (i = 0; i < pmu_chip_reg; i++) {
6516*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, RSRCTABLEADDR, ~0, i);
6517*4882a593Smuzhiyun 		bcm_bprintf(b, "[%d]=0x%x ", i, si_corereg(sih, SI_CC_IDX, PMU_RES_DEP_MASK, 0, 0));
6518*4882a593Smuzhiyun 	}
6519*4882a593Smuzhiyun 	bcm_bprintf(b, "\n");
6520*4882a593Smuzhiyun }
6521*4882a593Smuzhiyun 
6522*4882a593Smuzhiyun int
si_dump_pcieregs(const si_t * sih,struct bcmstrbuf * b)6523*4882a593Smuzhiyun si_dump_pcieregs(const si_t *sih, struct bcmstrbuf *b)
6524*4882a593Smuzhiyun {
6525*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6526*4882a593Smuzhiyun 
6527*4882a593Smuzhiyun 	if (!PCIE_GEN1(sii) && !PCIE_GEN2(sii))
6528*4882a593Smuzhiyun 		return BCME_ERROR;
6529*4882a593Smuzhiyun 
6530*4882a593Smuzhiyun 	return pcicore_dump_pcieregs(sii->pch, b);
6531*4882a593Smuzhiyun }
6532*4882a593Smuzhiyun 
6533*4882a593Smuzhiyun #endif /* BCMDBG || BCMDBG_DUMP || WLTEST */
6534*4882a593Smuzhiyun 
6535*4882a593Smuzhiyun #if defined(BCMDBG) || defined(BCMDBG_DUMP) || defined(BCMDBG_PHYDUMP)
6536*4882a593Smuzhiyun void
si_dump(const si_t * sih,struct bcmstrbuf * b)6537*4882a593Smuzhiyun si_dump(const si_t *sih, struct bcmstrbuf *b)
6538*4882a593Smuzhiyun {
6539*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6540*4882a593Smuzhiyun 	const si_cores_info_t *cores_info = (const si_cores_info_t *)sii->cores_info;
6541*4882a593Smuzhiyun 	uint i;
6542*4882a593Smuzhiyun 
6543*4882a593Smuzhiyun 	bcm_bprintf(b, "si %p chip 0x%x chiprev 0x%x boardtype 0x%x boardvendor 0x%x bus %d\n",
6544*4882a593Smuzhiyun 		OSL_OBFUSCATE_BUF(sii), sih->chip, sih->chiprev,
6545*4882a593Smuzhiyun 		sih->boardtype, sih->boardvendor, sih->bustype);
6546*4882a593Smuzhiyun 	bcm_bprintf(b, "osh %p curmap %p\n",
6547*4882a593Smuzhiyun 		OSL_OBFUSCATE_BUF(sii->osh), OSL_OBFUSCATE_BUF(sii->curmap));
6548*4882a593Smuzhiyun 
6549*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_SB)
6550*4882a593Smuzhiyun 		bcm_bprintf(b, "sonicsrev %d ", sih->socirev);
6551*4882a593Smuzhiyun 	bcm_bprintf(b, "ccrev %d buscoretype 0x%x buscorerev %d curidx %d\n",
6552*4882a593Smuzhiyun 	            CCREV(sih->ccrev), sih->buscoretype, sih->buscorerev, sii->curidx);
6553*4882a593Smuzhiyun 
6554*4882a593Smuzhiyun #ifdef	BCMDBG
6555*4882a593Smuzhiyun 	if ((BUSTYPE(sih->bustype) == PCI_BUS) && (sii->pch))
6556*4882a593Smuzhiyun 		pcicore_dump(sii->pch, b);
6557*4882a593Smuzhiyun #endif
6558*4882a593Smuzhiyun 
6559*4882a593Smuzhiyun 	bcm_bprintf(b, "cores:  ");
6560*4882a593Smuzhiyun 	for (i = 0; i < sii->numcores; i++)
6561*4882a593Smuzhiyun 		bcm_bprintf(b, "0x%x ", cores_info->coreid[i]);
6562*4882a593Smuzhiyun 	bcm_bprintf(b, "\n");
6563*4882a593Smuzhiyun }
6564*4882a593Smuzhiyun 
6565*4882a593Smuzhiyun void
si_ccreg_dump(si_t * sih,struct bcmstrbuf * b)6566*4882a593Smuzhiyun si_ccreg_dump(si_t *sih, struct bcmstrbuf *b)
6567*4882a593Smuzhiyun {
6568*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6569*4882a593Smuzhiyun 	uint origidx;
6570*4882a593Smuzhiyun 	uint i;
6571*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
6572*4882a593Smuzhiyun 	chipcregs_t *cc;
6573*4882a593Smuzhiyun 
6574*4882a593Smuzhiyun 	/* only support corerev 22 for now */
6575*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) != 23)
6576*4882a593Smuzhiyun 		return;
6577*4882a593Smuzhiyun 
6578*4882a593Smuzhiyun 	origidx = sii->curidx;
6579*4882a593Smuzhiyun 
6580*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
6581*4882a593Smuzhiyun 
6582*4882a593Smuzhiyun 	cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
6583*4882a593Smuzhiyun 	ASSERT(cc);
6584*4882a593Smuzhiyun 
6585*4882a593Smuzhiyun 	bcm_bprintf(b, "\n===cc(rev %d) registers(offset val)===\n", CCREV(sih->ccrev));
6586*4882a593Smuzhiyun 	for (i = 0; i <= 0xc4; i += 4) {
6587*4882a593Smuzhiyun 		if (i == 0x4c) {
6588*4882a593Smuzhiyun 			bcm_bprintf(b, "\n");
6589*4882a593Smuzhiyun 			continue;
6590*4882a593Smuzhiyun 		}
6591*4882a593Smuzhiyun 		bcm_bprintf(b, "0x%x\t0x%x\n", i, *(uint32 *)((uintptr)cc + i));
6592*4882a593Smuzhiyun 	}
6593*4882a593Smuzhiyun 
6594*4882a593Smuzhiyun 	bcm_bprintf(b, "\n");
6595*4882a593Smuzhiyun 
6596*4882a593Smuzhiyun 	for (i = 0x1e0; i <= 0x1e4; i += 4) {
6597*4882a593Smuzhiyun 		bcm_bprintf(b, "0x%x\t0x%x\n", i, *(uint32 *)((uintptr)cc + i));
6598*4882a593Smuzhiyun 	}
6599*4882a593Smuzhiyun 	bcm_bprintf(b, "\n");
6600*4882a593Smuzhiyun 
6601*4882a593Smuzhiyun 	if (sih->cccaps & CC_CAP_PMU) {
6602*4882a593Smuzhiyun 		for (i = 0x600; i <= 0x660; i += 4) {
6603*4882a593Smuzhiyun 			bcm_bprintf(b, "0x%x\t0x%x\n", i, *(uint32 *)((uintptr)cc + i));
6604*4882a593Smuzhiyun 		}
6605*4882a593Smuzhiyun 	}
6606*4882a593Smuzhiyun 	bcm_bprintf(b, "\n");
6607*4882a593Smuzhiyun 
6608*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
6609*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
6610*4882a593Smuzhiyun }
6611*4882a593Smuzhiyun 
6612*4882a593Smuzhiyun /** dump dynamic clock control related registers */
6613*4882a593Smuzhiyun void
si_clkctl_dump(si_t * sih,struct bcmstrbuf * b)6614*4882a593Smuzhiyun si_clkctl_dump(si_t *sih, struct bcmstrbuf *b)
6615*4882a593Smuzhiyun {
6616*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6617*4882a593Smuzhiyun 	chipcregs_t *cc;
6618*4882a593Smuzhiyun 	uint origidx;
6619*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
6620*4882a593Smuzhiyun 
6621*4882a593Smuzhiyun 	if (!(sih->cccaps & CC_CAP_PWR_CTL))
6622*4882a593Smuzhiyun 		return;
6623*4882a593Smuzhiyun 
6624*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
6625*4882a593Smuzhiyun 	origidx = sii->curidx;
6626*4882a593Smuzhiyun 	if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL)
6627*4882a593Smuzhiyun 		goto done;
6628*4882a593Smuzhiyun 
6629*4882a593Smuzhiyun 	bcm_bprintf(b, "pll_on_delay 0x%x fref_sel_delay 0x%x ",
6630*4882a593Smuzhiyun 		cc->pll_on_delay, cc->fref_sel_delay);
6631*4882a593Smuzhiyun 	if ((CCREV(sih->ccrev) >= 6) && (CCREV(sih->ccrev) < 10))
6632*4882a593Smuzhiyun 		bcm_bprintf(b, "slow_clk_ctl 0x%x ", cc->slow_clk_ctl);
6633*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) >= 10) {
6634*4882a593Smuzhiyun 		bcm_bprintf(b, "system_clk_ctl 0x%x ", cc->system_clk_ctl);
6635*4882a593Smuzhiyun 		bcm_bprintf(b, "clkstatestretch 0x%x ", cc->clkstatestretch);
6636*4882a593Smuzhiyun 	}
6637*4882a593Smuzhiyun 
6638*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == PCI_BUS)
6639*4882a593Smuzhiyun 		bcm_bprintf(b, "gpioout 0x%x gpioouten 0x%x ",
6640*4882a593Smuzhiyun 		            OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)),
6641*4882a593Smuzhiyun 		            OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUTEN, sizeof(uint32)));
6642*4882a593Smuzhiyun 
6643*4882a593Smuzhiyun 	if (sih->cccaps & CC_CAP_PMU) {
6644*4882a593Smuzhiyun 		/* dump some PMU register ? */
6645*4882a593Smuzhiyun 	}
6646*4882a593Smuzhiyun 	bcm_bprintf(b, "\n");
6647*4882a593Smuzhiyun 
6648*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
6649*4882a593Smuzhiyun done:
6650*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
6651*4882a593Smuzhiyun }
6652*4882a593Smuzhiyun 
6653*4882a593Smuzhiyun int
si_gpiodump(si_t * sih,struct bcmstrbuf * b)6654*4882a593Smuzhiyun si_gpiodump(si_t *sih, struct bcmstrbuf *b)
6655*4882a593Smuzhiyun {
6656*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
6657*4882a593Smuzhiyun 	uint origidx;
6658*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
6659*4882a593Smuzhiyun 	chipcregs_t *cc;
6660*4882a593Smuzhiyun 
6661*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
6662*4882a593Smuzhiyun 
6663*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
6664*4882a593Smuzhiyun 
6665*4882a593Smuzhiyun 	cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
6666*4882a593Smuzhiyun 	ASSERT(cc);
6667*4882a593Smuzhiyun 
6668*4882a593Smuzhiyun 	bcm_bprintf(b, "GPIOregs\t");
6669*4882a593Smuzhiyun 
6670*4882a593Smuzhiyun 	bcm_bprintf(b, "gpioin 0x%x ", R_REG(sii->osh, &cc->gpioin));
6671*4882a593Smuzhiyun 	bcm_bprintf(b, "gpioout 0x%x ", R_REG(sii->osh, &cc->gpioout));
6672*4882a593Smuzhiyun 	bcm_bprintf(b, "gpioouten 0x%x ", R_REG(sii->osh, &cc->gpioouten));
6673*4882a593Smuzhiyun 	bcm_bprintf(b, "gpiocontrol 0x%x ", R_REG(sii->osh, &cc->gpiocontrol));
6674*4882a593Smuzhiyun 	bcm_bprintf(b, "gpiointpolarity 0x%x ", R_REG(sii->osh, &cc->gpiointpolarity));
6675*4882a593Smuzhiyun 	bcm_bprintf(b, "gpiointmask 0x%x ", R_REG(sii->osh, &cc->gpiointmask));
6676*4882a593Smuzhiyun 
6677*4882a593Smuzhiyun 	bcm_bprintf(b, "\n");
6678*4882a593Smuzhiyun 
6679*4882a593Smuzhiyun 	/* restore the original index */
6680*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
6681*4882a593Smuzhiyun 
6682*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
6683*4882a593Smuzhiyun 	return 0;
6684*4882a593Smuzhiyun 
6685*4882a593Smuzhiyun }
6686*4882a593Smuzhiyun #endif /* BCMDBG || BCMDBG_DUMP || BCMDBG_PHYDUMP */
6687*4882a593Smuzhiyun 
6688*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
6689*4882a593Smuzhiyun 
6690*4882a593Smuzhiyun /** change logical "focus" to the gpio core for optimized access */
6691*4882a593Smuzhiyun volatile void *
si_gpiosetcore(si_t * sih)6692*4882a593Smuzhiyun si_gpiosetcore(si_t *sih)
6693*4882a593Smuzhiyun {
6694*4882a593Smuzhiyun 	return (si_setcoreidx(sih, SI_CC_IDX));
6695*4882a593Smuzhiyun }
6696*4882a593Smuzhiyun 
6697*4882a593Smuzhiyun /**
6698*4882a593Smuzhiyun  * mask & set gpiocontrol bits.
6699*4882a593Smuzhiyun  * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin.
6700*4882a593Smuzhiyun  * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated
6701*4882a593Smuzhiyun  *   to some chip-specific purpose.
6702*4882a593Smuzhiyun  */
6703*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_gpiocontrol)6704*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gpiocontrol)(si_t *sih, uint32 mask, uint32 val, uint8 priority)
6705*4882a593Smuzhiyun {
6706*4882a593Smuzhiyun 	uint regoff;
6707*4882a593Smuzhiyun 
6708*4882a593Smuzhiyun 	regoff = 0;
6709*4882a593Smuzhiyun 
6710*4882a593Smuzhiyun 	/* gpios could be shared on router platforms
6711*4882a593Smuzhiyun 	 * ignore reservation if it's high priority (e.g., test apps)
6712*4882a593Smuzhiyun 	 */
6713*4882a593Smuzhiyun 	if ((priority != GPIO_HI_PRIORITY) &&
6714*4882a593Smuzhiyun 	    (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
6715*4882a593Smuzhiyun 		mask = priority ? (si_gpioreservation & mask) :
6716*4882a593Smuzhiyun 			((si_gpioreservation | mask) & ~(si_gpioreservation));
6717*4882a593Smuzhiyun 		val &= mask;
6718*4882a593Smuzhiyun 	}
6719*4882a593Smuzhiyun 
6720*4882a593Smuzhiyun 	regoff = OFFSETOF(chipcregs_t, gpiocontrol);
6721*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
6722*4882a593Smuzhiyun }
6723*4882a593Smuzhiyun 
6724*4882a593Smuzhiyun /** mask&set gpio output enable bits */
6725*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_gpioouten)6726*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gpioouten)(si_t *sih, uint32 mask, uint32 val, uint8 priority)
6727*4882a593Smuzhiyun {
6728*4882a593Smuzhiyun 	uint regoff;
6729*4882a593Smuzhiyun 
6730*4882a593Smuzhiyun 	regoff = 0;
6731*4882a593Smuzhiyun 
6732*4882a593Smuzhiyun 	/* gpios could be shared on router platforms
6733*4882a593Smuzhiyun 	 * ignore reservation if it's high priority (e.g., test apps)
6734*4882a593Smuzhiyun 	 */
6735*4882a593Smuzhiyun 	if ((priority != GPIO_HI_PRIORITY) &&
6736*4882a593Smuzhiyun 	    (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
6737*4882a593Smuzhiyun 		mask = priority ? (si_gpioreservation & mask) :
6738*4882a593Smuzhiyun 			((si_gpioreservation | mask) & ~(si_gpioreservation));
6739*4882a593Smuzhiyun 		val &= mask;
6740*4882a593Smuzhiyun 	}
6741*4882a593Smuzhiyun 
6742*4882a593Smuzhiyun 	regoff = OFFSETOF(chipcregs_t, gpioouten);
6743*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
6744*4882a593Smuzhiyun }
6745*4882a593Smuzhiyun 
6746*4882a593Smuzhiyun /** mask&set gpio output bits */
6747*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_gpioout)6748*4882a593Smuzhiyun BCMPOSTTRAPFN(si_gpioout)(si_t *sih, uint32 mask, uint32 val, uint8 priority)
6749*4882a593Smuzhiyun {
6750*4882a593Smuzhiyun 	uint regoff;
6751*4882a593Smuzhiyun 
6752*4882a593Smuzhiyun 	regoff = 0;
6753*4882a593Smuzhiyun 
6754*4882a593Smuzhiyun 	/* gpios could be shared on router platforms
6755*4882a593Smuzhiyun 	 * ignore reservation if it's high priority (e.g., test apps)
6756*4882a593Smuzhiyun 	 */
6757*4882a593Smuzhiyun 	if ((priority != GPIO_HI_PRIORITY) &&
6758*4882a593Smuzhiyun 	    (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
6759*4882a593Smuzhiyun 		mask = priority ? (si_gpioreservation & mask) :
6760*4882a593Smuzhiyun 			((si_gpioreservation | mask) & ~(si_gpioreservation));
6761*4882a593Smuzhiyun 		val &= mask;
6762*4882a593Smuzhiyun 	}
6763*4882a593Smuzhiyun 
6764*4882a593Smuzhiyun 	regoff = OFFSETOF(chipcregs_t, gpioout);
6765*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
6766*4882a593Smuzhiyun }
6767*4882a593Smuzhiyun 
6768*4882a593Smuzhiyun /** reserve one gpio */
6769*4882a593Smuzhiyun uint32
si_gpioreserve(const si_t * sih,uint32 gpio_bitmask,uint8 priority)6770*4882a593Smuzhiyun si_gpioreserve(const si_t *sih, uint32 gpio_bitmask, uint8 priority)
6771*4882a593Smuzhiyun {
6772*4882a593Smuzhiyun 	/* only cores on SI_BUS share GPIO's and only applcation users need to
6773*4882a593Smuzhiyun 	 * reserve/release GPIO
6774*4882a593Smuzhiyun 	 */
6775*4882a593Smuzhiyun 	if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
6776*4882a593Smuzhiyun 		ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
6777*4882a593Smuzhiyun 		return 0xffffffff;
6778*4882a593Smuzhiyun 	}
6779*4882a593Smuzhiyun 	/* make sure only one bit is set */
6780*4882a593Smuzhiyun 	if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
6781*4882a593Smuzhiyun 		ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
6782*4882a593Smuzhiyun 		return 0xffffffff;
6783*4882a593Smuzhiyun 	}
6784*4882a593Smuzhiyun 
6785*4882a593Smuzhiyun 	/* already reserved */
6786*4882a593Smuzhiyun 	if (si_gpioreservation & gpio_bitmask)
6787*4882a593Smuzhiyun 		return 0xffffffff;
6788*4882a593Smuzhiyun 	/* set reservation */
6789*4882a593Smuzhiyun 	si_gpioreservation |= gpio_bitmask;
6790*4882a593Smuzhiyun 
6791*4882a593Smuzhiyun 	return si_gpioreservation;
6792*4882a593Smuzhiyun }
6793*4882a593Smuzhiyun 
6794*4882a593Smuzhiyun /**
6795*4882a593Smuzhiyun  * release one gpio.
6796*4882a593Smuzhiyun  *
6797*4882a593Smuzhiyun  * releasing the gpio doesn't change the current value on the GPIO last write value
6798*4882a593Smuzhiyun  * persists till someone overwrites it.
6799*4882a593Smuzhiyun  */
6800*4882a593Smuzhiyun uint32
si_gpiorelease(const si_t * sih,uint32 gpio_bitmask,uint8 priority)6801*4882a593Smuzhiyun si_gpiorelease(const si_t *sih, uint32 gpio_bitmask, uint8 priority)
6802*4882a593Smuzhiyun {
6803*4882a593Smuzhiyun 	/* only cores on SI_BUS share GPIO's and only applcation users need to
6804*4882a593Smuzhiyun 	 * reserve/release GPIO
6805*4882a593Smuzhiyun 	 */
6806*4882a593Smuzhiyun 	if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
6807*4882a593Smuzhiyun 		ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
6808*4882a593Smuzhiyun 		return 0xffffffff;
6809*4882a593Smuzhiyun 	}
6810*4882a593Smuzhiyun 	/* make sure only one bit is set */
6811*4882a593Smuzhiyun 	if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
6812*4882a593Smuzhiyun 		ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
6813*4882a593Smuzhiyun 		return 0xffffffff;
6814*4882a593Smuzhiyun 	}
6815*4882a593Smuzhiyun 
6816*4882a593Smuzhiyun 	/* already released */
6817*4882a593Smuzhiyun 	if (!(si_gpioreservation & gpio_bitmask))
6818*4882a593Smuzhiyun 		return 0xffffffff;
6819*4882a593Smuzhiyun 
6820*4882a593Smuzhiyun 	/* clear reservation */
6821*4882a593Smuzhiyun 	si_gpioreservation &= ~gpio_bitmask;
6822*4882a593Smuzhiyun 
6823*4882a593Smuzhiyun 	return si_gpioreservation;
6824*4882a593Smuzhiyun }
6825*4882a593Smuzhiyun 
6826*4882a593Smuzhiyun /* return the current gpioin register value */
6827*4882a593Smuzhiyun uint32
si_gpioin(si_t * sih)6828*4882a593Smuzhiyun si_gpioin(si_t *sih)
6829*4882a593Smuzhiyun {
6830*4882a593Smuzhiyun 	uint regoff;
6831*4882a593Smuzhiyun 
6832*4882a593Smuzhiyun 	regoff = OFFSETOF(chipcregs_t, gpioin);
6833*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0));
6834*4882a593Smuzhiyun }
6835*4882a593Smuzhiyun 
6836*4882a593Smuzhiyun /* mask&set gpio interrupt polarity bits */
6837*4882a593Smuzhiyun uint32
si_gpiointpolarity(si_t * sih,uint32 mask,uint32 val,uint8 priority)6838*4882a593Smuzhiyun si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority)
6839*4882a593Smuzhiyun {
6840*4882a593Smuzhiyun 	uint regoff;
6841*4882a593Smuzhiyun 
6842*4882a593Smuzhiyun 	/* gpios could be shared on router platforms */
6843*4882a593Smuzhiyun 	if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
6844*4882a593Smuzhiyun 		mask = priority ? (si_gpioreservation & mask) :
6845*4882a593Smuzhiyun 			((si_gpioreservation | mask) & ~(si_gpioreservation));
6846*4882a593Smuzhiyun 		val &= mask;
6847*4882a593Smuzhiyun 	}
6848*4882a593Smuzhiyun 
6849*4882a593Smuzhiyun 	regoff = OFFSETOF(chipcregs_t, gpiointpolarity);
6850*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
6851*4882a593Smuzhiyun }
6852*4882a593Smuzhiyun 
6853*4882a593Smuzhiyun /* mask&set gpio interrupt mask bits */
6854*4882a593Smuzhiyun uint32
si_gpiointmask(si_t * sih,uint32 mask,uint32 val,uint8 priority)6855*4882a593Smuzhiyun si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority)
6856*4882a593Smuzhiyun {
6857*4882a593Smuzhiyun 	uint regoff;
6858*4882a593Smuzhiyun 
6859*4882a593Smuzhiyun 	/* gpios could be shared on router platforms */
6860*4882a593Smuzhiyun 	if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
6861*4882a593Smuzhiyun 		mask = priority ? (si_gpioreservation & mask) :
6862*4882a593Smuzhiyun 			((si_gpioreservation | mask) & ~(si_gpioreservation));
6863*4882a593Smuzhiyun 		val &= mask;
6864*4882a593Smuzhiyun 	}
6865*4882a593Smuzhiyun 
6866*4882a593Smuzhiyun 	regoff = OFFSETOF(chipcregs_t, gpiointmask);
6867*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
6868*4882a593Smuzhiyun }
6869*4882a593Smuzhiyun 
6870*4882a593Smuzhiyun uint32
si_gpioeventintmask(si_t * sih,uint32 mask,uint32 val,uint8 priority)6871*4882a593Smuzhiyun si_gpioeventintmask(si_t *sih, uint32 mask, uint32 val, uint8 priority)
6872*4882a593Smuzhiyun {
6873*4882a593Smuzhiyun 	uint regoff;
6874*4882a593Smuzhiyun 	/* gpios could be shared on router platforms */
6875*4882a593Smuzhiyun 	if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
6876*4882a593Smuzhiyun 		mask = priority ? (si_gpioreservation & mask) :
6877*4882a593Smuzhiyun 			((si_gpioreservation | mask) & ~(si_gpioreservation));
6878*4882a593Smuzhiyun 		val &= mask;
6879*4882a593Smuzhiyun 	}
6880*4882a593Smuzhiyun 	regoff = OFFSETOF(chipcregs_t, gpioeventintmask);
6881*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
6882*4882a593Smuzhiyun }
6883*4882a593Smuzhiyun 
6884*4882a593Smuzhiyun uint32
si_gpiopull(si_t * sih,bool updown,uint32 mask,uint32 val)6885*4882a593Smuzhiyun si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val)
6886*4882a593Smuzhiyun {
6887*4882a593Smuzhiyun 	uint offs;
6888*4882a593Smuzhiyun 
6889*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) < 20)
6890*4882a593Smuzhiyun 		return 0xffffffff;
6891*4882a593Smuzhiyun 
6892*4882a593Smuzhiyun 	offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup));
6893*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, offs, mask, val));
6894*4882a593Smuzhiyun }
6895*4882a593Smuzhiyun 
6896*4882a593Smuzhiyun uint32
si_gpioevent(si_t * sih,uint regtype,uint32 mask,uint32 val)6897*4882a593Smuzhiyun si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val)
6898*4882a593Smuzhiyun {
6899*4882a593Smuzhiyun 	uint offs;
6900*4882a593Smuzhiyun 
6901*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) < 11)
6902*4882a593Smuzhiyun 		return 0xffffffff;
6903*4882a593Smuzhiyun 
6904*4882a593Smuzhiyun 	if (regtype == GPIO_REGEVT)
6905*4882a593Smuzhiyun 		offs = OFFSETOF(chipcregs_t, gpioevent);
6906*4882a593Smuzhiyun 	else if (regtype == GPIO_REGEVT_INTMSK)
6907*4882a593Smuzhiyun 		offs = OFFSETOF(chipcregs_t, gpioeventintmask);
6908*4882a593Smuzhiyun 	else if (regtype == GPIO_REGEVT_INTPOL)
6909*4882a593Smuzhiyun 		offs = OFFSETOF(chipcregs_t, gpioeventintpolarity);
6910*4882a593Smuzhiyun 	else
6911*4882a593Smuzhiyun 		return 0xffffffff;
6912*4882a593Smuzhiyun 
6913*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, offs, mask, val));
6914*4882a593Smuzhiyun }
6915*4882a593Smuzhiyun 
6916*4882a593Smuzhiyun uint32
BCMATTACHFN(si_gpio_int_enable)6917*4882a593Smuzhiyun BCMATTACHFN(si_gpio_int_enable)(si_t *sih, bool enable)
6918*4882a593Smuzhiyun {
6919*4882a593Smuzhiyun 	uint offs;
6920*4882a593Smuzhiyun 
6921*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) < 11)
6922*4882a593Smuzhiyun 		return 0xffffffff;
6923*4882a593Smuzhiyun 
6924*4882a593Smuzhiyun 	offs = OFFSETOF(chipcregs_t, intmask);
6925*4882a593Smuzhiyun 	return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0)));
6926*4882a593Smuzhiyun }
6927*4882a593Smuzhiyun 
6928*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
6929*4882a593Smuzhiyun void
si_gci_shif_config_wake_pin(si_t * sih,uint8 gpio_n,uint8 wake_events,bool gci_gpio)6930*4882a593Smuzhiyun si_gci_shif_config_wake_pin(si_t *sih, uint8 gpio_n, uint8 wake_events,
6931*4882a593Smuzhiyun 		bool gci_gpio)
6932*4882a593Smuzhiyun {
6933*4882a593Smuzhiyun 	uint8 chipcontrol = 0;
6934*4882a593Smuzhiyun 	uint32 gci_wakset;
6935*4882a593Smuzhiyun 
6936*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
6937*4882a593Smuzhiyun 		case BCM4376_CHIP_GRPID :
6938*4882a593Smuzhiyun 		case BCM4378_CHIP_GRPID :
6939*4882a593Smuzhiyun 			{
6940*4882a593Smuzhiyun 				if (!gci_gpio) {
6941*4882a593Smuzhiyun 					chipcontrol = (1 << GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT);
6942*4882a593Smuzhiyun 				}
6943*4882a593Smuzhiyun 				chipcontrol |= (1 << GCI_GPIO_CHIPCTRL_PULLUP_BIT);
6944*4882a593Smuzhiyun 				chipcontrol |= (1 << GCI_GPIO_CHIPCTRL_INVERT_BIT);
6945*4882a593Smuzhiyun 				si_gci_gpio_chipcontrol(sih, gpio_n,
6946*4882a593Smuzhiyun 					(chipcontrol | (1 << GCI_GPIO_CHIPCTRL_ENAB_IN_BIT)));
6947*4882a593Smuzhiyun 
6948*4882a593Smuzhiyun 				/* enable gci gpio int/wake events */
6949*4882a593Smuzhiyun 				si_gci_gpio_intmask(sih, gpio_n, wake_events, wake_events);
6950*4882a593Smuzhiyun 				si_gci_gpio_wakemask(sih, gpio_n, wake_events, wake_events);
6951*4882a593Smuzhiyun 
6952*4882a593Smuzhiyun 				/* clear the existing status bits */
6953*4882a593Smuzhiyun 				si_gci_gpio_status(sih, gpio_n,
6954*4882a593Smuzhiyun 						GCI_GPIO_STS_CLEAR, GCI_GPIO_STS_CLEAR);
6955*4882a593Smuzhiyun 
6956*4882a593Smuzhiyun 				/* Enable gci2wl_wake for 4378 */
6957*4882a593Smuzhiyun 				si_pmu_chipcontrol(sih, PMU_CHIPCTL2,
6958*4882a593Smuzhiyun 						CC2_4378_GCI2WAKE_MASK, CC2_4378_GCI2WAKE_MASK);
6959*4882a593Smuzhiyun 
6960*4882a593Smuzhiyun 				/* enable gci int/wake events */
6961*4882a593Smuzhiyun 				gci_wakset = (GCI_INTSTATUS_GPIOWAKE) | (GCI_INTSTATUS_GPIOINT);
6962*4882a593Smuzhiyun 
6963*4882a593Smuzhiyun 				si_gci_indirect(sih, 0,	GCI_OFFSETOF(sih, gci_intmask),
6964*4882a593Smuzhiyun 						gci_wakset, gci_wakset);
6965*4882a593Smuzhiyun 				/* Enable wake on GciWake */
6966*4882a593Smuzhiyun 				si_gci_indirect(sih, 0,	GCI_OFFSETOF(sih, gci_wakemask),
6967*4882a593Smuzhiyun 						gci_wakset, gci_wakset);
6968*4882a593Smuzhiyun 				break;
6969*4882a593Smuzhiyun 			}
6970*4882a593Smuzhiyun 		case BCM4385_CHIP_GRPID :
6971*4882a593Smuzhiyun 		case BCM4387_CHIP_GRPID :
6972*4882a593Smuzhiyun 			{
6973*4882a593Smuzhiyun 				if (!gci_gpio) {
6974*4882a593Smuzhiyun 					chipcontrol = (1 << GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT);
6975*4882a593Smuzhiyun 				}
6976*4882a593Smuzhiyun 				chipcontrol |= (1 << GCI_GPIO_CHIPCTRL_PULLUP_BIT);
6977*4882a593Smuzhiyun 				chipcontrol |= (1 << GCI_GPIO_CHIPCTRL_INVERT_BIT);
6978*4882a593Smuzhiyun 				si_gci_gpio_chipcontrol(sih, gpio_n,
6979*4882a593Smuzhiyun 					(chipcontrol | (1 << GCI_GPIO_CHIPCTRL_ENAB_IN_BIT)));
6980*4882a593Smuzhiyun 
6981*4882a593Smuzhiyun 				/* enable gci gpio int/wake events */
6982*4882a593Smuzhiyun 				si_gci_gpio_intmask(sih, gpio_n, wake_events, wake_events);
6983*4882a593Smuzhiyun 				si_gci_gpio_wakemask(sih, gpio_n, wake_events, wake_events);
6984*4882a593Smuzhiyun 
6985*4882a593Smuzhiyun 				/* clear the existing status bits */
6986*4882a593Smuzhiyun 				si_gci_gpio_status(sih, gpio_n,
6987*4882a593Smuzhiyun 						GCI_GPIO_STS_CLEAR, GCI_GPIO_STS_CLEAR);
6988*4882a593Smuzhiyun 
6989*4882a593Smuzhiyun 				/* Enable gci2wl_wake for 4387 */
6990*4882a593Smuzhiyun 				si_pmu_chipcontrol(sih, PMU_CHIPCTL2,
6991*4882a593Smuzhiyun 						CC2_4387_GCI2WAKE_MASK, CC2_4387_GCI2WAKE_MASK);
6992*4882a593Smuzhiyun 
6993*4882a593Smuzhiyun 				/* enable gci int/wake events */
6994*4882a593Smuzhiyun 				gci_wakset = (GCI_INTSTATUS_GPIOWAKE) | (GCI_INTSTATUS_GPIOINT);
6995*4882a593Smuzhiyun 
6996*4882a593Smuzhiyun 				si_gci_indirect(sih, 0,	GCI_OFFSETOF(sih, gci_intmask),
6997*4882a593Smuzhiyun 						gci_wakset, gci_wakset);
6998*4882a593Smuzhiyun 				/* Enable wake on GciWake */
6999*4882a593Smuzhiyun 				si_gci_indirect(sih, 0,	GCI_OFFSETOF(sih, gci_wakemask),
7000*4882a593Smuzhiyun 						gci_wakset, gci_wakset);
7001*4882a593Smuzhiyun 				break;
7002*4882a593Smuzhiyun 			}
7003*4882a593Smuzhiyun 		default:;
7004*4882a593Smuzhiyun 	}
7005*4882a593Smuzhiyun }
7006*4882a593Smuzhiyun 
7007*4882a593Smuzhiyun void
si_shif_int_enable(si_t * sih,uint8 gpio_n,uint8 wake_events,bool enable)7008*4882a593Smuzhiyun si_shif_int_enable(si_t *sih, uint8 gpio_n, uint8 wake_events, bool enable)
7009*4882a593Smuzhiyun {
7010*4882a593Smuzhiyun 	if (enable) {
7011*4882a593Smuzhiyun 		si_gci_gpio_intmask(sih, gpio_n, wake_events, wake_events);
7012*4882a593Smuzhiyun 		si_gci_gpio_wakemask(sih, gpio_n, wake_events, wake_events);
7013*4882a593Smuzhiyun 	} else {
7014*4882a593Smuzhiyun 		si_gci_gpio_intmask(sih, gpio_n, wake_events, 0);
7015*4882a593Smuzhiyun 		si_gci_gpio_wakemask(sih, gpio_n, wake_events, 0);
7016*4882a593Smuzhiyun 	}
7017*4882a593Smuzhiyun }
7018*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
7019*4882a593Smuzhiyun 
7020*4882a593Smuzhiyun /** Return the size of the specified SYSMEM bank */
7021*4882a593Smuzhiyun static uint
sysmem_banksize(const si_info_t * sii,sysmemregs_t * regs,uint8 idx)7022*4882a593Smuzhiyun sysmem_banksize(const si_info_t *sii, sysmemregs_t *regs, uint8 idx)
7023*4882a593Smuzhiyun {
7024*4882a593Smuzhiyun 	uint banksize, bankinfo;
7025*4882a593Smuzhiyun 	uint bankidx = idx;
7026*4882a593Smuzhiyun 
7027*4882a593Smuzhiyun 	W_REG(sii->osh, &regs->bankidx, bankidx);
7028*4882a593Smuzhiyun 	bankinfo = R_REG(sii->osh, &regs->bankinfo);
7029*4882a593Smuzhiyun 	banksize = SYSMEM_BANKINFO_SZBASE * ((bankinfo & SYSMEM_BANKINFO_SZMASK) + 1);
7030*4882a593Smuzhiyun 	return banksize;
7031*4882a593Smuzhiyun }
7032*4882a593Smuzhiyun 
7033*4882a593Smuzhiyun /** Return the RAM size of the SYSMEM core */
7034*4882a593Smuzhiyun uint32
si_sysmem_size(si_t * sih)7035*4882a593Smuzhiyun si_sysmem_size(si_t *sih)
7036*4882a593Smuzhiyun {
7037*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7038*4882a593Smuzhiyun 	uint origidx;
7039*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
7040*4882a593Smuzhiyun 
7041*4882a593Smuzhiyun 	sysmemregs_t *regs;
7042*4882a593Smuzhiyun 	bool wasup;
7043*4882a593Smuzhiyun 	uint32 coreinfo;
7044*4882a593Smuzhiyun 	uint memsize = 0;
7045*4882a593Smuzhiyun 	uint8 i;
7046*4882a593Smuzhiyun 	uint nb, nrb;
7047*4882a593Smuzhiyun 
7048*4882a593Smuzhiyun 	/* Block ints and save current core */
7049*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
7050*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7051*4882a593Smuzhiyun 
7052*4882a593Smuzhiyun 	/* Switch to SYSMEM core */
7053*4882a593Smuzhiyun 	if (!(regs = si_setcore(sih, SYSMEM_CORE_ID, 0)))
7054*4882a593Smuzhiyun 		goto done;
7055*4882a593Smuzhiyun 
7056*4882a593Smuzhiyun 	/* Get info for determining size */
7057*4882a593Smuzhiyun 	if (!(wasup = si_iscoreup(sih)))
7058*4882a593Smuzhiyun 		si_core_reset(sih, 0, 0);
7059*4882a593Smuzhiyun 	coreinfo = R_REG(sii->osh, &regs->coreinfo);
7060*4882a593Smuzhiyun 
7061*4882a593Smuzhiyun 	/* Number of ROM banks, SW need to skip the ROM banks. */
7062*4882a593Smuzhiyun 	if (si_corerev(sih) < 12) {
7063*4882a593Smuzhiyun 		nrb = (coreinfo & SYSMEM_SRCI_ROMNB_MASK) >> SYSMEM_SRCI_ROMNB_SHIFT;
7064*4882a593Smuzhiyun 		nb = (coreinfo & SYSMEM_SRCI_SRNB_MASK) >> SYSMEM_SRCI_SRNB_SHIFT;
7065*4882a593Smuzhiyun 	} else {
7066*4882a593Smuzhiyun 		nrb = (coreinfo & SYSMEM_SRCI_NEW_ROMNB_MASK) >> SYSMEM_SRCI_NEW_ROMNB_SHIFT;
7067*4882a593Smuzhiyun 		nb = (coreinfo & SYSMEM_SRCI_NEW_SRNB_MASK) >> SYSMEM_SRCI_NEW_SRNB_SHIFT;
7068*4882a593Smuzhiyun 	}
7069*4882a593Smuzhiyun 	for (i = 0; i < nb; i++)
7070*4882a593Smuzhiyun 		memsize += sysmem_banksize(sii, regs, i + nrb);
7071*4882a593Smuzhiyun 
7072*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
7073*4882a593Smuzhiyun 
7074*4882a593Smuzhiyun done:
7075*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
7076*4882a593Smuzhiyun 
7077*4882a593Smuzhiyun 	return memsize;
7078*4882a593Smuzhiyun }
7079*4882a593Smuzhiyun 
7080*4882a593Smuzhiyun /** Return the size of the specified SOCRAM bank */
7081*4882a593Smuzhiyun static uint
socram_banksize(const si_info_t * sii,sbsocramregs_t * regs,uint8 idx,uint8 mem_type)7082*4882a593Smuzhiyun socram_banksize(const si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type)
7083*4882a593Smuzhiyun {
7084*4882a593Smuzhiyun 	uint banksize, bankinfo;
7085*4882a593Smuzhiyun 	uint bankidx = idx | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT);
7086*4882a593Smuzhiyun 
7087*4882a593Smuzhiyun 	ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM);
7088*4882a593Smuzhiyun 
7089*4882a593Smuzhiyun 	W_REG(sii->osh, &regs->bankidx, bankidx);
7090*4882a593Smuzhiyun 	bankinfo = R_REG(sii->osh, &regs->bankinfo);
7091*4882a593Smuzhiyun 	banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1);
7092*4882a593Smuzhiyun 	return banksize;
7093*4882a593Smuzhiyun }
7094*4882a593Smuzhiyun 
si_socram_set_bankpda(si_t * sih,uint32 bankidx,uint32 bankpda)7095*4882a593Smuzhiyun void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda)
7096*4882a593Smuzhiyun {
7097*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7098*4882a593Smuzhiyun 	uint origidx;
7099*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
7100*4882a593Smuzhiyun 	sbsocramregs_t *regs;
7101*4882a593Smuzhiyun 	bool wasup;
7102*4882a593Smuzhiyun 	uint corerev;
7103*4882a593Smuzhiyun 
7104*4882a593Smuzhiyun 	/* Block ints and save current core */
7105*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
7106*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7107*4882a593Smuzhiyun 
7108*4882a593Smuzhiyun 	/* Switch to SOCRAM core */
7109*4882a593Smuzhiyun 	if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
7110*4882a593Smuzhiyun 		goto done;
7111*4882a593Smuzhiyun 
7112*4882a593Smuzhiyun 	if (!(wasup = si_iscoreup(sih)))
7113*4882a593Smuzhiyun 		si_core_reset(sih, 0, 0);
7114*4882a593Smuzhiyun 
7115*4882a593Smuzhiyun 	corerev = si_corerev(sih);
7116*4882a593Smuzhiyun 	if (corerev >= 16) {
7117*4882a593Smuzhiyun 		W_REG(sii->osh, &regs->bankidx, bankidx);
7118*4882a593Smuzhiyun 		W_REG(sii->osh, &regs->bankpda, bankpda);
7119*4882a593Smuzhiyun 	}
7120*4882a593Smuzhiyun 
7121*4882a593Smuzhiyun 	/* Return to previous state and core */
7122*4882a593Smuzhiyun 	if (!wasup)
7123*4882a593Smuzhiyun 		si_core_disable(sih, 0);
7124*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
7125*4882a593Smuzhiyun 
7126*4882a593Smuzhiyun done:
7127*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
7128*4882a593Smuzhiyun }
7129*4882a593Smuzhiyun 
7130*4882a593Smuzhiyun /** Return the RAM size of the SOCRAM core */
7131*4882a593Smuzhiyun uint32
si_socram_size(si_t * sih)7132*4882a593Smuzhiyun si_socram_size(si_t *sih)
7133*4882a593Smuzhiyun {
7134*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7135*4882a593Smuzhiyun 	uint origidx;
7136*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
7137*4882a593Smuzhiyun 
7138*4882a593Smuzhiyun 	sbsocramregs_t *regs;
7139*4882a593Smuzhiyun 	bool wasup;
7140*4882a593Smuzhiyun 	uint corerev;
7141*4882a593Smuzhiyun 	uint32 coreinfo;
7142*4882a593Smuzhiyun 	uint memsize = 0;
7143*4882a593Smuzhiyun 
7144*4882a593Smuzhiyun 	/* Block ints and save current core */
7145*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
7146*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7147*4882a593Smuzhiyun 
7148*4882a593Smuzhiyun 	/* Switch to SOCRAM core */
7149*4882a593Smuzhiyun 	if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
7150*4882a593Smuzhiyun 		goto done;
7151*4882a593Smuzhiyun 
7152*4882a593Smuzhiyun 	/* Get info for determining size */
7153*4882a593Smuzhiyun 	if (!(wasup = si_iscoreup(sih)))
7154*4882a593Smuzhiyun 		si_core_reset(sih, 0, 0);
7155*4882a593Smuzhiyun 	corerev = si_corerev(sih);
7156*4882a593Smuzhiyun 	coreinfo = R_REG(sii->osh, &regs->coreinfo);
7157*4882a593Smuzhiyun 
7158*4882a593Smuzhiyun 	/* Calculate size from coreinfo based on rev */
7159*4882a593Smuzhiyun 	if (corerev == 0)
7160*4882a593Smuzhiyun 		memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK));
7161*4882a593Smuzhiyun 	else if (corerev < 3) {
7162*4882a593Smuzhiyun 		memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK));
7163*4882a593Smuzhiyun 		memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
7164*4882a593Smuzhiyun 	} else if ((corerev <= 7) || (corerev == 12)) {
7165*4882a593Smuzhiyun 		uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
7166*4882a593Smuzhiyun 		uint bsz = (coreinfo & SRCI_SRBSZ_MASK);
7167*4882a593Smuzhiyun 		uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT;
7168*4882a593Smuzhiyun 		if (lss != 0)
7169*4882a593Smuzhiyun 			nb --;
7170*4882a593Smuzhiyun 		memsize = nb * (1 << (bsz + SR_BSZ_BASE));
7171*4882a593Smuzhiyun 		if (lss != 0)
7172*4882a593Smuzhiyun 			memsize += (1 << ((lss - 1) + SR_BSZ_BASE));
7173*4882a593Smuzhiyun 	} else {
7174*4882a593Smuzhiyun 		uint8 i;
7175*4882a593Smuzhiyun 		uint nb;
7176*4882a593Smuzhiyun 		/* length of SRAM Banks increased for corerev greater than 23 */
7177*4882a593Smuzhiyun 		if (corerev >= 23) {
7178*4882a593Smuzhiyun 			nb = (coreinfo & (SRCI_SRNB_MASK | SRCI_SRNB_MASK_EXT)) >> SRCI_SRNB_SHIFT;
7179*4882a593Smuzhiyun 		} else {
7180*4882a593Smuzhiyun 			nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
7181*4882a593Smuzhiyun 		}
7182*4882a593Smuzhiyun 		for (i = 0; i < nb; i++)
7183*4882a593Smuzhiyun 			memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM);
7184*4882a593Smuzhiyun 	}
7185*4882a593Smuzhiyun 
7186*4882a593Smuzhiyun 	/* Return to previous state and core */
7187*4882a593Smuzhiyun 	if (!wasup)
7188*4882a593Smuzhiyun 		si_core_disable(sih, 0);
7189*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
7190*4882a593Smuzhiyun 
7191*4882a593Smuzhiyun done:
7192*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
7193*4882a593Smuzhiyun 
7194*4882a593Smuzhiyun 	return memsize;
7195*4882a593Smuzhiyun }
7196*4882a593Smuzhiyun 
7197*4882a593Smuzhiyun /* Return true if bus MPU is present */
7198*4882a593Smuzhiyun bool
si_is_bus_mpu_present(si_t * sih)7199*4882a593Smuzhiyun si_is_bus_mpu_present(si_t *sih)
7200*4882a593Smuzhiyun {
7201*4882a593Smuzhiyun 	uint origidx, newidx = NODEV_CORE_ID;
7202*4882a593Smuzhiyun 	sysmemregs_t *sysmemregs = NULL;
7203*4882a593Smuzhiyun 	cr4regs_t *cr4regs;
7204*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7205*4882a593Smuzhiyun 	uint ret = 0;
7206*4882a593Smuzhiyun 	bool wasup;
7207*4882a593Smuzhiyun 
7208*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7209*4882a593Smuzhiyun 
7210*4882a593Smuzhiyun 	cr4regs = si_setcore(sih, ARMCR4_CORE_ID, 0);
7211*4882a593Smuzhiyun 	if (cr4regs) {
7212*4882a593Smuzhiyun 		/* ARMCR4 */
7213*4882a593Smuzhiyun 		newidx = ARMCR4_CORE_ID;
7214*4882a593Smuzhiyun 	} else {
7215*4882a593Smuzhiyun 		sysmemregs = si_setcore(sih, SYSMEM_CORE_ID, 0);
7216*4882a593Smuzhiyun 		if (sysmemregs) {
7217*4882a593Smuzhiyun 			/* ARMCA7 */
7218*4882a593Smuzhiyun 			newidx = SYSMEM_CORE_ID;
7219*4882a593Smuzhiyun 		}
7220*4882a593Smuzhiyun 	}
7221*4882a593Smuzhiyun 
7222*4882a593Smuzhiyun 	if (newidx != NODEV_CORE_ID) {
7223*4882a593Smuzhiyun 		if (!(wasup = si_iscoreup(sih))) {
7224*4882a593Smuzhiyun 			si_core_reset(sih, 0, 0);
7225*4882a593Smuzhiyun 		}
7226*4882a593Smuzhiyun 		if (newidx == ARMCR4_CORE_ID) {
7227*4882a593Smuzhiyun 			/* ARMCR4 */
7228*4882a593Smuzhiyun 			ret = R_REG(sii->osh, &cr4regs->corecapabilities) & CAP_MPU_MASK;
7229*4882a593Smuzhiyun 		} else {
7230*4882a593Smuzhiyun 			/* ARMCA7 */
7231*4882a593Smuzhiyun 			ret = R_REG(sii->osh, &sysmemregs->mpucapabilities) &
7232*4882a593Smuzhiyun 				ACC_MPU_REGION_CNT_MASK;
7233*4882a593Smuzhiyun 		}
7234*4882a593Smuzhiyun 		if (!wasup) {
7235*4882a593Smuzhiyun 			si_core_disable(sih, 0);
7236*4882a593Smuzhiyun 		}
7237*4882a593Smuzhiyun 	}
7238*4882a593Smuzhiyun 
7239*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
7240*4882a593Smuzhiyun 
7241*4882a593Smuzhiyun 	return ret ? TRUE : FALSE;
7242*4882a593Smuzhiyun }
7243*4882a593Smuzhiyun 
7244*4882a593Smuzhiyun #if defined(BCMDONGLEHOST)
7245*4882a593Smuzhiyun 
7246*4882a593Smuzhiyun /** Return the TCM-RAM size of the ARMCR4 core. */
7247*4882a593Smuzhiyun uint32
si_tcm_size(si_t * sih)7248*4882a593Smuzhiyun si_tcm_size(si_t *sih)
7249*4882a593Smuzhiyun {
7250*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7251*4882a593Smuzhiyun 	uint origidx;
7252*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
7253*4882a593Smuzhiyun 	volatile uint8 *regs;
7254*4882a593Smuzhiyun 	bool wasup;
7255*4882a593Smuzhiyun 	uint32 corecap;
7256*4882a593Smuzhiyun 	uint memsize = 0;
7257*4882a593Smuzhiyun 	uint banku_size = 0;
7258*4882a593Smuzhiyun 	uint32 nab = 0;
7259*4882a593Smuzhiyun 	uint32 nbb = 0;
7260*4882a593Smuzhiyun 	uint32 totb = 0;
7261*4882a593Smuzhiyun 	uint32 bxinfo = 0;
7262*4882a593Smuzhiyun 	uint32 idx = 0;
7263*4882a593Smuzhiyun 	volatile uint32 *arm_cap_reg;
7264*4882a593Smuzhiyun 	volatile uint32 *arm_bidx;
7265*4882a593Smuzhiyun 	volatile uint32 *arm_binfo;
7266*4882a593Smuzhiyun 
7267*4882a593Smuzhiyun 	/* Block ints and save current core */
7268*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
7269*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7270*4882a593Smuzhiyun 
7271*4882a593Smuzhiyun 	/* Switch to CR4 core */
7272*4882a593Smuzhiyun 	if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0)))
7273*4882a593Smuzhiyun 		goto done;
7274*4882a593Smuzhiyun 
7275*4882a593Smuzhiyun 	/* Get info for determining size. If in reset, come out of reset,
7276*4882a593Smuzhiyun 	 * but remain in halt
7277*4882a593Smuzhiyun 	 */
7278*4882a593Smuzhiyun 	if (!(wasup = si_iscoreup(sih)))
7279*4882a593Smuzhiyun 		si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT);
7280*4882a593Smuzhiyun 
7281*4882a593Smuzhiyun 	arm_cap_reg = (volatile uint32 *)(regs + SI_CR4_CAP);
7282*4882a593Smuzhiyun 	corecap = R_REG(sii->osh, arm_cap_reg);
7283*4882a593Smuzhiyun 
7284*4882a593Smuzhiyun 	nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT;
7285*4882a593Smuzhiyun 	nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT;
7286*4882a593Smuzhiyun 	totb = nab + nbb;
7287*4882a593Smuzhiyun 
7288*4882a593Smuzhiyun 	arm_bidx = (volatile uint32 *)(regs + SI_CR4_BANKIDX);
7289*4882a593Smuzhiyun 	arm_binfo = (volatile uint32 *)(regs + SI_CR4_BANKINFO);
7290*4882a593Smuzhiyun 	for (idx = 0; idx < totb; idx++) {
7291*4882a593Smuzhiyun 		W_REG(sii->osh, arm_bidx, idx);
7292*4882a593Smuzhiyun 
7293*4882a593Smuzhiyun 		bxinfo = R_REG(sii->osh, arm_binfo);
7294*4882a593Smuzhiyun 		if (bxinfo & ARMCR4_BUNITSZ_MASK) {
7295*4882a593Smuzhiyun 			banku_size = ARMCR4_BSZ_1K;
7296*4882a593Smuzhiyun 		} else {
7297*4882a593Smuzhiyun 			banku_size = ARMCR4_BSZ_8K;
7298*4882a593Smuzhiyun 		}
7299*4882a593Smuzhiyun 		memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * banku_size;
7300*4882a593Smuzhiyun 	}
7301*4882a593Smuzhiyun 
7302*4882a593Smuzhiyun 	/* Return to previous state and core */
7303*4882a593Smuzhiyun 	if (!wasup)
7304*4882a593Smuzhiyun 		si_core_disable(sih, 0);
7305*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
7306*4882a593Smuzhiyun 
7307*4882a593Smuzhiyun done:
7308*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
7309*4882a593Smuzhiyun 
7310*4882a593Smuzhiyun 	return memsize;
7311*4882a593Smuzhiyun }
7312*4882a593Smuzhiyun 
7313*4882a593Smuzhiyun bool
si_has_flops(si_t * sih)7314*4882a593Smuzhiyun si_has_flops(si_t *sih)
7315*4882a593Smuzhiyun {
7316*4882a593Smuzhiyun 	uint origidx, cr4_rev;
7317*4882a593Smuzhiyun 
7318*4882a593Smuzhiyun 	/* Find out CR4 core revision */
7319*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7320*4882a593Smuzhiyun 	if (si_setcore(sih, ARMCR4_CORE_ID, 0)) {
7321*4882a593Smuzhiyun 		cr4_rev = si_corerev(sih);
7322*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
7323*4882a593Smuzhiyun 
7324*4882a593Smuzhiyun 		if (cr4_rev == 1 || cr4_rev >= 3)
7325*4882a593Smuzhiyun 			return TRUE;
7326*4882a593Smuzhiyun 	}
7327*4882a593Smuzhiyun 	return FALSE;
7328*4882a593Smuzhiyun }
7329*4882a593Smuzhiyun #endif /* BCMDONGLEHOST */
7330*4882a593Smuzhiyun 
7331*4882a593Smuzhiyun uint32
si_socram_srmem_size(si_t * sih)7332*4882a593Smuzhiyun si_socram_srmem_size(si_t *sih)
7333*4882a593Smuzhiyun {
7334*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7335*4882a593Smuzhiyun 	uint origidx;
7336*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
7337*4882a593Smuzhiyun 
7338*4882a593Smuzhiyun 	sbsocramregs_t *regs;
7339*4882a593Smuzhiyun 	bool wasup;
7340*4882a593Smuzhiyun 	uint corerev;
7341*4882a593Smuzhiyun 	uint32 coreinfo;
7342*4882a593Smuzhiyun 	uint memsize = 0;
7343*4882a593Smuzhiyun 
7344*4882a593Smuzhiyun 	/* Block ints and save current core */
7345*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
7346*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7347*4882a593Smuzhiyun 
7348*4882a593Smuzhiyun 	/* Switch to SOCRAM core */
7349*4882a593Smuzhiyun 	if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
7350*4882a593Smuzhiyun 		goto done;
7351*4882a593Smuzhiyun 
7352*4882a593Smuzhiyun 	/* Get info for determining size */
7353*4882a593Smuzhiyun 	if (!(wasup = si_iscoreup(sih)))
7354*4882a593Smuzhiyun 		si_core_reset(sih, 0, 0);
7355*4882a593Smuzhiyun 	corerev = si_corerev(sih);
7356*4882a593Smuzhiyun 	coreinfo = R_REG(sii->osh, &regs->coreinfo);
7357*4882a593Smuzhiyun 
7358*4882a593Smuzhiyun 	/* Calculate size from coreinfo based on rev */
7359*4882a593Smuzhiyun 	if (corerev >= 16) {
7360*4882a593Smuzhiyun 		uint8 i;
7361*4882a593Smuzhiyun 		uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
7362*4882a593Smuzhiyun 		for (i = 0; i < nb; i++) {
7363*4882a593Smuzhiyun 			W_REG(sii->osh, &regs->bankidx, i);
7364*4882a593Smuzhiyun 			if (R_REG(sii->osh, &regs->bankinfo) & SOCRAM_BANKINFO_RETNTRAM_MASK)
7365*4882a593Smuzhiyun 				memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM);
7366*4882a593Smuzhiyun 		}
7367*4882a593Smuzhiyun 	}
7368*4882a593Smuzhiyun 
7369*4882a593Smuzhiyun 	/* Return to previous state and core */
7370*4882a593Smuzhiyun 	if (!wasup)
7371*4882a593Smuzhiyun 		si_core_disable(sih, 0);
7372*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
7373*4882a593Smuzhiyun 
7374*4882a593Smuzhiyun done:
7375*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
7376*4882a593Smuzhiyun 
7377*4882a593Smuzhiyun 	return memsize;
7378*4882a593Smuzhiyun }
7379*4882a593Smuzhiyun 
7380*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
7381*4882a593Smuzhiyun static bool
BCMPOSTTRAPFN(si_seci_uart)7382*4882a593Smuzhiyun BCMPOSTTRAPFN(si_seci_uart)(const si_t *sih)
7383*4882a593Smuzhiyun {
7384*4882a593Smuzhiyun 	return (sih->cccaps_ext & CC_CAP_EXT_SECI_PUART_PRESENT);
7385*4882a593Smuzhiyun }
7386*4882a593Smuzhiyun 
7387*4882a593Smuzhiyun /** seci clock enable/disable */
7388*4882a593Smuzhiyun static void
BCMPOSTTRAPFN(si_seci_clkreq)7389*4882a593Smuzhiyun BCMPOSTTRAPFN(si_seci_clkreq)(si_t *sih, bool enable)
7390*4882a593Smuzhiyun {
7391*4882a593Smuzhiyun 	uint32 clk_ctl_st;
7392*4882a593Smuzhiyun 	uint32 offset;
7393*4882a593Smuzhiyun 	uint32 val;
7394*4882a593Smuzhiyun 	pmuregs_t *pmu;
7395*4882a593Smuzhiyun 	uint32 origidx = 0;
7396*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7397*4882a593Smuzhiyun #ifdef SECI_UART
7398*4882a593Smuzhiyun 	bool fast;
7399*4882a593Smuzhiyun 	chipcregs_t *cc = seci_set_core(sih, &origidx, &fast);
7400*4882a593Smuzhiyun 	ASSERT(cc);
7401*4882a593Smuzhiyun #endif /* SECI_UART */
7402*4882a593Smuzhiyun 	if (!si_seci(sih) && !si_seci_uart(sih))
7403*4882a593Smuzhiyun 		return;
7404*4882a593Smuzhiyun 	offset = OFFSETOF(chipcregs_t, clk_ctl_st);
7405*4882a593Smuzhiyun 	clk_ctl_st = si_corereg(sih, 0, offset, 0, 0);
7406*4882a593Smuzhiyun 
7407*4882a593Smuzhiyun 	if (enable && !(clk_ctl_st & CLKCTL_STS_SECI_CLK_REQ)) {
7408*4882a593Smuzhiyun 		val = CLKCTL_STS_SECI_CLK_REQ | CLKCTL_STS_HT_AVAIL_REQ;
7409*4882a593Smuzhiyun #ifdef SECI_UART
7410*4882a593Smuzhiyun 		/* Restore the fast UART function select when enabling */
7411*4882a593Smuzhiyun 		if (fast_uart_init) {
7412*4882a593Smuzhiyun 			si_gci_set_functionsel(sih, fast_uart_tx, fast_uart_functionsel);
7413*4882a593Smuzhiyun 			if (fuart_pullup_rx_cts_enab) {
7414*4882a593Smuzhiyun 				si_gci_set_functionsel(sih, fast_uart_rx, fast_uart_functionsel);
7415*4882a593Smuzhiyun 				si_gci_set_functionsel(sih, fast_uart_cts_in,
7416*4882a593Smuzhiyun 					fast_uart_functionsel);
7417*4882a593Smuzhiyun 			}
7418*4882a593Smuzhiyun 		}
7419*4882a593Smuzhiyun #endif /* SECI_UART */
7420*4882a593Smuzhiyun 	} else if (!enable && (clk_ctl_st & CLKCTL_STS_SECI_CLK_REQ)) {
7421*4882a593Smuzhiyun 		val = 0;
7422*4882a593Smuzhiyun #ifdef SECI_UART
7423*4882a593Smuzhiyun 		if (force_seci_clk) {
7424*4882a593Smuzhiyun 			return;
7425*4882a593Smuzhiyun 		}
7426*4882a593Smuzhiyun #endif /* SECI_UART */
7427*4882a593Smuzhiyun 	} else {
7428*4882a593Smuzhiyun 		return;
7429*4882a593Smuzhiyun 	}
7430*4882a593Smuzhiyun #ifdef SECI_UART
7431*4882a593Smuzhiyun 	/* park the fast UART as PULL UP when disabling the clocks to avoid sending
7432*4882a593Smuzhiyun 	 * breaks to the host
7433*4882a593Smuzhiyun 	 */
7434*4882a593Smuzhiyun 	if (!enable && fast_uart_init) {
7435*4882a593Smuzhiyun 		si_gci_set_functionsel(sih, fast_uart_tx, fast_uart_pup);
7436*4882a593Smuzhiyun 		if (fuart_pullup_rx_cts_enab) {
7437*4882a593Smuzhiyun 			W_REG(sii->osh, &cc->SECI_status, SECI_STAT_BI);
7438*4882a593Smuzhiyun 			si_gci_set_functionsel(sih, fast_uart_rx, fast_uart_pup);
7439*4882a593Smuzhiyun 			si_gci_set_functionsel(sih, fast_uart_cts_in, fast_uart_pup);
7440*4882a593Smuzhiyun 			SPINWAIT(!(R_REG(sii->osh, &cc->SECI_status) & SECI_STAT_BI), 1000);
7441*4882a593Smuzhiyun 		}
7442*4882a593Smuzhiyun 	}
7443*4882a593Smuzhiyun #endif /* SECI_UART */
7444*4882a593Smuzhiyun 
7445*4882a593Smuzhiyun 	/* Setting/clearing bit 4 along with bit 8 of 0x1e0 block. the core requests that
7446*4882a593Smuzhiyun 	  * the PMU set the device state such that the HT clock will be available on short notice.
7447*4882a593Smuzhiyun 	  */
7448*4882a593Smuzhiyun 	si_corereg(sih, SI_CC_IDX, offset,
7449*4882a593Smuzhiyun 		CLKCTL_STS_SECI_CLK_REQ | CLKCTL_STS_HT_AVAIL_REQ, val);
7450*4882a593Smuzhiyun 
7451*4882a593Smuzhiyun 	if (!enable)
7452*4882a593Smuzhiyun 		return;
7453*4882a593Smuzhiyun #ifndef SECI_UART
7454*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
7455*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7456*4882a593Smuzhiyun #endif
7457*4882a593Smuzhiyun 
7458*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
7459*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
7460*4882a593Smuzhiyun 	} else {
7461*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
7462*4882a593Smuzhiyun 	}
7463*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
7464*4882a593Smuzhiyun 	(void)si_pmu_wait_for_steady_state(sih, sii->osh, pmu);
7465*4882a593Smuzhiyun 	/* Return to original core */
7466*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
7467*4882a593Smuzhiyun 
7468*4882a593Smuzhiyun 	SPINWAIT(!(si_corereg(sih, 0, offset, 0, 0) & CLKCTL_STS_SECI_CLK_AVAIL),
7469*4882a593Smuzhiyun 	        PMU_MAX_TRANSITION_DLY);
7470*4882a593Smuzhiyun 
7471*4882a593Smuzhiyun 	clk_ctl_st = si_corereg(sih, 0, offset, 0, 0);
7472*4882a593Smuzhiyun 	if (enable) {
7473*4882a593Smuzhiyun 		if (!(clk_ctl_st & CLKCTL_STS_SECI_CLK_AVAIL)) {
7474*4882a593Smuzhiyun 			SI_ERROR(("SECI clock is not available\n"));
7475*4882a593Smuzhiyun 			ASSERT(0);
7476*4882a593Smuzhiyun 			return;
7477*4882a593Smuzhiyun 		}
7478*4882a593Smuzhiyun 	}
7479*4882a593Smuzhiyun }
7480*4882a593Smuzhiyun 
7481*4882a593Smuzhiyun #if defined(BCMECICOEX) || defined(SECI_UART)
7482*4882a593Smuzhiyun static chipcregs_t *
BCMPOSTTRAPFN(seci_set_core)7483*4882a593Smuzhiyun BCMPOSTTRAPFN(seci_set_core)(si_t *sih, uint32 *origidx, bool *fast)
7484*4882a593Smuzhiyun {
7485*4882a593Smuzhiyun 	chipcregs_t *cc;
7486*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7487*4882a593Smuzhiyun 	*fast = SI_FAST(sii);
7488*4882a593Smuzhiyun 
7489*4882a593Smuzhiyun 	if (!*fast) {
7490*4882a593Smuzhiyun 		*origidx = sii->curidx;
7491*4882a593Smuzhiyun 		cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
7492*4882a593Smuzhiyun 	} else {
7493*4882a593Smuzhiyun 		*origidx = 0;
7494*4882a593Smuzhiyun 		cc = (chipcregs_t *)CCREGS_FAST(sii);
7495*4882a593Smuzhiyun 	}
7496*4882a593Smuzhiyun 	return cc;
7497*4882a593Smuzhiyun }
7498*4882a593Smuzhiyun 
7499*4882a593Smuzhiyun static chipcregs_t *
BCMPOSTTRAPFN(si_seci_access_preamble)7500*4882a593Smuzhiyun BCMPOSTTRAPFN(si_seci_access_preamble)(si_t *sih, const si_info_t *sii, uint32 *origidx, bool *fast)
7501*4882a593Smuzhiyun {
7502*4882a593Smuzhiyun 	chipcregs_t *cc = seci_set_core(sih, origidx, fast);
7503*4882a593Smuzhiyun 
7504*4882a593Smuzhiyun 	if (cc) {
7505*4882a593Smuzhiyun 		if (((R_REG(sii->osh, &cc->clk_ctl_st) & CCS_SECICLKREQ) != CCS_SECICLKREQ)) {
7506*4882a593Smuzhiyun 			/* enable SECI clock */
7507*4882a593Smuzhiyun 			si_seci_clkreq(sih, TRUE);
7508*4882a593Smuzhiyun 		}
7509*4882a593Smuzhiyun 	}
7510*4882a593Smuzhiyun 	return cc;
7511*4882a593Smuzhiyun }
7512*4882a593Smuzhiyun #endif /* BCMECICOEX||SECI_UART */
7513*4882a593Smuzhiyun #ifdef SECI_UART
7514*4882a593Smuzhiyun 
7515*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_seci_access)7516*4882a593Smuzhiyun BCMPOSTTRAPFN(si_seci_access)(si_t *sih, uint32 val, int access)
7517*4882a593Smuzhiyun {
7518*4882a593Smuzhiyun 	uint32 origidx;
7519*4882a593Smuzhiyun 	bool fast;
7520*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7521*4882a593Smuzhiyun 	chipcregs_t *cc;
7522*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
7523*4882a593Smuzhiyun 	uint32 offset, retval = 1;
7524*4882a593Smuzhiyun 
7525*4882a593Smuzhiyun 	if (!si_seci_uart(sih))
7526*4882a593Smuzhiyun 		return 0;
7527*4882a593Smuzhiyun 
7528*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
7529*4882a593Smuzhiyun 	if (!(cc = si_seci_access_preamble(sih, sii, &origidx, &fast)))
7530*4882a593Smuzhiyun 		goto exit;
7531*4882a593Smuzhiyun 
7532*4882a593Smuzhiyun 	switch (access) {
7533*4882a593Smuzhiyun 	case SECI_ACCESS_STATUSMASK_SET:
7534*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, SECI_statusmask);
7535*4882a593Smuzhiyun 		retval = si_corereg(sih, SI_CC_IDX, offset, ALLONES_32, val);
7536*4882a593Smuzhiyun 		break;
7537*4882a593Smuzhiyun 	case SECI_ACCESS_STATUSMASK_GET:
7538*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, SECI_statusmask);
7539*4882a593Smuzhiyun 		retval = si_corereg(sih, SI_CC_IDX, offset, 0, 0);
7540*4882a593Smuzhiyun 		break;
7541*4882a593Smuzhiyun 	case SECI_ACCESS_INTRS:
7542*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, SECI_status);
7543*4882a593Smuzhiyun 		retval = si_corereg(sih, SI_CC_IDX, offset,
7544*4882a593Smuzhiyun 		                    ALLONES_32, ALLONES_32);
7545*4882a593Smuzhiyun 		break;
7546*4882a593Smuzhiyun 	case SECI_ACCESS_UART_CTS:
7547*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, seci_uart_msr);
7548*4882a593Smuzhiyun 		retval = si_corereg(sih, SI_CC_IDX, offset, 0, 0);
7549*4882a593Smuzhiyun 		retval = retval & SECI_UART_MSR_CTS_STATE;
7550*4882a593Smuzhiyun 		break;
7551*4882a593Smuzhiyun 	case SECI_ACCESS_UART_RTS:
7552*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, seci_uart_mcr);
7553*4882a593Smuzhiyun 		if (val) {
7554*4882a593Smuzhiyun 			/* clear forced flow control; enable auto rts */
7555*4882a593Smuzhiyun 			retval = si_corereg(sih, SI_CC_IDX, offset,
7556*4882a593Smuzhiyun 			           SECI_UART_MCR_PRTS |  SECI_UART_MCR_AUTO_RTS,
7557*4882a593Smuzhiyun 			           SECI_UART_MCR_AUTO_RTS);
7558*4882a593Smuzhiyun 		} else {
7559*4882a593Smuzhiyun 			/* set forced flow control; clear auto rts */
7560*4882a593Smuzhiyun 			retval = si_corereg(sih, SI_CC_IDX, offset,
7561*4882a593Smuzhiyun 			           SECI_UART_MCR_PRTS |  SECI_UART_MCR_AUTO_RTS,
7562*4882a593Smuzhiyun 			           SECI_UART_MCR_PRTS);
7563*4882a593Smuzhiyun 		}
7564*4882a593Smuzhiyun 		break;
7565*4882a593Smuzhiyun 	case SECI_ACCESS_UART_RXEMPTY:
7566*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, SECI_status);
7567*4882a593Smuzhiyun 		retval = si_corereg(sih, SI_CC_IDX, offset, 0, 0);
7568*4882a593Smuzhiyun 		retval = (retval & SECI_STAT_SRFE) == SECI_STAT_SRFE;
7569*4882a593Smuzhiyun 		break;
7570*4882a593Smuzhiyun 	case SECI_ACCESS_UART_GETC:
7571*4882a593Smuzhiyun 		/* assumes caller checked for nonempty rx FIFO */
7572*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, seci_uart_data);
7573*4882a593Smuzhiyun 		retval = si_corereg(sih, SI_CC_IDX, offset, 0, 0) & 0xff;
7574*4882a593Smuzhiyun 		break;
7575*4882a593Smuzhiyun 	case SECI_ACCESS_UART_TXFULL:
7576*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, SECI_status);
7577*4882a593Smuzhiyun 		retval = si_corereg(sih, SI_CC_IDX, offset, 0, 0);
7578*4882a593Smuzhiyun 		retval = (retval & SECI_STAT_STFF) == SECI_STAT_STFF;
7579*4882a593Smuzhiyun 		break;
7580*4882a593Smuzhiyun 	case SECI_ACCESS_UART_PUTC:
7581*4882a593Smuzhiyun 		/* This register must not do a RMW otherwise it will affect the RX FIFO */
7582*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->seci_uart_data, (uint32)(val & 0xff));
7583*4882a593Smuzhiyun 		retval = 0;
7584*4882a593Smuzhiyun 		break;
7585*4882a593Smuzhiyun 	default:
7586*4882a593Smuzhiyun 		ASSERT(0);
7587*4882a593Smuzhiyun 	}
7588*4882a593Smuzhiyun 
7589*4882a593Smuzhiyun exit:
7590*4882a593Smuzhiyun 	/* restore previous core */
7591*4882a593Smuzhiyun 	if (!fast)
7592*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
7593*4882a593Smuzhiyun 
7594*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
7595*4882a593Smuzhiyun 
7596*4882a593Smuzhiyun 	return retval;
7597*4882a593Smuzhiyun }
7598*4882a593Smuzhiyun 
si_seci_clk_force(si_t * sih,bool val)7599*4882a593Smuzhiyun void si_seci_clk_force(si_t *sih, bool val)
7600*4882a593Smuzhiyun {
7601*4882a593Smuzhiyun 	force_seci_clk = val;
7602*4882a593Smuzhiyun 	if (force_seci_clk) {
7603*4882a593Smuzhiyun 		si_seci_clkreq(sih, TRUE);
7604*4882a593Smuzhiyun 	} else {
7605*4882a593Smuzhiyun 		si_seci_down(sih);
7606*4882a593Smuzhiyun 	}
7607*4882a593Smuzhiyun }
7608*4882a593Smuzhiyun 
si_seci_clk_force_status(si_t * sih)7609*4882a593Smuzhiyun bool si_seci_clk_force_status(si_t *sih)
7610*4882a593Smuzhiyun {
7611*4882a593Smuzhiyun 	return force_seci_clk;
7612*4882a593Smuzhiyun }
7613*4882a593Smuzhiyun #endif /* SECI_UART */
7614*4882a593Smuzhiyun 
7615*4882a593Smuzhiyun /** SECI Init routine, pass in seci_mode */
7616*4882a593Smuzhiyun volatile void *
BCMINITFN(si_seci_init)7617*4882a593Smuzhiyun BCMINITFN(si_seci_init)(si_t *sih, uint8  seci_mode)
7618*4882a593Smuzhiyun {
7619*4882a593Smuzhiyun 	uint32 origidx = 0;
7620*4882a593Smuzhiyun 	uint32 offset;
7621*4882a593Smuzhiyun 	const si_info_t *sii;
7622*4882a593Smuzhiyun 	volatile void *ptr;
7623*4882a593Smuzhiyun 	chipcregs_t *cc;
7624*4882a593Smuzhiyun 	bool fast;
7625*4882a593Smuzhiyun 	uint32 seci_conf;
7626*4882a593Smuzhiyun 
7627*4882a593Smuzhiyun 	if (sih->ccrev < 35)
7628*4882a593Smuzhiyun 		return NULL;
7629*4882a593Smuzhiyun 
7630*4882a593Smuzhiyun #ifdef SECI_UART
7631*4882a593Smuzhiyun 	if (seci_mode == SECI_MODE_UART) {
7632*4882a593Smuzhiyun 		if (!si_seci_uart(sih))
7633*4882a593Smuzhiyun 			return NULL;
7634*4882a593Smuzhiyun 	}
7635*4882a593Smuzhiyun 	else {
7636*4882a593Smuzhiyun #endif /* SECI_UART */
7637*4882a593Smuzhiyun 	if (!si_seci(sih))
7638*4882a593Smuzhiyun 		return NULL;
7639*4882a593Smuzhiyun #ifdef SECI_UART
7640*4882a593Smuzhiyun 	}
7641*4882a593Smuzhiyun #endif /* SECI_UART */
7642*4882a593Smuzhiyun 
7643*4882a593Smuzhiyun 	if (seci_mode > SECI_MODE_MASK)
7644*4882a593Smuzhiyun 		return NULL;
7645*4882a593Smuzhiyun 
7646*4882a593Smuzhiyun 	sii = SI_INFO(sih);
7647*4882a593Smuzhiyun 	fast = SI_FAST(sii);
7648*4882a593Smuzhiyun 	if (!fast) {
7649*4882a593Smuzhiyun 		origidx = sii->curidx;
7650*4882a593Smuzhiyun 		if ((ptr = si_setcore(sih, CC_CORE_ID, 0)) == NULL)
7651*4882a593Smuzhiyun 			return NULL;
7652*4882a593Smuzhiyun 	} else if ((ptr = CCREGS_FAST(sii)) == NULL)
7653*4882a593Smuzhiyun 		return NULL;
7654*4882a593Smuzhiyun 	cc = (chipcregs_t *)ptr;
7655*4882a593Smuzhiyun 	ASSERT(cc);
7656*4882a593Smuzhiyun 
7657*4882a593Smuzhiyun 	/* enable SECI clock */
7658*4882a593Smuzhiyun 	if (seci_mode != SECI_MODE_LEGACY_3WIRE_WLAN)
7659*4882a593Smuzhiyun 		si_seci_clkreq(sih, TRUE);
7660*4882a593Smuzhiyun 
7661*4882a593Smuzhiyun 	/* put the SECI in reset */
7662*4882a593Smuzhiyun 	seci_conf = R_REG(sii->osh, &cc->SECI_config);
7663*4882a593Smuzhiyun 	seci_conf &= ~SECI_ENAB_SECI_ECI;
7664*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->SECI_config, seci_conf);
7665*4882a593Smuzhiyun 	seci_conf = SECI_RESET;
7666*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->SECI_config, seci_conf);
7667*4882a593Smuzhiyun 
7668*4882a593Smuzhiyun 	/* set force-low, and set EN_SECI for all non-legacy modes */
7669*4882a593Smuzhiyun 	seci_conf |= SECI_ENAB_SECIOUT_DIS;
7670*4882a593Smuzhiyun 	if ((seci_mode == SECI_MODE_UART) || (seci_mode == SECI_MODE_SECI) ||
7671*4882a593Smuzhiyun 	    (seci_mode == SECI_MODE_HALF_SECI))
7672*4882a593Smuzhiyun 	{
7673*4882a593Smuzhiyun 		seci_conf |= SECI_ENAB_SECI_ECI;
7674*4882a593Smuzhiyun 	}
7675*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->SECI_config, seci_conf);
7676*4882a593Smuzhiyun 
7677*4882a593Smuzhiyun 	if (seci_mode != SECI_MODE_LEGACY_3WIRE_WLAN) {
7678*4882a593Smuzhiyun 		/* take seci out of reset */
7679*4882a593Smuzhiyun 		seci_conf = R_REG(sii->osh, &cc->SECI_config);
7680*4882a593Smuzhiyun 		seci_conf &= ~(SECI_RESET);
7681*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->SECI_config, seci_conf);
7682*4882a593Smuzhiyun 	}
7683*4882a593Smuzhiyun 	/* set UART/SECI baud rate */
7684*4882a593Smuzhiyun 	/* hard-coded at 4MBaud for now */
7685*4882a593Smuzhiyun 	if ((seci_mode == SECI_MODE_UART) || (seci_mode == SECI_MODE_SECI) ||
7686*4882a593Smuzhiyun 	    (seci_mode == SECI_MODE_HALF_SECI)) {
7687*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, seci_uart_bauddiv);
7688*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, offset, 0xFF, 0xFF); /* 4MBaud */
7689*4882a593Smuzhiyun 		if ((CHIPID(sih->chip) == BCM4360_CHIP_ID) ||
7690*4882a593Smuzhiyun 			(CHIPID(sih->chip) == BCM43460_CHIP_ID) ||
7691*4882a593Smuzhiyun 			(CHIPID(sih->chip) == BCM43526_CHIP_ID) ||
7692*4882a593Smuzhiyun 			(CHIPID(sih->chip) == BCM4352_CHIP_ID)) {
7693*4882a593Smuzhiyun 			/* MAC clk is 160MHz */
7694*4882a593Smuzhiyun 			offset = OFFSETOF(chipcregs_t, seci_uart_bauddiv);
7695*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, offset, 0xFF, 0xFE);
7696*4882a593Smuzhiyun 			offset = OFFSETOF(chipcregs_t, seci_uart_baudadj);
7697*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, offset, 0xFF, 0x44);
7698*4882a593Smuzhiyun 			offset = OFFSETOF(chipcregs_t, seci_uart_mcr);
7699*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, offset,
7700*4882a593Smuzhiyun 				0xFF, SECI_UART_MCR_BAUD_ADJ_EN); /* 0x81 */
7701*4882a593Smuzhiyun 		}
7702*4882a593Smuzhiyun #ifdef SECI_UART
7703*4882a593Smuzhiyun 		else if (CCREV(sih->ccrev) >= 62) {
7704*4882a593Smuzhiyun 			/* rx FIFO level at which an interrupt is generated */
7705*4882a593Smuzhiyun 			offset = OFFSETOF(chipcregs_t, eci.ge35.eci_uartfifolevel);
7706*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, offset, 0xff, 0x01);
7707*4882a593Smuzhiyun 			offset = OFFSETOF(chipcregs_t, seci_uart_mcr);
7708*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, offset, SECI_UART_MCR_AUTO_RTS,
7709*4882a593Smuzhiyun 				SECI_UART_MCR_AUTO_RTS);
7710*4882a593Smuzhiyun 		}
7711*4882a593Smuzhiyun #endif /* SECI_UART */
7712*4882a593Smuzhiyun 		else {
7713*4882a593Smuzhiyun 			/* 4336 MAC clk is 80MHz */
7714*4882a593Smuzhiyun 			offset = OFFSETOF(chipcregs_t, seci_uart_baudadj);
7715*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, offset, 0xFF, 0x22);
7716*4882a593Smuzhiyun 			offset = OFFSETOF(chipcregs_t, seci_uart_mcr);
7717*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, offset,
7718*4882a593Smuzhiyun 				0xFF, SECI_UART_MCR_BAUD_ADJ_EN); /* 0x80 */
7719*4882a593Smuzhiyun 		}
7720*4882a593Smuzhiyun 
7721*4882a593Smuzhiyun 		/* LCR/MCR settings */
7722*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, seci_uart_lcr);
7723*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, offset, 0xFF,
7724*4882a593Smuzhiyun 			(SECI_UART_LCR_RX_EN | SECI_UART_LCR_TXO_EN)); /* 0x28 */
7725*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, seci_uart_mcr);
7726*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX, offset,
7727*4882a593Smuzhiyun 			SECI_UART_MCR_TX_EN, SECI_UART_MCR_TX_EN); /* 0x01 */
7728*4882a593Smuzhiyun 
7729*4882a593Smuzhiyun #ifndef SECI_UART
7730*4882a593Smuzhiyun 		/* Give control of ECI output regs to MAC core */
7731*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, eci.ge35.eci_controllo);
7732*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, offset, ALLONES_32, ECI_MACCTRLLO_BITS);
7733*4882a593Smuzhiyun 		offset = OFFSETOF(chipcregs_t, eci.ge35.eci_controlhi);
7734*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, offset, 0xFFFF, ECI_MACCTRLHI_BITS);
7735*4882a593Smuzhiyun #endif /* SECI_UART */
7736*4882a593Smuzhiyun 	}
7737*4882a593Smuzhiyun 
7738*4882a593Smuzhiyun 	/* set the seci mode in seci conf register */
7739*4882a593Smuzhiyun 	seci_conf = R_REG(sii->osh, &cc->SECI_config);
7740*4882a593Smuzhiyun 	seci_conf &= ~(SECI_MODE_MASK << SECI_MODE_SHIFT);
7741*4882a593Smuzhiyun 	seci_conf |= (seci_mode << SECI_MODE_SHIFT);
7742*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->SECI_config, seci_conf);
7743*4882a593Smuzhiyun 
7744*4882a593Smuzhiyun 	/* Clear force-low bit */
7745*4882a593Smuzhiyun 	seci_conf = R_REG(sii->osh, &cc->SECI_config);
7746*4882a593Smuzhiyun 	seci_conf &= ~SECI_ENAB_SECIOUT_DIS;
7747*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->SECI_config, seci_conf);
7748*4882a593Smuzhiyun 
7749*4882a593Smuzhiyun 	/* restore previous core */
7750*4882a593Smuzhiyun 	if (!fast)
7751*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
7752*4882a593Smuzhiyun 
7753*4882a593Smuzhiyun 	return ptr;
7754*4882a593Smuzhiyun }
7755*4882a593Smuzhiyun 
7756*4882a593Smuzhiyun #ifdef BCMECICOEX
7757*4882a593Smuzhiyun #define NOTIFY_BT_FM_DISABLE(sih, val) \
7758*4882a593Smuzhiyun 	si_eci_notify_bt((sih), ECI_OUT_FM_DISABLE_MASK(CCREV(sih->ccrev)), \
7759*4882a593Smuzhiyun 			 ((val) << ECI_OUT_FM_DISABLE_SHIFT(CCREV(sih->ccrev))), FALSE)
7760*4882a593Smuzhiyun 
7761*4882a593Smuzhiyun /** Query OTP to see if FM is disabled */
7762*4882a593Smuzhiyun static int
BCMINITFN(si_query_FMDisabled_from_OTP)7763*4882a593Smuzhiyun BCMINITFN(si_query_FMDisabled_from_OTP)(si_t *sih, uint16 *FMDisabled)
7764*4882a593Smuzhiyun {
7765*4882a593Smuzhiyun 	int error = BCME_OK;
7766*4882a593Smuzhiyun 	uint bitoff = 0;
7767*4882a593Smuzhiyun 	bool wasup;
7768*4882a593Smuzhiyun 	void *oh;
7769*4882a593Smuzhiyun 	uint32 min_res_mask = 0;
7770*4882a593Smuzhiyun 
7771*4882a593Smuzhiyun 	/* If there is a bit for this chip, check it */
7772*4882a593Smuzhiyun 	if (bitoff) {
7773*4882a593Smuzhiyun 		if (!(wasup = si_is_otp_powered(sih))) {
7774*4882a593Smuzhiyun 			si_otp_power(sih, TRUE, &min_res_mask);
7775*4882a593Smuzhiyun 		}
7776*4882a593Smuzhiyun 
7777*4882a593Smuzhiyun 		if ((oh = otp_init(sih)) != NULL)
7778*4882a593Smuzhiyun 			*FMDisabled = !otp_read_bit(oh, OTP4325_FM_DISABLED_OFFSET);
7779*4882a593Smuzhiyun 		else
7780*4882a593Smuzhiyun 			error = BCME_NOTFOUND;
7781*4882a593Smuzhiyun 
7782*4882a593Smuzhiyun 		if (!wasup) {
7783*4882a593Smuzhiyun 			si_otp_power(sih, FALSE, &min_res_mask);
7784*4882a593Smuzhiyun 		}
7785*4882a593Smuzhiyun 	}
7786*4882a593Smuzhiyun 
7787*4882a593Smuzhiyun 	return error;
7788*4882a593Smuzhiyun }
7789*4882a593Smuzhiyun 
7790*4882a593Smuzhiyun bool
si_eci(const si_t * sih)7791*4882a593Smuzhiyun si_eci(const si_t *sih)
7792*4882a593Smuzhiyun {
7793*4882a593Smuzhiyun 	return (!!(sih->cccaps & CC_CAP_ECI));
7794*4882a593Smuzhiyun }
7795*4882a593Smuzhiyun 
7796*4882a593Smuzhiyun bool
BCMPOSTTRAPFN(si_seci)7797*4882a593Smuzhiyun BCMPOSTTRAPFN(si_seci)(const si_t *sih)
7798*4882a593Smuzhiyun {
7799*4882a593Smuzhiyun 	return (sih->cccaps_ext & CC_CAP_EXT_SECI_PRESENT);
7800*4882a593Smuzhiyun }
7801*4882a593Smuzhiyun 
7802*4882a593Smuzhiyun bool
si_gci(const si_t * sih)7803*4882a593Smuzhiyun si_gci(const si_t *sih)
7804*4882a593Smuzhiyun {
7805*4882a593Smuzhiyun 	return (sih->cccaps_ext & CC_CAP_EXT_GCI_PRESENT);
7806*4882a593Smuzhiyun }
7807*4882a593Smuzhiyun 
7808*4882a593Smuzhiyun bool
si_sraon(const si_t * sih)7809*4882a593Smuzhiyun si_sraon(const si_t *sih)
7810*4882a593Smuzhiyun {
7811*4882a593Smuzhiyun 	return (sih->cccaps_ext & CC_CAP_SR_AON_PRESENT);
7812*4882a593Smuzhiyun }
7813*4882a593Smuzhiyun 
7814*4882a593Smuzhiyun /** ECI Init routine */
7815*4882a593Smuzhiyun int
BCMINITFN(si_eci_init)7816*4882a593Smuzhiyun BCMINITFN(si_eci_init)(si_t *sih)
7817*4882a593Smuzhiyun {
7818*4882a593Smuzhiyun 	uint32 origidx = 0;
7819*4882a593Smuzhiyun 	const si_info_t *sii;
7820*4882a593Smuzhiyun 	chipcregs_t *cc;
7821*4882a593Smuzhiyun 	bool fast;
7822*4882a593Smuzhiyun 	uint16 FMDisabled = FALSE;
7823*4882a593Smuzhiyun 
7824*4882a593Smuzhiyun 	/* check for ECI capability */
7825*4882a593Smuzhiyun 	if (!(sih->cccaps & CC_CAP_ECI))
7826*4882a593Smuzhiyun 		return BCME_ERROR;
7827*4882a593Smuzhiyun 
7828*4882a593Smuzhiyun 	sii = SI_INFO(sih);
7829*4882a593Smuzhiyun 	fast = SI_FAST(sii);
7830*4882a593Smuzhiyun 	if (!fast) {
7831*4882a593Smuzhiyun 		origidx = sii->curidx;
7832*4882a593Smuzhiyun 		if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL)
7833*4882a593Smuzhiyun 			return BCME_ERROR;
7834*4882a593Smuzhiyun 	} else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL)
7835*4882a593Smuzhiyun 		return BCME_ERROR;
7836*4882a593Smuzhiyun 	ASSERT(cc);
7837*4882a593Smuzhiyun 
7838*4882a593Smuzhiyun 	/* disable level based interrupts */
7839*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) < 35) {
7840*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.lt35.eci_intmaskhi, 0x0);
7841*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.lt35.eci_intmaskmi, 0x0);
7842*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.lt35.eci_intmasklo, 0x0);
7843*4882a593Smuzhiyun 	} else {
7844*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.ge35.eci_intmaskhi, 0x0);
7845*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.ge35.eci_intmasklo, 0x0);
7846*4882a593Smuzhiyun 	}
7847*4882a593Smuzhiyun 
7848*4882a593Smuzhiyun 	/* Assign eci_output bits between 'wl' and dot11mac */
7849*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) < 35) {
7850*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.lt35.eci_control, ECI_MACCTRL_BITS);
7851*4882a593Smuzhiyun 	} else {
7852*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.ge35.eci_controllo, ECI_MACCTRLLO_BITS);
7853*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.ge35.eci_controlhi, ECI_MACCTRLHI_BITS);
7854*4882a593Smuzhiyun 	}
7855*4882a593Smuzhiyun 
7856*4882a593Smuzhiyun 	/* enable only edge based interrupts
7857*4882a593Smuzhiyun 	 * only toggle on bit 62 triggers an interrupt
7858*4882a593Smuzhiyun 	 */
7859*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) < 35) {
7860*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.lt35.eci_eventmaskhi, 0x0);
7861*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.lt35.eci_eventmaskmi, 0x0);
7862*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.lt35.eci_eventmasklo, 0x0);
7863*4882a593Smuzhiyun 	} else {
7864*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.ge35.eci_eventmaskhi, 0x0);
7865*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->eci.ge35.eci_eventmasklo, 0x0);
7866*4882a593Smuzhiyun 	}
7867*4882a593Smuzhiyun 
7868*4882a593Smuzhiyun 	/* restore previous core */
7869*4882a593Smuzhiyun 	if (!fast)
7870*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
7871*4882a593Smuzhiyun 
7872*4882a593Smuzhiyun 	/* if FM disabled in OTP, let BT know */
7873*4882a593Smuzhiyun 	if (!si_query_FMDisabled_from_OTP(sih, &FMDisabled)) {
7874*4882a593Smuzhiyun 		if (FMDisabled) {
7875*4882a593Smuzhiyun 			NOTIFY_BT_FM_DISABLE(sih, 1);
7876*4882a593Smuzhiyun 		}
7877*4882a593Smuzhiyun 	}
7878*4882a593Smuzhiyun 
7879*4882a593Smuzhiyun 	return 0;
7880*4882a593Smuzhiyun }
7881*4882a593Smuzhiyun 
7882*4882a593Smuzhiyun /** Write values to BT on eci_output. */
7883*4882a593Smuzhiyun void
si_eci_notify_bt(si_t * sih,uint32 mask,uint32 val,bool is_interrupt)7884*4882a593Smuzhiyun si_eci_notify_bt(si_t *sih, uint32 mask, uint32 val, bool is_interrupt)
7885*4882a593Smuzhiyun {
7886*4882a593Smuzhiyun 	uint32 offset;
7887*4882a593Smuzhiyun 
7888*4882a593Smuzhiyun 	if ((sih->cccaps & CC_CAP_ECI) ||
7889*4882a593Smuzhiyun 		(si_seci(sih)))
7890*4882a593Smuzhiyun 	{
7891*4882a593Smuzhiyun 		/* ECI or SECI mode */
7892*4882a593Smuzhiyun 		/* Clear interrupt bit by default */
7893*4882a593Smuzhiyun 		if (is_interrupt) {
7894*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX,
7895*4882a593Smuzhiyun 			   (CCREV(sih->ccrev) < 35 ?
7896*4882a593Smuzhiyun 			    OFFSETOF(chipcregs_t, eci.lt35.eci_output) :
7897*4882a593Smuzhiyun 			    OFFSETOF(chipcregs_t, eci.ge35.eci_outputlo)),
7898*4882a593Smuzhiyun 			   (1 << 30), 0);
7899*4882a593Smuzhiyun 		}
7900*4882a593Smuzhiyun 
7901*4882a593Smuzhiyun 		if (CCREV(sih->ccrev) >= 35) {
7902*4882a593Smuzhiyun 			if ((mask & 0xFFFF0000) == ECI48_OUT_MASKMAGIC_HIWORD) {
7903*4882a593Smuzhiyun 				offset = OFFSETOF(chipcregs_t, eci.ge35.eci_outputhi);
7904*4882a593Smuzhiyun 				mask = mask & ~0xFFFF0000;
7905*4882a593Smuzhiyun 			} else {
7906*4882a593Smuzhiyun 				offset = OFFSETOF(chipcregs_t, eci.ge35.eci_outputlo);
7907*4882a593Smuzhiyun 				mask = mask | (1<<30);
7908*4882a593Smuzhiyun 				val = val & ~(1 << 30);
7909*4882a593Smuzhiyun 			}
7910*4882a593Smuzhiyun 		} else {
7911*4882a593Smuzhiyun 			offset = OFFSETOF(chipcregs_t, eci.lt35.eci_output);
7912*4882a593Smuzhiyun 			val = val & ~(1 << 30);
7913*4882a593Smuzhiyun 		}
7914*4882a593Smuzhiyun 
7915*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, offset, mask, val);
7916*4882a593Smuzhiyun 
7917*4882a593Smuzhiyun 		/* Set interrupt bit if needed */
7918*4882a593Smuzhiyun 		if (is_interrupt) {
7919*4882a593Smuzhiyun 			si_corereg(sih, SI_CC_IDX,
7920*4882a593Smuzhiyun 			   (CCREV(sih->ccrev) < 35 ?
7921*4882a593Smuzhiyun 			    OFFSETOF(chipcregs_t, eci.lt35.eci_output) :
7922*4882a593Smuzhiyun 			    OFFSETOF(chipcregs_t, eci.ge35.eci_outputlo)),
7923*4882a593Smuzhiyun 			   (1 << 30), (1 << 30));
7924*4882a593Smuzhiyun 		}
7925*4882a593Smuzhiyun 	} else if (sih->cccaps_ext & CC_CAP_EXT_GCI_PRESENT) {
7926*4882a593Smuzhiyun 		/* GCI Mode */
7927*4882a593Smuzhiyun 		if ((mask & 0xFFFF0000) == ECI48_OUT_MASKMAGIC_HIWORD) {
7928*4882a593Smuzhiyun 			mask = mask & ~0xFFFF0000;
7929*4882a593Smuzhiyun 			si_gci_direct(sih, GCI_OFFSETOF(sih, gci_output[1]), mask, val);
7930*4882a593Smuzhiyun 		}
7931*4882a593Smuzhiyun 	}
7932*4882a593Smuzhiyun }
7933*4882a593Smuzhiyun 
7934*4882a593Smuzhiyun static void
BCMPOSTTRAPFN(seci_restore_coreidx)7935*4882a593Smuzhiyun BCMPOSTTRAPFN(seci_restore_coreidx)(si_t *sih, uint32 origidx, bool fast)
7936*4882a593Smuzhiyun {
7937*4882a593Smuzhiyun 	if (!fast)
7938*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
7939*4882a593Smuzhiyun 	return;
7940*4882a593Smuzhiyun }
7941*4882a593Smuzhiyun 
7942*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_seci_down)7943*4882a593Smuzhiyun BCMPOSTTRAPFN(si_seci_down)(si_t *sih)
7944*4882a593Smuzhiyun {
7945*4882a593Smuzhiyun 	uint32 origidx;
7946*4882a593Smuzhiyun 	bool fast;
7947*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7948*4882a593Smuzhiyun 	const chipcregs_t *cc;
7949*4882a593Smuzhiyun 	uint32 offset;
7950*4882a593Smuzhiyun 
7951*4882a593Smuzhiyun 	if (!si_seci(sih) && !si_seci_uart(sih))
7952*4882a593Smuzhiyun 		return;
7953*4882a593Smuzhiyun 	/* Don't proceed if request is already made to bring down the clock */
7954*4882a593Smuzhiyun 	offset = OFFSETOF(chipcregs_t, clk_ctl_st);
7955*4882a593Smuzhiyun 	if (!(si_corereg(sih, 0, offset, 0, 0) & CLKCTL_STS_SECI_CLK_REQ))
7956*4882a593Smuzhiyun 		return;
7957*4882a593Smuzhiyun 	if (!(cc = si_seci_access_preamble(sih, sii, &origidx, &fast)))
7958*4882a593Smuzhiyun 	    goto exit;
7959*4882a593Smuzhiyun 
7960*4882a593Smuzhiyun exit:
7961*4882a593Smuzhiyun 	/* bring down the clock if up */
7962*4882a593Smuzhiyun 	si_seci_clkreq(sih, FALSE);
7963*4882a593Smuzhiyun 
7964*4882a593Smuzhiyun 	/* restore previous core */
7965*4882a593Smuzhiyun 	seci_restore_coreidx(sih, origidx, fast);
7966*4882a593Smuzhiyun }
7967*4882a593Smuzhiyun 
7968*4882a593Smuzhiyun void
si_seci_upd(si_t * sih,bool enable)7969*4882a593Smuzhiyun si_seci_upd(si_t *sih, bool enable)
7970*4882a593Smuzhiyun {
7971*4882a593Smuzhiyun 	uint32 origidx = 0;
7972*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
7973*4882a593Smuzhiyun 	chipcregs_t *cc;
7974*4882a593Smuzhiyun 	bool fast;
7975*4882a593Smuzhiyun 	uint32 regval, seci_ctrl;
7976*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
7977*4882a593Smuzhiyun 
7978*4882a593Smuzhiyun 	if (!si_seci(sih))
7979*4882a593Smuzhiyun 		return;
7980*4882a593Smuzhiyun 
7981*4882a593Smuzhiyun 	fast = SI_FAST(sii);
7982*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
7983*4882a593Smuzhiyun 	if (!fast) {
7984*4882a593Smuzhiyun 		origidx = sii->curidx;
7985*4882a593Smuzhiyun 		if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL)
7986*4882a593Smuzhiyun 			goto exit;
7987*4882a593Smuzhiyun 	} else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL)
7988*4882a593Smuzhiyun 		goto exit;
7989*4882a593Smuzhiyun 
7990*4882a593Smuzhiyun 	ASSERT(cc);
7991*4882a593Smuzhiyun 
7992*4882a593Smuzhiyun 	/* Select SECI based on enable input */
7993*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM4352_CHIP_ID) || (CHIPID(sih->chip) == BCM4360_CHIP_ID)) {
7994*4882a593Smuzhiyun 		regval = R_REG(sii->osh, &cc->chipcontrol);
7995*4882a593Smuzhiyun 
7996*4882a593Smuzhiyun 		seci_ctrl = CCTRL4360_SECI_ON_GPIO01;
7997*4882a593Smuzhiyun 
7998*4882a593Smuzhiyun 		if (enable) {
7999*4882a593Smuzhiyun 			regval |= seci_ctrl;
8000*4882a593Smuzhiyun 		} else {
8001*4882a593Smuzhiyun 			regval &= ~seci_ctrl;
8002*4882a593Smuzhiyun 		}
8003*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->chipcontrol, regval);
8004*4882a593Smuzhiyun 
8005*4882a593Smuzhiyun 		if (enable) {
8006*4882a593Smuzhiyun 			/* Send ECI update to BT */
8007*4882a593Smuzhiyun 			regval = R_REG(sii->osh, &cc->SECI_config);
8008*4882a593Smuzhiyun 			regval |= SECI_UPD_SECI;
8009*4882a593Smuzhiyun 			W_REG(sii->osh, &cc->SECI_config, regval);
8010*4882a593Smuzhiyun 			SPINWAIT((R_REG(sii->osh, &cc->SECI_config) & SECI_UPD_SECI), 1000);
8011*4882a593Smuzhiyun 			/* Request ECI update from BT */
8012*4882a593Smuzhiyun 			W_REG(sii->osh, &cc->seci_uart_data, SECI_SLIP_ESC_CHAR);
8013*4882a593Smuzhiyun 			W_REG(sii->osh, &cc->seci_uart_data, SECI_REFRESH_REQ);
8014*4882a593Smuzhiyun 		}
8015*4882a593Smuzhiyun 	}
8016*4882a593Smuzhiyun 
8017*4882a593Smuzhiyun exit:
8018*4882a593Smuzhiyun 	/* restore previous core */
8019*4882a593Smuzhiyun 	if (!fast)
8020*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
8021*4882a593Smuzhiyun 
8022*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
8023*4882a593Smuzhiyun }
8024*4882a593Smuzhiyun 
8025*4882a593Smuzhiyun void *
BCMINITFN(si_gci_init)8026*4882a593Smuzhiyun BCMINITFN(si_gci_init)(si_t *sih)
8027*4882a593Smuzhiyun {
8028*4882a593Smuzhiyun #ifdef HNDGCI
8029*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8030*4882a593Smuzhiyun #endif /* HNDGCI */
8031*4882a593Smuzhiyun 
8032*4882a593Smuzhiyun 	if (sih->cccaps_ext & CC_CAP_EXT_GCI_PRESENT)
8033*4882a593Smuzhiyun 	{
8034*4882a593Smuzhiyun 		si_gci_reset(sih);
8035*4882a593Smuzhiyun 
8036*4882a593Smuzhiyun 		if (sih->boardflags4 & BFL4_BTCOEX_OVER_SECI) {
8037*4882a593Smuzhiyun 			si_gci_seci_init(sih);
8038*4882a593Smuzhiyun 		}
8039*4882a593Smuzhiyun 
8040*4882a593Smuzhiyun 		/* Set GCI Control bits 40 - 47 to be SW Controlled. These bits
8041*4882a593Smuzhiyun 		contain WL channel info and are sent to BT.
8042*4882a593Smuzhiyun 		*/
8043*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, gci_control_1),
8044*4882a593Smuzhiyun 			GCI_WL_CHN_INFO_MASK, GCI_WL_CHN_INFO_MASK);
8045*4882a593Smuzhiyun 	}
8046*4882a593Smuzhiyun #ifdef HNDGCI
8047*4882a593Smuzhiyun 	hndgci_init(sih, sii->osh, HND_GCI_PLAIN_UART_MODE,
8048*4882a593Smuzhiyun 		GCI_UART_BR_115200);
8049*4882a593Smuzhiyun #endif /* HNDGCI */
8050*4882a593Smuzhiyun 
8051*4882a593Smuzhiyun 	return (NULL);
8052*4882a593Smuzhiyun }
8053*4882a593Smuzhiyun #endif /* BCMECICOEX */
8054*4882a593Smuzhiyun #endif /* !(BCMDONGLEHOST) */
8055*4882a593Smuzhiyun 
8056*4882a593Smuzhiyun /**
8057*4882a593Smuzhiyun  * For boards that use GPIO(8) is used for Bluetooth Coex TX_WLAN pin,
8058*4882a593Smuzhiyun  * when GPIOControl for Pin 8 is with ChipCommon core,
8059*4882a593Smuzhiyun  * if UART_TX_1 (bit 5: Chipc capabilities) strapping option is set, then
8060*4882a593Smuzhiyun  * GPIO pin 8 is driven by Uart0MCR:2 rather than GPIOOut:8. To drive this pin
8061*4882a593Smuzhiyun  * low, one has to set Uart0MCR:2 to 1. This is required when the BTC is disabled,
8062*4882a593Smuzhiyun  * or the driver goes down. Refer to PR35488.
8063*4882a593Smuzhiyun  */
8064*4882a593Smuzhiyun void
si_btcgpiowar(si_t * sih)8065*4882a593Smuzhiyun si_btcgpiowar(si_t *sih)
8066*4882a593Smuzhiyun {
8067*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8068*4882a593Smuzhiyun 	uint origidx;
8069*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
8070*4882a593Smuzhiyun 	chipcregs_t *cc;
8071*4882a593Smuzhiyun 
8072*4882a593Smuzhiyun 	/* Make sure that there is ChipCommon core present &&
8073*4882a593Smuzhiyun 	 * UART_TX is strapped to 1
8074*4882a593Smuzhiyun 	 */
8075*4882a593Smuzhiyun 	if (!(sih->cccaps & CC_CAP_UARTGPIO))
8076*4882a593Smuzhiyun 		return;
8077*4882a593Smuzhiyun 
8078*4882a593Smuzhiyun 	/* si_corereg cannot be used as we have to guarantee 8-bit read/writes */
8079*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
8080*4882a593Smuzhiyun 
8081*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8082*4882a593Smuzhiyun 
8083*4882a593Smuzhiyun 	cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
8084*4882a593Smuzhiyun 	ASSERT(cc != NULL);
8085*4882a593Smuzhiyun 
8086*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04);
8087*4882a593Smuzhiyun 
8088*4882a593Smuzhiyun 	/* restore the original index */
8089*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8090*4882a593Smuzhiyun 
8091*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
8092*4882a593Smuzhiyun }
8093*4882a593Smuzhiyun 
8094*4882a593Smuzhiyun void
si_chipcontrl_restore(si_t * sih,uint32 val)8095*4882a593Smuzhiyun si_chipcontrl_restore(si_t *sih, uint32 val)
8096*4882a593Smuzhiyun {
8097*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8098*4882a593Smuzhiyun 	chipcregs_t *cc;
8099*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
8100*4882a593Smuzhiyun 
8101*4882a593Smuzhiyun 	if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) {
8102*4882a593Smuzhiyun 		SI_ERROR(("si_chipcontrl_restore: Failed to find CORE ID!\n"));
8103*4882a593Smuzhiyun 		return;
8104*4882a593Smuzhiyun 	}
8105*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->chipcontrol, val);
8106*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8107*4882a593Smuzhiyun }
8108*4882a593Smuzhiyun 
8109*4882a593Smuzhiyun uint32
si_chipcontrl_read(si_t * sih)8110*4882a593Smuzhiyun si_chipcontrl_read(si_t *sih)
8111*4882a593Smuzhiyun {
8112*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8113*4882a593Smuzhiyun 	chipcregs_t *cc;
8114*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
8115*4882a593Smuzhiyun 	uint32 val;
8116*4882a593Smuzhiyun 
8117*4882a593Smuzhiyun 	if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) {
8118*4882a593Smuzhiyun 		SI_ERROR(("si_chipcontrl_read: Failed to find CORE ID!\n"));
8119*4882a593Smuzhiyun 		return -1;
8120*4882a593Smuzhiyun 	}
8121*4882a593Smuzhiyun 	val = R_REG(sii->osh, &cc->chipcontrol);
8122*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8123*4882a593Smuzhiyun 	return val;
8124*4882a593Smuzhiyun }
8125*4882a593Smuzhiyun 
8126*4882a593Smuzhiyun /** switch muxed pins, on: SROM, off: FEMCTRL. Called for a family of ac chips, not just 4360. */
8127*4882a593Smuzhiyun void
si_chipcontrl_srom4360(si_t * sih,bool on)8128*4882a593Smuzhiyun si_chipcontrl_srom4360(si_t *sih, bool on)
8129*4882a593Smuzhiyun {
8130*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8131*4882a593Smuzhiyun 	chipcregs_t *cc;
8132*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
8133*4882a593Smuzhiyun 	uint32 val;
8134*4882a593Smuzhiyun 
8135*4882a593Smuzhiyun 	if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) {
8136*4882a593Smuzhiyun 		SI_ERROR(("si_chipcontrl_srom4360: Failed to find CORE ID!\n"));
8137*4882a593Smuzhiyun 		return;
8138*4882a593Smuzhiyun 	}
8139*4882a593Smuzhiyun 	val = R_REG(sii->osh, &cc->chipcontrol);
8140*4882a593Smuzhiyun 
8141*4882a593Smuzhiyun 	if (on) {
8142*4882a593Smuzhiyun 		val &= ~(CCTRL4360_SECI_MODE |
8143*4882a593Smuzhiyun 			CCTRL4360_BTSWCTRL_MODE |
8144*4882a593Smuzhiyun 			CCTRL4360_EXTRA_FEMCTRL_MODE |
8145*4882a593Smuzhiyun 			CCTRL4360_BT_LGCY_MODE |
8146*4882a593Smuzhiyun 			CCTRL4360_CORE2FEMCTRL4_ON);
8147*4882a593Smuzhiyun 
8148*4882a593Smuzhiyun 		W_REG(sii->osh, &cc->chipcontrol, val);
8149*4882a593Smuzhiyun 	} else {
8150*4882a593Smuzhiyun 		/* huh, nothing here? */
8151*4882a593Smuzhiyun 	}
8152*4882a593Smuzhiyun 
8153*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8154*4882a593Smuzhiyun }
8155*4882a593Smuzhiyun 
8156*4882a593Smuzhiyun /**
8157*4882a593Smuzhiyun  * The SROM clock is derived from the backplane clock. For chips having a fast
8158*4882a593Smuzhiyun  * backplane clock that requires a higher-than-POR-default clock divisor ratio for the SROM clock.
8159*4882a593Smuzhiyun  */
8160*4882a593Smuzhiyun void
si_srom_clk_set(si_t * sih)8161*4882a593Smuzhiyun si_srom_clk_set(si_t *sih)
8162*4882a593Smuzhiyun {
8163*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8164*4882a593Smuzhiyun 	chipcregs_t *cc;
8165*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
8166*4882a593Smuzhiyun 	uint32 val;
8167*4882a593Smuzhiyun 	uint32 divisor = 1;
8168*4882a593Smuzhiyun 
8169*4882a593Smuzhiyun 	if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) {
8170*4882a593Smuzhiyun 		SI_ERROR(("si_srom_clk_set: Failed to find CORE ID!\n"));
8171*4882a593Smuzhiyun 		return;
8172*4882a593Smuzhiyun 	}
8173*4882a593Smuzhiyun 
8174*4882a593Smuzhiyun 	val = R_REG(sii->osh, &cc->clkdiv2);
8175*4882a593Smuzhiyun 	ASSERT(0);
8176*4882a593Smuzhiyun 
8177*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->clkdiv2, ((val & ~CLKD2_SROM) | divisor));
8178*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8179*4882a593Smuzhiyun }
8180*4882a593Smuzhiyun 
8181*4882a593Smuzhiyun void
si_pmu_avb_clk_set(si_t * sih,osl_t * osh,bool set_flag)8182*4882a593Smuzhiyun si_pmu_avb_clk_set(si_t *sih, osl_t *osh, bool set_flag)
8183*4882a593Smuzhiyun {
8184*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8185*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8186*4882a593Smuzhiyun 		case BCM43460_CHIP_ID:
8187*4882a593Smuzhiyun 		case BCM4360_CHIP_ID:
8188*4882a593Smuzhiyun 			si_pmu_avbtimer_enable(sih, osh, set_flag);
8189*4882a593Smuzhiyun 			break;
8190*4882a593Smuzhiyun 		default:
8191*4882a593Smuzhiyun 			break;
8192*4882a593Smuzhiyun 	}
8193*4882a593Smuzhiyun #endif
8194*4882a593Smuzhiyun }
8195*4882a593Smuzhiyun 
8196*4882a593Smuzhiyun void
si_btc_enable_chipcontrol(si_t * sih)8197*4882a593Smuzhiyun si_btc_enable_chipcontrol(si_t *sih)
8198*4882a593Smuzhiyun {
8199*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8200*4882a593Smuzhiyun 	chipcregs_t *cc;
8201*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
8202*4882a593Smuzhiyun 
8203*4882a593Smuzhiyun 	if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) {
8204*4882a593Smuzhiyun 		SI_ERROR(("si_btc_enable_chipcontrol: Failed to find CORE ID!\n"));
8205*4882a593Smuzhiyun 		return;
8206*4882a593Smuzhiyun 	}
8207*4882a593Smuzhiyun 
8208*4882a593Smuzhiyun 	/* BT fix */
8209*4882a593Smuzhiyun 	W_REG(sii->osh, &cc->chipcontrol,
8210*4882a593Smuzhiyun 		R_REG(sii->osh, &cc->chipcontrol) | CC_BTCOEX_EN_MASK);
8211*4882a593Smuzhiyun 
8212*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8213*4882a593Smuzhiyun }
8214*4882a593Smuzhiyun 
8215*4882a593Smuzhiyun /** cache device removed state */
si_set_device_removed(si_t * sih,bool status)8216*4882a593Smuzhiyun void si_set_device_removed(si_t *sih, bool status)
8217*4882a593Smuzhiyun {
8218*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
8219*4882a593Smuzhiyun 
8220*4882a593Smuzhiyun 	sii->device_removed = status;
8221*4882a593Smuzhiyun }
8222*4882a593Smuzhiyun 
8223*4882a593Smuzhiyun /** check if the device is removed */
8224*4882a593Smuzhiyun bool
si_deviceremoved(const si_t * sih)8225*4882a593Smuzhiyun si_deviceremoved(const si_t *sih)
8226*4882a593Smuzhiyun {
8227*4882a593Smuzhiyun 	uint32 w;
8228*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8229*4882a593Smuzhiyun 
8230*4882a593Smuzhiyun 	if (sii->device_removed) {
8231*4882a593Smuzhiyun 		return TRUE;
8232*4882a593Smuzhiyun 	}
8233*4882a593Smuzhiyun 
8234*4882a593Smuzhiyun 	switch (BUSTYPE(sih->bustype)) {
8235*4882a593Smuzhiyun 	case PCI_BUS:
8236*4882a593Smuzhiyun 		ASSERT(SI_INFO(sih)->osh != NULL);
8237*4882a593Smuzhiyun 		w = OSL_PCI_READ_CONFIG(SI_INFO(sih)->osh, PCI_CFG_VID, sizeof(uint32));
8238*4882a593Smuzhiyun 		if ((w & 0xFFFF) != VENDOR_BROADCOM)
8239*4882a593Smuzhiyun 			return TRUE;
8240*4882a593Smuzhiyun 		break;
8241*4882a593Smuzhiyun 	default:
8242*4882a593Smuzhiyun 		break;
8243*4882a593Smuzhiyun 	}
8244*4882a593Smuzhiyun 	return FALSE;
8245*4882a593Smuzhiyun }
8246*4882a593Smuzhiyun 
8247*4882a593Smuzhiyun bool
si_is_warmboot(void)8248*4882a593Smuzhiyun si_is_warmboot(void)
8249*4882a593Smuzhiyun {
8250*4882a593Smuzhiyun 
8251*4882a593Smuzhiyun 	return FALSE;
8252*4882a593Smuzhiyun }
8253*4882a593Smuzhiyun 
8254*4882a593Smuzhiyun bool
si_is_sprom_available(si_t * sih)8255*4882a593Smuzhiyun si_is_sprom_available(si_t *sih)
8256*4882a593Smuzhiyun {
8257*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) >= 31) {
8258*4882a593Smuzhiyun 		const si_info_t *sii;
8259*4882a593Smuzhiyun 		uint origidx;
8260*4882a593Smuzhiyun 		chipcregs_t *cc;
8261*4882a593Smuzhiyun 		uint32 sromctrl;
8262*4882a593Smuzhiyun 
8263*4882a593Smuzhiyun 		if ((sih->cccaps & CC_CAP_SROM) == 0)
8264*4882a593Smuzhiyun 			return FALSE;
8265*4882a593Smuzhiyun 
8266*4882a593Smuzhiyun 		sii = SI_INFO(sih);
8267*4882a593Smuzhiyun 		origidx = sii->curidx;
8268*4882a593Smuzhiyun 		cc = si_setcoreidx(sih, SI_CC_IDX);
8269*4882a593Smuzhiyun 		ASSERT(cc);
8270*4882a593Smuzhiyun 		sromctrl = R_REG(sii->osh, &cc->sromcontrol);
8271*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
8272*4882a593Smuzhiyun 		return (sromctrl & SRC_PRESENT);
8273*4882a593Smuzhiyun 	}
8274*4882a593Smuzhiyun 
8275*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8276*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
8277*4882a593Smuzhiyun 		if (CHIPREV(sih->chiprev) == 0) {
8278*4882a593Smuzhiyun 			/* WAR for 4369a0: HW4369-1729. no sprom, default to otp always. */
8279*4882a593Smuzhiyun 			return 0;
8280*4882a593Smuzhiyun 		} else {
8281*4882a593Smuzhiyun 			return (sih->chipst & CST4369_SPROM_PRESENT) != 0;
8282*4882a593Smuzhiyun 		}
8283*4882a593Smuzhiyun 		break;
8284*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
8285*4882a593Smuzhiyun 		return (sih->chipst & CST43602_SPROM_PRESENT) != 0;
8286*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
8287*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
8288*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
8289*4882a593Smuzhiyun 		return FALSE;
8290*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
8291*4882a593Smuzhiyun 		return (sih->chipst & CST4362_SPROM_PRESENT) != 0;
8292*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
8293*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
8294*4882a593Smuzhiyun 		return (sih->chipst & CST4378_SPROM_PRESENT) != 0;
8295*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
8296*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
8297*4882a593Smuzhiyun 		return (sih->chipst & CST4387_SPROM_PRESENT) != 0;
8298*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
8299*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
8300*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
8301*4882a593Smuzhiyun 		/* 4389 supports only OTP */
8302*4882a593Smuzhiyun 		return FALSE;
8303*4882a593Smuzhiyun 	default:
8304*4882a593Smuzhiyun 		return TRUE;
8305*4882a593Smuzhiyun 	}
8306*4882a593Smuzhiyun }
8307*4882a593Smuzhiyun 
8308*4882a593Smuzhiyun bool
si_is_sflash_available(const si_t * sih)8309*4882a593Smuzhiyun si_is_sflash_available(const si_t *sih)
8310*4882a593Smuzhiyun {
8311*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8312*4882a593Smuzhiyun 	case BCM4387_CHIP_ID:
8313*4882a593Smuzhiyun 		return (sih->chipst & CST4387_SFLASH_PRESENT) != 0;
8314*4882a593Smuzhiyun 	default:
8315*4882a593Smuzhiyun 		return FALSE;
8316*4882a593Smuzhiyun 	}
8317*4882a593Smuzhiyun }
8318*4882a593Smuzhiyun 
8319*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8320*4882a593Smuzhiyun bool
si_is_otp_disabled(const si_t * sih)8321*4882a593Smuzhiyun si_is_otp_disabled(const si_t *sih)
8322*4882a593Smuzhiyun {
8323*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8324*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
8325*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
8326*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
8327*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
8328*4882a593Smuzhiyun 	case BCM43602_CHIP_ID:
8329*4882a593Smuzhiyun 		/* 4360 OTP is always powered and enabled */
8330*4882a593Smuzhiyun 		return FALSE;
8331*4882a593Smuzhiyun 	/* These chips always have their OTP on */
8332*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
8333*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
8334*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
8335*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
8336*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
8337*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
8338*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
8339*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
8340*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
8341*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
8342*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
8343*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
8344*4882a593Smuzhiyun 	default:
8345*4882a593Smuzhiyun 		return FALSE;
8346*4882a593Smuzhiyun 	}
8347*4882a593Smuzhiyun }
8348*4882a593Smuzhiyun 
8349*4882a593Smuzhiyun bool
si_is_otp_powered(si_t * sih)8350*4882a593Smuzhiyun si_is_otp_powered(si_t *sih)
8351*4882a593Smuzhiyun {
8352*4882a593Smuzhiyun 	if (PMUCTL_ENAB(sih))
8353*4882a593Smuzhiyun 		return si_pmu_is_otp_powered(sih, si_osh(sih));
8354*4882a593Smuzhiyun 	return TRUE;
8355*4882a593Smuzhiyun }
8356*4882a593Smuzhiyun 
8357*4882a593Smuzhiyun void
si_otp_power(si_t * sih,bool on,uint32 * min_res_mask)8358*4882a593Smuzhiyun si_otp_power(si_t *sih, bool on, uint32* min_res_mask)
8359*4882a593Smuzhiyun {
8360*4882a593Smuzhiyun 	if (PMUCTL_ENAB(sih))
8361*4882a593Smuzhiyun 		si_pmu_otp_power(sih, si_osh(sih), on, min_res_mask);
8362*4882a593Smuzhiyun 	OSL_DELAY(1000);
8363*4882a593Smuzhiyun }
8364*4882a593Smuzhiyun 
8365*4882a593Smuzhiyun /* Return BCME_NOTFOUND if the card doesn't have CIS format nvram */
8366*4882a593Smuzhiyun int
si_cis_source(const si_t * sih)8367*4882a593Smuzhiyun si_cis_source(const si_t *sih)
8368*4882a593Smuzhiyun {
8369*4882a593Smuzhiyun 	/* Most PCI chips use SROM format instead of CIS */
8370*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == PCI_BUS) {
8371*4882a593Smuzhiyun 		return BCME_NOTFOUND;
8372*4882a593Smuzhiyun 	}
8373*4882a593Smuzhiyun 
8374*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8375*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
8376*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
8377*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
8378*4882a593Smuzhiyun 	case BCM43526_CHIP_ID: {
8379*4882a593Smuzhiyun 		if ((sih->chipst & CST4360_OTP_ENABLED))
8380*4882a593Smuzhiyun 			return CIS_OTP;
8381*4882a593Smuzhiyun 		return CIS_DEFAULT;
8382*4882a593Smuzhiyun 	}
8383*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
8384*4882a593Smuzhiyun 		if (sih->chipst & CST43602_SPROM_PRESENT) {
8385*4882a593Smuzhiyun 			/* Don't support CIS formatted SROM, use 'real' SROM format instead */
8386*4882a593Smuzhiyun 			return BCME_NOTFOUND;
8387*4882a593Smuzhiyun 		}
8388*4882a593Smuzhiyun 		return CIS_OTP;
8389*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
8390*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
8391*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
8392*4882a593Smuzhiyun 		return CIS_OTP;
8393*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
8394*4882a593Smuzhiyun 		if (CHIPREV(sih->chiprev) == 0) {
8395*4882a593Smuzhiyun 			/* WAR for 4369a0: HW4369-1729 */
8396*4882a593Smuzhiyun 			return CIS_OTP;
8397*4882a593Smuzhiyun 		} else if (sih->chipst & CST4369_SPROM_PRESENT) {
8398*4882a593Smuzhiyun 			return CIS_SROM;
8399*4882a593Smuzhiyun 		}
8400*4882a593Smuzhiyun 		return CIS_OTP;
8401*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
8402*4882a593Smuzhiyun 		return ((sih->chipst & CST4362_SPROM_PRESENT)? CIS_SROM : CIS_OTP);
8403*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
8404*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
8405*4882a593Smuzhiyun 		if (sih->chipst & CST4378_SPROM_PRESENT)
8406*4882a593Smuzhiyun 			return CIS_SROM;
8407*4882a593Smuzhiyun 		return CIS_OTP;
8408*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
8409*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
8410*4882a593Smuzhiyun 		if (sih->chipst & CST4387_SPROM_PRESENT)
8411*4882a593Smuzhiyun 			return CIS_SROM;
8412*4882a593Smuzhiyun 		return CIS_OTP;
8413*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
8414*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
8415*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
8416*4882a593Smuzhiyun 		/* 4389 supports only OTP */
8417*4882a593Smuzhiyun 		return CIS_OTP;
8418*4882a593Smuzhiyun 	default:
8419*4882a593Smuzhiyun 		return CIS_DEFAULT;
8420*4882a593Smuzhiyun 	}
8421*4882a593Smuzhiyun }
8422*4882a593Smuzhiyun 
BCMATTACHFN(si_fabid)8423*4882a593Smuzhiyun uint16 BCMATTACHFN(si_fabid)(si_t *sih)
8424*4882a593Smuzhiyun {
8425*4882a593Smuzhiyun 	uint32 data;
8426*4882a593Smuzhiyun 	uint16 fabid = 0;
8427*4882a593Smuzhiyun 
8428*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8429*4882a593Smuzhiyun 		CASE_BCM43602_CHIP:
8430*4882a593Smuzhiyun 		case BCM43012_CHIP_ID:
8431*4882a593Smuzhiyun 		case BCM43013_CHIP_ID:
8432*4882a593Smuzhiyun 		case BCM43014_CHIP_ID:
8433*4882a593Smuzhiyun 		case BCM4369_CHIP_GRPID:
8434*4882a593Smuzhiyun 		case BCM4362_CHIP_GRPID:
8435*4882a593Smuzhiyun 		case BCM4376_CHIP_GRPID:
8436*4882a593Smuzhiyun 		case BCM4378_CHIP_GRPID:
8437*4882a593Smuzhiyun 		case BCM4385_CHIP_GRPID:
8438*4882a593Smuzhiyun 		case BCM4387_CHIP_GRPID:
8439*4882a593Smuzhiyun 		case BCM4388_CHIP_GRPID:
8440*4882a593Smuzhiyun 		case BCM4389_CHIP_GRPID:
8441*4882a593Smuzhiyun 		case BCM4397_CHIP_GRPID:
8442*4882a593Smuzhiyun 			data = si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, fabid),	0, 0);
8443*4882a593Smuzhiyun 			fabid = data & 0xf;
8444*4882a593Smuzhiyun 			break;
8445*4882a593Smuzhiyun 
8446*4882a593Smuzhiyun 		default:
8447*4882a593Smuzhiyun 			break;
8448*4882a593Smuzhiyun 	}
8449*4882a593Smuzhiyun 
8450*4882a593Smuzhiyun 	return fabid;
8451*4882a593Smuzhiyun }
8452*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
8453*4882a593Smuzhiyun 
BCMATTACHFN(si_get_sromctl)8454*4882a593Smuzhiyun uint32 BCMATTACHFN(si_get_sromctl)(si_t *sih)
8455*4882a593Smuzhiyun {
8456*4882a593Smuzhiyun 	chipcregs_t *cc;
8457*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
8458*4882a593Smuzhiyun 	uint32 sromctl;
8459*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
8460*4882a593Smuzhiyun 
8461*4882a593Smuzhiyun 	cc = si_setcoreidx(sih, SI_CC_IDX);
8462*4882a593Smuzhiyun 	ASSERT((uintptr)cc);
8463*4882a593Smuzhiyun 
8464*4882a593Smuzhiyun 	sromctl = R_REG(osh, &cc->sromcontrol);
8465*4882a593Smuzhiyun 
8466*4882a593Smuzhiyun 	/* return to the original core */
8467*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8468*4882a593Smuzhiyun 	return sromctl;
8469*4882a593Smuzhiyun }
8470*4882a593Smuzhiyun 
BCMATTACHFN(si_set_sromctl)8471*4882a593Smuzhiyun int BCMATTACHFN(si_set_sromctl)(si_t *sih, uint32 value)
8472*4882a593Smuzhiyun {
8473*4882a593Smuzhiyun 	chipcregs_t *cc;
8474*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
8475*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
8476*4882a593Smuzhiyun 	int ret = BCME_OK;
8477*4882a593Smuzhiyun 
8478*4882a593Smuzhiyun 	cc = si_setcoreidx(sih, SI_CC_IDX);
8479*4882a593Smuzhiyun 	ASSERT((uintptr)cc);
8480*4882a593Smuzhiyun 
8481*4882a593Smuzhiyun 	/* get chipcommon rev */
8482*4882a593Smuzhiyun 	if (si_corerev(sih) >= 32) {
8483*4882a593Smuzhiyun 		/* SpromCtrl is only accessible if CoreCapabilities.SpromSupported and
8484*4882a593Smuzhiyun 		 * SpromPresent is 1.
8485*4882a593Smuzhiyun 		 */
8486*4882a593Smuzhiyun 		if ((R_REG(osh, &cc->capabilities) & CC_CAP_SROM) != 0 &&
8487*4882a593Smuzhiyun 		     (R_REG(osh, &cc->sromcontrol) & SRC_PRESENT)) {
8488*4882a593Smuzhiyun 			W_REG(osh, &cc->sromcontrol, value);
8489*4882a593Smuzhiyun 		} else {
8490*4882a593Smuzhiyun 			ret = BCME_NODEVICE;
8491*4882a593Smuzhiyun 		}
8492*4882a593Smuzhiyun 	} else {
8493*4882a593Smuzhiyun 		ret = BCME_UNSUPPORTED;
8494*4882a593Smuzhiyun 	}
8495*4882a593Smuzhiyun 
8496*4882a593Smuzhiyun 	/* return to the original core */
8497*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8498*4882a593Smuzhiyun 
8499*4882a593Smuzhiyun 	return ret;
8500*4882a593Smuzhiyun }
8501*4882a593Smuzhiyun 
8502*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_core_wrapperreg)8503*4882a593Smuzhiyun BCMPOSTTRAPFN(si_core_wrapperreg)(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val)
8504*4882a593Smuzhiyun {
8505*4882a593Smuzhiyun 	uint origidx;
8506*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
8507*4882a593Smuzhiyun 	uint ret_val;
8508*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8509*4882a593Smuzhiyun 
8510*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8511*4882a593Smuzhiyun 
8512*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
8513*4882a593Smuzhiyun 	/* Validate the core idx */
8514*4882a593Smuzhiyun 	si_setcoreidx(sih, coreidx);
8515*4882a593Smuzhiyun 
8516*4882a593Smuzhiyun 	ret_val = si_wrapperreg(sih, offset, mask, val);
8517*4882a593Smuzhiyun 
8518*4882a593Smuzhiyun 	/* return to the original core */
8519*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8520*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
8521*4882a593Smuzhiyun 	return ret_val;
8522*4882a593Smuzhiyun }
8523*4882a593Smuzhiyun 
8524*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8525*4882a593Smuzhiyun static void
si_pmu_sr_upd(si_t * sih)8526*4882a593Smuzhiyun si_pmu_sr_upd(si_t *sih)
8527*4882a593Smuzhiyun {
8528*4882a593Smuzhiyun #if defined(SAVERESTORE)
8529*4882a593Smuzhiyun 	if (SR_ENAB()) {
8530*4882a593Smuzhiyun 		const si_info_t *sii = SI_INFO(sih);
8531*4882a593Smuzhiyun 
8532*4882a593Smuzhiyun 		/* min_mask is updated after SR code is downloaded to txfifo */
8533*4882a593Smuzhiyun 		if (PMUCTL_ENAB(sih))
8534*4882a593Smuzhiyun 			si_pmu_res_minmax_update(sih, sii->osh);
8535*4882a593Smuzhiyun 	}
8536*4882a593Smuzhiyun #endif
8537*4882a593Smuzhiyun }
8538*4882a593Smuzhiyun 
8539*4882a593Smuzhiyun /**
8540*4882a593Smuzhiyun  * To make sure that, res mask is minimal to save power and also, to indicate
8541*4882a593Smuzhiyun  * specifically to host about the SR logic.
8542*4882a593Smuzhiyun  */
8543*4882a593Smuzhiyun void
si_update_masks(si_t * sih)8544*4882a593Smuzhiyun si_update_masks(si_t *sih)
8545*4882a593Smuzhiyun {
8546*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8547*4882a593Smuzhiyun 
8548*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8549*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
8550*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
8551*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
8552*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
8553*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
8554*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
8555*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
8556*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
8557*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
8558*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
8559*4882a593Smuzhiyun 		/* Assumes SR engine has been enabled */
8560*4882a593Smuzhiyun 		if (PMUCTL_ENAB(sih))
8561*4882a593Smuzhiyun 			si_pmu_res_minmax_update(sih, sii->osh);
8562*4882a593Smuzhiyun 		break;
8563*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
8564*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
8565*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
8566*4882a593Smuzhiyun 		/* min_mask is updated after SR code is downloaded to txfifo */
8567*4882a593Smuzhiyun 		si_pmu_sr_upd(sih);
8568*4882a593Smuzhiyun 		PMU_REG(sih, mac_res_req_timer, ~0x0, PMU43012_MAC_RES_REQ_TIMER);
8569*4882a593Smuzhiyun 		PMU_REG(sih, mac_res_req_mask, ~0x0, PMU43012_MAC_RES_REQ_MASK);
8570*4882a593Smuzhiyun 		break;
8571*4882a593Smuzhiyun 
8572*4882a593Smuzhiyun 	default:
8573*4882a593Smuzhiyun 		ASSERT(0);
8574*4882a593Smuzhiyun 	break;
8575*4882a593Smuzhiyun 	}
8576*4882a593Smuzhiyun }
8577*4882a593Smuzhiyun 
8578*4882a593Smuzhiyun void
si_force_islanding(si_t * sih,bool enable)8579*4882a593Smuzhiyun si_force_islanding(si_t *sih, bool enable)
8580*4882a593Smuzhiyun {
8581*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8582*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
8583*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
8584*4882a593Smuzhiyun 	case BCM43014_CHIP_ID: {
8585*4882a593Smuzhiyun 		if (enable) {
8586*4882a593Smuzhiyun 			/* Turn on the islands */
8587*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, CHIPCTRLREG2, 0x00000053, 0x0);
8588*4882a593Smuzhiyun #ifdef USE_MEMLPLDO
8589*4882a593Smuzhiyun 			/* Force vddm pwrsw always on */
8590*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, CHIPCTRLREG2, 0x000003, 0x000003);
8591*4882a593Smuzhiyun #endif
8592*4882a593Smuzhiyun #ifdef BCMQT
8593*4882a593Smuzhiyun 			/* Turn off the islands */
8594*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, CHIPCTRLREG2, 0x000050, 0x000050);
8595*4882a593Smuzhiyun #endif
8596*4882a593Smuzhiyun 		} else {
8597*4882a593Smuzhiyun 			/* Turn off the islands */
8598*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, CHIPCTRLREG2, 0x000050, 0x000050);
8599*4882a593Smuzhiyun 		}
8600*4882a593Smuzhiyun 	}
8601*4882a593Smuzhiyun 	break;
8602*4882a593Smuzhiyun 
8603*4882a593Smuzhiyun 	default:
8604*4882a593Smuzhiyun 		ASSERT(0);
8605*4882a593Smuzhiyun 	break;
8606*4882a593Smuzhiyun 	}
8607*4882a593Smuzhiyun }
8608*4882a593Smuzhiyun 
8609*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
8610*4882a593Smuzhiyun 
8611*4882a593Smuzhiyun /* cleanup the timer from the host when ARM is been halted
8612*4882a593Smuzhiyun  * without a chance for ARM cleanup its resources
8613*4882a593Smuzhiyun  * If left not cleanup, Intr from a software timer can still
8614*4882a593Smuzhiyun  * request HT clk when ARM is halted.
8615*4882a593Smuzhiyun  */
8616*4882a593Smuzhiyun uint32
si_pmu_res_req_timer_clr(si_t * sih)8617*4882a593Smuzhiyun si_pmu_res_req_timer_clr(si_t *sih)
8618*4882a593Smuzhiyun {
8619*4882a593Smuzhiyun 	uint32 mask;
8620*4882a593Smuzhiyun 
8621*4882a593Smuzhiyun 	mask = PRRT_REQ_ACTIVE | PRRT_INTEN | PRRT_HT_REQ;
8622*4882a593Smuzhiyun 	mask <<= 14;
8623*4882a593Smuzhiyun 	/* clear mask bits */
8624*4882a593Smuzhiyun 	pmu_corereg(sih, SI_CC_IDX, res_req_timer, mask, 0);
8625*4882a593Smuzhiyun 	/* readback to ensure write completes */
8626*4882a593Smuzhiyun 	return pmu_corereg(sih, SI_CC_IDX, res_req_timer, 0, 0);
8627*4882a593Smuzhiyun }
8628*4882a593Smuzhiyun 
8629*4882a593Smuzhiyun /** turn on/off rfldo */
8630*4882a593Smuzhiyun void
si_pmu_rfldo(si_t * sih,bool on)8631*4882a593Smuzhiyun si_pmu_rfldo(si_t *sih, bool on)
8632*4882a593Smuzhiyun {
8633*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8634*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8635*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
8636*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
8637*4882a593Smuzhiyun 	case BCM43526_CHIP_ID: {
8638*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
8639*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_0, RCTRL4360_RFLDO_PWR_DOWN,
8640*4882a593Smuzhiyun 			on ? 0 : RCTRL4360_RFLDO_PWR_DOWN);
8641*4882a593Smuzhiyun 		break;
8642*4882a593Smuzhiyun 	}
8643*4882a593Smuzhiyun 	default:
8644*4882a593Smuzhiyun 		ASSERT(0);
8645*4882a593Smuzhiyun 	break;
8646*4882a593Smuzhiyun 	}
8647*4882a593Smuzhiyun #endif
8648*4882a593Smuzhiyun }
8649*4882a593Smuzhiyun 
8650*4882a593Smuzhiyun /* Caller of this function should make sure is on PCIE core
8651*4882a593Smuzhiyun  * Used in pciedev.c.
8652*4882a593Smuzhiyun  */
8653*4882a593Smuzhiyun void
si_pcie_disable_oobselltr(const si_t * sih)8654*4882a593Smuzhiyun si_pcie_disable_oobselltr(const si_t *sih)
8655*4882a593Smuzhiyun {
8656*4882a593Smuzhiyun 	ASSERT(si_coreid(sih) == PCIE2_CORE_ID);
8657*4882a593Smuzhiyun 	if (PCIECOREREV(sih->buscorerev) >= 23)
8658*4882a593Smuzhiyun 		si_wrapperreg(sih, AI_OOBSELIND74, ~0, 0);
8659*4882a593Smuzhiyun 	else
8660*4882a593Smuzhiyun 		si_wrapperreg(sih, AI_OOBSELIND30, ~0, 0);
8661*4882a593Smuzhiyun }
8662*4882a593Smuzhiyun 
8663*4882a593Smuzhiyun void
si_pcie_ltr_war(const si_t * sih)8664*4882a593Smuzhiyun si_pcie_ltr_war(const si_t *sih)
8665*4882a593Smuzhiyun {
8666*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8667*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8668*4882a593Smuzhiyun 
8669*4882a593Smuzhiyun 	if (PCIE_GEN2(sii))
8670*4882a593Smuzhiyun 		pcie_ltr_war(sii->pch, si_pcieltrenable(sih, 0, 0));
8671*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST */
8672*4882a593Smuzhiyun }
8673*4882a593Smuzhiyun 
8674*4882a593Smuzhiyun void
si_pcie_hw_LTR_war(const si_t * sih)8675*4882a593Smuzhiyun si_pcie_hw_LTR_war(const si_t *sih)
8676*4882a593Smuzhiyun {
8677*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8678*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8679*4882a593Smuzhiyun 
8680*4882a593Smuzhiyun 	if (PCIE_GEN2(sii))
8681*4882a593Smuzhiyun 		pcie_hw_LTR_war(sii->pch);
8682*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST */
8683*4882a593Smuzhiyun }
8684*4882a593Smuzhiyun 
8685*4882a593Smuzhiyun void
si_pciedev_reg_pm_clk_period(const si_t * sih)8686*4882a593Smuzhiyun si_pciedev_reg_pm_clk_period(const si_t *sih)
8687*4882a593Smuzhiyun {
8688*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8689*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8690*4882a593Smuzhiyun 
8691*4882a593Smuzhiyun 	if (PCIE_GEN2(sii))
8692*4882a593Smuzhiyun 		pciedev_reg_pm_clk_period(sii->pch);
8693*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST */
8694*4882a593Smuzhiyun }
8695*4882a593Smuzhiyun 
8696*4882a593Smuzhiyun void
si_pciedev_crwlpciegen2(const si_t * sih)8697*4882a593Smuzhiyun si_pciedev_crwlpciegen2(const si_t *sih)
8698*4882a593Smuzhiyun {
8699*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8700*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8701*4882a593Smuzhiyun 
8702*4882a593Smuzhiyun 	if (PCIE_GEN2(sii))
8703*4882a593Smuzhiyun 		pciedev_crwlpciegen2(sii->pch);
8704*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST */
8705*4882a593Smuzhiyun }
8706*4882a593Smuzhiyun 
8707*4882a593Smuzhiyun void
si_pcie_prep_D3(const si_t * sih,bool enter_D3)8708*4882a593Smuzhiyun si_pcie_prep_D3(const si_t *sih, bool enter_D3)
8709*4882a593Smuzhiyun {
8710*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8711*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8712*4882a593Smuzhiyun 
8713*4882a593Smuzhiyun 	if (PCIE_GEN2(sii))
8714*4882a593Smuzhiyun 		pciedev_prep_D3(sii->pch, enter_D3);
8715*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST */
8716*4882a593Smuzhiyun }
8717*4882a593Smuzhiyun 
8718*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8719*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_corereg_ifup)8720*4882a593Smuzhiyun BCMPOSTTRAPFN(si_corereg_ifup)(si_t *sih, uint core_id, uint regoff, uint mask, uint val)
8721*4882a593Smuzhiyun {
8722*4882a593Smuzhiyun 	bool isup;
8723*4882a593Smuzhiyun 	volatile void *regs;
8724*4882a593Smuzhiyun 	uint origidx, ret_val, coreidx;
8725*4882a593Smuzhiyun 
8726*4882a593Smuzhiyun 	/* Remember original core before switch to chipc */
8727*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8728*4882a593Smuzhiyun 	regs = si_setcore(sih, core_id, 0);
8729*4882a593Smuzhiyun 	BCM_REFERENCE(regs);
8730*4882a593Smuzhiyun 	ASSERT(regs != NULL);
8731*4882a593Smuzhiyun 
8732*4882a593Smuzhiyun 	coreidx = si_coreidx(sih);
8733*4882a593Smuzhiyun 
8734*4882a593Smuzhiyun 	isup = si_iscoreup(sih);
8735*4882a593Smuzhiyun 	if (isup == TRUE) {
8736*4882a593Smuzhiyun 		ret_val = si_corereg(sih, coreidx, regoff, mask, val);
8737*4882a593Smuzhiyun 	} else {
8738*4882a593Smuzhiyun 		ret_val = 0;
8739*4882a593Smuzhiyun 	}
8740*4882a593Smuzhiyun 
8741*4882a593Smuzhiyun 	/* Return to original core */
8742*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8743*4882a593Smuzhiyun 	return ret_val;
8744*4882a593Smuzhiyun }
8745*4882a593Smuzhiyun 
8746*4882a593Smuzhiyun /* 43012 specific low power settings.
8747*4882a593Smuzhiyun  * See http://confluence.broadcom.com/display/WLAN/BCM43012+Low+Power+Settings.
8748*4882a593Smuzhiyun  * See 47xxtcl/43012.tcl proc lp_enable.
8749*4882a593Smuzhiyun  */
si_43012_lp_enable(si_t * sih)8750*4882a593Smuzhiyun void si_43012_lp_enable(si_t *sih)
8751*4882a593Smuzhiyun {
8752*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
8753*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
8754*4882a593Smuzhiyun 	uint origidx;
8755*4882a593Smuzhiyun 	int count;
8756*4882a593Smuzhiyun 	gciregs_t *gciregs;
8757*4882a593Smuzhiyun 
8758*4882a593Smuzhiyun 	/* Block ints and save current core */
8759*4882a593Smuzhiyun 	INTR_OFF(sii, &intr_val);
8760*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8761*4882a593Smuzhiyun 
8762*4882a593Smuzhiyun 	/* Enable radiodig clk gating */
8763*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, CHIPCTRLREG5, PMUCCTL05_43012_RADIO_DIG_CLK_GATING_EN,
8764*4882a593Smuzhiyun 			PMUCCTL05_43012_RADIO_DIG_CLK_GATING_EN);
8765*4882a593Smuzhiyun 
8766*4882a593Smuzhiyun 	/* Disable SPM clock */
8767*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, CHIPCTRLREG5, PMUCCTL05_43012_DISABLE_SPM_CLK,
8768*4882a593Smuzhiyun 			PMUCCTL05_43012_DISABLE_SPM_CLK);
8769*4882a593Smuzhiyun 
8770*4882a593Smuzhiyun 	/* Enable access of radiodig registers using async apb interface */
8771*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, CHIPCTRLREG6, PMUCCTL06_43012_GCI2RDIG_USE_ASYNCAPB,
8772*4882a593Smuzhiyun 			PMUCCTL06_43012_GCI2RDIG_USE_ASYNCAPB);
8773*4882a593Smuzhiyun 
8774*4882a593Smuzhiyun 	/* Remove SFLASH clock request (which is default on for boot-from-flash support) */
8775*4882a593Smuzhiyun 	CHIPC_REG(sih, clk_ctl_st, CCS_SFLASH_CLKREQ | CCS_HQCLKREQ, CCS_HQCLKREQ);
8776*4882a593Smuzhiyun 
8777*4882a593Smuzhiyun 	/* Switch to GCI core */
8778*4882a593Smuzhiyun 	if (!(gciregs = si_setcore(sih, GCI_CORE_ID, 0))) {
8779*4882a593Smuzhiyun 		goto done;
8780*4882a593Smuzhiyun 	}
8781*4882a593Smuzhiyun 
8782*4882a593Smuzhiyun 	/* GCIForceRegClk Off */
8783*4882a593Smuzhiyun 	if (!(sih->lpflags & LPFLAGS_SI_GCI_FORCE_REGCLK_DISABLE)) {
8784*4882a593Smuzhiyun 		si_gci_direct(sih, GET_GCI_OFFSET(sih, gci_corectrl),
8785*4882a593Smuzhiyun 				GCI_CORECTRL_FORCEREGCLK_MASK, 0);
8786*4882a593Smuzhiyun 	}
8787*4882a593Smuzhiyun 
8788*4882a593Smuzhiyun 	/* Disable the sflash pad */
8789*4882a593Smuzhiyun 	if (!(sih->lpflags & LPFLAGS_SI_SFLASH_DISABLE)) {
8790*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_03,
8791*4882a593Smuzhiyun 			CC_GCI_03_LPFLAGS_SFLASH_MASK, CC_GCI_03_LPFLAGS_SFLASH_VAL);
8792*4882a593Smuzhiyun 	}
8793*4882a593Smuzhiyun 
8794*4882a593Smuzhiyun 	/* Input disable all LHL I/O pins */
8795*4882a593Smuzhiyun 	for (count = 0; count < GPIO_CTRL_REG_COUNT; count++) {
8796*4882a593Smuzhiyun 		OR_REG(sii->osh, &gciregs->gpio_ctrl_iocfg_p_adr[count],
8797*4882a593Smuzhiyun 			GPIO_CTRL_REG_DISABLE_INTERRUPT);
8798*4882a593Smuzhiyun 	}
8799*4882a593Smuzhiyun 
8800*4882a593Smuzhiyun 	/* Power down BT LDO3p3 */
8801*4882a593Smuzhiyun 	if (!(sih->lpflags & LPFLAGS_SI_BTLDO3P3_DISABLE)) {
8802*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, CHIPCTRLREG2, PMUCCTL02_43012_BTLDO3P3_PU_FORCE_OFF,
8803*4882a593Smuzhiyun 				PMUCCTL02_43012_BTLDO3P3_PU_FORCE_OFF);
8804*4882a593Smuzhiyun 	}
8805*4882a593Smuzhiyun 
8806*4882a593Smuzhiyun done:
8807*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8808*4882a593Smuzhiyun 	INTR_RESTORE(sii, &intr_val);
8809*4882a593Smuzhiyun }
8810*4882a593Smuzhiyun 
8811*4882a593Smuzhiyun /** this function is called from the BMAC during (re) initialisation */
8812*4882a593Smuzhiyun void
si_lowpwr_opt(si_t * sih)8813*4882a593Smuzhiyun si_lowpwr_opt(si_t *sih)
8814*4882a593Smuzhiyun {
8815*4882a593Smuzhiyun 	uint mask, val;
8816*4882a593Smuzhiyun 
8817*4882a593Smuzhiyun 	/* 43602 chip (all revision) related changes */
8818*4882a593Smuzhiyun 	if (BCM43602_CHIP(sih->chip)) {
8819*4882a593Smuzhiyun 		uint hosti = si_chip_hostif(sih);
8820*4882a593Smuzhiyun 		uint origidx = si_coreidx(sih);
8821*4882a593Smuzhiyun 		volatile void *regs;
8822*4882a593Smuzhiyun 
8823*4882a593Smuzhiyun 		regs = si_setcore(sih, CC_CORE_ID, 0);
8824*4882a593Smuzhiyun 		BCM_REFERENCE(regs);
8825*4882a593Smuzhiyun 		ASSERT(regs != NULL);
8826*4882a593Smuzhiyun 
8827*4882a593Smuzhiyun 		/* disable usb app clk */
8828*4882a593Smuzhiyun 		/* Can be done any time. If it is not USB, then do it. In case */
8829*4882a593Smuzhiyun 		/* of USB, do not write it */
8830*4882a593Smuzhiyun 		if (hosti != CHIP_HOSTIF_USBMODE && !BCM43602_CHIP(sih->chip)) {
8831*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL5, (1 << USBAPP_CLK_BIT), 0);
8832*4882a593Smuzhiyun 		}
8833*4882a593Smuzhiyun 		/* disable pcie clks */
8834*4882a593Smuzhiyun 		if (hosti != CHIP_HOSTIF_PCIEMODE) {
8835*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL5, (1 << PCIE_CLK_BIT), 0);
8836*4882a593Smuzhiyun 		}
8837*4882a593Smuzhiyun 
8838*4882a593Smuzhiyun 		/* disable armcr4 debug clk */
8839*4882a593Smuzhiyun 		/* Can be done anytime as long as driver is functional. */
8840*4882a593Smuzhiyun 		/* In TCL, dhalt commands needs to change to undo this */
8841*4882a593Smuzhiyun 		switch (CHIPID(sih->chip)) {
8842*4882a593Smuzhiyun 			CASE_BCM43602_CHIP:
8843*4882a593Smuzhiyun 				si_pmu_chipcontrol(sih, PMU_CHIPCTL3,
8844*4882a593Smuzhiyun 					PMU43602_CC3_ARMCR4_DBG_CLK, 0);
8845*4882a593Smuzhiyun 				break;
8846*4882a593Smuzhiyun 			case BCM4369_CHIP_GRPID:
8847*4882a593Smuzhiyun 			case BCM4362_CHIP_GRPID:
8848*4882a593Smuzhiyun 				{
8849*4882a593Smuzhiyun 					uint32 tapsel =	si_corereg(sih, SI_CC_IDX,
8850*4882a593Smuzhiyun 						OFFSETOF(chipcregs_t, jtagctrl), 0, 0)
8851*4882a593Smuzhiyun 						& JCTRL_TAPSEL_BIT;
8852*4882a593Smuzhiyun 					/* SWD: if tap sel bit set, */
8853*4882a593Smuzhiyun 					/* enable armcr4 debug clock */
8854*4882a593Smuzhiyun 					si_pmu_chipcontrol(sih, PMU_CHIPCTL5,
8855*4882a593Smuzhiyun 						(1 << ARMCR4_DBG_CLK_BIT),
8856*4882a593Smuzhiyun 						tapsel?(1 << ARMCR4_DBG_CLK_BIT):0);
8857*4882a593Smuzhiyun 				}
8858*4882a593Smuzhiyun 				break;
8859*4882a593Smuzhiyun 			default:
8860*4882a593Smuzhiyun 				si_pmu_chipcontrol(sih, PMU_CHIPCTL5,
8861*4882a593Smuzhiyun 					(1 << ARMCR4_DBG_CLK_BIT), 0);
8862*4882a593Smuzhiyun 				break;
8863*4882a593Smuzhiyun 		}
8864*4882a593Smuzhiyun 
8865*4882a593Smuzhiyun 		/* Power down unused BBPLL ch-6(pcie_tl_clk) and ch-5(sample-sync-clk), */
8866*4882a593Smuzhiyun 		/* valid in all modes, ch-5 needs to be reenabled for sample-capture */
8867*4882a593Smuzhiyun 		/* this needs to be done in the pmu init path, at the beginning. Should not be */
8868*4882a593Smuzhiyun 		/* a pcie driver. Enable the sample-sync-clk in the sample capture function */
8869*4882a593Smuzhiyun 		if (BCM43602_CHIP(sih->chip)) {
8870*4882a593Smuzhiyun 			/* configure open loop PLL parameters, open loop is used during S/R */
8871*4882a593Smuzhiyun 			val = (3 << PMU1_PLL0_PC1_M1DIV_SHIFT) | (6 << PMU1_PLL0_PC1_M2DIV_SHIFT) |
8872*4882a593Smuzhiyun 			      (6 << PMU1_PLL0_PC1_M3DIV_SHIFT) | (8 << PMU1_PLL0_PC1_M4DIV_SHIFT);
8873*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL4, ~0, val);
8874*4882a593Smuzhiyun 			si_pmu_pllupd(sih);
8875*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL2,
8876*4882a593Smuzhiyun 			  PMU43602_CC2_PCIE_CLKREQ_L_WAKE_EN |  PMU43602_CC2_PMU_WAKE_ALP_AVAIL_EN,
8877*4882a593Smuzhiyun 			  PMU43602_CC2_PCIE_CLKREQ_L_WAKE_EN |  PMU43602_CC2_PMU_WAKE_ALP_AVAIL_EN);
8878*4882a593Smuzhiyun 		}
8879*4882a593Smuzhiyun 
8880*4882a593Smuzhiyun 		/* Return to original core */
8881*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
8882*4882a593Smuzhiyun 	}
8883*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
8884*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
8885*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID)) {
8886*4882a593Smuzhiyun 		/* Enable memory standby based on lpflags */
8887*4882a593Smuzhiyun 		if (sih->lpflags & LPFLAGS_SI_GLOBAL_DISABLE) {
8888*4882a593Smuzhiyun 			SI_MSG(("si_lowpwr_opt: Disable lower power configuration!\n"));
8889*4882a593Smuzhiyun 			goto exit;
8890*4882a593Smuzhiyun 		}
8891*4882a593Smuzhiyun 
8892*4882a593Smuzhiyun 		SI_MSG(("si_lowpwr_opt: Enable lower power configuration!\n"));
8893*4882a593Smuzhiyun 
8894*4882a593Smuzhiyun 		/* Enable mem clk gating */
8895*4882a593Smuzhiyun 		mask = (0x1 << MEM_CLK_GATE_BIT);
8896*4882a593Smuzhiyun 		val = (0x1 << MEM_CLK_GATE_BIT);
8897*4882a593Smuzhiyun 
8898*4882a593Smuzhiyun 		si_corereg_ifup(sih, SDIOD_CORE_ID, SI_PWR_CTL_ST, mask, val);
8899*4882a593Smuzhiyun 		si_corereg_ifup(sih, SOCRAM_CORE_ID, SI_PWR_CTL_ST, mask, val);
8900*4882a593Smuzhiyun 
8901*4882a593Smuzhiyun 		si_43012_lp_enable(sih);
8902*4882a593Smuzhiyun 	}
8903*4882a593Smuzhiyun exit:
8904*4882a593Smuzhiyun 	return;
8905*4882a593Smuzhiyun }
8906*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
8907*4882a593Smuzhiyun 
8908*4882a593Smuzhiyun #if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC)
8909*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_clear_backplane_to_per_core)8910*4882a593Smuzhiyun BCMPOSTTRAPFN(si_clear_backplane_to_per_core)(si_t *sih, uint coreid, uint coreunit, void * wrap)
8911*4882a593Smuzhiyun {
8912*4882a593Smuzhiyun 	if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
8913*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS)) {
8914*4882a593Smuzhiyun 		return ai_clear_backplane_to_per_core(sih, coreid, coreunit, wrap);
8915*4882a593Smuzhiyun 	}
8916*4882a593Smuzhiyun 	return AXI_WRAP_STS_NONE;
8917*4882a593Smuzhiyun }
8918*4882a593Smuzhiyun #endif /* AXI_TIMEOUTS || AXI_TIMEOUTS_NIC */
8919*4882a593Smuzhiyun 
8920*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_clear_backplane_to)8921*4882a593Smuzhiyun BCMPOSTTRAPFN(si_clear_backplane_to)(si_t *sih)
8922*4882a593Smuzhiyun {
8923*4882a593Smuzhiyun 	if ((CHIPTYPE(sih->socitype) == SOCI_AI) ||
8924*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) == SOCI_DVTBUS)) {
8925*4882a593Smuzhiyun 		return ai_clear_backplane_to(sih);
8926*4882a593Smuzhiyun 	}
8927*4882a593Smuzhiyun 
8928*4882a593Smuzhiyun 	return 0;
8929*4882a593Smuzhiyun }
8930*4882a593Smuzhiyun 
8931*4882a593Smuzhiyun void
BCMATTACHFN(si_update_backplane_timeouts)8932*4882a593Smuzhiyun BCMATTACHFN(si_update_backplane_timeouts)(const si_t *sih, bool enable, uint32 timeout_exp,
8933*4882a593Smuzhiyun 	uint32 cid)
8934*4882a593Smuzhiyun {
8935*4882a593Smuzhiyun #if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC)
8936*4882a593Smuzhiyun 	/* Enable only for AXI */
8937*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) != SOCI_AI) {
8938*4882a593Smuzhiyun 		return;
8939*4882a593Smuzhiyun 	}
8940*4882a593Smuzhiyun 
8941*4882a593Smuzhiyun 	ai_update_backplane_timeouts(sih, enable, timeout_exp, cid);
8942*4882a593Smuzhiyun #endif /* AXI_TIMEOUTS  || AXI_TIMEOUTS_NIC */
8943*4882a593Smuzhiyun }
8944*4882a593Smuzhiyun 
8945*4882a593Smuzhiyun /*
8946*4882a593Smuzhiyun  * This routine adds the AXI timeouts for
8947*4882a593Smuzhiyun  * chipcommon, pcie and ARM slave wrappers
8948*4882a593Smuzhiyun  */
8949*4882a593Smuzhiyun void
si_slave_wrapper_add(si_t * sih)8950*4882a593Smuzhiyun si_slave_wrapper_add(si_t *sih)
8951*4882a593Smuzhiyun {
8952*4882a593Smuzhiyun #if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC)
8953*4882a593Smuzhiyun 	uint32 axi_to = 0;
8954*4882a593Smuzhiyun 
8955*4882a593Smuzhiyun 	/* Enable only for AXI */
8956*4882a593Smuzhiyun 	if ((CHIPTYPE(sih->socitype) != SOCI_AI) &&
8957*4882a593Smuzhiyun 		(CHIPTYPE(sih->socitype) != SOCI_DVTBUS)) {
8958*4882a593Smuzhiyun 		return;
8959*4882a593Smuzhiyun 	}
8960*4882a593Smuzhiyun 
8961*4882a593Smuzhiyun 	axi_to = AXI_TO_VAL;
8962*4882a593Smuzhiyun 
8963*4882a593Smuzhiyun 	/* All required slave wrappers are added in ai_scan */
8964*4882a593Smuzhiyun 	ai_update_backplane_timeouts(sih, TRUE, axi_to, 0);
8965*4882a593Smuzhiyun 
8966*4882a593Smuzhiyun #ifdef DISABLE_PCIE2_AXI_TIMEOUT
8967*4882a593Smuzhiyun 	ai_update_backplane_timeouts(sih, FALSE, 0, PCIE_CORE_ID);
8968*4882a593Smuzhiyun 	ai_update_backplane_timeouts(sih, FALSE, 0, PCIE2_CORE_ID);
8969*4882a593Smuzhiyun #endif
8970*4882a593Smuzhiyun 
8971*4882a593Smuzhiyun #endif /* AXI_TIMEOUTS  || AXI_TIMEOUTS_NIC */
8972*4882a593Smuzhiyun 
8973*4882a593Smuzhiyun }
8974*4882a593Smuzhiyun 
8975*4882a593Smuzhiyun #ifndef BCMDONGLEHOST
8976*4882a593Smuzhiyun /* read from pcie space using back plane  indirect access */
8977*4882a593Smuzhiyun /* Set Below mask for reading 1, 2, 4 bytes in single read */
8978*4882a593Smuzhiyun /* #define	SI_BPIND_1BYTE		0x1 */
8979*4882a593Smuzhiyun /* #define	SI_BPIND_2BYTE		0x3 */
8980*4882a593Smuzhiyun /* #define	SI_BPIND_4BYTE		0xF */
8981*4882a593Smuzhiyun int
BCMPOSTTRAPFN(si_bpind_access)8982*4882a593Smuzhiyun BCMPOSTTRAPFN(si_bpind_access)(si_t *sih, uint32 addr_high, uint32 addr_low,
8983*4882a593Smuzhiyun 		int32 * data, bool read, uint32 us_timeout)
8984*4882a593Smuzhiyun {
8985*4882a593Smuzhiyun 
8986*4882a593Smuzhiyun 	uint32 status = 0;
8987*4882a593Smuzhiyun 	uint8 mask = SI_BPIND_4BYTE;
8988*4882a593Smuzhiyun 	int ret_val = BCME_OK;
8989*4882a593Smuzhiyun 
8990*4882a593Smuzhiyun 	/* Program Address low and high fields */
8991*4882a593Smuzhiyun 	si_ccreg(sih, OFFSETOF(chipcregs_t, bp_addrlow), ~0, addr_low);
8992*4882a593Smuzhiyun 	si_ccreg(sih, OFFSETOF(chipcregs_t, bp_addrhigh), ~0, addr_high);
8993*4882a593Smuzhiyun 
8994*4882a593Smuzhiyun 	if (read) {
8995*4882a593Smuzhiyun 		/* Start the read */
8996*4882a593Smuzhiyun 		si_ccreg(sih, OFFSETOF(chipcregs_t, bp_indaccess), ~0,
8997*4882a593Smuzhiyun 			CC_BP_IND_ACCESS_START_MASK | mask);
8998*4882a593Smuzhiyun 	} else {
8999*4882a593Smuzhiyun 		/* Write the data and force the trigger */
9000*4882a593Smuzhiyun 		si_ccreg(sih, OFFSETOF(chipcregs_t, bp_data), ~0, *data);
9001*4882a593Smuzhiyun 		si_ccreg(sih, OFFSETOF(chipcregs_t, bp_indaccess), ~0,
9002*4882a593Smuzhiyun 			CC_BP_IND_ACCESS_START_MASK |
9003*4882a593Smuzhiyun 			CC_BP_IND_ACCESS_RDWR_MASK | mask);
9004*4882a593Smuzhiyun 
9005*4882a593Smuzhiyun 	}
9006*4882a593Smuzhiyun 
9007*4882a593Smuzhiyun 	/* Wait for status to be cleared */
9008*4882a593Smuzhiyun 	SPINWAIT(((status = si_ccreg(sih, OFFSETOF(chipcregs_t, bp_indaccess), 0, 0)) &
9009*4882a593Smuzhiyun 		CC_BP_IND_ACCESS_START_MASK), us_timeout);
9010*4882a593Smuzhiyun 
9011*4882a593Smuzhiyun 	if (status & (CC_BP_IND_ACCESS_START_MASK | CC_BP_IND_ACCESS_ERROR_MASK)) {
9012*4882a593Smuzhiyun 		ret_val = BCME_ERROR;
9013*4882a593Smuzhiyun 		SI_ERROR(("Action Failed for address 0x%08x:0x%08x \t status: 0x%x\n",
9014*4882a593Smuzhiyun 			addr_high, addr_low, status));
9015*4882a593Smuzhiyun 	/* For ATE, Stop execution here, to catch BPind timeout */
9016*4882a593Smuzhiyun #ifdef ATE_BUILD
9017*4882a593Smuzhiyun 		hnd_die();
9018*4882a593Smuzhiyun #endif /* ATE_BUILD */
9019*4882a593Smuzhiyun 	} else {
9020*4882a593Smuzhiyun 		/* read data */
9021*4882a593Smuzhiyun 		if (read)
9022*4882a593Smuzhiyun 			*data = si_ccreg(sih, OFFSETOF(chipcregs_t, bp_data), 0, 0);
9023*4882a593Smuzhiyun 	}
9024*4882a593Smuzhiyun 
9025*4882a593Smuzhiyun 	return ret_val;
9026*4882a593Smuzhiyun }
9027*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
9028*4882a593Smuzhiyun 
9029*4882a593Smuzhiyun void
si_pll_sr_reinit(si_t * sih)9030*4882a593Smuzhiyun si_pll_sr_reinit(si_t *sih)
9031*4882a593Smuzhiyun {
9032*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST) && !defined(DONGLEBUILD)
9033*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9034*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9035*4882a593Smuzhiyun 	uint32 data;
9036*4882a593Smuzhiyun 
9037*4882a593Smuzhiyun 	/* disable PLL open loop operation */
9038*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
9039*4882a593Smuzhiyun 		case BCM43602_CHIP_ID:
9040*4882a593Smuzhiyun 			/* read back the pll openloop state */
9041*4882a593Smuzhiyun 			data = si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL8, 0, 0);
9042*4882a593Smuzhiyun 			/* check current pll mode */
9043*4882a593Smuzhiyun 			if ((data & PMU1_PLLCTL8_OPENLOOP_MASK) == 0) {
9044*4882a593Smuzhiyun 				/* no POR; don't required pll and saverestore init */
9045*4882a593Smuzhiyun 				return;
9046*4882a593Smuzhiyun 			}
9047*4882a593Smuzhiyun 			si_pmu_pll_init(sih, osh, sii->xtalfreq);
9048*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL8, PMU1_PLLCTL8_OPENLOOP_MASK, 0);
9049*4882a593Smuzhiyun 			si_pmu_pllupd(sih);
9050*4882a593Smuzhiyun 			/* allow PLL to settle after config PLL for closeloop operation */
9051*4882a593Smuzhiyun 			OSL_DELAY(100);
9052*4882a593Smuzhiyun 			break;
9053*4882a593Smuzhiyun 		default:
9054*4882a593Smuzhiyun 			/* any unsupported chip bail */
9055*4882a593Smuzhiyun 			return;
9056*4882a593Smuzhiyun 	}
9057*4882a593Smuzhiyun 	si_pmu_init(sih, osh);
9058*4882a593Smuzhiyun 	si_pmu_chip_init(sih, osh);
9059*4882a593Smuzhiyun #if defined(BCMPMU_STATS)
9060*4882a593Smuzhiyun 	if (PMU_STATS_ENAB()) {
9061*4882a593Smuzhiyun 		si_pmustatstimer_init(sih);
9062*4882a593Smuzhiyun 	}
9063*4882a593Smuzhiyun #endif /* BCMPMU_STATS */
9064*4882a593Smuzhiyun #if defined(SR_ESSENTIALS)
9065*4882a593Smuzhiyun 	/* Module can be power down during D3 state, thus
9066*4882a593Smuzhiyun 	 * needs this before si_pmu_res_init() to use sr_isenab()
9067*4882a593Smuzhiyun 	 * Full dongle may not need to reinit saverestore
9068*4882a593Smuzhiyun 	 */
9069*4882a593Smuzhiyun 	if (SR_ESSENTIALS_ENAB()) {
9070*4882a593Smuzhiyun 		sr_save_restore_init(sih);
9071*4882a593Smuzhiyun 	}
9072*4882a593Smuzhiyun #endif /* SR_ESSENTIALS */
9073*4882a593Smuzhiyun 	si_pmu_res_init(sih, sii->osh);
9074*4882a593Smuzhiyun 	si_pmu_swreg_init(sih, osh);
9075*4882a593Smuzhiyun 	si_lowpwr_opt(sih);
9076*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST && !DONGLEBUILD */
9077*4882a593Smuzhiyun }
9078*4882a593Smuzhiyun 
9079*4882a593Smuzhiyun void
BCMATTACHFN(si_pll_closeloop)9080*4882a593Smuzhiyun BCMATTACHFN(si_pll_closeloop)(si_t *sih)
9081*4882a593Smuzhiyun {
9082*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST) && !defined(DONGLEBUILD) || defined(SAVERESTORE)
9083*4882a593Smuzhiyun 	uint32 data;
9084*4882a593Smuzhiyun 
9085*4882a593Smuzhiyun 	BCM_REFERENCE(data);
9086*4882a593Smuzhiyun 
9087*4882a593Smuzhiyun 	/* disable PLL open loop operation */
9088*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
9089*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST) && !defined(DONGLEBUILD)
9090*4882a593Smuzhiyun 		/* Don't apply those changes to FULL DONGLE mode since the
9091*4882a593Smuzhiyun 		 * behaviour was not verified
9092*4882a593Smuzhiyun 		 */
9093*4882a593Smuzhiyun 		case BCM43602_CHIP_ID:
9094*4882a593Smuzhiyun 			/* read back the pll openloop state */
9095*4882a593Smuzhiyun 			data = si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL8, 0, 0);
9096*4882a593Smuzhiyun 			/* current mode is openloop (possible POR) */
9097*4882a593Smuzhiyun 			if ((data & PMU1_PLLCTL8_OPENLOOP_MASK) != 0) {
9098*4882a593Smuzhiyun 				si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL8,
9099*4882a593Smuzhiyun 					PMU1_PLLCTL8_OPENLOOP_MASK, 0);
9100*4882a593Smuzhiyun 				si_pmu_pllupd(sih);
9101*4882a593Smuzhiyun 				/* allow PLL to settle after config PLL for closeloop operation */
9102*4882a593Smuzhiyun 				OSL_DELAY(100);
9103*4882a593Smuzhiyun 			}
9104*4882a593Smuzhiyun 			break;
9105*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST && !DONGLEBUILD */
9106*4882a593Smuzhiyun 		case BCM4369_CHIP_GRPID:
9107*4882a593Smuzhiyun 		case BCM4362_CHIP_GRPID:
9108*4882a593Smuzhiyun 		case BCM4376_CHIP_GRPID:
9109*4882a593Smuzhiyun 		case BCM4378_CHIP_GRPID:
9110*4882a593Smuzhiyun 		case BCM4385_CHIP_GRPID:
9111*4882a593Smuzhiyun 		case BCM4387_CHIP_GRPID:
9112*4882a593Smuzhiyun 		case BCM4388_CHIP_GRPID:
9113*4882a593Smuzhiyun 		case BCM4389_CHIP_GRPID:
9114*4882a593Smuzhiyun 		case BCM4397_CHIP_GRPID:
9115*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL1,
9116*4882a593Smuzhiyun 				PMU_CC1_ENABLE_CLOSED_LOOP_MASK, PMU_CC1_ENABLE_CLOSED_LOOP);
9117*4882a593Smuzhiyun 			break;
9118*4882a593Smuzhiyun 		default:
9119*4882a593Smuzhiyun 			/* any unsupported chip bail */
9120*4882a593Smuzhiyun 			return;
9121*4882a593Smuzhiyun 	}
9122*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST && !DONGLEBUILD || SAVERESTORE */
9123*4882a593Smuzhiyun }
9124*4882a593Smuzhiyun 
9125*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
9126*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_introff)9127*4882a593Smuzhiyun BCMPOSTTRAPFN(si_introff)(const si_t *sih, bcm_int_bitmask_t *intr_val)
9128*4882a593Smuzhiyun {
9129*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9130*4882a593Smuzhiyun 	INTR_OFF(sii, intr_val);
9131*4882a593Smuzhiyun }
9132*4882a593Smuzhiyun 
9133*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_intrrestore)9134*4882a593Smuzhiyun BCMPOSTTRAPFN(si_intrrestore)(const si_t *sih, bcm_int_bitmask_t *intr_val)
9135*4882a593Smuzhiyun {
9136*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9137*4882a593Smuzhiyun 	INTR_RESTORE(sii, intr_val);
9138*4882a593Smuzhiyun }
9139*4882a593Smuzhiyun 
9140*4882a593Smuzhiyun bool
si_get_nvram_rfldo3p3_war(const si_t * sih)9141*4882a593Smuzhiyun si_get_nvram_rfldo3p3_war(const si_t *sih)
9142*4882a593Smuzhiyun {
9143*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9144*4882a593Smuzhiyun 	return sii->rfldo3p3_war;
9145*4882a593Smuzhiyun }
9146*4882a593Smuzhiyun 
9147*4882a593Smuzhiyun void
si_nvram_res_masks(const si_t * sih,uint32 * min_mask,uint32 * max_mask)9148*4882a593Smuzhiyun si_nvram_res_masks(const si_t *sih, uint32 *min_mask, uint32 *max_mask)
9149*4882a593Smuzhiyun {
9150*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9151*4882a593Smuzhiyun 	/* Apply nvram override to min mask */
9152*4882a593Smuzhiyun 	if (sii->min_mask_valid == TRUE) {
9153*4882a593Smuzhiyun 		SI_MSG(("Applying rmin=%d to min_mask\n", sii->nvram_min_mask));
9154*4882a593Smuzhiyun 		*min_mask = sii->nvram_min_mask;
9155*4882a593Smuzhiyun 	}
9156*4882a593Smuzhiyun 	/* Apply nvram override to max mask */
9157*4882a593Smuzhiyun 	if (sii->max_mask_valid == TRUE) {
9158*4882a593Smuzhiyun 		SI_MSG(("Applying rmax=%d to max_mask\n", sii->nvram_max_mask));
9159*4882a593Smuzhiyun 		*max_mask = sii->nvram_max_mask;
9160*4882a593Smuzhiyun 	}
9161*4882a593Smuzhiyun }
9162*4882a593Smuzhiyun 
9163*4882a593Smuzhiyun uint8
si_getspurmode(const si_t * sih)9164*4882a593Smuzhiyun si_getspurmode(const si_t *sih)
9165*4882a593Smuzhiyun {
9166*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9167*4882a593Smuzhiyun 	return sii->spurmode;
9168*4882a593Smuzhiyun }
9169*4882a593Smuzhiyun 
9170*4882a593Smuzhiyun uint32
si_xtalfreq(const si_t * sih)9171*4882a593Smuzhiyun si_xtalfreq(const si_t *sih)
9172*4882a593Smuzhiyun {
9173*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9174*4882a593Smuzhiyun 	return sii->xtalfreq;
9175*4882a593Smuzhiyun }
9176*4882a593Smuzhiyun 
9177*4882a593Smuzhiyun uint32
si_get_openloop_dco_code(const si_t * sih)9178*4882a593Smuzhiyun si_get_openloop_dco_code(const si_t *sih)
9179*4882a593Smuzhiyun {
9180*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9181*4882a593Smuzhiyun 	return sii->openloop_dco_code;
9182*4882a593Smuzhiyun }
9183*4882a593Smuzhiyun 
9184*4882a593Smuzhiyun void
si_set_openloop_dco_code(si_t * sih,uint32 _openloop_dco_code)9185*4882a593Smuzhiyun si_set_openloop_dco_code(si_t *sih, uint32 _openloop_dco_code)
9186*4882a593Smuzhiyun {
9187*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
9188*4882a593Smuzhiyun 	sii->openloop_dco_code = _openloop_dco_code;
9189*4882a593Smuzhiyun }
9190*4882a593Smuzhiyun 
9191*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_get_armpllclkfreq)9192*4882a593Smuzhiyun BCMPOSTTRAPFN(si_get_armpllclkfreq)(const si_t *sih)
9193*4882a593Smuzhiyun {
9194*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9195*4882a593Smuzhiyun 	uint32 armpllclkfreq = ARMPLL_FREQ_400MHZ;
9196*4882a593Smuzhiyun 	BCM_REFERENCE(sii);
9197*4882a593Smuzhiyun 
9198*4882a593Smuzhiyun #ifdef DONGLEBUILD
9199*4882a593Smuzhiyun 	uint32 armpllclk_max;
9200*4882a593Smuzhiyun 
9201*4882a593Smuzhiyun #if defined(__ARM_ARCH_7R__)
9202*4882a593Smuzhiyun 	armpllclk_max = ARMPLL_FREQ_400MHZ;
9203*4882a593Smuzhiyun #elif defined(__ARM_ARCH_7A__)
9204*4882a593Smuzhiyun 	armpllclk_max = ARMPLL_FREQ_1000MHZ;
9205*4882a593Smuzhiyun #else
9206*4882a593Smuzhiyun #error "Unknown CPU architecture for armpllclkfreq!"
9207*4882a593Smuzhiyun #endif
9208*4882a593Smuzhiyun 
9209*4882a593Smuzhiyun 	armpllclkfreq = (sii->armpllclkfreq) ? sii->armpllclkfreq : armpllclk_max;
9210*4882a593Smuzhiyun 
9211*4882a593Smuzhiyun 	SI_MSG(("armpllclkfreq = %d\n", armpllclkfreq));
9212*4882a593Smuzhiyun #endif /* DONGLEBUILD */
9213*4882a593Smuzhiyun 
9214*4882a593Smuzhiyun 	return armpllclkfreq;
9215*4882a593Smuzhiyun }
9216*4882a593Smuzhiyun 
9217*4882a593Smuzhiyun uint8
BCMPOSTTRAPFN(si_get_ccidiv)9218*4882a593Smuzhiyun BCMPOSTTRAPFN(si_get_ccidiv)(const si_t *sih)
9219*4882a593Smuzhiyun {
9220*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9221*4882a593Smuzhiyun 	uint8 ccidiv = 0xFF;
9222*4882a593Smuzhiyun 	BCM_REFERENCE(sii);
9223*4882a593Smuzhiyun 
9224*4882a593Smuzhiyun #ifdef DONGLEBUILD
9225*4882a593Smuzhiyun 	ccidiv = (sii->ccidiv) ? sii->ccidiv : CCIDIV_3_TO_1;
9226*4882a593Smuzhiyun #endif /* DONGLEBUILD */
9227*4882a593Smuzhiyun 
9228*4882a593Smuzhiyun 	return ccidiv;
9229*4882a593Smuzhiyun }
9230*4882a593Smuzhiyun #ifdef DONGLEBUILD
9231*4882a593Smuzhiyun uint32
BCMATTACHFN(si_wrapper_dump_buf_size)9232*4882a593Smuzhiyun BCMATTACHFN(si_wrapper_dump_buf_size)(const si_t *sih)
9233*4882a593Smuzhiyun {
9234*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI)
9235*4882a593Smuzhiyun 		return ai_wrapper_dump_buf_size(sih);
9236*4882a593Smuzhiyun 	return 0;
9237*4882a593Smuzhiyun }
9238*4882a593Smuzhiyun 
9239*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_wrapper_dump_binary)9240*4882a593Smuzhiyun BCMPOSTTRAPFN(si_wrapper_dump_binary)(const si_t *sih, uchar *p)
9241*4882a593Smuzhiyun {
9242*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI)
9243*4882a593Smuzhiyun 		return ai_wrapper_dump_binary(sih, p);
9244*4882a593Smuzhiyun 	return 0;
9245*4882a593Smuzhiyun }
9246*4882a593Smuzhiyun 
9247*4882a593Smuzhiyun #if defined(ETD) && !defined(ETD_DISABLED)
9248*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_wrapper_dump_last_timeout)9249*4882a593Smuzhiyun BCMPOSTTRAPFN(si_wrapper_dump_last_timeout)(const si_t *sih, uint32 *error, uint32 *core,
9250*4882a593Smuzhiyun 	uint32 *ba, uchar *p)
9251*4882a593Smuzhiyun {
9252*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI)
9253*4882a593Smuzhiyun 		return ai_wrapper_dump_last_timeout(sih, error, core, ba, p);
9254*4882a593Smuzhiyun 	return 0;
9255*4882a593Smuzhiyun }
9256*4882a593Smuzhiyun #endif /* ETD && !ETD_DISABLED */
9257*4882a593Smuzhiyun #endif /* DONGLEBUILD */
9258*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
9259*4882a593Smuzhiyun 
9260*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_findcoreidx_by_axiid)9261*4882a593Smuzhiyun BCMPOSTTRAPFN(si_findcoreidx_by_axiid)(const si_t *sih, uint32 axiid)
9262*4882a593Smuzhiyun {
9263*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI)
9264*4882a593Smuzhiyun 		return ai_findcoreidx_by_axiid(sih, axiid);
9265*4882a593Smuzhiyun 	return 0;
9266*4882a593Smuzhiyun }
9267*4882a593Smuzhiyun 
9268*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_wrapper_get_last_error)9269*4882a593Smuzhiyun BCMPOSTTRAPFN(si_wrapper_get_last_error)(const si_t *sih, uint32 *error_status, uint32 *core,
9270*4882a593Smuzhiyun 	uint32 *lo, uint32 *hi, uint32 *id)
9271*4882a593Smuzhiyun {
9272*4882a593Smuzhiyun #if defined(AXI_TIMEOUTS_NIC) || defined(AXI_TIMEOUTS)
9273*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI)
9274*4882a593Smuzhiyun 		ai_wrapper_get_last_error(sih, error_status, core, lo, hi, id);
9275*4882a593Smuzhiyun #endif /* (AXI_TIMEOUTS_NIC) || (AXI_TIMEOUTS) */
9276*4882a593Smuzhiyun 	return;
9277*4882a593Smuzhiyun }
9278*4882a593Smuzhiyun 
9279*4882a593Smuzhiyun uint32
si_get_axi_timeout_reg(const si_t * sih)9280*4882a593Smuzhiyun si_get_axi_timeout_reg(const si_t *sih)
9281*4882a593Smuzhiyun {
9282*4882a593Smuzhiyun #if defined(AXI_TIMEOUTS_NIC) || defined(AXI_TIMEOUTS)
9283*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI) {
9284*4882a593Smuzhiyun 		return ai_get_axi_timeout_reg();
9285*4882a593Smuzhiyun 	}
9286*4882a593Smuzhiyun #endif /* (AXI_TIMEOUTS_NIC) || (AXI_TIMEOUTS) */
9287*4882a593Smuzhiyun 	return 0;
9288*4882a593Smuzhiyun }
9289*4882a593Smuzhiyun 
9290*4882a593Smuzhiyun #if defined(BCMSRPWR) && !defined(BCMSRPWR_DISABLED)
9291*4882a593Smuzhiyun bool _bcmsrpwr = TRUE;
9292*4882a593Smuzhiyun #else
9293*4882a593Smuzhiyun bool _bcmsrpwr = FALSE;
9294*4882a593Smuzhiyun #endif
9295*4882a593Smuzhiyun 
9296*4882a593Smuzhiyun #define PWRREQ_OFFSET(sih)	OFFSETOF(chipcregs_t, powerctl)
9297*4882a593Smuzhiyun 
9298*4882a593Smuzhiyun static void
BCMPOSTTRAPFN(si_corereg_pciefast_write)9299*4882a593Smuzhiyun BCMPOSTTRAPFN(si_corereg_pciefast_write)(const si_t *sih, uint regoff, uint val)
9300*4882a593Smuzhiyun {
9301*4882a593Smuzhiyun 	volatile uint32 *r = NULL;
9302*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9303*4882a593Smuzhiyun 
9304*4882a593Smuzhiyun 	ASSERT((BUSTYPE(sih->bustype) == PCI_BUS));
9305*4882a593Smuzhiyun 
9306*4882a593Smuzhiyun 	r = (volatile uint32 *)((volatile char *)sii->curmap +
9307*4882a593Smuzhiyun 		PCI_16KB0_PCIREGS_OFFSET + regoff);
9308*4882a593Smuzhiyun 
9309*4882a593Smuzhiyun 	W_REG(sii->osh, r, val);
9310*4882a593Smuzhiyun }
9311*4882a593Smuzhiyun 
9312*4882a593Smuzhiyun static uint
BCMPOSTTRAPFN(si_corereg_pciefast_read)9313*4882a593Smuzhiyun BCMPOSTTRAPFN(si_corereg_pciefast_read)(const si_t *sih, uint regoff)
9314*4882a593Smuzhiyun {
9315*4882a593Smuzhiyun 	volatile uint32 *r = NULL;
9316*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9317*4882a593Smuzhiyun 
9318*4882a593Smuzhiyun 	ASSERT((BUSTYPE(sih->bustype) == PCI_BUS));
9319*4882a593Smuzhiyun 
9320*4882a593Smuzhiyun 	r = (volatile uint32 *)((volatile char *)sii->curmap +
9321*4882a593Smuzhiyun 		PCI_16KB0_PCIREGS_OFFSET + regoff);
9322*4882a593Smuzhiyun 
9323*4882a593Smuzhiyun 	return R_REG(sii->osh, r);
9324*4882a593Smuzhiyun }
9325*4882a593Smuzhiyun 
9326*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_srpwr_request)9327*4882a593Smuzhiyun BCMPOSTTRAPFN(si_srpwr_request)(const si_t *sih, uint32 mask, uint32 val)
9328*4882a593Smuzhiyun {
9329*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9330*4882a593Smuzhiyun 	uint32 r, offset = (BUSTYPE(sih->bustype) == SI_BUS) ?
9331*4882a593Smuzhiyun 		OFFSETOF(chipcregs_t, powerctl) : PWRREQ_OFFSET(sih);
9332*4882a593Smuzhiyun 	uint32 mask2 = mask;
9333*4882a593Smuzhiyun 	uint32 val2 = val;
9334*4882a593Smuzhiyun 	volatile uint32 *fast_srpwr_addr = (volatile uint32 *)((uintptr)SI_ENUM_BASE(sih)
9335*4882a593Smuzhiyun 					 + (uintptr)offset);
9336*4882a593Smuzhiyun 
9337*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
9338*4882a593Smuzhiyun 		return 0;
9339*4882a593Smuzhiyun 	}
9340*4882a593Smuzhiyun 
9341*4882a593Smuzhiyun 	if (mask || val) {
9342*4882a593Smuzhiyun 		mask <<= SRPWR_REQON_SHIFT;
9343*4882a593Smuzhiyun 		val  <<= SRPWR_REQON_SHIFT;
9344*4882a593Smuzhiyun 
9345*4882a593Smuzhiyun 		/* Return if requested power request is already set */
9346*4882a593Smuzhiyun 		if (BUSTYPE(sih->bustype) == SI_BUS) {
9347*4882a593Smuzhiyun 			r = R_REG(sii->osh, fast_srpwr_addr);
9348*4882a593Smuzhiyun 		} else {
9349*4882a593Smuzhiyun 			r = si_corereg_pciefast_read(sih, offset);
9350*4882a593Smuzhiyun 		}
9351*4882a593Smuzhiyun 
9352*4882a593Smuzhiyun 		if ((r & mask) == val) {
9353*4882a593Smuzhiyun 			return r;
9354*4882a593Smuzhiyun 		}
9355*4882a593Smuzhiyun 
9356*4882a593Smuzhiyun 		r = (r & ~mask) | val;
9357*4882a593Smuzhiyun 
9358*4882a593Smuzhiyun 		if (BUSTYPE(sih->bustype) == SI_BUS) {
9359*4882a593Smuzhiyun 			W_REG(sii->osh, fast_srpwr_addr, r);
9360*4882a593Smuzhiyun 			r = R_REG(sii->osh, fast_srpwr_addr);
9361*4882a593Smuzhiyun 		} else {
9362*4882a593Smuzhiyun 			si_corereg_pciefast_write(sih, offset, r);
9363*4882a593Smuzhiyun 			r = si_corereg_pciefast_read(sih, offset);
9364*4882a593Smuzhiyun 		}
9365*4882a593Smuzhiyun 
9366*4882a593Smuzhiyun 		if (val2) {
9367*4882a593Smuzhiyun 			if ((r & (mask2 << SRPWR_STATUS_SHIFT)) ==
9368*4882a593Smuzhiyun 			(val2 << SRPWR_STATUS_SHIFT)) {
9369*4882a593Smuzhiyun 				return r;
9370*4882a593Smuzhiyun 			}
9371*4882a593Smuzhiyun 			si_srpwr_stat_spinwait(sih, mask2, val2);
9372*4882a593Smuzhiyun 		}
9373*4882a593Smuzhiyun 	} else {
9374*4882a593Smuzhiyun 		if (BUSTYPE(sih->bustype) == SI_BUS) {
9375*4882a593Smuzhiyun 			r = R_REG(sii->osh, fast_srpwr_addr);
9376*4882a593Smuzhiyun 		} else {
9377*4882a593Smuzhiyun 			r = si_corereg_pciefast_read(sih, offset);
9378*4882a593Smuzhiyun 		}
9379*4882a593Smuzhiyun 	}
9380*4882a593Smuzhiyun 
9381*4882a593Smuzhiyun 	return r;
9382*4882a593Smuzhiyun }
9383*4882a593Smuzhiyun 
9384*4882a593Smuzhiyun #ifdef CORE_PWRUP_WAR
9385*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_srpwr_request_on_rev80)9386*4882a593Smuzhiyun BCMPOSTTRAPFN(si_srpwr_request_on_rev80)(si_t *sih, uint32 mask, uint32 val, uint32 ucode_awake)
9387*4882a593Smuzhiyun {
9388*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9389*4882a593Smuzhiyun 	uint32 r, offset = OFFSETOF(chipcregs_t, powerctl); /* Same 0x1e8 per core */
9390*4882a593Smuzhiyun 	uint cidx = (BUSTYPE(sih->bustype) == SI_BUS) ? SI_CC_IDX : sih->buscoreidx;
9391*4882a593Smuzhiyun 	uint32 mask2 = mask;
9392*4882a593Smuzhiyun 	uint32 val2 = val;
9393*4882a593Smuzhiyun 	volatile uint32 *fast_srpwr_addr = (volatile uint32 *)((uintptr)SI_ENUM_BASE(sih)
9394*4882a593Smuzhiyun 					 + (uintptr)offset);
9395*4882a593Smuzhiyun 	if (mask || val) {
9396*4882a593Smuzhiyun 		mask <<= SRPWR_REQON_SHIFT;
9397*4882a593Smuzhiyun 		val  <<= SRPWR_REQON_SHIFT;
9398*4882a593Smuzhiyun 
9399*4882a593Smuzhiyun 		/* Return if requested power request is already set */
9400*4882a593Smuzhiyun 		if (BUSTYPE(sih->bustype) == SI_BUS) {
9401*4882a593Smuzhiyun 			r = R_REG(sii->osh, fast_srpwr_addr);
9402*4882a593Smuzhiyun 		} else {
9403*4882a593Smuzhiyun 			r = si_corereg(sih, cidx, offset, 0, 0);
9404*4882a593Smuzhiyun 		}
9405*4882a593Smuzhiyun 
9406*4882a593Smuzhiyun 		if ((r & mask) == val) {
9407*4882a593Smuzhiyun 			W_REG(sii->osh, fast_srpwr_addr, r);
9408*4882a593Smuzhiyun 			return r;
9409*4882a593Smuzhiyun 		}
9410*4882a593Smuzhiyun 
9411*4882a593Smuzhiyun 		r = (r & ~mask) | val;
9412*4882a593Smuzhiyun 
9413*4882a593Smuzhiyun 		if (BUSTYPE(sih->bustype) == SI_BUS) {
9414*4882a593Smuzhiyun 			W_REG(sii->osh, fast_srpwr_addr, r);
9415*4882a593Smuzhiyun 			r = R_REG(sii->osh, fast_srpwr_addr);
9416*4882a593Smuzhiyun 		} else {
9417*4882a593Smuzhiyun 			r = si_corereg(sih, cidx, offset, ~0, r);
9418*4882a593Smuzhiyun 		}
9419*4882a593Smuzhiyun 
9420*4882a593Smuzhiyun 		if (val2) {
9421*4882a593Smuzhiyun 
9422*4882a593Smuzhiyun 			/*
9423*4882a593Smuzhiyun 			 * When ucode is not requested to be awake by FW,
9424*4882a593Smuzhiyun 			 * the power status may indicate ON due to FW or
9425*4882a593Smuzhiyun 			 * ucode's earlier power down request is not
9426*4882a593Smuzhiyun 			 * honored yet. In such case, FW will find the
9427*4882a593Smuzhiyun 			 * power status high at this stage, but as it is in
9428*4882a593Smuzhiyun 			 * transition (from ON to OFF), it may go down any
9429*4882a593Smuzhiyun 			 * time and lead to AXI slave error. Hence we need
9430*4882a593Smuzhiyun 			 * a fixed delay to cross any such transition state.
9431*4882a593Smuzhiyun 			 */
9432*4882a593Smuzhiyun 			if (ucode_awake == 0) {
9433*4882a593Smuzhiyun 				hnd_delay(SRPWR_UP_DOWN_DELAY);
9434*4882a593Smuzhiyun 			}
9435*4882a593Smuzhiyun 
9436*4882a593Smuzhiyun 			if ((r & (mask2 << SRPWR_STATUS_SHIFT)) ==
9437*4882a593Smuzhiyun 			(val2 << SRPWR_STATUS_SHIFT)) {
9438*4882a593Smuzhiyun 				return r;
9439*4882a593Smuzhiyun 			}
9440*4882a593Smuzhiyun 			si_srpwr_stat_spinwait(sih, mask2, val2);
9441*4882a593Smuzhiyun 		}
9442*4882a593Smuzhiyun 	} else {
9443*4882a593Smuzhiyun 		if (BUSTYPE(sih->bustype) == SI_BUS) {
9444*4882a593Smuzhiyun 			r = R_REG(sii->osh, fast_srpwr_addr);
9445*4882a593Smuzhiyun 		} else {
9446*4882a593Smuzhiyun 			r = si_corereg(sih, cidx, offset, 0, 0);
9447*4882a593Smuzhiyun 		}
9448*4882a593Smuzhiyun 		SPINWAIT(((R_REG(sii->osh, fast_srpwr_addr) &
9449*4882a593Smuzhiyun 				(mask2 << SRPWR_REQON_SHIFT)) != 0),
9450*4882a593Smuzhiyun 				PMU_MAX_TRANSITION_DLY);
9451*4882a593Smuzhiyun 	}
9452*4882a593Smuzhiyun 
9453*4882a593Smuzhiyun 	return r;
9454*4882a593Smuzhiyun }
9455*4882a593Smuzhiyun #endif /* CORE_PWRUP_WAR */
9456*4882a593Smuzhiyun 
9457*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_srpwr_stat_spinwait)9458*4882a593Smuzhiyun BCMPOSTTRAPFN(si_srpwr_stat_spinwait)(const si_t *sih, uint32 mask, uint32 val)
9459*4882a593Smuzhiyun {
9460*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9461*4882a593Smuzhiyun 	uint32 r, offset = (BUSTYPE(sih->bustype) == SI_BUS) ?
9462*4882a593Smuzhiyun 		OFFSETOF(chipcregs_t, powerctl) : PWRREQ_OFFSET(sih);
9463*4882a593Smuzhiyun 	volatile uint32 *fast_srpwr_addr = (volatile uint32 *)((uintptr)SI_ENUM_BASE(sih)
9464*4882a593Smuzhiyun 					 + (uintptr)offset);
9465*4882a593Smuzhiyun 
9466*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
9467*4882a593Smuzhiyun 		return 0;
9468*4882a593Smuzhiyun 	}
9469*4882a593Smuzhiyun 	ASSERT(mask);
9470*4882a593Smuzhiyun 	ASSERT(val);
9471*4882a593Smuzhiyun 
9472*4882a593Smuzhiyun 	/* spinwait on pwrstatus */
9473*4882a593Smuzhiyun 	mask <<= SRPWR_STATUS_SHIFT;
9474*4882a593Smuzhiyun 	val <<= SRPWR_STATUS_SHIFT;
9475*4882a593Smuzhiyun 
9476*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == SI_BUS) {
9477*4882a593Smuzhiyun 		SPINWAIT(((R_REG(sii->osh, fast_srpwr_addr) & mask) != val),
9478*4882a593Smuzhiyun 			PMU_MAX_TRANSITION_DLY);
9479*4882a593Smuzhiyun 		r = R_REG(sii->osh, fast_srpwr_addr) & mask;
9480*4882a593Smuzhiyun 		ASSERT(r == val);
9481*4882a593Smuzhiyun 	} else {
9482*4882a593Smuzhiyun 		SPINWAIT(((si_corereg_pciefast_read(sih, offset) & mask) != val),
9483*4882a593Smuzhiyun 			PMU_MAX_TRANSITION_DLY);
9484*4882a593Smuzhiyun 		r = si_corereg_pciefast_read(sih, offset) & mask;
9485*4882a593Smuzhiyun 		ASSERT(r == val);
9486*4882a593Smuzhiyun 	}
9487*4882a593Smuzhiyun 
9488*4882a593Smuzhiyun 	r = (r >> SRPWR_STATUS_SHIFT) & SRPWR_DMN_ALL_MASK(sih);
9489*4882a593Smuzhiyun 
9490*4882a593Smuzhiyun 	return r;
9491*4882a593Smuzhiyun }
9492*4882a593Smuzhiyun 
9493*4882a593Smuzhiyun uint32
si_srpwr_stat(si_t * sih)9494*4882a593Smuzhiyun si_srpwr_stat(si_t *sih)
9495*4882a593Smuzhiyun {
9496*4882a593Smuzhiyun 	uint32 r, offset = (BUSTYPE(sih->bustype) == SI_BUS) ?
9497*4882a593Smuzhiyun 		OFFSETOF(chipcregs_t, powerctl) : PWRREQ_OFFSET(sih);
9498*4882a593Smuzhiyun 	uint cidx = (BUSTYPE(sih->bustype) == SI_BUS) ? SI_CC_IDX : sih->buscoreidx;
9499*4882a593Smuzhiyun 
9500*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == SI_BUS) {
9501*4882a593Smuzhiyun 		r = si_corereg(sih, cidx, offset, 0, 0);
9502*4882a593Smuzhiyun 	} else {
9503*4882a593Smuzhiyun 		r = si_corereg_pciefast_read(sih, offset);
9504*4882a593Smuzhiyun 	}
9505*4882a593Smuzhiyun 
9506*4882a593Smuzhiyun 	r = (r >> SRPWR_STATUS_SHIFT) & SRPWR_DMN_ALL_MASK(sih);
9507*4882a593Smuzhiyun 
9508*4882a593Smuzhiyun 	return r;
9509*4882a593Smuzhiyun }
9510*4882a593Smuzhiyun 
9511*4882a593Smuzhiyun uint32
si_srpwr_domain(si_t * sih)9512*4882a593Smuzhiyun si_srpwr_domain(si_t *sih)
9513*4882a593Smuzhiyun {
9514*4882a593Smuzhiyun 	uint32 r, offset = (BUSTYPE(sih->bustype) == SI_BUS) ?
9515*4882a593Smuzhiyun 		OFFSETOF(chipcregs_t, powerctl) : PWRREQ_OFFSET(sih);
9516*4882a593Smuzhiyun 	uint cidx = (BUSTYPE(sih->bustype) == SI_BUS) ? SI_CC_IDX : sih->buscoreidx;
9517*4882a593Smuzhiyun 
9518*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
9519*4882a593Smuzhiyun 		return 0;
9520*4882a593Smuzhiyun 	}
9521*4882a593Smuzhiyun 
9522*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == SI_BUS) {
9523*4882a593Smuzhiyun 		r = si_corereg(sih, cidx, offset, 0, 0);
9524*4882a593Smuzhiyun 	} else {
9525*4882a593Smuzhiyun 		r = si_corereg_pciefast_read(sih, offset);
9526*4882a593Smuzhiyun 	}
9527*4882a593Smuzhiyun 
9528*4882a593Smuzhiyun 	r = (r >> SRPWR_DMN_ID_SHIFT) & SRPWR_DMN_ID_MASK;
9529*4882a593Smuzhiyun 
9530*4882a593Smuzhiyun 	return r;
9531*4882a593Smuzhiyun }
9532*4882a593Smuzhiyun 
9533*4882a593Smuzhiyun uint8
si_srpwr_domain_wl(si_t * sih)9534*4882a593Smuzhiyun si_srpwr_domain_wl(si_t *sih)
9535*4882a593Smuzhiyun {
9536*4882a593Smuzhiyun 	return SRPWR_DMN1_ARMBPSD;
9537*4882a593Smuzhiyun }
9538*4882a593Smuzhiyun 
9539*4882a593Smuzhiyun bool
si_srpwr_cap(si_t * sih)9540*4882a593Smuzhiyun si_srpwr_cap(si_t *sih)
9541*4882a593Smuzhiyun {
9542*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
9543*4882a593Smuzhiyun 		return FALSE;
9544*4882a593Smuzhiyun 	}
9545*4882a593Smuzhiyun 
9546*4882a593Smuzhiyun 	/* If domain ID is non-zero, chip supports power domain control */
9547*4882a593Smuzhiyun 	return si_srpwr_domain(sih) != 0 ? TRUE : FALSE;
9548*4882a593Smuzhiyun }
9549*4882a593Smuzhiyun 
9550*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_srpwr_domain_all_mask)9551*4882a593Smuzhiyun BCMPOSTTRAPFN(si_srpwr_domain_all_mask)(const si_t *sih)
9552*4882a593Smuzhiyun {
9553*4882a593Smuzhiyun 	uint32 mask = SRPWR_DMN0_PCIE_MASK |
9554*4882a593Smuzhiyun 	              SRPWR_DMN1_ARMBPSD_MASK |
9555*4882a593Smuzhiyun 	              SRPWR_DMN2_MACAUX_MASK |
9556*4882a593Smuzhiyun 	              SRPWR_DMN3_MACMAIN_MASK;
9557*4882a593Smuzhiyun 
9558*4882a593Smuzhiyun 	if (si_scan_core_present(sih)) {
9559*4882a593Smuzhiyun 		mask |= SRPWR_DMN4_MACSCAN_MASK;
9560*4882a593Smuzhiyun 	}
9561*4882a593Smuzhiyun 
9562*4882a593Smuzhiyun 	return mask;
9563*4882a593Smuzhiyun }
9564*4882a593Smuzhiyun 
9565*4882a593Smuzhiyun uint32
si_srpwr_bt_status(si_t * sih)9566*4882a593Smuzhiyun si_srpwr_bt_status(si_t *sih)
9567*4882a593Smuzhiyun {
9568*4882a593Smuzhiyun 	uint32 r;
9569*4882a593Smuzhiyun 	uint32 offset = (BUSTYPE(sih->bustype) == SI_BUS) ?
9570*4882a593Smuzhiyun 		OFFSETOF(chipcregs_t, powerctl) : PWRREQ_OFFSET(sih);
9571*4882a593Smuzhiyun 	uint32 cidx = (BUSTYPE(sih->bustype) == SI_BUS) ? SI_CC_IDX : sih->buscoreidx;
9572*4882a593Smuzhiyun 
9573*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == SI_BUS) {
9574*4882a593Smuzhiyun 		r = si_corereg(sih, cidx, offset, 0, 0);
9575*4882a593Smuzhiyun 	} else {
9576*4882a593Smuzhiyun 		r = si_corereg_pciefast_read(sih, offset);
9577*4882a593Smuzhiyun 	}
9578*4882a593Smuzhiyun 
9579*4882a593Smuzhiyun 	r = (r >> SRPWR_BT_STATUS_SHIFT) & SRPWR_BT_STATUS_MASK;
9580*4882a593Smuzhiyun 
9581*4882a593Smuzhiyun 	return r;
9582*4882a593Smuzhiyun }
9583*4882a593Smuzhiyun /* Utility API to read/write the raw registers with absolute address.
9584*4882a593Smuzhiyun  * This function can be invoked from either FW or host driver.
9585*4882a593Smuzhiyun  */
9586*4882a593Smuzhiyun uint32
si_raw_reg(const si_t * sih,uint32 reg,uint32 val,uint32 wrire_req)9587*4882a593Smuzhiyun si_raw_reg(const si_t *sih, uint32 reg, uint32 val, uint32 wrire_req)
9588*4882a593Smuzhiyun {
9589*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9590*4882a593Smuzhiyun 	uint32 address_space = reg & ~0xFFF;
9591*4882a593Smuzhiyun 	volatile uint32 * addr = (void*)(uintptr)(reg);
9592*4882a593Smuzhiyun 	uint32 prev_value = 0;
9593*4882a593Smuzhiyun 	uint32 cfg_reg = 0;
9594*4882a593Smuzhiyun 
9595*4882a593Smuzhiyun 	if (sii == NULL) {
9596*4882a593Smuzhiyun 		return 0;
9597*4882a593Smuzhiyun 	}
9598*4882a593Smuzhiyun 
9599*4882a593Smuzhiyun 	/* No need to translate the absolute address on SI bus */
9600*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == SI_BUS) {
9601*4882a593Smuzhiyun 		goto skip_cfg;
9602*4882a593Smuzhiyun 	}
9603*4882a593Smuzhiyun 
9604*4882a593Smuzhiyun 	/* This API supports only the PCI host interface */
9605*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) != PCI_BUS) {
9606*4882a593Smuzhiyun 		return ID32_INVALID;
9607*4882a593Smuzhiyun 	}
9608*4882a593Smuzhiyun 
9609*4882a593Smuzhiyun 	if (PCIE_GEN2(sii)) {
9610*4882a593Smuzhiyun 		/* Use BAR0 Secondary window is PCIe Gen2.
9611*4882a593Smuzhiyun 		 * Set the secondary BAR0 Window to current register of interest
9612*4882a593Smuzhiyun 		 */
9613*4882a593Smuzhiyun 		addr = (volatile uint32*)(((volatile uint8*)sii->curmap) +
9614*4882a593Smuzhiyun 			PCI_SEC_BAR0_WIN_OFFSET + (reg & 0xfff));
9615*4882a593Smuzhiyun 		cfg_reg = PCIE2_BAR0_CORE2_WIN;
9616*4882a593Smuzhiyun 
9617*4882a593Smuzhiyun 	} else {
9618*4882a593Smuzhiyun 		/* PCIe Gen1 do not have secondary BAR0 window.
9619*4882a593Smuzhiyun 		 * reuse the BAR0 WIN2
9620*4882a593Smuzhiyun 		 */
9621*4882a593Smuzhiyun 		addr = (volatile uint32*)(((volatile uint8*)sii->curmap) +
9622*4882a593Smuzhiyun 			PCI_BAR0_WIN2_OFFSET + (reg & 0xfff));
9623*4882a593Smuzhiyun 		cfg_reg = PCI_BAR0_WIN2;
9624*4882a593Smuzhiyun 	}
9625*4882a593Smuzhiyun 
9626*4882a593Smuzhiyun 	prev_value = OSL_PCI_READ_CONFIG(sii->osh, cfg_reg, 4);
9627*4882a593Smuzhiyun 
9628*4882a593Smuzhiyun 	if (prev_value != address_space) {
9629*4882a593Smuzhiyun 		OSL_PCI_WRITE_CONFIG(sii->osh, cfg_reg,
9630*4882a593Smuzhiyun 			sizeof(uint32), address_space);
9631*4882a593Smuzhiyun 	} else {
9632*4882a593Smuzhiyun 		prev_value = 0;
9633*4882a593Smuzhiyun 	}
9634*4882a593Smuzhiyun 
9635*4882a593Smuzhiyun skip_cfg:
9636*4882a593Smuzhiyun 	if (wrire_req) {
9637*4882a593Smuzhiyun 		W_REG(sii->osh, addr, val);
9638*4882a593Smuzhiyun 	} else {
9639*4882a593Smuzhiyun 		val = R_REG(sii->osh, addr);
9640*4882a593Smuzhiyun 	}
9641*4882a593Smuzhiyun 
9642*4882a593Smuzhiyun 	if (prev_value) {
9643*4882a593Smuzhiyun 		/* Restore BAR0 WIN2 for PCIE GEN1 devices */
9644*4882a593Smuzhiyun 		OSL_PCI_WRITE_CONFIG(sii->osh,
9645*4882a593Smuzhiyun 			cfg_reg, sizeof(uint32), prev_value);
9646*4882a593Smuzhiyun 	}
9647*4882a593Smuzhiyun 
9648*4882a593Smuzhiyun 	return val;
9649*4882a593Smuzhiyun }
9650*4882a593Smuzhiyun 
9651*4882a593Smuzhiyun #ifdef DONGLEBUILD
9652*4882a593Smuzhiyun /* if the logs could be gathered, host could be notified with to take logs or not  */
9653*4882a593Smuzhiyun bool
BCMPOSTTRAPFN(si_check_enable_backplane_log)9654*4882a593Smuzhiyun BCMPOSTTRAPFN(si_check_enable_backplane_log)(const si_t *sih)
9655*4882a593Smuzhiyun {
9656*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI) {
9657*4882a593Smuzhiyun 		return ai_check_enable_backplane_log(sih);
9658*4882a593Smuzhiyun 	}
9659*4882a593Smuzhiyun 	return TRUE;
9660*4882a593Smuzhiyun }
9661*4882a593Smuzhiyun #endif /* DONGLEBUILD */
9662*4882a593Smuzhiyun 
9663*4882a593Smuzhiyun uint8
si_lhl_ps_mode(const si_t * sih)9664*4882a593Smuzhiyun si_lhl_ps_mode(const si_t *sih)
9665*4882a593Smuzhiyun {
9666*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9667*4882a593Smuzhiyun 	return sii->lhl_ps_mode;
9668*4882a593Smuzhiyun }
9669*4882a593Smuzhiyun 
9670*4882a593Smuzhiyun uint8
si_hib_ext_wakeup_isenab(const si_t * sih)9671*4882a593Smuzhiyun si_hib_ext_wakeup_isenab(const si_t *sih)
9672*4882a593Smuzhiyun {
9673*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
9674*4882a593Smuzhiyun 	return sii->hib_ext_wakeup_enab;
9675*4882a593Smuzhiyun }
9676*4882a593Smuzhiyun 
9677*4882a593Smuzhiyun static void
BCMATTACHFN(si_oob_war_BT_F1)9678*4882a593Smuzhiyun BCMATTACHFN(si_oob_war_BT_F1)(si_t *sih)
9679*4882a593Smuzhiyun {
9680*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
9681*4882a593Smuzhiyun 	volatile void *regs;
9682*4882a593Smuzhiyun 
9683*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
9684*4882a593Smuzhiyun 		return;
9685*4882a593Smuzhiyun 	}
9686*4882a593Smuzhiyun 	regs = si_setcore(sih, AXI2AHB_BRIDGE_ID, 0);
9687*4882a593Smuzhiyun 	ASSERT(regs);
9688*4882a593Smuzhiyun 	BCM_REFERENCE(regs);
9689*4882a593Smuzhiyun 
9690*4882a593Smuzhiyun 	si_wrapperreg(sih, AI_OOBSELINA30, 0xF00, 0x300);
9691*4882a593Smuzhiyun 
9692*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9693*4882a593Smuzhiyun }
9694*4882a593Smuzhiyun 
9695*4882a593Smuzhiyun #ifndef BCMDONGLEHOST
9696*4882a593Smuzhiyun 
9697*4882a593Smuzhiyun #define RF_SW_CTRL_ELNABYP_ANT_MASK	0x000CC330
9698*4882a593Smuzhiyun 
9699*4882a593Smuzhiyun /* These are the outputs to the rfem which go out via the CLB */
9700*4882a593Smuzhiyun #define RF_SW_CTRL_ELNABYP_2G0_MASK	0x00000010
9701*4882a593Smuzhiyun #define RF_SW_CTRL_ELNABYP_5G0_MASK	0x00000020
9702*4882a593Smuzhiyun #define RF_SW_CTRL_ELNABYP_2G1_MASK	0x00004000
9703*4882a593Smuzhiyun #define RF_SW_CTRL_ELNABYP_5G1_MASK	0x00008000
9704*4882a593Smuzhiyun 
9705*4882a593Smuzhiyun /* Feedback values go into the phy from CLB output
9706*4882a593Smuzhiyun  * The polarity of the feedback is opposite to the elnabyp signal going out to the rfem
9707*4882a593Smuzhiyun  */
9708*4882a593Smuzhiyun #define RF_SW_CTRL_ELNABYP_2G0_MASK_FB	0x00000100
9709*4882a593Smuzhiyun #define RF_SW_CTRL_ELNABYP_5G0_MASK_FB	0x00000200
9710*4882a593Smuzhiyun #define RF_SW_CTRL_ELNABYP_2G1_MASK_FB	0x00040000
9711*4882a593Smuzhiyun #define RF_SW_CTRL_ELNABYP_5G1_MASK_FB	0x00080000
9712*4882a593Smuzhiyun 
9713*4882a593Smuzhiyun /* The elnabyp override values for each rfem */
9714*4882a593Smuzhiyun #define ELNABYP_IOVAR_2G0_VALUE_MASK	0x01
9715*4882a593Smuzhiyun #define ELNABYP_IOVAR_5G0_VALUE_MASK	0x02
9716*4882a593Smuzhiyun #define ELNABYP_IOVAR_2G1_VALUE_MASK	0x04
9717*4882a593Smuzhiyun #define ELNABYP_IOVAR_5G1_VALUE_MASK	0x08
9718*4882a593Smuzhiyun 
9719*4882a593Smuzhiyun /* The elnabyp override enables for each rfem
9720*4882a593Smuzhiyun  * The values are 'don't care' if the corresponding enables are 0
9721*4882a593Smuzhiyun  */
9722*4882a593Smuzhiyun #define ELNABYP_IOVAR_2G0_ENABLE_MASK	0x10
9723*4882a593Smuzhiyun #define ELNABYP_IOVAR_5G0_ENABLE_MASK	0x20
9724*4882a593Smuzhiyun #define ELNABYP_IOVAR_2G1_ENABLE_MASK	0x40
9725*4882a593Smuzhiyun #define ELNABYP_IOVAR_5G1_ENABLE_MASK	0x80
9726*4882a593Smuzhiyun 
9727*4882a593Smuzhiyun #define ANTENNA_0_ENABLE	0x00000044
9728*4882a593Smuzhiyun #define ANTENNA_1_ENABLE	0x20000000
9729*4882a593Smuzhiyun #define RFFE_CTRL_START		0x80000000
9730*4882a593Smuzhiyun #define RFFE_CTRL_READ		0x40000000
9731*4882a593Smuzhiyun #define RFFE_CTRL_RFEM_SEL	0x08000000
9732*4882a593Smuzhiyun #define RFFE_MISC_EN_PHYCYCLES	0x00000002
9733*4882a593Smuzhiyun 
9734*4882a593Smuzhiyun void
si_rffe_rfem_init(si_t * sih)9735*4882a593Smuzhiyun si_rffe_rfem_init(si_t *sih)
9736*4882a593Smuzhiyun {
9737*4882a593Smuzhiyun 	ASSERT(GCI_OFFSETOF(sih, gci_chipctrl) == OFFSETOF(gciregs_t, gci_chipctrl));
9738*4882a593Smuzhiyun 	/* Enable RFFE clock
9739*4882a593Smuzhiyun 	 * GCI Chip Control reg 15 - Bits 29 & 30 (Global 509 & 510)
9740*4882a593Smuzhiyun 	 */
9741*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_15, ALLONES_32, 0x60000000);
9742*4882a593Smuzhiyun 	/* SDATA0/1 rf_sw_ctrl pull down
9743*4882a593Smuzhiyun 	 * GCI chip control reg 23 - Bits 29 & 30 (Global 765 & 766)
9744*4882a593Smuzhiyun 	 */
9745*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_23, 0x3 << 29, 0x3 << 29);
9746*4882a593Smuzhiyun 	/* RFFE Clk Ctrl Reg */
9747*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_clk_ctrl), ALLONES_32, 0x101);
9748*4882a593Smuzhiyun 
9749*4882a593Smuzhiyun 	/* Disable override control of RFFE controller and enable phy control */
9750*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_change_detect_ovr_wlmc), ALLONES_32, 0);
9751*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_change_detect_ovr_wlac), ALLONES_32, 0);
9752*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_change_detect_ovr_wlsc), ALLONES_32, 0);
9753*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_change_detect_ovr_btmc), ALLONES_32, 0);
9754*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_change_detect_ovr_btsc), ALLONES_32, 0);
9755*4882a593Smuzhiyun 
9756*4882a593Smuzhiyun 	/* reg address = 0x16, deviceID of rffe dev1 = 0xE, deviceID of dev0 = 0xC,
9757*4882a593Smuzhiyun 	 * last_mux_ctrl = 0, disable_preemption = 0 (1 for 4387b0), tssi_mask = 3, tssi_en = 0,
9758*4882a593Smuzhiyun 	 * rffe_disable_line1 = 0, enable rffe_en_phyaccess = 1,
9759*4882a593Smuzhiyun 	 * disable BRCM proprietary reg0 wr = 0
9760*4882a593Smuzhiyun 	 */
9761*4882a593Smuzhiyun 	if (sih->ccrev == 68) {
9762*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_misc_ctrl), ALLONES_32, 0x0016EC72);
9763*4882a593Smuzhiyun 	} else {
9764*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_misc_ctrl), ALLONES_32, 0x0016EC32);
9765*4882a593Smuzhiyun 	}
9766*4882a593Smuzhiyun 
9767*4882a593Smuzhiyun 	/* Enable Dual RFFE Master: rffe_single_master = 0
9768*4882a593Smuzhiyun 	 * Use Master0 SW interface only : rffe_dis_sw_intf_m1 = 1
9769*4882a593Smuzhiyun 	 */
9770*4882a593Smuzhiyun 	if (sih->ccrev >= 71) {
9771*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_clk_ctrl),
9772*4882a593Smuzhiyun 			1u << 20u | 1u << 26u, 1u << 26u);
9773*4882a593Smuzhiyun 	}
9774*4882a593Smuzhiyun 
9775*4882a593Smuzhiyun 	/* Enable antenna access for both cores */
9776*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_03, ALLONES_32, ANTENNA_0_ENABLE);
9777*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_02, ALLONES_32, ANTENNA_1_ENABLE);
9778*4882a593Smuzhiyun }
9779*4882a593Smuzhiyun 
9780*4882a593Smuzhiyun void
si_rffe_set_debug_mode(si_t * sih,bool enable)9781*4882a593Smuzhiyun si_rffe_set_debug_mode(si_t *sih, bool enable)
9782*4882a593Smuzhiyun {
9783*4882a593Smuzhiyun 	uint32 misc_ctrl_set = 0;
9784*4882a593Smuzhiyun 	/* Enable/Disable rffe_en_phyaccess bit */
9785*4882a593Smuzhiyun 	if (!enable) {
9786*4882a593Smuzhiyun 		misc_ctrl_set = RFFE_MISC_EN_PHYCYCLES;
9787*4882a593Smuzhiyun 	}
9788*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_misc_ctrl), RFFE_MISC_EN_PHYCYCLES,
9789*4882a593Smuzhiyun 		misc_ctrl_set);
9790*4882a593Smuzhiyun 
9791*4882a593Smuzhiyun 	sih->rffe_debug_mode =  enable;
9792*4882a593Smuzhiyun }
9793*4882a593Smuzhiyun 
9794*4882a593Smuzhiyun bool
si_rffe_get_debug_mode(si_t * sih)9795*4882a593Smuzhiyun si_rffe_get_debug_mode(si_t *sih)
9796*4882a593Smuzhiyun {
9797*4882a593Smuzhiyun 	return sih->rffe_debug_mode;
9798*4882a593Smuzhiyun }
9799*4882a593Smuzhiyun 
9800*4882a593Smuzhiyun int8
si_rffe_get_elnabyp_mode(si_t * sih)9801*4882a593Smuzhiyun si_rffe_get_elnabyp_mode(si_t *sih)
9802*4882a593Smuzhiyun {
9803*4882a593Smuzhiyun 	return sih->rffe_elnabyp_mode;
9804*4882a593Smuzhiyun }
9805*4882a593Smuzhiyun 
9806*4882a593Smuzhiyun int
si_rffe_set_elnabyp_mode(si_t * sih,uint8 mode)9807*4882a593Smuzhiyun si_rffe_set_elnabyp_mode(si_t *sih, uint8 mode)
9808*4882a593Smuzhiyun {
9809*4882a593Smuzhiyun 	int ret = BCME_OK;
9810*4882a593Smuzhiyun 	uint32 elnabyp_ovr_val = 0;
9811*4882a593Smuzhiyun 	uint32 elnabyp_ovr_en  = 0;
9812*4882a593Smuzhiyun 
9813*4882a593Smuzhiyun 	if ((mode & ELNABYP_IOVAR_2G0_VALUE_MASK) && (mode & ELNABYP_IOVAR_2G0_ENABLE_MASK)) {
9814*4882a593Smuzhiyun 		elnabyp_ovr_val |= RF_SW_CTRL_ELNABYP_2G0_MASK;
9815*4882a593Smuzhiyun 	} else if (mode & ELNABYP_IOVAR_2G0_ENABLE_MASK) {
9816*4882a593Smuzhiyun 		elnabyp_ovr_val |= RF_SW_CTRL_ELNABYP_2G0_MASK_FB;
9817*4882a593Smuzhiyun 	}
9818*4882a593Smuzhiyun 	if ((mode & ELNABYP_IOVAR_5G0_VALUE_MASK) && (mode & ELNABYP_IOVAR_5G0_ENABLE_MASK)) {
9819*4882a593Smuzhiyun 		elnabyp_ovr_val |= RF_SW_CTRL_ELNABYP_5G0_MASK;
9820*4882a593Smuzhiyun 	} else if (mode & ELNABYP_IOVAR_5G0_ENABLE_MASK) {
9821*4882a593Smuzhiyun 		elnabyp_ovr_val |= RF_SW_CTRL_ELNABYP_5G0_MASK_FB;
9822*4882a593Smuzhiyun 	}
9823*4882a593Smuzhiyun 	if ((mode & ELNABYP_IOVAR_2G1_VALUE_MASK) && (mode & ELNABYP_IOVAR_2G1_ENABLE_MASK)) {
9824*4882a593Smuzhiyun 		elnabyp_ovr_val |= RF_SW_CTRL_ELNABYP_2G1_MASK;
9825*4882a593Smuzhiyun 	} else if (mode & ELNABYP_IOVAR_2G1_ENABLE_MASK) {
9826*4882a593Smuzhiyun 		elnabyp_ovr_val |= RF_SW_CTRL_ELNABYP_2G1_MASK_FB;
9827*4882a593Smuzhiyun 	}
9828*4882a593Smuzhiyun 	if ((mode & ELNABYP_IOVAR_5G1_VALUE_MASK) && (mode & ELNABYP_IOVAR_5G1_ENABLE_MASK)) {
9829*4882a593Smuzhiyun 		elnabyp_ovr_val |= RF_SW_CTRL_ELNABYP_5G1_MASK;
9830*4882a593Smuzhiyun 	} else if (mode & ELNABYP_IOVAR_5G1_ENABLE_MASK) {
9831*4882a593Smuzhiyun 		elnabyp_ovr_val |= RF_SW_CTRL_ELNABYP_5G1_MASK_FB;
9832*4882a593Smuzhiyun 	}
9833*4882a593Smuzhiyun 
9834*4882a593Smuzhiyun 	if (mode & ELNABYP_IOVAR_2G0_ENABLE_MASK) {
9835*4882a593Smuzhiyun 		elnabyp_ovr_en |= (RF_SW_CTRL_ELNABYP_2G0_MASK | RF_SW_CTRL_ELNABYP_2G0_MASK_FB);
9836*4882a593Smuzhiyun 	}
9837*4882a593Smuzhiyun 	if (mode & ELNABYP_IOVAR_5G0_ENABLE_MASK) {
9838*4882a593Smuzhiyun 		elnabyp_ovr_en |= (RF_SW_CTRL_ELNABYP_5G0_MASK | RF_SW_CTRL_ELNABYP_5G0_MASK_FB);
9839*4882a593Smuzhiyun 	}
9840*4882a593Smuzhiyun 	if (mode & ELNABYP_IOVAR_2G1_ENABLE_MASK) {
9841*4882a593Smuzhiyun 		elnabyp_ovr_en |= (RF_SW_CTRL_ELNABYP_2G1_MASK | RF_SW_CTRL_ELNABYP_2G1_MASK_FB);
9842*4882a593Smuzhiyun 	}
9843*4882a593Smuzhiyun 	if (mode & ELNABYP_IOVAR_5G1_ENABLE_MASK) {
9844*4882a593Smuzhiyun 		elnabyp_ovr_en |= (RF_SW_CTRL_ELNABYP_5G1_MASK | RF_SW_CTRL_ELNABYP_5G1_MASK_FB);
9845*4882a593Smuzhiyun 	}
9846*4882a593Smuzhiyun 
9847*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_14, RF_SW_CTRL_ELNABYP_ANT_MASK,
9848*4882a593Smuzhiyun 		elnabyp_ovr_val);
9849*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_15, RF_SW_CTRL_ELNABYP_ANT_MASK,
9850*4882a593Smuzhiyun 		elnabyp_ovr_en);
9851*4882a593Smuzhiyun 
9852*4882a593Smuzhiyun 	sih->rffe_elnabyp_mode = mode;
9853*4882a593Smuzhiyun 
9854*4882a593Smuzhiyun 	return ret;
9855*4882a593Smuzhiyun }
9856*4882a593Smuzhiyun 
9857*4882a593Smuzhiyun int
BCMPOSTTRAPFN(si_rffe_rfem_read)9858*4882a593Smuzhiyun BCMPOSTTRAPFN(si_rffe_rfem_read)(si_t *sih, uint8 dev_id, uint8 antenna, uint16 reg_addr,
9859*4882a593Smuzhiyun 	uint32 *val)
9860*4882a593Smuzhiyun {
9861*4882a593Smuzhiyun 	int ret = BCME_OK;
9862*4882a593Smuzhiyun 	uint32 gci_rffe_ctrl_val, antenna_0_enable, antenna_1_enable;
9863*4882a593Smuzhiyun 	uint32 gci_rffe_ctrl = si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), 0, 0);
9864*4882a593Smuzhiyun 	uint32 gci_chipcontrol_03 = si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_03, 0, 0);
9865*4882a593Smuzhiyun 	uint32 gci_chipcontrol_02 = si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_02, 0, 0);
9866*4882a593Smuzhiyun 
9867*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), ALLONES_32, 0);
9868*4882a593Smuzhiyun 
9869*4882a593Smuzhiyun 	switch (antenna) {
9870*4882a593Smuzhiyun 		case 1:
9871*4882a593Smuzhiyun 			gci_rffe_ctrl_val = RFFE_CTRL_START | RFFE_CTRL_READ;
9872*4882a593Smuzhiyun 			antenna_0_enable = ANTENNA_0_ENABLE;
9873*4882a593Smuzhiyun 			antenna_1_enable = 0;
9874*4882a593Smuzhiyun 			break;
9875*4882a593Smuzhiyun 		case 2:
9876*4882a593Smuzhiyun 			gci_rffe_ctrl_val = RFFE_CTRL_START | RFFE_CTRL_READ | RFFE_CTRL_RFEM_SEL;
9877*4882a593Smuzhiyun 			antenna_0_enable = 0;
9878*4882a593Smuzhiyun 			antenna_1_enable = ANTENNA_1_ENABLE;
9879*4882a593Smuzhiyun 			break;
9880*4882a593Smuzhiyun 		default:
9881*4882a593Smuzhiyun 			ret = BCME_BADOPTION;
9882*4882a593Smuzhiyun 	}
9883*4882a593Smuzhiyun 
9884*4882a593Smuzhiyun 	if (ret == BCME_OK) {
9885*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_config), ALLONES_32,
9886*4882a593Smuzhiyun 			((uint16) dev_id) << 8);
9887*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_rfem_addr), ALLONES_32, reg_addr);
9888*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_03, ANTENNA_0_ENABLE, antenna_0_enable);
9889*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_02, ANTENNA_1_ENABLE, antenna_1_enable);
9890*4882a593Smuzhiyun 		/* Initiate read */
9891*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl),
9892*4882a593Smuzhiyun 			RFFE_CTRL_START | RFFE_CTRL_READ | RFFE_CTRL_RFEM_SEL, gci_rffe_ctrl_val);
9893*4882a593Smuzhiyun 		/* Wait for status */
9894*4882a593Smuzhiyun 		SPINWAIT(si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), 0, 0) &
9895*4882a593Smuzhiyun 			RFFE_CTRL_START, 100);
9896*4882a593Smuzhiyun 		if (si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), 0, 0) &
9897*4882a593Smuzhiyun 			RFFE_CTRL_START) {
9898*4882a593Smuzhiyun 			OSL_SYS_HALT();
9899*4882a593Smuzhiyun 			ret = BCME_NOTREADY;
9900*4882a593Smuzhiyun 		} else {
9901*4882a593Smuzhiyun 			*val = si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_rfem_data0), 0, 0);
9902*4882a593Smuzhiyun 			/* Clear read and rfem_sel flags */
9903*4882a593Smuzhiyun 			si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl),
9904*4882a593Smuzhiyun 				RFFE_CTRL_READ | RFFE_CTRL_RFEM_SEL, 0);
9905*4882a593Smuzhiyun 		}
9906*4882a593Smuzhiyun 	}
9907*4882a593Smuzhiyun 
9908*4882a593Smuzhiyun 	/* Restore the values */
9909*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), ALLONES_32, gci_rffe_ctrl);
9910*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_03, ALLONES_32, gci_chipcontrol_03);
9911*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_02, ALLONES_32, gci_chipcontrol_02);
9912*4882a593Smuzhiyun 	return ret;
9913*4882a593Smuzhiyun }
9914*4882a593Smuzhiyun 
9915*4882a593Smuzhiyun int
BCMPOSTTRAPFN(si_rffe_rfem_write)9916*4882a593Smuzhiyun BCMPOSTTRAPFN(si_rffe_rfem_write)(si_t *sih, uint8 dev_id, uint8 antenna, uint16 reg_addr,
9917*4882a593Smuzhiyun 	uint32 data)
9918*4882a593Smuzhiyun {
9919*4882a593Smuzhiyun 	int ret = BCME_OK;
9920*4882a593Smuzhiyun 	uint32 antenna_0_enable, antenna_1_enable;
9921*4882a593Smuzhiyun 	uint32 gci_rffe_ctrl = si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), 0, 0);
9922*4882a593Smuzhiyun 	uint32 gci_chipcontrol_03 = si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_03, 0, 0);
9923*4882a593Smuzhiyun 	uint32 gci_chipcontrol_02 = si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_02, 0, 0);
9924*4882a593Smuzhiyun 	uint8 repeat = (sih->ccrev == 69) ? 2 : 1; /* WAR for 4387c0 */
9925*4882a593Smuzhiyun 
9926*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), ALLONES_32, 0);
9927*4882a593Smuzhiyun 
9928*4882a593Smuzhiyun 	switch (antenna) {
9929*4882a593Smuzhiyun 		case 1:
9930*4882a593Smuzhiyun 			antenna_0_enable = ANTENNA_0_ENABLE;
9931*4882a593Smuzhiyun 			antenna_1_enable = 0;
9932*4882a593Smuzhiyun 			break;
9933*4882a593Smuzhiyun 		case 2:
9934*4882a593Smuzhiyun 			antenna_0_enable = 0;
9935*4882a593Smuzhiyun 			antenna_1_enable = ANTENNA_1_ENABLE;
9936*4882a593Smuzhiyun 			break;
9937*4882a593Smuzhiyun 		case 3:
9938*4882a593Smuzhiyun 			antenna_0_enable = ANTENNA_0_ENABLE;
9939*4882a593Smuzhiyun 			antenna_1_enable = ANTENNA_1_ENABLE;
9940*4882a593Smuzhiyun 			break;
9941*4882a593Smuzhiyun 		default:
9942*4882a593Smuzhiyun 			ret = BCME_BADOPTION;
9943*4882a593Smuzhiyun 	}
9944*4882a593Smuzhiyun 
9945*4882a593Smuzhiyun 	if (ret == BCME_OK) {
9946*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_config), ALLONES_32,
9947*4882a593Smuzhiyun 			((uint16) dev_id) << 8);
9948*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_rfem_addr), ALLONES_32, reg_addr);
9949*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_03, ANTENNA_0_ENABLE, antenna_0_enable);
9950*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_02, ANTENNA_1_ENABLE, antenna_1_enable);
9951*4882a593Smuzhiyun 		si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_rfem_data0), ALLONES_32, data);
9952*4882a593Smuzhiyun 		while (repeat--) {
9953*4882a593Smuzhiyun 			/* Initiate write */
9954*4882a593Smuzhiyun 			si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), RFFE_CTRL_START |
9955*4882a593Smuzhiyun 				RFFE_CTRL_READ | RFFE_CTRL_RFEM_SEL, RFFE_CTRL_START);
9956*4882a593Smuzhiyun 			/* Wait for status */
9957*4882a593Smuzhiyun 			SPINWAIT(si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), 0, 0) &
9958*4882a593Smuzhiyun 				RFFE_CTRL_START, 100);
9959*4882a593Smuzhiyun 			if (si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), 0, 0) &
9960*4882a593Smuzhiyun 				RFFE_CTRL_START) {
9961*4882a593Smuzhiyun 				OSL_SYS_HALT();
9962*4882a593Smuzhiyun 				ret = BCME_NOTREADY;
9963*4882a593Smuzhiyun 			}
9964*4882a593Smuzhiyun 		}
9965*4882a593Smuzhiyun 	}
9966*4882a593Smuzhiyun 
9967*4882a593Smuzhiyun 	/* Restore the values */
9968*4882a593Smuzhiyun 	si_gci_direct(sih, OFFSETOF(gciregs_t, gci_rffe_ctrl), ALLONES_32, gci_rffe_ctrl);
9969*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_03, ALLONES_32, gci_chipcontrol_03);
9970*4882a593Smuzhiyun 	si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_02, ALLONES_32, gci_chipcontrol_02);
9971*4882a593Smuzhiyun 	return ret;
9972*4882a593Smuzhiyun }
9973*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
9974*4882a593Smuzhiyun 
9975*4882a593Smuzhiyun #if defined(BCMSDIODEV_ENABLED) && defined(ATE_BUILD)
9976*4882a593Smuzhiyun bool
si_chipcap_sdio_ate_only(const si_t * sih)9977*4882a593Smuzhiyun si_chipcap_sdio_ate_only(const si_t *sih)
9978*4882a593Smuzhiyun {
9979*4882a593Smuzhiyun 	bool ate_build = FALSE;
9980*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
9981*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
9982*4882a593Smuzhiyun 		if (CST4369_CHIPMODE_SDIOD(sih->chipst) &&
9983*4882a593Smuzhiyun 			CST4369_CHIPMODE_PCIE(sih->chipst)) {
9984*4882a593Smuzhiyun 			ate_build = TRUE;
9985*4882a593Smuzhiyun 		}
9986*4882a593Smuzhiyun 		break;
9987*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
9988*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
9989*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
9990*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
9991*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
9992*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
9993*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
9994*4882a593Smuzhiyun 		ate_build = TRUE;
9995*4882a593Smuzhiyun 		break;
9996*4882a593Smuzhiyun 	 case BCM4362_CHIP_GRPID:
9997*4882a593Smuzhiyun 		if (CST4362_CHIPMODE_SDIOD(sih->chipst) &&
9998*4882a593Smuzhiyun 			CST4362_CHIPMODE_PCIE(sih->chipst)) {
9999*4882a593Smuzhiyun 			ate_build = TRUE;
10000*4882a593Smuzhiyun 		}
10001*4882a593Smuzhiyun 		break;
10002*4882a593Smuzhiyun 	default:
10003*4882a593Smuzhiyun 		break;
10004*4882a593Smuzhiyun 	}
10005*4882a593Smuzhiyun 	return ate_build;
10006*4882a593Smuzhiyun }
10007*4882a593Smuzhiyun #endif /* BCMSDIODEV_ENABLED && ATE_BUILD */
10008*4882a593Smuzhiyun 
10009*4882a593Smuzhiyun #ifdef UART_TRAP_DBG
10010*4882a593Smuzhiyun void
si_dump_APB_Bridge_registers(const si_t * sih)10011*4882a593Smuzhiyun si_dump_APB_Bridge_registers(const si_t *sih)
10012*4882a593Smuzhiyun {
10013*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI) {
10014*4882a593Smuzhiyun 		ai_dump_APB_Bridge_registers(sih);
10015*4882a593Smuzhiyun 	}
10016*4882a593Smuzhiyun }
10017*4882a593Smuzhiyun #endif /* UART_TRAP_DBG */
10018*4882a593Smuzhiyun 
10019*4882a593Smuzhiyun void
si_force_clocks(const si_t * sih,uint clock_state)10020*4882a593Smuzhiyun si_force_clocks(const si_t *sih, uint clock_state)
10021*4882a593Smuzhiyun {
10022*4882a593Smuzhiyun 	if (CHIPTYPE(sih->socitype) == SOCI_AI) {
10023*4882a593Smuzhiyun 		ai_force_clocks(sih, clock_state);
10024*4882a593Smuzhiyun 	}
10025*4882a593Smuzhiyun }
10026*4882a593Smuzhiyun 
10027*4882a593Smuzhiyun /* Indicates to the siutils how the PICe BAR0 is mappend,
10028*4882a593Smuzhiyun  * used for siutils to arrange BAR0 window management,
10029*4882a593Smuzhiyun  * for PCI NIC driver.
10030*4882a593Smuzhiyun  *
10031*4882a593Smuzhiyun  * Here is the current scheme, which are all using BAR0:
10032*4882a593Smuzhiyun  *
10033*4882a593Smuzhiyun  * id     enum       wrapper
10034*4882a593Smuzhiyun  * ====   =========  =========
10035*4882a593Smuzhiyun  *    0   0000-0FFF  1000-1FFF
10036*4882a593Smuzhiyun  *    1   4000-4FFF  5000-5FFF
10037*4882a593Smuzhiyun  *    2   9000-9FFF  A000-AFFF
10038*4882a593Smuzhiyun  * >= 3   not supported
10039*4882a593Smuzhiyun  */
10040*4882a593Smuzhiyun void
si_set_slice_id(si_t * sih,uint8 slice)10041*4882a593Smuzhiyun si_set_slice_id(si_t *sih, uint8 slice)
10042*4882a593Smuzhiyun {
10043*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
10044*4882a593Smuzhiyun 
10045*4882a593Smuzhiyun 	sii->slice = slice;
10046*4882a593Smuzhiyun }
10047*4882a593Smuzhiyun 
10048*4882a593Smuzhiyun uint8
si_get_slice_id(const si_t * sih)10049*4882a593Smuzhiyun si_get_slice_id(const si_t *sih)
10050*4882a593Smuzhiyun {
10051*4882a593Smuzhiyun 	const si_info_t *sii = SI_INFO(sih);
10052*4882a593Smuzhiyun 
10053*4882a593Smuzhiyun 	return sii->slice;
10054*4882a593Smuzhiyun }
10055*4882a593Smuzhiyun 
10056*4882a593Smuzhiyun bool
BCMPOSTTRAPRAMFN(si_scan_core_present)10057*4882a593Smuzhiyun BCMPOSTTRAPRAMFN(si_scan_core_present)(const si_t *sih)
10058*4882a593Smuzhiyun {
10059*4882a593Smuzhiyun 	return (si_numcoreunits(sih, D11_CORE_ID) > 2);
10060*4882a593Smuzhiyun }
10061*4882a593Smuzhiyun 
10062*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
10063*4882a593Smuzhiyun bool
si_btc_bt_status_in_reset(si_t * sih)10064*4882a593Smuzhiyun si_btc_bt_status_in_reset(si_t *sih)
10065*4882a593Smuzhiyun {
10066*4882a593Smuzhiyun 	uint32 chipst = 0;
10067*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
10068*4882a593Smuzhiyun 		case BCM4387_CHIP_GRPID:
10069*4882a593Smuzhiyun 			chipst = si_corereg(sih, SI_CC_IDX,
10070*4882a593Smuzhiyun 				OFFSETOF(chipcregs_t, chipstatus), 0, 0);
10071*4882a593Smuzhiyun 			/* 1 =bt in reset 0 = bt out of reset */
10072*4882a593Smuzhiyun 			return (chipst & (1 << BT_IN_RESET_BIT_SHIFT)) ? TRUE : FALSE;
10073*4882a593Smuzhiyun 			break;
10074*4882a593Smuzhiyun 		default:
10075*4882a593Smuzhiyun 			ASSERT(0);
10076*4882a593Smuzhiyun 			break;
10077*4882a593Smuzhiyun 	}
10078*4882a593Smuzhiyun 	return FALSE;
10079*4882a593Smuzhiyun }
10080*4882a593Smuzhiyun 
10081*4882a593Smuzhiyun bool
si_btc_bt_status_in_pds(si_t * sih)10082*4882a593Smuzhiyun si_btc_bt_status_in_pds(si_t *sih)
10083*4882a593Smuzhiyun {
10084*4882a593Smuzhiyun 	return !((si_gci_chipstatus(sih, GCI_CHIPSTATUS_04) >>
10085*4882a593Smuzhiyun 		BT_IN_PDS_BIT_SHIFT) & 0x1);
10086*4882a593Smuzhiyun }
10087*4882a593Smuzhiyun 
10088*4882a593Smuzhiyun int
si_btc_bt_pds_wakeup_force(si_t * sih,bool force)10089*4882a593Smuzhiyun si_btc_bt_pds_wakeup_force(si_t *sih, bool force)
10090*4882a593Smuzhiyun {
10091*4882a593Smuzhiyun 	if (force) {
10092*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL0,
10093*4882a593Smuzhiyun 			PMU_CC0_4387_BT_PU_WAKE_MASK, PMU_CC0_4387_BT_PU_WAKE_MASK);
10094*4882a593Smuzhiyun 		SPINWAIT((si_btc_bt_status_in_pds(sih) == TRUE), PMU_MAX_TRANSITION_DLY);
10095*4882a593Smuzhiyun 		if (si_btc_bt_status_in_pds(sih) == TRUE) {
10096*4882a593Smuzhiyun 			SI_ERROR(("si_btc_bt_pds_wakeup_force"
10097*4882a593Smuzhiyun 				" ERROR : BT still in PDS after pds_wakeup_force \n"));
10098*4882a593Smuzhiyun 			return BCME_ERROR;
10099*4882a593Smuzhiyun 		} else {
10100*4882a593Smuzhiyun 			return BCME_OK;
10101*4882a593Smuzhiyun 		}
10102*4882a593Smuzhiyun 	} else {
10103*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL0, PMU_CC0_4387_BT_PU_WAKE_MASK, 0);
10104*4882a593Smuzhiyun 		return BCME_OK;
10105*4882a593Smuzhiyun 	}
10106*4882a593Smuzhiyun }
10107*4882a593Smuzhiyun 
10108*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
10109*4882a593Smuzhiyun 
10110*4882a593Smuzhiyun #ifndef BCMDONGLEHOST
10111*4882a593Smuzhiyun /* query d11 core type */
10112*4882a593Smuzhiyun uint
BCMATTACHFN(si_core_d11_type)10113*4882a593Smuzhiyun BCMATTACHFN(si_core_d11_type)(si_t *sih, uint coreunit)
10114*4882a593Smuzhiyun {
10115*4882a593Smuzhiyun #ifdef WL_SCAN_CORE_SIM
10116*4882a593Smuzhiyun 	/* use the core unit WL_SCAN_CORE_SIM as the scan core */
10117*4882a593Smuzhiyun 	return (coreunit == WL_SCAN_CORE_SIM) ?
10118*4882a593Smuzhiyun 	        D11_CORE_TYPE_SCAN : D11_CORE_TYPE_NORM;
10119*4882a593Smuzhiyun #else
10120*4882a593Smuzhiyun 	uint coreidx;
10121*4882a593Smuzhiyun 	volatile void *regs;
10122*4882a593Smuzhiyun 	uint coretype;
10123*4882a593Smuzhiyun 
10124*4882a593Smuzhiyun 	coreidx = si_coreidx(sih);
10125*4882a593Smuzhiyun 	regs = si_setcore(sih, D11_CORE_ID, coreunit);
10126*4882a593Smuzhiyun 	ASSERT(regs != NULL);
10127*4882a593Smuzhiyun 	BCM_REFERENCE(regs);
10128*4882a593Smuzhiyun 
10129*4882a593Smuzhiyun 	coretype = (si_core_sflags(sih, 0, 0) & SISF_CORE_BITS_SCAN) != 0 ?
10130*4882a593Smuzhiyun 	        D11_CORE_TYPE_SCAN : D11_CORE_TYPE_NORM;
10131*4882a593Smuzhiyun 
10132*4882a593Smuzhiyun 	si_setcoreidx(sih, coreidx);
10133*4882a593Smuzhiyun 	return coretype;
10134*4882a593Smuzhiyun #endif /* WL_SCAN_CORE_SIM */
10135*4882a593Smuzhiyun }
10136*4882a593Smuzhiyun 
10137*4882a593Smuzhiyun /* decide if this core is allowed by the package option or not... */
10138*4882a593Smuzhiyun bool
BCMATTACHFN(si_pkgopt_d11_allowed)10139*4882a593Smuzhiyun BCMATTACHFN(si_pkgopt_d11_allowed)(si_t *sih, uint coreunit)
10140*4882a593Smuzhiyun {
10141*4882a593Smuzhiyun 	uint coreidx;
10142*4882a593Smuzhiyun 	volatile void *regs;
10143*4882a593Smuzhiyun 	bool allowed;
10144*4882a593Smuzhiyun 
10145*4882a593Smuzhiyun 	coreidx = si_coreidx(sih);
10146*4882a593Smuzhiyun 	regs = si_setcore(sih, D11_CORE_ID, coreunit);
10147*4882a593Smuzhiyun 	ASSERT(regs != NULL);
10148*4882a593Smuzhiyun 	BCM_REFERENCE(regs);
10149*4882a593Smuzhiyun 
10150*4882a593Smuzhiyun 	allowed = ((si_core_sflags(sih, 0, 0) & SISF_CORE_BITS_SCAN) == 0 ||
10151*4882a593Smuzhiyun 	        (si_gci_chipstatus(sih, GCI_CHIPSTATUS_09) & GCI_CST9_SCAN_DIS) == 0);
10152*4882a593Smuzhiyun 
10153*4882a593Smuzhiyun 	si_setcoreidx(sih, coreidx);
10154*4882a593Smuzhiyun 	return allowed;
10155*4882a593Smuzhiyun }
10156*4882a593Smuzhiyun 
10157*4882a593Smuzhiyun void
si_configure_pwrthrottle_gpio(si_t * sih,uint8 pwrthrottle_gpio_in)10158*4882a593Smuzhiyun si_configure_pwrthrottle_gpio(si_t *sih, uint8 pwrthrottle_gpio_in)
10159*4882a593Smuzhiyun {
10160*4882a593Smuzhiyun 	uint32 board_gpio = 0;
10161*4882a593Smuzhiyun 	if (CHIPID(sih->chip) == BCM4369_CHIP_ID || CHIPID(sih->chip) == BCM4377_CHIP_ID) {
10162*4882a593Smuzhiyun 		si_gci_set_functionsel(sih, pwrthrottle_gpio_in, 1);
10163*4882a593Smuzhiyun 	}
10164*4882a593Smuzhiyun 	board_gpio = 1 << pwrthrottle_gpio_in;
10165*4882a593Smuzhiyun 	si_gpiocontrol(sih, board_gpio, 0, GPIO_DRV_PRIORITY);
10166*4882a593Smuzhiyun 	si_gpioouten(sih, board_gpio, 0, GPIO_DRV_PRIORITY);
10167*4882a593Smuzhiyun }
10168*4882a593Smuzhiyun 
10169*4882a593Smuzhiyun void
si_configure_onbody_gpio(si_t * sih,uint8 onbody_gpio_in)10170*4882a593Smuzhiyun si_configure_onbody_gpio(si_t *sih, uint8 onbody_gpio_in)
10171*4882a593Smuzhiyun {
10172*4882a593Smuzhiyun 	uint32 board_gpio = 0;
10173*4882a593Smuzhiyun 	if (CHIPID(sih->chip) == BCM4369_CHIP_ID || CHIPID(sih->chip) == BCM4377_CHIP_ID) {
10174*4882a593Smuzhiyun 		si_gci_set_functionsel(sih, onbody_gpio_in, 1);
10175*4882a593Smuzhiyun 	}
10176*4882a593Smuzhiyun 	board_gpio = 1 << onbody_gpio_in;
10177*4882a593Smuzhiyun 	si_gpiocontrol(sih, board_gpio, 0, GPIO_DRV_PRIORITY);
10178*4882a593Smuzhiyun 	si_gpioouten(sih, board_gpio, 0, GPIO_DRV_PRIORITY);
10179*4882a593Smuzhiyun }
10180*4882a593Smuzhiyun 
10181*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
10182*4882a593Smuzhiyun 
10183*4882a593Smuzhiyun void
si_jtag_udr_pwrsw_main_toggle(si_t * sih,bool on)10184*4882a593Smuzhiyun si_jtag_udr_pwrsw_main_toggle(si_t *sih, bool on)
10185*4882a593Smuzhiyun {
10186*4882a593Smuzhiyun #ifdef DONGLEBUILD
10187*4882a593Smuzhiyun 	int val = on ? 0 : 1;
10188*4882a593Smuzhiyun 
10189*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
10190*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
10191*4882a593Smuzhiyun 		jtag_setbit_128(sih, 8, 99, val);
10192*4882a593Smuzhiyun 		jtag_setbit_128(sih, 8, 101, val);
10193*4882a593Smuzhiyun 		jtag_setbit_128(sih, 8, 105, val);
10194*4882a593Smuzhiyun 		break;
10195*4882a593Smuzhiyun 	default:
10196*4882a593Smuzhiyun 		SI_ERROR(("si_jtag_udr_pwrsw_main_toggle: add support for this chip!\n"));
10197*4882a593Smuzhiyun 		OSL_SYS_HALT();
10198*4882a593Smuzhiyun 		break;
10199*4882a593Smuzhiyun 	}
10200*4882a593Smuzhiyun #endif
10201*4882a593Smuzhiyun }
10202*4882a593Smuzhiyun 
10203*4882a593Smuzhiyun /* return the backplane address where the sssr dumps are stored per D11 core */
10204*4882a593Smuzhiyun uint32
BCMATTACHFN(si_d11_core_sssr_addr)10205*4882a593Smuzhiyun BCMATTACHFN(si_d11_core_sssr_addr)(si_t *sih, uint unit, uint32 *sssr_size)
10206*4882a593Smuzhiyun {
10207*4882a593Smuzhiyun 	uint32 sssr_dmp_src = 0;
10208*4882a593Smuzhiyun 	*sssr_size = 0;
10209*4882a593Smuzhiyun 	/* ideally these addresses should be grok'ed from EROM map */
10210*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
10211*4882a593Smuzhiyun 		case BCM4387_CHIP_GRPID:
10212*4882a593Smuzhiyun 			if (unit == 0) {
10213*4882a593Smuzhiyun 				sssr_dmp_src = BCM4387_SSSR_DUMP_AXI_MAIN;
10214*4882a593Smuzhiyun 				*sssr_size = (uint32)BCM4387_SSSR_DUMP_MAIN_SIZE;
10215*4882a593Smuzhiyun 			} else if (unit == 1) {
10216*4882a593Smuzhiyun 				sssr_dmp_src = BCM4387_SSSR_DUMP_AXI_AUX;
10217*4882a593Smuzhiyun 				*sssr_size = (uint32)BCM4387_SSSR_DUMP_AUX_SIZE;
10218*4882a593Smuzhiyun 			} else if (unit == 2) {
10219*4882a593Smuzhiyun 				sssr_dmp_src = BCM4387_SSSR_DUMP_AXI_SCAN;
10220*4882a593Smuzhiyun 				*sssr_size = (uint32)BCM4387_SSSR_DUMP_SCAN_SIZE;
10221*4882a593Smuzhiyun 			}
10222*4882a593Smuzhiyun 			break;
10223*4882a593Smuzhiyun 		default:
10224*4882a593Smuzhiyun 			break;
10225*4882a593Smuzhiyun 	}
10226*4882a593Smuzhiyun 	return (sssr_dmp_src);
10227*4882a593Smuzhiyun }
10228*4882a593Smuzhiyun 
10229*4882a593Smuzhiyun #ifdef USE_LHL_TIMER
10230*4882a593Smuzhiyun /* Get current HIB time API */
10231*4882a593Smuzhiyun uint32
si_cur_hib_time(si_t * sih)10232*4882a593Smuzhiyun si_cur_hib_time(si_t *sih)
10233*4882a593Smuzhiyun {
10234*4882a593Smuzhiyun 	uint32 hib_time;
10235*4882a593Smuzhiyun 
10236*4882a593Smuzhiyun 	hib_time = LHL_REG(sih, lhl_hibtim_adr, 0, 0);
10237*4882a593Smuzhiyun 
10238*4882a593Smuzhiyun 	/* there is no HW sync on the read path for LPO regs,
10239*4882a593Smuzhiyun 	 * so SW should read twice and if values are same,
10240*4882a593Smuzhiyun 	 * then use the value, else read again and use the
10241*4882a593Smuzhiyun 	 * latest value
10242*4882a593Smuzhiyun 	 */
10243*4882a593Smuzhiyun 	if (hib_time != LHL_REG(sih, lhl_hibtim_adr, 0, 0)) {
10244*4882a593Smuzhiyun 		hib_time = LHL_REG(sih, lhl_hibtim_adr, 0, 0);
10245*4882a593Smuzhiyun 	}
10246*4882a593Smuzhiyun 
10247*4882a593Smuzhiyun 	return (hib_time);
10248*4882a593Smuzhiyun }
10249*4882a593Smuzhiyun #endif /* USE_LHL_TIMER */
10250