xref: /OK3568_Linux_fs/external/rkwifibt/drivers/infineon/hndpmu.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Misc utility routines for accessing PMU corerev specific features
3*4882a593Smuzhiyun  * of the SiliconBackplane-based Broadcom chips.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Portions of this code are copyright (c) 2021 Cypress Semiconductor Corporation
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (C) 1999-2017, Broadcom Corporation
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *      Unless you and Broadcom execute a separate written software license
10*4882a593Smuzhiyun  * agreement governing use of this software, this software is licensed to you
11*4882a593Smuzhiyun  * under the terms of the GNU General Public License version 2 (the "GPL"),
12*4882a593Smuzhiyun  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13*4882a593Smuzhiyun  * following added to such license:
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  *      As a special exception, the copyright holders of this software give you
16*4882a593Smuzhiyun  * permission to link this software with independent modules, and to copy and
17*4882a593Smuzhiyun  * distribute the resulting executable under terms of your choice, provided that
18*4882a593Smuzhiyun  * you also meet, for each linked independent module, the terms and conditions of
19*4882a593Smuzhiyun  * the license of that module.  An independent module is a module which is not
20*4882a593Smuzhiyun  * derived from this software.  The special exception does not apply to any
21*4882a593Smuzhiyun  * modifications of the software.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  *      Notwithstanding the above, under no circumstances may you combine this
24*4882a593Smuzhiyun  * software in any way with any other Broadcom software provided under a license
25*4882a593Smuzhiyun  * other than the GPL, without Broadcom's express prior written consent.
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  * <<Broadcom-WL-IPTag/Open:>>
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * $Id: hndpmu.c 700652 2017-05-20 02:44:31Z $
31*4882a593Smuzhiyun  */
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /**
34*4882a593Smuzhiyun  * @file
35*4882a593Smuzhiyun  * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs.
36*4882a593Smuzhiyun  * However, in the context of this file the baseband ('BB') PLL/FLL is referred to.
37*4882a593Smuzhiyun  *
38*4882a593Smuzhiyun  * Throughout this code, the prefixes 'pmu1_' and 'pmu2_' are used.
39*4882a593Smuzhiyun  * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012)
40*4882a593Smuzhiyun  * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports
41*4882a593Smuzhiyun  * fractional frequency generation. pmu2_ does not support fractional frequency generation.
42*4882a593Smuzhiyun  */
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #include <bcm_cfg.h>
45*4882a593Smuzhiyun #include <typedefs.h>
46*4882a593Smuzhiyun #include <bcmdefs.h>
47*4882a593Smuzhiyun #include <osl.h>
48*4882a593Smuzhiyun #include <bcmutils.h>
49*4882a593Smuzhiyun #include <siutils.h>
50*4882a593Smuzhiyun #include <bcmdevs.h>
51*4882a593Smuzhiyun #include <hndsoc.h>
52*4882a593Smuzhiyun #include <sbchipc.h>
53*4882a593Smuzhiyun #include <hndchipc.h>
54*4882a593Smuzhiyun #include <hndpmu.h>
55*4882a593Smuzhiyun #include <hndlhl.h>
56*4882a593Smuzhiyun #if defined(BCMULP)
57*4882a593Smuzhiyun #include <ulp.h>
58*4882a593Smuzhiyun #endif /* defined(BCMULP) */
59*4882a593Smuzhiyun #include <sbgci.h>
60*4882a593Smuzhiyun #ifdef EVENT_LOG_COMPILE
61*4882a593Smuzhiyun #include <event_log.h>
62*4882a593Smuzhiyun #endif // endif
63*4882a593Smuzhiyun #include <sbgci.h>
64*4882a593Smuzhiyun #include <lpflags.h>
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define	PMU_ERROR(args)
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #define	PMU_MSG(args)
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /* To check in verbose debugging messages not intended
71*4882a593Smuzhiyun  * to be on except on private builds.
72*4882a593Smuzhiyun  */
73*4882a593Smuzhiyun #define	PMU_NONE(args)
74*4882a593Smuzhiyun #define flags_shift	14
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /** contains resource bit positions for a specific chip */
77*4882a593Smuzhiyun struct rsc_per_chip_s {
78*4882a593Smuzhiyun 	uint8 ht_avail;
79*4882a593Smuzhiyun 	uint8 macphy_clkavail;
80*4882a593Smuzhiyun 	uint8 ht_start;
81*4882a593Smuzhiyun 	uint8 otp_pu;
82*4882a593Smuzhiyun 	uint8 macphy_aux_clkavail;
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun typedef struct rsc_per_chip_s rsc_per_chip_t;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #if defined(BCMPMU_STATS) && !defined(BCMPMU_STATS_DISABLED)
88*4882a593Smuzhiyun bool	_pmustatsenab = TRUE;
89*4882a593Smuzhiyun #else
90*4882a593Smuzhiyun bool	_pmustatsenab = FALSE;
91*4882a593Smuzhiyun #endif /* BCMPMU_STATS */
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /**
94*4882a593Smuzhiyun  * Balance between stable SDIO operation and power consumption is achieved using this function.
95*4882a593Smuzhiyun  * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this
96*4882a593Smuzhiyun  * function should read the VDDIO itself to select the correct table. For now it has been solved
97*4882a593Smuzhiyun  * with the 'BCM_SDIO_VDDIO' preprocessor constant.
98*4882a593Smuzhiyun  *
99*4882a593Smuzhiyun  * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if
100*4882a593Smuzhiyun  *		    hardware supports this), if no hw support drive strength is not programmed.
101*4882a593Smuzhiyun  */
102*4882a593Smuzhiyun void
si_sdiod_drive_strength_init(si_t * sih,osl_t * osh,uint32 drivestrength)103*4882a593Smuzhiyun si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	/*
106*4882a593Smuzhiyun 	 * Note:
107*4882a593Smuzhiyun 	 * This function used to set the SDIO drive strength via PMU_CHIPCTL1 for the
108*4882a593Smuzhiyun 	 * 43143, 4330, 4334, 4336, 43362 chips.  These chips are now no longer supported, so
109*4882a593Smuzhiyun 	 * the code has been deleted.
110*4882a593Smuzhiyun 	 * Newer chips have the SDIO drive strength setting via a GCI Chip Control register,
111*4882a593Smuzhiyun 	 * but the bit definitions are chip-specific.  We are keeping this function available
112*4882a593Smuzhiyun 	 * (accessed via DHD 'sdiod_drive' IOVar) in case these newer chips need to provide access.
113*4882a593Smuzhiyun 	 */
114*4882a593Smuzhiyun 	UNUSED_PARAMETER(sih);
115*4882a593Smuzhiyun 	UNUSED_PARAMETER(osh);
116*4882a593Smuzhiyun 	UNUSED_PARAMETER(drivestrength);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun void
si_switch_pmu_dependency(si_t * sih,uint mode)120*4882a593Smuzhiyun si_switch_pmu_dependency(si_t *sih, uint mode)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun #ifdef DUAL_PMU_SEQUENCE
123*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
124*4882a593Smuzhiyun 	uint32 current_res_state;
125*4882a593Smuzhiyun 	uint32 min_mask, max_mask;
126*4882a593Smuzhiyun 	const pmu_res_depend_t *pmu_res_depend_table = NULL;
127*4882a593Smuzhiyun 	uint pmu_res_depend_table_sz = 0;
128*4882a593Smuzhiyun 	uint origidx;
129*4882a593Smuzhiyun 	pmuregs_t *pmu;
130*4882a593Smuzhiyun 	chipcregs_t *cc;
131*4882a593Smuzhiyun 	BCM_REFERENCE(cc);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
134*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
135*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
136*4882a593Smuzhiyun 		cc  = si_setcore(sih, CC_CORE_ID, 0);
137*4882a593Smuzhiyun 	} else {
138*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
139*4882a593Smuzhiyun 		cc  = si_setcoreidx(sih, SI_CC_IDX);
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	current_res_state = R_REG(osh, &pmu->res_state);
144*4882a593Smuzhiyun 	min_mask = R_REG(osh, &pmu->min_res_mask);
145*4882a593Smuzhiyun 	max_mask = R_REG(osh, &pmu->max_res_mask);
146*4882a593Smuzhiyun 	W_REG(osh, &pmu->min_res_mask, (min_mask | current_res_state));
147*4882a593Smuzhiyun 	switch (mode) {
148*4882a593Smuzhiyun 		case PMU_4364_1x1_MODE:
149*4882a593Smuzhiyun 		{
150*4882a593Smuzhiyun 			if (CHIPID(sih->chip) == BCM4364_CHIP_ID) {
151*4882a593Smuzhiyun 					pmu_res_depend_table = bcm4364a0_res_depend_1x1;
152*4882a593Smuzhiyun 					pmu_res_depend_table_sz =
153*4882a593Smuzhiyun 						ARRAYSIZE(bcm4364a0_res_depend_1x1);
154*4882a593Smuzhiyun 			max_mask = PMU_4364_MAX_MASK_1x1;
155*4882a593Smuzhiyun 			W_REG(osh, &pmu->res_table_sel, RES4364_SR_SAVE_RESTORE);
156*4882a593Smuzhiyun 			W_REG(osh, &pmu->res_updn_timer, PMU_4364_SAVE_RESTORE_UPDNTIME_1x1);
157*4882a593Smuzhiyun #if defined(SAVERESTORE)
158*4882a593Smuzhiyun 				if (SR_ENAB()) {
159*4882a593Smuzhiyun 					/* Disable 3x3 SR engine */
160*4882a593Smuzhiyun 					W_REG(osh, &cc->sr1_control0,
161*4882a593Smuzhiyun 					CC_SR0_4364_SR_ENG_CLK_EN |
162*4882a593Smuzhiyun 					CC_SR0_4364_SR_RSRC_TRIGGER |
163*4882a593Smuzhiyun 					CC_SR0_4364_SR_WD_MEM_MIN_DIV |
164*4882a593Smuzhiyun 					CC_SR0_4364_SR_INVERT_CLK |
165*4882a593Smuzhiyun 					CC_SR0_4364_SR_ENABLE_HT |
166*4882a593Smuzhiyun 					CC_SR0_4364_SR_ALLOW_PIC |
167*4882a593Smuzhiyun 					CC_SR0_4364_SR_PMU_MEM_DISABLE);
168*4882a593Smuzhiyun 				}
169*4882a593Smuzhiyun #endif /* SAVERESTORE */
170*4882a593Smuzhiyun 			}
171*4882a593Smuzhiyun 			break;
172*4882a593Smuzhiyun 		}
173*4882a593Smuzhiyun 		case PMU_4364_3x3_MODE:
174*4882a593Smuzhiyun 		{
175*4882a593Smuzhiyun 			if (CHIPID(sih->chip) == BCM4364_CHIP_ID) {
176*4882a593Smuzhiyun 				W_REG(osh, &pmu->res_table_sel, RES4364_SR_SAVE_RESTORE);
177*4882a593Smuzhiyun 				W_REG(osh, &pmu->res_updn_timer,
178*4882a593Smuzhiyun 					PMU_4364_SAVE_RESTORE_UPDNTIME_3x3);
179*4882a593Smuzhiyun 				/* Change the dependency table only if required */
180*4882a593Smuzhiyun 				if ((max_mask != PMU_4364_MAX_MASK_3x3) ||
181*4882a593Smuzhiyun 					(max_mask != PMU_4364_MAX_MASK_RSDB)) {
182*4882a593Smuzhiyun 						pmu_res_depend_table = bcm4364a0_res_depend_rsdb;
183*4882a593Smuzhiyun 						pmu_res_depend_table_sz =
184*4882a593Smuzhiyun 							ARRAYSIZE(bcm4364a0_res_depend_rsdb);
185*4882a593Smuzhiyun 						max_mask = PMU_4364_MAX_MASK_3x3;
186*4882a593Smuzhiyun 				}
187*4882a593Smuzhiyun #if defined(SAVERESTORE)
188*4882a593Smuzhiyun 				if (SR_ENAB()) {
189*4882a593Smuzhiyun 					/* Enable 3x3 SR engine */
190*4882a593Smuzhiyun 					W_REG(osh, &cc->sr1_control0,
191*4882a593Smuzhiyun 					CC_SR0_4364_SR_ENG_CLK_EN |
192*4882a593Smuzhiyun 					CC_SR0_4364_SR_RSRC_TRIGGER |
193*4882a593Smuzhiyun 					CC_SR0_4364_SR_WD_MEM_MIN_DIV |
194*4882a593Smuzhiyun 					CC_SR0_4364_SR_INVERT_CLK |
195*4882a593Smuzhiyun 					CC_SR0_4364_SR_ENABLE_HT |
196*4882a593Smuzhiyun 					CC_SR0_4364_SR_ALLOW_PIC |
197*4882a593Smuzhiyun 					CC_SR0_4364_SR_PMU_MEM_DISABLE |
198*4882a593Smuzhiyun 					CC_SR0_4364_SR_ENG_EN_MASK);
199*4882a593Smuzhiyun 				}
200*4882a593Smuzhiyun #endif /* SAVERESTORE */
201*4882a593Smuzhiyun 			}
202*4882a593Smuzhiyun 			break;
203*4882a593Smuzhiyun 		}
204*4882a593Smuzhiyun 		case PMU_4364_RSDB_MODE:
205*4882a593Smuzhiyun 		default:
206*4882a593Smuzhiyun 		{
207*4882a593Smuzhiyun 			if (CHIPID(sih->chip) == BCM4364_CHIP_ID) {
208*4882a593Smuzhiyun 				W_REG(osh, &pmu->res_table_sel, RES4364_SR_SAVE_RESTORE);
209*4882a593Smuzhiyun 				W_REG(osh, &pmu->res_updn_timer,
210*4882a593Smuzhiyun 					PMU_4364_SAVE_RESTORE_UPDNTIME_3x3);
211*4882a593Smuzhiyun 				/* Change the dependency table only if required */
212*4882a593Smuzhiyun 				if ((max_mask != PMU_4364_MAX_MASK_3x3) ||
213*4882a593Smuzhiyun 					(max_mask != PMU_4364_MAX_MASK_RSDB)) {
214*4882a593Smuzhiyun 						pmu_res_depend_table =
215*4882a593Smuzhiyun 							bcm4364a0_res_depend_rsdb;
216*4882a593Smuzhiyun 						pmu_res_depend_table_sz =
217*4882a593Smuzhiyun 							ARRAYSIZE(bcm4364a0_res_depend_rsdb);
218*4882a593Smuzhiyun 						max_mask = PMU_4364_MAX_MASK_RSDB;
219*4882a593Smuzhiyun 				}
220*4882a593Smuzhiyun #if defined(SAVERESTORE)
221*4882a593Smuzhiyun 			if (SR_ENAB()) {
222*4882a593Smuzhiyun 					/* Enable 3x3 SR engine */
223*4882a593Smuzhiyun 					W_REG(osh, &cc->sr1_control0,
224*4882a593Smuzhiyun 					CC_SR0_4364_SR_ENG_CLK_EN |
225*4882a593Smuzhiyun 					CC_SR0_4364_SR_RSRC_TRIGGER |
226*4882a593Smuzhiyun 					CC_SR0_4364_SR_WD_MEM_MIN_DIV |
227*4882a593Smuzhiyun 					CC_SR0_4364_SR_INVERT_CLK |
228*4882a593Smuzhiyun 					CC_SR0_4364_SR_ENABLE_HT |
229*4882a593Smuzhiyun 					CC_SR0_4364_SR_ALLOW_PIC |
230*4882a593Smuzhiyun 					CC_SR0_4364_SR_PMU_MEM_DISABLE |
231*4882a593Smuzhiyun 					CC_SR0_4364_SR_ENG_EN_MASK);
232*4882a593Smuzhiyun 				}
233*4882a593Smuzhiyun #endif /* SAVERESTORE */
234*4882a593Smuzhiyun 			}
235*4882a593Smuzhiyun 			break;
236*4882a593Smuzhiyun 		}
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 	si_pmu_resdeptbl_upd(sih, osh, pmu, pmu_res_depend_table, pmu_res_depend_table_sz);
239*4882a593Smuzhiyun 	W_REG(osh, &pmu->max_res_mask, max_mask);
240*4882a593Smuzhiyun 	W_REG(osh, &pmu->min_res_mask, min_mask);
241*4882a593Smuzhiyun 	si_pmu_wait_for_steady_state(sih, osh, pmu);
242*4882a593Smuzhiyun 	/* Add some delay; allow resources to come up and settle. */
243*4882a593Smuzhiyun 	OSL_DELAY(200);
244*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
245*4882a593Smuzhiyun #endif /* DUAL_PMU_SEQUENCE */
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun #if defined(BCMULP)
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun int
si_pmu_ulp_register(si_t * sih)251*4882a593Smuzhiyun si_pmu_ulp_register(si_t *sih)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	return ulp_p1_module_register(ULP_MODULE_ID_PMU, &ulp_pmu_ctx, (void *)sih);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun static uint
si_pmu_ulp_get_retention_size_cb(void * handle,ulp_ext_info_t * einfo)257*4882a593Smuzhiyun si_pmu_ulp_get_retention_size_cb(void *handle, ulp_ext_info_t *einfo)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	ULP_DBG(("%s: sz: %d\n", __FUNCTION__, sizeof(si_pmu_ulp_cr_dat_t)));
260*4882a593Smuzhiyun 	return sizeof(si_pmu_ulp_cr_dat_t);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun static int
si_pmu_ulp_enter_cb(void * handle,ulp_ext_info_t * einfo,uint8 * cache_data)264*4882a593Smuzhiyun si_pmu_ulp_enter_cb(void *handle, ulp_ext_info_t *einfo, uint8 *cache_data)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	si_pmu_ulp_cr_dat_t crinfo = {0};
267*4882a593Smuzhiyun 	crinfo.ilpcycles_per_sec = ilpcycles_per_sec;
268*4882a593Smuzhiyun 	ULP_DBG(("%s: ilpcycles_per_sec: %x\n", __FUNCTION__, ilpcycles_per_sec));
269*4882a593Smuzhiyun 	memcpy(cache_data, (void*)&crinfo, sizeof(crinfo));
270*4882a593Smuzhiyun 	return BCME_OK;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun static int
si_pmu_ulp_exit_cb(void * handle,uint8 * cache_data,uint8 * p2_cache_data)274*4882a593Smuzhiyun si_pmu_ulp_exit_cb(void *handle, uint8 *cache_data,
275*4882a593Smuzhiyun 	uint8 *p2_cache_data)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	si_pmu_ulp_cr_dat_t *crinfo = (si_pmu_ulp_cr_dat_t *)cache_data;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	ilpcycles_per_sec = crinfo->ilpcycles_per_sec;
280*4882a593Smuzhiyun 	ULP_DBG(("%s: ilpcycles_per_sec: %x, cache_data: %p\n", __FUNCTION__,
281*4882a593Smuzhiyun 		ilpcycles_per_sec, cache_data));
282*4882a593Smuzhiyun 	return BCME_OK;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun void
si_pmu_ulp_chipconfig(si_t * sih,osl_t * osh)286*4882a593Smuzhiyun si_pmu_ulp_chipconfig(si_t *sih, osl_t *osh)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	uint32 reg_val;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	BCM_REFERENCE(reg_val);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	if (CHIPID(sih->chip) == BCM43012_CHIP_ID) {
293*4882a593Smuzhiyun 		/* DS1 reset and clk enable init value config */
294*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL14, ~0x0,
295*4882a593Smuzhiyun 			(PMUCCTL14_43012_ARMCM3_RESET_INITVAL |
296*4882a593Smuzhiyun 			PMUCCTL14_43012_DOT11MAC_CLKEN_INITVAL |
297*4882a593Smuzhiyun 			PMUCCTL14_43012_SDIOD_RESET_INIVAL |
298*4882a593Smuzhiyun 			PMUCCTL14_43012_SDIO_CLK_DMN_RESET_INITVAL |
299*4882a593Smuzhiyun 			PMUCCTL14_43012_SOCRAM_CLKEN_INITVAL |
300*4882a593Smuzhiyun 			PMUCCTL14_43012_M2MDMA_RESET_INITVAL |
301*4882a593Smuzhiyun 			PMUCCTL14_43012_DOT11MAC_PHY_CLK_EN_INITVAL |
302*4882a593Smuzhiyun 			PMUCCTL14_43012_DOT11MAC_PHY_CNTL_EN_INITVAL));
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 		/* Clear SFlash clock request and enable High Quality clock */
305*4882a593Smuzhiyun 		CHIPC_REG(sih, clk_ctl_st, CCS_SFLASH_CLKREQ | CCS_HQCLKREQ, CCS_HQCLKREQ);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 		reg_val = PMU_REG(sih, min_res_mask, ~0x0, ULP_MIN_RES_MASK);
308*4882a593Smuzhiyun 		ULP_DBG(("si_pmu_ulp_chipconfig: min_res_mask: 0x%08x\n", reg_val));
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 		/* Force power switch off */
311*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL2,
312*4882a593Smuzhiyun 				(PMUCCTL02_43012_SUBCORE_PWRSW_FORCE_ON |
313*4882a593Smuzhiyun 				PMUCCTL02_43012_PHY_PWRSW_FORCE_ON), 0);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun void
si_pmu_ulp_ilp_config(si_t * sih,osl_t * osh,uint32 ilp_period)319*4882a593Smuzhiyun si_pmu_ulp_ilp_config(si_t *sih, osl_t *osh, uint32 ilp_period)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	pmuregs_t *pmu;
322*4882a593Smuzhiyun 	pmu = si_setcoreidx(sih, si_findcoreidx(sih, PMU_CORE_ID, 0));
323*4882a593Smuzhiyun 	W_REG(osh, &pmu->ILPPeriod, ilp_period);
324*4882a593Smuzhiyun 	si_lhl_ilp_config(sih, osh, ilp_period);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun /** Initialize DS1 PMU hardware resources */
328*4882a593Smuzhiyun void
si_pmu_ds1_res_init(si_t * sih,osl_t * osh)329*4882a593Smuzhiyun si_pmu_ds1_res_init(si_t *sih, osl_t *osh)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	pmuregs_t *pmu;
332*4882a593Smuzhiyun 	uint origidx;
333*4882a593Smuzhiyun 	const pmu_res_updown_t *pmu_res_updown_table = NULL;
334*4882a593Smuzhiyun 	uint pmu_res_updown_table_sz = 0;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
337*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
338*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
339*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
340*4882a593Smuzhiyun 	} else {
341*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
346*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
347*4882a593Smuzhiyun 		pmu_res_updown_table = bcm43012a0_res_updown_ds1;
348*4882a593Smuzhiyun 		pmu_res_updown_table_sz = ARRAYSIZE(bcm43012a0_res_updown_ds1);
349*4882a593Smuzhiyun 		break;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	default:
352*4882a593Smuzhiyun 		break;
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	/* Program up/down timers */
356*4882a593Smuzhiyun 	while (pmu_res_updown_table_sz--) {
357*4882a593Smuzhiyun 		ASSERT(pmu_res_updown_table != NULL);
358*4882a593Smuzhiyun 		PMU_MSG(("DS1: Changing rsrc %d res_updn_timer to 0x%x\n",
359*4882a593Smuzhiyun 			pmu_res_updown_table[pmu_res_updown_table_sz].resnum,
360*4882a593Smuzhiyun 			pmu_res_updown_table[pmu_res_updown_table_sz].updown));
361*4882a593Smuzhiyun 		W_REG(osh, &pmu->res_table_sel,
362*4882a593Smuzhiyun 			pmu_res_updown_table[pmu_res_updown_table_sz].resnum);
363*4882a593Smuzhiyun 		W_REG(osh, &pmu->res_updn_timer,
364*4882a593Smuzhiyun 			pmu_res_updown_table[pmu_res_updown_table_sz].updown);
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	/* Return to original core */
368*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun #endif /* defined(BCMULP) */
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun uint32
si_pmu_wake_bit_offset(si_t * sih)374*4882a593Smuzhiyun si_pmu_wake_bit_offset(si_t *sih)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun 	uint32 wakebit;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
379*4882a593Smuzhiyun 	case BCM4347_CHIP_GRPID:
380*4882a593Smuzhiyun 		wakebit = CC2_4347_GCI2WAKE_MASK;
381*4882a593Smuzhiyun 		break;
382*4882a593Smuzhiyun 	default:
383*4882a593Smuzhiyun 		wakebit = 0;
384*4882a593Smuzhiyun 		ASSERT(0);
385*4882a593Smuzhiyun 		break;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	return wakebit;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
si_pmu_set_min_res_mask(si_t * sih,osl_t * osh,uint min_res_mask)391*4882a593Smuzhiyun void si_pmu_set_min_res_mask(si_t *sih, osl_t *osh, uint min_res_mask)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	pmuregs_t *pmu;
394*4882a593Smuzhiyun 	uint origidx;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
397*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
398*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
399*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
400*4882a593Smuzhiyun 	}
401*4882a593Smuzhiyun 	else {
402*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	W_REG(osh, &pmu->min_res_mask, min_res_mask);
407*4882a593Smuzhiyun 	OSL_DELAY(100);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	/* Return to original core */
410*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun bool
si_pmu_cap_fast_lpo(si_t * sih)414*4882a593Smuzhiyun si_pmu_cap_fast_lpo(si_t *sih)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun 	return (PMU_REG(sih, core_cap_ext, 0, 0) & PCAP_EXT_USE_MUXED_ILP_CLK_MASK) ? TRUE : FALSE;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun int
si_pmu_fast_lpo_disable(si_t * sih)420*4882a593Smuzhiyun si_pmu_fast_lpo_disable(si_t *sih)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	if (!si_pmu_cap_fast_lpo(sih)) {
423*4882a593Smuzhiyun 		PMU_ERROR(("%s: No Fast LPO capability\n", __FUNCTION__));
424*4882a593Smuzhiyun 		return BCME_ERROR;
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	PMU_REG(sih, pmucontrol_ext,
428*4882a593Smuzhiyun 		PCTL_EXT_FASTLPO_ENAB |
429*4882a593Smuzhiyun 		PCTL_EXT_FASTLPO_SWENAB |
430*4882a593Smuzhiyun 		PCTL_EXT_FASTLPO_PCIE_SWENAB,
431*4882a593Smuzhiyun 		0);
432*4882a593Smuzhiyun 	OSL_DELAY(1000);
433*4882a593Smuzhiyun 	return BCME_OK;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun #ifdef BCMPMU_STATS
437*4882a593Smuzhiyun /*
438*4882a593Smuzhiyun  * 8 pmu statistics timer default map
439*4882a593Smuzhiyun  *
440*4882a593Smuzhiyun  * for CORE_RDY_AUX measure, set as below for timer 6 and 7 instead of CORE_RDY_MAIN.
441*4882a593Smuzhiyun  *	//core-n active duration : pmu_rsrc_state(CORE_RDY_AUX)
442*4882a593Smuzhiyun  *	{ SRC_CORE_RDY_AUX, FALSE, TRUE, LEVEL_HIGH},
443*4882a593Smuzhiyun  *	//core-n active duration : pmu_rsrc_state(CORE_RDY_AUX)
444*4882a593Smuzhiyun  *	{ SRC_CORE_RDY_AUX, FALSE, TRUE, EDGE_RISE}
445*4882a593Smuzhiyun  */
446*4882a593Smuzhiyun static pmu_stats_timer_t pmustatstimer[] = {
447*4882a593Smuzhiyun 	{ SRC_LINK_IN_L12, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},	//link_in_l12
448*4882a593Smuzhiyun 	{ SRC_LINK_IN_L23, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},	//link_in_l23
449*4882a593Smuzhiyun 	{ SRC_PM_ST_IN_D0, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},	//pm_st_in_d0
450*4882a593Smuzhiyun 	{ SRC_PM_ST_IN_D3, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},	//pm_st_in_d3
451*4882a593Smuzhiyun 	//deep-sleep duration : pmu_rsrc_state(XTAL_PU)
452*4882a593Smuzhiyun 	{ SRC_XTAL_PU, FALSE, TRUE, PMU_STATS_LEVEL_LOW},
453*4882a593Smuzhiyun 	//deep-sleep entry count : pmu_rsrc_state(XTAL_PU)
454*4882a593Smuzhiyun 	{ SRC_XTAL_PU, FALSE, TRUE, PMU_STATS_EDGE_FALL},
455*4882a593Smuzhiyun 	//core-n active duration : pmu_rsrc_state(CORE_RDY_MAIN)
456*4882a593Smuzhiyun 	{ SRC_CORE_RDY_MAIN, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},
457*4882a593Smuzhiyun 	//core-n active duration : pmu_rsrc_state(CORE_RDY_MAIN)
458*4882a593Smuzhiyun 	{ SRC_CORE_RDY_MAIN, FALSE, TRUE, PMU_STATS_EDGE_RISE}
459*4882a593Smuzhiyun };
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun static void
si_pmustatstimer_update(osl_t * osh,pmuregs_t * pmu,uint8 timerid)462*4882a593Smuzhiyun si_pmustatstimer_update(osl_t *osh, pmuregs_t *pmu, uint8 timerid)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun 	uint32 stats_timer_ctrl;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
467*4882a593Smuzhiyun 	stats_timer_ctrl =
468*4882a593Smuzhiyun 		((pmustatstimer[timerid].src_num << PMU_ST_SRC_SHIFT) &
469*4882a593Smuzhiyun 			PMU_ST_SRC_MASK) |
470*4882a593Smuzhiyun 		((pmustatstimer[timerid].cnt_mode << PMU_ST_CNT_MODE_SHIFT) &
471*4882a593Smuzhiyun 			PMU_ST_CNT_MODE_MASK) |
472*4882a593Smuzhiyun 		((pmustatstimer[timerid].enable << PMU_ST_EN_SHIFT) & PMU_ST_EN_MASK) |
473*4882a593Smuzhiyun 		((pmustatstimer[timerid].int_enable << PMU_ST_INT_EN_SHIFT) & PMU_ST_INT_EN_MASK);
474*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_ctrl, stats_timer_ctrl);
475*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_N, 0);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun void
si_pmustatstimer_int_enable(si_t * sih)479*4882a593Smuzhiyun si_pmustatstimer_int_enable(si_t *sih)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun 	pmuregs_t *pmu;
482*4882a593Smuzhiyun 	uint origidx;
483*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
486*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
487*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
488*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
489*4882a593Smuzhiyun 	} else {
490*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
491*4882a593Smuzhiyun 	}
492*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	OR_REG(osh, &pmu->pmuintmask0, PMU_INT_STAT_TIMER_INT_MASK);
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	/* Return to original core */
497*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun void
si_pmustatstimer_int_disable(si_t * sih)501*4882a593Smuzhiyun si_pmustatstimer_int_disable(si_t *sih)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	pmuregs_t *pmu;
504*4882a593Smuzhiyun 	uint origidx;
505*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
508*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
509*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
510*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
511*4882a593Smuzhiyun 	} else {
512*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
513*4882a593Smuzhiyun 	}
514*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	AND_REG(osh, &pmu->pmuintmask0, ~PMU_INT_STAT_TIMER_INT_MASK);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	/* Return to original core */
519*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun void
si_pmustatstimer_init(si_t * sih)523*4882a593Smuzhiyun si_pmustatstimer_init(si_t *sih)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun 	pmuregs_t *pmu;
526*4882a593Smuzhiyun 	uint origidx;
527*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
528*4882a593Smuzhiyun 	uint32 core_cap_ext;
529*4882a593Smuzhiyun 	uint8 max_stats_timer_num;
530*4882a593Smuzhiyun 	int8 i;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
533*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
534*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
535*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
536*4882a593Smuzhiyun 	} else {
537*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	core_cap_ext = R_REG(osh, &pmu->core_cap_ext);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >> PCAP_EXT_ST_NUM_SHIFT) + 1;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	for (i = 0; i < max_stats_timer_num; i++) {
546*4882a593Smuzhiyun 		si_pmustatstimer_update(osh, pmu, i);
547*4882a593Smuzhiyun 	}
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	OR_REG(osh, &pmu->pmuintmask0, PMU_INT_STAT_TIMER_INT_MASK);
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	/* Return to original core */
552*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun void
si_pmustatstimer_dump(si_t * sih)556*4882a593Smuzhiyun si_pmustatstimer_dump(si_t *sih)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	pmuregs_t *pmu;
559*4882a593Smuzhiyun 	uint origidx;
560*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
561*4882a593Smuzhiyun 	uint32 core_cap_ext, pmucapabilities, AlpPeriod, ILPPeriod, pmuintmask0, pmuintstatus;
562*4882a593Smuzhiyun 	uint8 max_stats_timer_num, max_stats_timer_src_num;
563*4882a593Smuzhiyun 	uint32 stat_timer_ctrl, stat_timer_N;
564*4882a593Smuzhiyun 	uint8 i;
565*4882a593Smuzhiyun 	uint32 current_time_ms = OSL_SYSUPTIME();
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
568*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
569*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
570*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
571*4882a593Smuzhiyun 	} else {
572*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
573*4882a593Smuzhiyun 	}
574*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	pmucapabilities = R_REG(osh, &pmu->pmucapabilities);
577*4882a593Smuzhiyun 	core_cap_ext = R_REG(osh, &pmu->core_cap_ext);
578*4882a593Smuzhiyun 	AlpPeriod = R_REG(osh, &pmu->slowclkperiod);
579*4882a593Smuzhiyun 	ILPPeriod = R_REG(osh, &pmu->ILPPeriod);
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >>
582*4882a593Smuzhiyun 		PCAP_EXT_ST_NUM_SHIFT) + 1;
583*4882a593Smuzhiyun 	max_stats_timer_src_num = ((core_cap_ext & PCAP_EXT_ST_SRC_NUM_MASK) >>
584*4882a593Smuzhiyun 		PCAP_EXT_ST_SRC_NUM_SHIFT) + 1;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	pmuintstatus = R_REG(osh, &pmu->pmuintstatus);
587*4882a593Smuzhiyun 	pmuintmask0 = R_REG(osh, &pmu->pmuintmask0);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	PMU_ERROR(("%s : TIME %d\n", __FUNCTION__, current_time_ms));
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	PMU_ERROR(("\tMAX Timer Num %d, MAX Source Num %d\n",
592*4882a593Smuzhiyun 		max_stats_timer_num, max_stats_timer_src_num));
593*4882a593Smuzhiyun 	PMU_ERROR(("\tpmucapabilities 0x%8x, core_cap_ext 0x%8x, AlpPeriod 0x%8x, ILPPeriod 0x%8x, "
594*4882a593Smuzhiyun 		"pmuintmask0 0x%8x, pmuintstatus 0x%8x, pmurev %d\n",
595*4882a593Smuzhiyun 		pmucapabilities, core_cap_ext, AlpPeriod, ILPPeriod,
596*4882a593Smuzhiyun 		pmuintmask0, pmuintstatus, PMUREV(sih->pmurev)));
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	for (i = 0; i < max_stats_timer_num; i++) {
599*4882a593Smuzhiyun 		W_REG(osh, &pmu->pmu_statstimer_addr, i);
600*4882a593Smuzhiyun 		stat_timer_ctrl = R_REG(osh, &pmu->pmu_statstimer_ctrl);
601*4882a593Smuzhiyun 		stat_timer_N = R_REG(osh, &pmu->pmu_statstimer_N);
602*4882a593Smuzhiyun 		PMU_ERROR(("\t Timer %d : control 0x%8x, %d\n",
603*4882a593Smuzhiyun 			i, stat_timer_ctrl, stat_timer_N));
604*4882a593Smuzhiyun 	}
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	/* Return to original core */
607*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun void
si_pmustatstimer_start(si_t * sih,uint8 timerid)611*4882a593Smuzhiyun si_pmustatstimer_start(si_t *sih, uint8 timerid)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	pmuregs_t *pmu;
614*4882a593Smuzhiyun 	uint origidx;
615*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
618*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
619*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
620*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
621*4882a593Smuzhiyun 	} else {
622*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
623*4882a593Smuzhiyun 	}
624*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	pmustatstimer[timerid].enable = TRUE;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
629*4882a593Smuzhiyun 	OR_REG(osh, &pmu->pmu_statstimer_ctrl, PMU_ST_ENAB << PMU_ST_EN_SHIFT);
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	/* Return to original core */
632*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun void
si_pmustatstimer_stop(si_t * sih,uint8 timerid)636*4882a593Smuzhiyun si_pmustatstimer_stop(si_t *sih, uint8 timerid)
637*4882a593Smuzhiyun {
638*4882a593Smuzhiyun 	pmuregs_t *pmu;
639*4882a593Smuzhiyun 	uint origidx;
640*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
643*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
644*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
645*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
646*4882a593Smuzhiyun 	} else {
647*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
648*4882a593Smuzhiyun 	}
649*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	pmustatstimer[timerid].enable = FALSE;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
654*4882a593Smuzhiyun 	AND_REG(osh, &pmu->pmu_statstimer_ctrl, ~(PMU_ST_ENAB << PMU_ST_EN_SHIFT));
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	/* Return to original core */
657*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun void
si_pmustatstimer_clear(si_t * sih,uint8 timerid)661*4882a593Smuzhiyun si_pmustatstimer_clear(si_t *sih, uint8 timerid)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun 	pmuregs_t *pmu;
664*4882a593Smuzhiyun 	uint origidx;
665*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
668*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
669*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
670*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
671*4882a593Smuzhiyun 	} else {
672*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
673*4882a593Smuzhiyun 	}
674*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
677*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_N, 0);
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	/* Return to original core */
680*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun void
si_pmustatstimer_clear_overflow(si_t * sih)684*4882a593Smuzhiyun si_pmustatstimer_clear_overflow(si_t *sih)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun 	uint8 i;
687*4882a593Smuzhiyun 	uint32 core_cap_ext;
688*4882a593Smuzhiyun 	uint8 max_stats_timer_num;
689*4882a593Smuzhiyun 	uint32 timerN;
690*4882a593Smuzhiyun 	pmuregs_t *pmu;
691*4882a593Smuzhiyun 	uint origidx;
692*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
695*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
696*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
697*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
698*4882a593Smuzhiyun 	} else {
699*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
700*4882a593Smuzhiyun 	}
701*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	core_cap_ext = R_REG(osh, &pmu->core_cap_ext);
704*4882a593Smuzhiyun 	max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >> PCAP_EXT_ST_NUM_SHIFT) + 1;
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 	for (i = 0; i < max_stats_timer_num; i++) {
707*4882a593Smuzhiyun 		W_REG(osh, &pmu->pmu_statstimer_addr, i);
708*4882a593Smuzhiyun 		timerN = R_REG(osh, &pmu->pmu_statstimer_N);
709*4882a593Smuzhiyun 		if (timerN == 0xFFFFFFFF) {
710*4882a593Smuzhiyun 			PMU_ERROR(("pmustatstimer overflow clear - timerid : %d\n", i));
711*4882a593Smuzhiyun 			si_pmustatstimer_clear(sih, i);
712*4882a593Smuzhiyun 		}
713*4882a593Smuzhiyun 	}
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	/* Return to original core */
716*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun uint32
si_pmustatstimer_read(si_t * sih,uint8 timerid)720*4882a593Smuzhiyun si_pmustatstimer_read(si_t *sih, uint8 timerid)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun 	pmuregs_t *pmu;
723*4882a593Smuzhiyun 	uint origidx;
724*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
725*4882a593Smuzhiyun 	uint32 stats_timer_N;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
728*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
729*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
730*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
731*4882a593Smuzhiyun 	} else {
732*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
733*4882a593Smuzhiyun 	}
734*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
737*4882a593Smuzhiyun 	stats_timer_N = R_REG(osh, &pmu->pmu_statstimer_N);
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	/* Return to original core */
740*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	return stats_timer_N;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun void
si_pmustatstimer_cfg_src_num(si_t * sih,uint8 src_num,uint8 timerid)746*4882a593Smuzhiyun si_pmustatstimer_cfg_src_num(si_t *sih, uint8 src_num, uint8 timerid)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun 	pmuregs_t *pmu;
749*4882a593Smuzhiyun 	uint origidx;
750*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
753*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
754*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
755*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
756*4882a593Smuzhiyun 	} else {
757*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
758*4882a593Smuzhiyun 	}
759*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	pmustatstimer[timerid].src_num = src_num;
762*4882a593Smuzhiyun 	si_pmustatstimer_update(osh, pmu, timerid);
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	/* Return to original core */
765*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun void
si_pmustatstimer_cfg_cnt_mode(si_t * sih,uint8 cnt_mode,uint8 timerid)769*4882a593Smuzhiyun si_pmustatstimer_cfg_cnt_mode(si_t *sih, uint8 cnt_mode, uint8 timerid)
770*4882a593Smuzhiyun {
771*4882a593Smuzhiyun 	pmuregs_t *pmu;
772*4882a593Smuzhiyun 	uint origidx;
773*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
776*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
777*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
778*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
779*4882a593Smuzhiyun 	} else {
780*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
781*4882a593Smuzhiyun 	}
782*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	pmustatstimer[timerid].cnt_mode = cnt_mode;
785*4882a593Smuzhiyun 	si_pmustatstimer_update(osh, pmu, timerid);
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	/* Return to original core */
788*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun #endif /* BCMPMU_STATS */
791