xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/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  * 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 /**
26*4882a593Smuzhiyun  * @file
27*4882a593Smuzhiyun  * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs.
28*4882a593Smuzhiyun  * However, in the context of this file the baseband ('BB') PLL/FLL is referred to.
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * Throughout this code, the prefixes 'pmu1_' and 'pmu2_' are used.
31*4882a593Smuzhiyun  * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012)
32*4882a593Smuzhiyun  * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports
33*4882a593Smuzhiyun  * fractional frequency generation. pmu2_ does not support fractional frequency generation.
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #include <typedefs.h>
37*4882a593Smuzhiyun #include <bcmdefs.h>
38*4882a593Smuzhiyun #include <osl.h>
39*4882a593Smuzhiyun #include <bcmutils.h>
40*4882a593Smuzhiyun #include <siutils.h>
41*4882a593Smuzhiyun #include <bcmdevs.h>
42*4882a593Smuzhiyun #include <hndsoc.h>
43*4882a593Smuzhiyun #include <sbchipc.h>
44*4882a593Smuzhiyun #include <hndchipc.h>
45*4882a593Smuzhiyun #include <hndpmu.h>
46*4882a593Smuzhiyun #if defined DONGLEBUILD
47*4882a593Smuzhiyun #include <hndcpu.h>
48*4882a593Smuzhiyun #ifdef __arm__
49*4882a593Smuzhiyun #include <hndarm.h>
50*4882a593Smuzhiyun #endif
51*4882a593Smuzhiyun #endif /* DONGLEBUILD */
52*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
53*4882a593Smuzhiyun #include <bcm_math.h>
54*4882a593Smuzhiyun #include <bcmotp.h>
55*4882a593Smuzhiyun #ifdef BCM_OTP_API
56*4882a593Smuzhiyun #include <bcm_otp_api.h>
57*4882a593Smuzhiyun #endif /* BCM_OTP_API */
58*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
59*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
60*4882a593Smuzhiyun #include <saverestore.h>
61*4882a593Smuzhiyun #endif
62*4882a593Smuzhiyun #include <hndlhl.h>
63*4882a593Smuzhiyun #include <sbgci.h>
64*4882a593Smuzhiyun #ifdef EVENT_LOG_COMPILE
65*4882a593Smuzhiyun #include <event_log.h>
66*4882a593Smuzhiyun #endif
67*4882a593Smuzhiyun #include <sbgci.h>
68*4882a593Smuzhiyun #include <lpflags.h>
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #include "siutils_priv.h"
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #ifdef BCM_AVS
73*4882a593Smuzhiyun #include <bcm_avs.h>
74*4882a593Smuzhiyun #endif
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #if defined(EVENT_LOG_COMPILE) && defined(BCMDBG_ERR) && defined(ERR_USE_EVENT_LOG)
77*4882a593Smuzhiyun #if defined(ERR_USE_EVENT_LOG_RA)
78*4882a593Smuzhiyun #define PMU_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_PMU_ERROR, args)
79*4882a593Smuzhiyun #else
80*4882a593Smuzhiyun #define PMU_ERROR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_PMU_ERROR, args)
81*4882a593Smuzhiyun #endif /* ERR_USE_EVENT_LOG_RA */
82*4882a593Smuzhiyun #elif defined(BCMDBG_ERR)
83*4882a593Smuzhiyun #define	PMU_ERROR(args)	printf args
84*4882a593Smuzhiyun #else
85*4882a593Smuzhiyun #define	PMU_ERROR(args)
86*4882a593Smuzhiyun #endif	/* defined(BCMDBG_ERR) && defined(ERR_USE_EVENT_LOG) */
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun #ifdef BCMDBG
89*4882a593Smuzhiyun //#define BCMDBG_PMU
90*4882a593Smuzhiyun #endif
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun #ifdef BCMDBG_PMU
93*4882a593Smuzhiyun #define	PMU_MSG(args)	printf args
94*4882a593Smuzhiyun #else
95*4882a593Smuzhiyun #define	PMU_MSG(args)
96*4882a593Smuzhiyun #endif	/* BCMDBG_MPU */
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun /* To check in verbose debugging messages not intended
99*4882a593Smuzhiyun  * to be on except on private builds.
100*4882a593Smuzhiyun  */
101*4882a593Smuzhiyun #define	PMU_NONE(args)
102*4882a593Smuzhiyun #define flags_shift	14
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /** contains resource bit positions for a specific chip */
105*4882a593Smuzhiyun struct rsc_per_chip {
106*4882a593Smuzhiyun 	uint8 ht_avail;
107*4882a593Smuzhiyun 	uint8 macphy_clkavail;
108*4882a593Smuzhiyun 	uint8 ht_start;
109*4882a593Smuzhiyun 	uint8 otp_pu;
110*4882a593Smuzhiyun 	uint8 macphy_aux_clkavail;
111*4882a593Smuzhiyun 	uint8 macphy_scan_clkavail;
112*4882a593Smuzhiyun 	uint8 cb_ready;
113*4882a593Smuzhiyun 	uint8 dig_ready;
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun typedef struct rsc_per_chip rsc_per_chip_t;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun #if defined(BCMPMU_STATS) && !defined(BCMPMU_STATS_DISABLED)
119*4882a593Smuzhiyun bool	_pmustatsenab = TRUE;
120*4882a593Smuzhiyun #else
121*4882a593Smuzhiyun bool	_pmustatsenab = FALSE;
122*4882a593Smuzhiyun #endif /* BCMPMU_STATS */
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun /* 1MHz lpo enable */
125*4882a593Smuzhiyun /* PLEASE USE THIS MACRO IN ATTACH PATH ONLY! */
126*4882a593Smuzhiyun #if defined(BCM_FASTLPO) && !defined(BCM_FASTLPO_DISABLED)
127*4882a593Smuzhiyun 	#define FASTLPO_ENAB()	(TRUE)
128*4882a593Smuzhiyun #else
129*4882a593Smuzhiyun 	#define FASTLPO_ENAB()	(FALSE)
130*4882a593Smuzhiyun #endif
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun /* Disable the power optimization feature */
133*4882a593Smuzhiyun bool	_bcm_pwr_opt_dis = FALSE;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun #ifdef BCMSRTOPOFF
136*4882a593Smuzhiyun bool _srtopoff_enab = FALSE;
137*4882a593Smuzhiyun #endif
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun pmuregs_t *hnd_pmur = NULL;  /* PMU core regs */
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
142*4882a593Smuzhiyun static void si_pmu_chipcontrol_xtal_settings_4369(si_t *sih);
143*4882a593Smuzhiyun static void si_pmu_chipcontrol_xtal_settings_4362(si_t *sih);
144*4882a593Smuzhiyun static void si_pmu_chipcontrol_xtal_settings_4378(si_t *sih);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /* PLL controls/clocks */
147*4882a593Smuzhiyun static void si_pmu1_pllinit1(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 xtal);
148*4882a593Smuzhiyun static void si_pmu_pll_off(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 *min_mask,
149*4882a593Smuzhiyun 	uint32 *max_mask, uint32 *clk_ctl_st);
150*4882a593Smuzhiyun static void si_pmu_pll_on(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 min_mask,
151*4882a593Smuzhiyun 	uint32 max_mask, uint32 clk_ctl_st);
152*4882a593Smuzhiyun static void si_pmu_otp_pllcontrol(si_t *sih, osl_t *osh);
153*4882a593Smuzhiyun static void si_pmu_otp_vreg_control(si_t *sih, osl_t *osh);
154*4882a593Smuzhiyun static void si_pmu_otp_chipcontrol(si_t *sih, osl_t *osh);
155*4882a593Smuzhiyun static uint32 si_pmu_def_alp_clock(si_t *sih, osl_t *osh);
156*4882a593Smuzhiyun static bool si_pmu_update_pllcontrol(si_t *sih, osl_t *osh, uint32 xtal, bool update_required);
157*4882a593Smuzhiyun static uint32 si_pmu_htclk_mask(si_t *sih);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun static uint32 si_pmu1_cpuclk0(si_t *sih, osl_t *osh, pmuregs_t *pmu);
160*4882a593Smuzhiyun static uint32 si_pmu1_alpclk0(si_t *sih, osl_t *osh, pmuregs_t *pmu);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun static uint32 si_pmu1_cpuclk0_pll2(si_t *sih);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun /* PMU resources */
165*4882a593Smuzhiyun static uint32 si_pmu_res_deps(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 rsrcs, bool all);
166*4882a593Smuzhiyun static uint si_pmu_res_uptime(si_t *sih, osl_t *osh, pmuregs_t *pmu,
167*4882a593Smuzhiyun 	uint8 rsrc, bool pmu_fast_trans_en);
168*4882a593Smuzhiyun static void si_pmu_res_masks(si_t *sih, uint32 *pmin, uint32 *pmax);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun uint32 si_pmu_get_pmutime_diff(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 *prev);
171*4882a593Smuzhiyun bool si_pmu_wait_for_res_pending(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint usec,
172*4882a593Smuzhiyun 	bool cond, uint32 *elapsed_time);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun #ifdef __ARM_ARCH_7A__
175*4882a593Smuzhiyun static uint32 si_pmu_mem_ca7clock(si_t *sih, osl_t *osh);
176*4882a593Smuzhiyun #endif
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun static uint8 fastlpo_dis_get(void);
179*4882a593Smuzhiyun static uint8 fastlpo_pcie_dis_get(void);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun static uint32 si_pmu_bpclk_4387(si_t *sih);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun static int si_pmu_openloop_cal_43012(si_t *sih, uint16 currtemp);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun static uint32 si_pmu_pll6val_armclk_calc(osl_t *osh, pmuregs_t *pmu, uint32 armclk, uint32 xtal,
186*4882a593Smuzhiyun 		bool write);
187*4882a593Smuzhiyun static bool si_pmu_armpll_write_required(si_t *sih, uint32 xtal);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun uint8 si_pmu_pll28nm_calc_ndiv(uint32 fvco, uint32 xtal, uint32 *ndiv_int, uint32 *ndiv_frac);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun void si_pmu_armpll_freq_upd(si_t *sih, uint8 p1div, uint32 ndiv_int, uint32 ndiv_frac);
192*4882a593Smuzhiyun void si_pmu_bbpll_freq_upd(si_t *sih, uint8 p1div, uint32 ndiv_int, uint32 ndiv_frac);
193*4882a593Smuzhiyun void si_pmu_armpll_chmdiv_upd(si_t *sih, uint32 ch0_mdiv, uint32 ch1_mdiv);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun #ifdef BCM_LDO3P3_SOFTSTART
196*4882a593Smuzhiyun static int si_pmu_ldo3p3_soft_start_get(si_t *sih, osl_t *osh, uint32 bt_or_wl, int *res);
197*4882a593Smuzhiyun static int si_pmu_ldo3p3_soft_start_set(si_t *sih, osl_t *osh, uint32 bt_or_wl, uint32 slew_rate);
198*4882a593Smuzhiyun #endif /* BCM_LDO3P3_SOFTSTART */
199*4882a593Smuzhiyun #ifdef XTAL_BIAS_FROM_OTP
200*4882a593Smuzhiyun static void si_pmu_chipcontrol_xtal_bias_from_otp(si_t *sih, uint8* flag, uint8* val);
201*4882a593Smuzhiyun #ifndef BCM_OTP_API
202*4882a593Smuzhiyun static void si_pmu_chipcontrol_xtal_bias_cal_done_offsets(si_t *sih, uint16* wrd_offset,
203*4882a593Smuzhiyun 		uint8* wrd_shift, uint8* wrd_mask);
204*4882a593Smuzhiyun static void si_pmu_chipcontrol_xtal_bias_val_offsets(si_t *sih, uint16* wrd_offset,
205*4882a593Smuzhiyun 		uint8* wrd_shift, uint8* wrd_mask);
206*4882a593Smuzhiyun #endif /* !BCM_OTP_API */
207*4882a593Smuzhiyun #endif /* XTAL_BIAS_FROM_OTP */
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun /* PMU timer ticks once in 32uS */
210*4882a593Smuzhiyun #define PMU_US_STEPS (32)
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun void *g_si_pmutmr_lock_arg = NULL;
213*4882a593Smuzhiyun si_pmu_callback_t g_si_pmutmr_lock_cb = NULL, g_si_pmutmr_unlock_cb = NULL;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun /* FVCO frequency in [KHz] */
216*4882a593Smuzhiyun #define FVCO_640	640000  /**< 640MHz */
217*4882a593Smuzhiyun #define FVCO_880	880000	/**< 880MHz */
218*4882a593Smuzhiyun #define FVCO_1760	1760000	/**< 1760MHz */
219*4882a593Smuzhiyun #define FVCO_1440	1440000	/**< 1440MHz */
220*4882a593Smuzhiyun #define FVCO_960	960000	/**< 960MHz */
221*4882a593Smuzhiyun #define FVCO_960p1	960100  /**< 960.1MHz */
222*4882a593Smuzhiyun #define FVCO_960010	960010	/**< 960.0098MHz */
223*4882a593Smuzhiyun #define FVCO_961	961000	/**< 961MHz */
224*4882a593Smuzhiyun #define FVCO_960p5	960500	/**< 960.5MHz */
225*4882a593Smuzhiyun #define FVCO_963	963000	/**< 963MHz */
226*4882a593Smuzhiyun #define FVCO_963p01	963010  /**< 963.01MHz */
227*4882a593Smuzhiyun #define FVCO_1000	1000000	/**< 1000MHz */
228*4882a593Smuzhiyun #define FVCO_1600	1600000	/**< 1600MHz */
229*4882a593Smuzhiyun #define FVCO_1920	1920000	/**< 1920MHz */
230*4882a593Smuzhiyun #define FVCO_1938	1938000 /* 1938MHz */
231*4882a593Smuzhiyun #define FVCO_385	385000  /**< 385MHz */
232*4882a593Smuzhiyun #define FVCO_400	400000  /**< 400MHz */
233*4882a593Smuzhiyun #define FVCO_720	720000  /**< 720MHz */
234*4882a593Smuzhiyun #define FVCO_2880	2880000	/**< 2880 MHz */
235*4882a593Smuzhiyun #define FVCO_2946	2946000	/**< 2946 MHz */
236*4882a593Smuzhiyun #define FVCO_3000	3000000	/**< 3000 MHz */
237*4882a593Smuzhiyun #define FVCO_3200	3200000	/**< 3200 MHz */
238*4882a593Smuzhiyun #define FVCO_1002p8	1002823 /**< 1002.823MHz */
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun /* defines to make the code more readable */
241*4882a593Smuzhiyun /* But 0 is a valid resource number! */
242*4882a593Smuzhiyun #define NO_SUCH_RESOURCE	0	/**< means: chip does not have such a PMU resource */
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun /* uses these defines instead of 'magic' values when writing to register pllcontrol_addr */
245*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG0	0
246*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG1	1
247*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG2	2
248*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG3	3
249*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG4	4
250*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG5	5
251*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG6	6
252*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG7	7
253*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG8	8
254*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG9	9
255*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG10	10
256*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG11	11
257*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG12	12
258*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG13	13
259*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG14	14
260*4882a593Smuzhiyun #define PMU_PLL_CTRL_REG15	15
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun #ifndef BCM_OTP_API
263*4882a593Smuzhiyun #define OTP_XTAL_BIAS_CAL_DONE_4378_WRD_OFFSET 743
264*4882a593Smuzhiyun #define OTP_XTAL_BIAS_CAL_DONE_4378_WRD_SHIFT  8
265*4882a593Smuzhiyun #define OTP_XTAL_BIAS_CAL_DONE_4378_WRD_MASK   0x1
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun #define OTP_XTAL_BIAS_VAL_4378_WRD_OFFSET 743
268*4882a593Smuzhiyun #define OTP_XTAL_BIAS_VAL_4378_WRD_SHIFT  0
269*4882a593Smuzhiyun #define OTP_XTAL_BIAS_VAL_4378_WRD_MASK   0xFF
270*4882a593Smuzhiyun #endif /* !BCM_OTP_API */
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun /* changes the drive strength of gpio_12 and gpio_14 from 0x3 to 0x01 */
273*4882a593Smuzhiyun #define GPIO_DRIVE_4378_MASK	0x3Fu
274*4882a593Smuzhiyun #define GPIO_DRIVE_4378_VAL	0x09u
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun /**
277*4882a593Smuzhiyun  * The chip has one or more PLLs/FLLs (e.g. baseband PLL, USB PHY PLL). The settings of each PLL are
278*4882a593Smuzhiyun  * contained within one or more 'PLL control' registers. Since the PLL hardware requires that
279*4882a593Smuzhiyun  * changes for one PLL are committed at once, the PMU has a provision for 'updating' all PLL control
280*4882a593Smuzhiyun  * registers at once.
281*4882a593Smuzhiyun  *
282*4882a593Smuzhiyun  * When software wants to change the any PLL parameters, it withdraws requests for that PLL clock,
283*4882a593Smuzhiyun  * updates the PLL control registers being careful not to alter any control signals for the other
284*4882a593Smuzhiyun  * PLLs, and then writes a 1 to PMUCtl.PllCtnlUpdate to commit the changes. Best usage model would
285*4882a593Smuzhiyun  * be bring PLL down then update the PLL control register.
286*4882a593Smuzhiyun  */
287*4882a593Smuzhiyun void
si_pmu_pllupd(si_t * sih)288*4882a593Smuzhiyun si_pmu_pllupd(si_t *sih)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	pmu_corereg(sih, SI_CC_IDX, pmucontrol,
291*4882a593Smuzhiyun 	           PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun /* 4360_OTP_PU is used for 4352, not a typo */
295*4882a593Smuzhiyun static rsc_per_chip_t rsc_4352 =  {NO_SUCH_RESOURCE,  NO_SUCH_RESOURCE,
296*4882a593Smuzhiyun 		NO_SUCH_RESOURCE,  RES4360_OTP_PU, NO_SUCH_RESOURCE,
297*4882a593Smuzhiyun 		NO_SUCH_RESOURCE, NO_SUCH_RESOURCE, NO_SUCH_RESOURCE};
298*4882a593Smuzhiyun static rsc_per_chip_t rsc_4360 =  {RES4360_HT_AVAIL,  NO_SUCH_RESOURCE,
299*4882a593Smuzhiyun 		NO_SUCH_RESOURCE,  RES4360_OTP_PU, NO_SUCH_RESOURCE,
300*4882a593Smuzhiyun 		NO_SUCH_RESOURCE, NO_SUCH_RESOURCE, NO_SUCH_RESOURCE};
301*4882a593Smuzhiyun static rsc_per_chip_t rsc_43602 = {RES43602_HT_AVAIL, RES43602_MACPHY_CLKAVAIL,
302*4882a593Smuzhiyun 		RES43602_HT_START, NO_SUCH_RESOURCE, NO_SUCH_RESOURCE,
303*4882a593Smuzhiyun 		NO_SUCH_RESOURCE, NO_SUCH_RESOURCE, NO_SUCH_RESOURCE};
304*4882a593Smuzhiyun static rsc_per_chip_t rsc_43012 = {RES43012_HT_AVAIL, RES43012_MACPHY_CLK_AVAIL,
305*4882a593Smuzhiyun 		RES43012_HT_START, RES43012_OTP_PU, NO_SUCH_RESOURCE,
306*4882a593Smuzhiyun 		NO_SUCH_RESOURCE, NO_SUCH_RESOURCE, NO_SUCH_RESOURCE};
307*4882a593Smuzhiyun /* As per the chip team OTP doesn't have the resource in 4369 */
308*4882a593Smuzhiyun static rsc_per_chip_t rsc_4369 = {RES4369_HT_AVAIL, RES4369_MACPHY_MAIN_CLK_AVAIL,
309*4882a593Smuzhiyun 		RES4369_HT_AVAIL, NO_SUCH_RESOURCE, RES4369_MACPHY_AUX_CLK_AVAIL,
310*4882a593Smuzhiyun 		NO_SUCH_RESOURCE, NO_SUCH_RESOURCE, RES4369_DIG_CORE_RDY};
311*4882a593Smuzhiyun static rsc_per_chip_t rsc_4378 = {RES4378_HT_AVAIL, RES4378_MACPHY_MAIN_CLK_AVAIL,
312*4882a593Smuzhiyun 		RES4378_HT_AVAIL, RES4378_PMU_SLEEP, RES4378_MACPHY_AUX_CLK_AVAIL,
313*4882a593Smuzhiyun 		NO_SUCH_RESOURCE, RES4378_CORE_RDY_CB, RES4378_CORE_RDY_DIG};
314*4882a593Smuzhiyun static rsc_per_chip_t rsc_4387 = {RES4387_HT_AVAIL, RES4387_MACPHY_CLK_MAIN,
315*4882a593Smuzhiyun 		RES4387_HT_AVAIL, RES4387_PMU_SLEEP, RES4387_MACPHY_CLK_AUX,
316*4882a593Smuzhiyun 		RES4387_MACPHY_CLK_SCAN, RES4387_CORE_RDY_CB, RES4387_CORE_RDY_DIG};
317*4882a593Smuzhiyun static rsc_per_chip_t rsc_4388 = {RES4388_HT_AVAIL, RES4388_MACPHY_CLK_MAIN,
318*4882a593Smuzhiyun 		RES4388_HT_AVAIL, RES4388_PMU_LP, RES4388_MACPHY_CLK_AUX,
319*4882a593Smuzhiyun 		RES4388_MACPHY_CLK_SCAN, RES4388_CORE_RDY_CB, RES4388_CORE_RDY_DIG};
320*4882a593Smuzhiyun static rsc_per_chip_t rsc_4389 = {RES4389_HT_AVAIL, RES4389_MACPHY_CLK_MAIN,
321*4882a593Smuzhiyun 		RES4389_HT_AVAIL, RES4389_PMU_LP, RES4389_MACPHY_CLK_AUX,
322*4882a593Smuzhiyun 		RES4389_MACPHY_CLK_SCAN, RES4389_CORE_RDY_CB, RES4389_CORE_RDY_DIG};
323*4882a593Smuzhiyun static rsc_per_chip_t rsc_4397 = {RES4397_HT_AVAIL, RES4397_MACPHY_CLK_MAIN,
324*4882a593Smuzhiyun 		RES4397_HT_AVAIL, RES4397_PMU_LP, RES4397_MACPHY_CLK_AUX,
325*4882a593Smuzhiyun 		RES4397_MACPHY_CLK_SCAN, RES4397_CORE_RDY_CB, RES4397_CORE_RDY_DIG};
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun static rsc_per_chip_t rsc_4362 = {RES4362_HT_AVAIL, RES4362_MACPHY_MAIN_CLK_AVAIL,
328*4882a593Smuzhiyun 		RES4362_HT_AVAIL, /* macphy aux clk */
329*4882a593Smuzhiyun 		NO_SUCH_RESOURCE, NO_SUCH_RESOURCE, NO_SUCH_RESOURCE, NO_SUCH_RESOURCE,
330*4882a593Smuzhiyun 		RES4362_DIG_CORE_RDY};
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun /**
333*4882a593Smuzhiyun * For each chip, location of resource bits (e.g., ht bit) in resource mask registers may differ.
334*4882a593Smuzhiyun * This function abstracts the bit position of commonly used resources, thus making the rest of the
335*4882a593Smuzhiyun * code in hndpmu.c cleaner.
336*4882a593Smuzhiyun */
BCMRAMFN(si_pmu_get_rsc_positions)337*4882a593Smuzhiyun static rsc_per_chip_t* BCMRAMFN(si_pmu_get_rsc_positions)(si_t *sih)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun 	rsc_per_chip_t *rsc = NULL;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
342*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
343*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:	/* usb variant of 4352 */
344*4882a593Smuzhiyun 		rsc = &rsc_4352;
345*4882a593Smuzhiyun 		break;
346*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
347*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
348*4882a593Smuzhiyun 		rsc = &rsc_4360;
349*4882a593Smuzhiyun 		break;
350*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
351*4882a593Smuzhiyun 		rsc = &rsc_43602;
352*4882a593Smuzhiyun 		break;
353*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
354*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
355*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
356*4882a593Smuzhiyun 		rsc = &rsc_43012;
357*4882a593Smuzhiyun 		break;
358*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
359*4882a593Smuzhiyun 		rsc = &rsc_4369;
360*4882a593Smuzhiyun 		break;
361*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
362*4882a593Smuzhiyun 		rsc = &rsc_4362;
363*4882a593Smuzhiyun 		break;
364*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
365*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
366*4882a593Smuzhiyun 		rsc = &rsc_4378;
367*4882a593Smuzhiyun 		break;
368*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
369*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
370*4882a593Smuzhiyun 		rsc = &rsc_4387;
371*4882a593Smuzhiyun 		break;
372*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
373*4882a593Smuzhiyun 		rsc = &rsc_4388;
374*4882a593Smuzhiyun 		break;
375*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
376*4882a593Smuzhiyun 		rsc = &rsc_4389;
377*4882a593Smuzhiyun 		break;
378*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
379*4882a593Smuzhiyun 		rsc = &rsc_4397;
380*4882a593Smuzhiyun 		break;
381*4882a593Smuzhiyun 	default:
382*4882a593Smuzhiyun 		ASSERT(0);
383*4882a593Smuzhiyun 		break;
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	return rsc;
387*4882a593Smuzhiyun }; /* si_pmu_get_rsc_positions */
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_pllD)[] = "pll%d";
390*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_regD)[] = "reg%d";
391*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_chipcD)[] = "chipc%d";
392*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_rDt)[] = "r%dt";
393*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_rDd)[] = "r%dd";
394*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_Invalid_Unsupported_xtal_value_D)[] =
395*4882a593Smuzhiyun 	"Invalid/Unsupported xtal value %d";
396*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_xtalfreq)[] = "xtalfreq";
397*4882a593Smuzhiyun #if defined(SAVERESTORE) && defined(LDO3P3_MIN_RES_MASK)
398*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_ldo_prot)[] = "ldo_prot";
399*4882a593Smuzhiyun #endif /* SAVERESTORE && LDO3P3_MIN_RES_MASK */
400*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_btldo3p3pu)[] = "btldopu";
401*4882a593Smuzhiyun #if defined(BCM_FASTLPO_PMU) && !defined(BCM_FASTLPO_PMU_DISABLED)
402*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_fastlpo_dis)[] = "fastlpo_dis";
403*4882a593Smuzhiyun #endif /* BCM_FASTLPO_PMU */
404*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_fastlpo_pcie_dis)[] = "fastlpo_pcie_dis";
405*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_memlpldo_volt)[] = "memlpldo_volt";
406*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_lpldo_volt)[] = "lpldo_volt";
407*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_dyn_clksw_en)[] = "dyn_clksw_en";
408*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_abuck_volt)[] = "abuck_volt";
409*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_cbuck_volt)[] = "cbuck_volt";
410*4882a593Smuzhiyun static const char BCMATTACHDATA(rstr_csrtune)[] = "csr_tune";
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun /* The check for OTP parameters for the PLL control registers is done and if found the
413*4882a593Smuzhiyun  * registers are updated accordingly.
414*4882a593Smuzhiyun  */
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun /**
417*4882a593Smuzhiyun  * As a hardware bug workaround, OTP can contain variables in the form 'pll%d=%d'.
418*4882a593Smuzhiyun  * If these variables are present, the corresponding PLL control register(s) are
419*4882a593Smuzhiyun  * overwritten, but not yet 'updated'.
420*4882a593Smuzhiyun  */
421*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_otp_pllcontrol)422*4882a593Smuzhiyun BCMATTACHFN(si_pmu_otp_pllcontrol)(si_t *sih, osl_t *osh)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	char name[16];
425*4882a593Smuzhiyun 	const char *otp_val;
426*4882a593Smuzhiyun 	uint8 i;
427*4882a593Smuzhiyun 	uint32 val;
428*4882a593Smuzhiyun 	uint8 pll_ctrlcnt = 0;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
431*4882a593Smuzhiyun 		return;
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 5) {
435*4882a593Smuzhiyun 		pll_ctrlcnt = (sih->pmucaps & PCAP5_PC_MASK) >> PCAP5_PC_SHIFT;
436*4882a593Smuzhiyun 	} else {
437*4882a593Smuzhiyun 		pll_ctrlcnt = (sih->pmucaps & PCAP_PC_MASK) >> PCAP_PC_SHIFT;
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	for (i = 0; i < pll_ctrlcnt; i++) {
441*4882a593Smuzhiyun 		snprintf(name, sizeof(name), rstr_pllD, i);
442*4882a593Smuzhiyun 		if ((otp_val = getvar(NULL, name)) == NULL)
443*4882a593Smuzhiyun 			continue;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 		val = (uint32)bcm_strtoul(otp_val, NULL, 0);
446*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, i, ~0, val);
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun /**
451*4882a593Smuzhiyun  * The check for OTP parameters for the Voltage Regulator registers is done and if found the
452*4882a593Smuzhiyun  * registers are updated accordingly.
453*4882a593Smuzhiyun  */
454*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_otp_vreg_control)455*4882a593Smuzhiyun BCMATTACHFN(si_pmu_otp_vreg_control)(si_t *sih, osl_t *osh)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	char name[16];
458*4882a593Smuzhiyun 	const char *otp_val;
459*4882a593Smuzhiyun 	uint8 i;
460*4882a593Smuzhiyun 	uint32 val;
461*4882a593Smuzhiyun 	uint8 vreg_ctrlcnt = 0;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
464*4882a593Smuzhiyun 		return;
465*4882a593Smuzhiyun 	}
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 5) {
468*4882a593Smuzhiyun 		vreg_ctrlcnt = (sih->pmucaps & PCAP5_VC_MASK) >> PCAP5_VC_SHIFT;
469*4882a593Smuzhiyun 	} else {
470*4882a593Smuzhiyun 		vreg_ctrlcnt = (sih->pmucaps & PCAP_VC_MASK) >> PCAP_VC_SHIFT;
471*4882a593Smuzhiyun 	}
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	for (i = 0; i < vreg_ctrlcnt; i++) {
474*4882a593Smuzhiyun 		snprintf(name, sizeof(name), rstr_regD, i);
475*4882a593Smuzhiyun 		if ((otp_val = getvar(NULL, name)) == NULL)
476*4882a593Smuzhiyun 			continue;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 		val = (uint32)bcm_strtoul(otp_val, NULL, 0);
479*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, i, ~0, val);
480*4882a593Smuzhiyun 	}
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun /**
484*4882a593Smuzhiyun  * The check for OTP parameters for the chip control registers is done and if found the
485*4882a593Smuzhiyun  * registers are updated accordingly.
486*4882a593Smuzhiyun  */
487*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_otp_chipcontrol)488*4882a593Smuzhiyun BCMATTACHFN(si_pmu_otp_chipcontrol)(si_t *sih, osl_t *osh)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun 	uint32 val, cc_ctrlcnt, i;
491*4882a593Smuzhiyun 	char name[16];
492*4882a593Smuzhiyun 	const char *otp_val;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (FWSIGN_ENAB()) {
495*4882a593Smuzhiyun 		return;
496*4882a593Smuzhiyun 	}
497*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 5) {
498*4882a593Smuzhiyun 		cc_ctrlcnt = (sih->pmucaps & PCAP5_CC_MASK) >> PCAP5_CC_SHIFT;
499*4882a593Smuzhiyun 	} else {
500*4882a593Smuzhiyun 		cc_ctrlcnt = (sih->pmucaps & PCAP_CC_MASK) >> PCAP_CC_SHIFT;
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	for (i = 0; i < cc_ctrlcnt; i++) {
504*4882a593Smuzhiyun 		snprintf(name, sizeof(name), rstr_chipcD, i);
505*4882a593Smuzhiyun 		if ((otp_val = getvar(NULL, name)) == NULL)
506*4882a593Smuzhiyun 			continue;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 		val = (uint32)bcm_strtoul(otp_val, NULL, 0);
509*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, i, 0xFFFFFFFF, val); /* writes to PMU chipctrl reg 'i' */
510*4882a593Smuzhiyun 	}
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun /**
514*4882a593Smuzhiyun  * A chip contains one or more LDOs (Low Drop Out regulators). During chip bringup, it can turn out
515*4882a593Smuzhiyun  * that the default (POR) voltage of a regulator is not right or optimal.
516*4882a593Smuzhiyun  * This function is called only by si_pmu_swreg_init() for specific chips
517*4882a593Smuzhiyun  */
518*4882a593Smuzhiyun void
si_pmu_set_ldo_voltage(si_t * sih,osl_t * osh,uint8 ldo,uint8 voltage)519*4882a593Smuzhiyun si_pmu_set_ldo_voltage(si_t *sih, osl_t *osh, uint8 ldo, uint8 voltage)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun 	uint8 sr_cntl_shift = 0, rc_shift = 0, shift = 0, mask = 0;
522*4882a593Smuzhiyun 	uint8 addr = 0;
523*4882a593Smuzhiyun 	uint8 do_reg2 = 0, rshift2 = 0, rc_shift2 = 0, mask2 = 0, addr2 = 0;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	BCM_REFERENCE(osh);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
530*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
531*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
532*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
533*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
534*4882a593Smuzhiyun 		switch (ldo) {
535*4882a593Smuzhiyun 		case  SET_LDO_VOLTAGE_PAREF:
536*4882a593Smuzhiyun 			addr = 1;
537*4882a593Smuzhiyun 			rc_shift = 0;
538*4882a593Smuzhiyun 			mask = 0xf;
539*4882a593Smuzhiyun 			break;
540*4882a593Smuzhiyun 		default:
541*4882a593Smuzhiyun 			ASSERT(FALSE);
542*4882a593Smuzhiyun 			break;
543*4882a593Smuzhiyun 		}
544*4882a593Smuzhiyun 		break;
545*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
546*4882a593Smuzhiyun 		switch (ldo) {
547*4882a593Smuzhiyun 		case  SET_LDO_VOLTAGE_PAREF:
548*4882a593Smuzhiyun 			addr = 0;
549*4882a593Smuzhiyun 			rc_shift = 29;
550*4882a593Smuzhiyun 			mask = 0x7;
551*4882a593Smuzhiyun 			do_reg2 = 1;
552*4882a593Smuzhiyun 			addr2 = 1;
553*4882a593Smuzhiyun 			rshift2 = 3;
554*4882a593Smuzhiyun 			mask2 = 0x8;
555*4882a593Smuzhiyun 			break;
556*4882a593Smuzhiyun 		default:
557*4882a593Smuzhiyun 			ASSERT(FALSE);
558*4882a593Smuzhiyun 			break;
559*4882a593Smuzhiyun 		}
560*4882a593Smuzhiyun 		break;
561*4882a593Smuzhiyun 	default:
562*4882a593Smuzhiyun 		ASSERT(FALSE);
563*4882a593Smuzhiyun 		return;
564*4882a593Smuzhiyun 	}
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	shift = sr_cntl_shift + rc_shift;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	pmu_corereg(sih, SI_CC_IDX, regcontrol_addr, /* PMU VREG register */
569*4882a593Smuzhiyun 		~0, addr);
570*4882a593Smuzhiyun 	pmu_corereg(sih, SI_CC_IDX, regcontrol_data,
571*4882a593Smuzhiyun 		mask << shift, (voltage & mask) << shift);
572*4882a593Smuzhiyun 	if (do_reg2) {
573*4882a593Smuzhiyun 		/* rshift2 - right shift moves mask2 to bit 0, rc_shift2 - left shift in reg */
574*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, addr2, (mask2 >> rshift2) << rc_shift2,
575*4882a593Smuzhiyun 			((voltage & mask2) >> rshift2) << rc_shift2);
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun } /* si_pmu_set_ldo_voltage */
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun /* d11 slow to fast clock transition time in slow clock cycles */
580*4882a593Smuzhiyun #define D11SCC_SLOW2FAST_TRANSITION	2
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun /* For legacy chips only, will be discarded eventually */
583*4882a593Smuzhiyun static uint16
BCMINITFN(si_pmu_fast_pwrup_delay_legacy)584*4882a593Smuzhiyun BCMINITFN(si_pmu_fast_pwrup_delay_legacy)(si_t *sih, osl_t *osh, pmuregs_t *pmu)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	uint pmudelay = PMU_MAX_TRANSITION_DLY;
587*4882a593Smuzhiyun 	uint32 ilp;			/* ILP clock frequency in [Hz] */
588*4882a593Smuzhiyun 	rsc_per_chip_t *rsc;		/* chip specific resource bit positions */
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	/* Should be calculated based on the PMU updown/depend tables */
591*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
592*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
593*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
594*4882a593Smuzhiyun 		pmudelay = 3700;
595*4882a593Smuzhiyun 		break;
596*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
597*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
598*4882a593Smuzhiyun 		if (CHIPREV(sih->chiprev) < 4) {
599*4882a593Smuzhiyun 			pmudelay = 1500;
600*4882a593Smuzhiyun 		} else {
601*4882a593Smuzhiyun 			pmudelay = 3000;
602*4882a593Smuzhiyun 		}
603*4882a593Smuzhiyun 		break;
604*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
605*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
606*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
607*4882a593Smuzhiyun 		pmudelay = 1500; /* In micro seconds for 43012 chip */
608*4882a593Smuzhiyun 		break;
609*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
610*4882a593Smuzhiyun 		rsc = si_pmu_get_rsc_positions(sih);
611*4882a593Smuzhiyun 		/* Retrieve time by reading it out of the hardware */
612*4882a593Smuzhiyun 		ilp = si_ilp_clock(sih);
613*4882a593Smuzhiyun 		if (ilp != 0) {
614*4882a593Smuzhiyun 			pmudelay = (si_pmu_res_uptime(sih, osh, pmu, rsc->macphy_clkavail, FALSE) +
615*4882a593Smuzhiyun 				D11SCC_SLOW2FAST_TRANSITION) * ((1000000 + ilp - 1) / ilp);
616*4882a593Smuzhiyun 			pmudelay = (11 * pmudelay) / 10;
617*4882a593Smuzhiyun 		}
618*4882a593Smuzhiyun 		break;
619*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
620*4882a593Smuzhiyun 		rsc = si_pmu_get_rsc_positions(sih);
621*4882a593Smuzhiyun 		/* Retrieve time by reading it out of the hardware */
622*4882a593Smuzhiyun 		ilp = si_ilp_clock(sih);
623*4882a593Smuzhiyun 		if (ilp != 0) {
624*4882a593Smuzhiyun 			pmudelay = si_pmu_res_uptime(sih, osh, pmu, rsc->ht_avail, FALSE) +
625*4882a593Smuzhiyun 				D11SCC_SLOW2FAST_TRANSITION;
626*4882a593Smuzhiyun 			pmudelay = (11 * pmudelay) / 10;
627*4882a593Smuzhiyun 			/* With PWR SW optimization, Need to add this addtional
628*4882a593Smuzhiyun 			time to fast power up delay to avoid beacon loss
629*4882a593Smuzhiyun 			*/
630*4882a593Smuzhiyun 			pmudelay += 600;
631*4882a593Smuzhiyun 		}
632*4882a593Smuzhiyun 		break;
633*4882a593Smuzhiyun 	default:
634*4882a593Smuzhiyun 		break;
635*4882a593Smuzhiyun 	}
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	return (uint16)pmudelay;
638*4882a593Smuzhiyun } /* si_pmu_fast_pwrup_delay_legacy */
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun /**
641*4882a593Smuzhiyun  * d11 core has a 'fastpwrup_dly' register that must be written to.
642*4882a593Smuzhiyun  * This function returns d11 slow to fast clock transition time in [us] units.
643*4882a593Smuzhiyun  * It does not write to the d11 core.
644*4882a593Smuzhiyun  */
645*4882a593Smuzhiyun uint16
BCMINITFN(si_pmu_fast_pwrup_delay)646*4882a593Smuzhiyun BCMINITFN(si_pmu_fast_pwrup_delay)(si_t *sih, osl_t *osh)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun 	uint pmudelay = PMU_MAX_TRANSITION_DLY;
649*4882a593Smuzhiyun 	pmuregs_t *pmu;
650*4882a593Smuzhiyun 	uint origidx;
651*4882a593Smuzhiyun 	rsc_per_chip_t *rsc;		/* chip specific resource bit positions */
652*4882a593Smuzhiyun 	uint macunit;
653*4882a593Smuzhiyun 	bool pmu_fast_trans_en;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	if (ISSIM_ENAB(sih)) {
658*4882a593Smuzhiyun 		pmudelay = 1000;
659*4882a593Smuzhiyun 		goto exit;
660*4882a593Smuzhiyun 	}
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	macunit = si_coreunit(sih);
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
665*4882a593Smuzhiyun 	/* Still support 43602 so need AOB check,
666*4882a593Smuzhiyun 	 * 43602 is the only non-AOB chip supported now
667*4882a593Smuzhiyun 	 */
668*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
669*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
670*4882a593Smuzhiyun 	} else {
671*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
672*4882a593Smuzhiyun 	}
673*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	pmu_fast_trans_en = (R_REG(osh, &pmu->pmucontrol_ext) & PCTL_EXT_FAST_TRANS_ENAB) ?
676*4882a593Smuzhiyun 		TRUE : FALSE;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	rsc = si_pmu_get_rsc_positions(sih);
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
681*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
682*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
683*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
684*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
685*4882a593Smuzhiyun 		if (macunit == 0) {
686*4882a593Smuzhiyun 			pmudelay = si_pmu_res_uptime(sih, osh, pmu,
687*4882a593Smuzhiyun 				rsc->macphy_clkavail, pmu_fast_trans_en);
688*4882a593Smuzhiyun 		} else if (macunit == 1) {
689*4882a593Smuzhiyun 			pmudelay = si_pmu_res_uptime(sih, osh, pmu,
690*4882a593Smuzhiyun 				rsc->macphy_aux_clkavail, pmu_fast_trans_en);
691*4882a593Smuzhiyun 		} else {
692*4882a593Smuzhiyun 			ASSERT(0);
693*4882a593Smuzhiyun 		}
694*4882a593Smuzhiyun 		break;
695*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
696*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
697*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
698*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
699*4882a593Smuzhiyun 		if (macunit == 0) {
700*4882a593Smuzhiyun 			pmudelay = si_pmu_res_uptime(sih, osh, pmu,
701*4882a593Smuzhiyun 				rsc->macphy_clkavail, pmu_fast_trans_en);
702*4882a593Smuzhiyun 		} else if (macunit == 1) {
703*4882a593Smuzhiyun 			pmudelay = si_pmu_res_uptime(sih, osh, pmu,
704*4882a593Smuzhiyun 				rsc->macphy_aux_clkavail, pmu_fast_trans_en);
705*4882a593Smuzhiyun 		} else if (macunit == 2) {
706*4882a593Smuzhiyun 			pmudelay = si_pmu_res_uptime(sih, osh, pmu,
707*4882a593Smuzhiyun 				rsc->macphy_scan_clkavail, pmu_fast_trans_en);
708*4882a593Smuzhiyun 		} else {
709*4882a593Smuzhiyun 			ASSERT(0);
710*4882a593Smuzhiyun 		}
711*4882a593Smuzhiyun 		break;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	default:
714*4882a593Smuzhiyun 		pmudelay = si_pmu_fast_pwrup_delay_legacy(sih, osh, pmu);
715*4882a593Smuzhiyun 		break;
716*4882a593Smuzhiyun 	}
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	/* Return to original core */
719*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun exit:
722*4882a593Smuzhiyun 	return (uint16)pmudelay;
723*4882a593Smuzhiyun } /* si_pmu_fast_pwrup_delay */
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun /*
726*4882a593Smuzhiyun  * Get fast pwrup delay for given resource
727*4882a593Smuzhiyun  */
728*4882a593Smuzhiyun static uint
BCMINITFN(si_pmu_fast_pwrup_delay_rsrc)729*4882a593Smuzhiyun BCMINITFN(si_pmu_fast_pwrup_delay_rsrc)(si_t *sih, osl_t *osh, uint8 rsrc)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun 	uint pmudelay = PMU_MAX_TRANSITION_DLY;
732*4882a593Smuzhiyun 	pmuregs_t *pmu = NULL;
733*4882a593Smuzhiyun 	bool pmu_fast_trans_en = TRUE;
734*4882a593Smuzhiyun 	uint origidx;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
737*4882a593Smuzhiyun 	pmu = si_setcore(sih, PMU_CORE_ID, 0);
738*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	pmu_fast_trans_en = (R_REG(osh, &pmu->pmucontrol_ext) & PCTL_EXT_FAST_TRANS_ENAB) ?
741*4882a593Smuzhiyun 		TRUE : FALSE;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	pmudelay = si_pmu_res_uptime(sih, osh, pmu, rsrc, pmu_fast_trans_en);
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	/* Return to original core */
746*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	return pmudelay;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun /*
752*4882a593Smuzhiyun  * Get fast pwrup delay for given DIG_READY resource
753*4882a593Smuzhiyun  */
754*4882a593Smuzhiyun uint
BCMINITFN(si_pmu_fast_pwrup_delay_dig)755*4882a593Smuzhiyun BCMINITFN(si_pmu_fast_pwrup_delay_dig)(si_t *sih, osl_t *osh)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun 	uint delay = 0;
758*4882a593Smuzhiyun 	rsc_per_chip_t *rsc = si_pmu_get_rsc_positions(sih);
759*4882a593Smuzhiyun 	ASSERT(rsc);
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	if (rsc) {
762*4882a593Smuzhiyun 		delay = si_pmu_fast_pwrup_delay_rsrc(sih, osh, rsc->dig_ready);
763*4882a593Smuzhiyun 	}
764*4882a593Smuzhiyun 	return delay;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun /*
768*4882a593Smuzhiyun  * During chip bringup, it can turn out that the 'hard wired' PMU dependencies are not fully
769*4882a593Smuzhiyun  * correct, or that up/down time values can be optimized. The following data structures and arrays
770*4882a593Smuzhiyun  * deal with that.
771*4882a593Smuzhiyun  */
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun /* Setup resource up/down timers */
774*4882a593Smuzhiyun typedef struct {
775*4882a593Smuzhiyun 	uint8 resnum;
776*4882a593Smuzhiyun 	uint32 updown;
777*4882a593Smuzhiyun } pmu_res_updown_t;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun #define PMU_RES_SUBSTATE_SHIFT		8
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun /* Setup resource substate transition timer value */
782*4882a593Smuzhiyun typedef struct {
783*4882a593Smuzhiyun 	uint8 resnum;
784*4882a593Smuzhiyun 	uint8 substate;
785*4882a593Smuzhiyun 	uint32 tmr;
786*4882a593Smuzhiyun } pmu_res_subst_trans_tmr_t;
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun /* Change resource dependencies masks */
789*4882a593Smuzhiyun typedef struct {
790*4882a593Smuzhiyun 	uint32 res_mask;		/* resources (chip specific) */
791*4882a593Smuzhiyun 	int8 action;			/* action, e.g. RES_DEPEND_SET */
792*4882a593Smuzhiyun 	uint32 depend_mask;		/* changes to the dependencies mask */
793*4882a593Smuzhiyun 	bool (*filter)(si_t *sih);	/* action is taken when filter is NULL or return TRUE */
794*4882a593Smuzhiyun } pmu_res_depend_t;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun /* Resource dependencies mask change action */
797*4882a593Smuzhiyun #define RES_DEPEND_SET		0	/* Override the dependencies mask */
798*4882a593Smuzhiyun #define RES_DEPEND_ADD		1	/* Add to the  dependencies mask */
799*4882a593Smuzhiyun #define RES_DEPEND_REMOVE	-1	/* Remove from the dependencies mask */
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun /* Using a safe SAVE_RESTORE up/down time, it will get updated after openloop cal */
802*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm43012a0_res_updown_ds0)[] = {
803*4882a593Smuzhiyun 	{RES43012_MEMLPLDO_PU,		0x00200020},
804*4882a593Smuzhiyun 	{RES43012_PMU_SLEEP,		0x00a600a6},
805*4882a593Smuzhiyun 	{RES43012_FAST_LPO,		0x00D20000},
806*4882a593Smuzhiyun 	{RES43012_BTLPO_3P3,		0x007D0000},
807*4882a593Smuzhiyun 	{RES43012_SR_POK,		0x00c80000},
808*4882a593Smuzhiyun 	{RES43012_DUMMY_PWRSW,		0x01400000},
809*4882a593Smuzhiyun 	{RES43012_DUMMY_LDO3P3,		0x00000000},
810*4882a593Smuzhiyun 	{RES43012_DUMMY_BT_LDO3P3,	0x00000000},
811*4882a593Smuzhiyun 	{RES43012_DUMMY_RADIO,		0x00000000},
812*4882a593Smuzhiyun 	{RES43012_VDDB_VDDRET,		0x0020000a},
813*4882a593Smuzhiyun 	{RES43012_HV_LDO3P3,		0x002C0000},
814*4882a593Smuzhiyun 	{RES43012_XTAL_PU,		0x04000000},
815*4882a593Smuzhiyun 	{RES43012_SR_CLK_START,		0x00080000},
816*4882a593Smuzhiyun 	{RES43012_XTAL_STABLE,		0x00000000},
817*4882a593Smuzhiyun 	{RES43012_FCBS,			0x00000000},
818*4882a593Smuzhiyun 	{RES43012_CBUCK_MODE,		0x00000000},
819*4882a593Smuzhiyun 	{RES43012_CORE_READY,		0x00000000},
820*4882a593Smuzhiyun 	{RES43012_ILP_REQ,		0x00000000},
821*4882a593Smuzhiyun 	{RES43012_ALP_AVAIL,		0x00280008},
822*4882a593Smuzhiyun 	{RES43012_RADIOLDO_1P8,		0x00220000},
823*4882a593Smuzhiyun 	{RES43012_MINI_PMU,		0x00220000},
824*4882a593Smuzhiyun 	{RES43012_SR_SAVE_RESTORE,	0x02600260},
825*4882a593Smuzhiyun 	{RES43012_PHY_PWRSW,		0x00800005},
826*4882a593Smuzhiyun 	{RES43012_VDDB_CLDO,		0x0020000a},
827*4882a593Smuzhiyun 	{RES43012_SUBCORE_PWRSW,	0x0060000a},
828*4882a593Smuzhiyun 	{RES43012_SR_SLEEP,		0x00000000},
829*4882a593Smuzhiyun 	{RES43012_HT_START,		0x00A00000},
830*4882a593Smuzhiyun 	{RES43012_HT_AVAIL,		0x00000000},
831*4882a593Smuzhiyun 	{RES43012_MACPHY_CLK_AVAIL,	0x00000000},
832*4882a593Smuzhiyun };
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4360_res_updown)[] = {
835*4882a593Smuzhiyun 	{RES4360_BBPLLPWRSW_PU,		0x00200001}
836*4882a593Smuzhiyun };
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm43602_res_updown)[] = {
839*4882a593Smuzhiyun 	{RES43602_SR_SAVE_RESTORE,	0x00190019},
840*4882a593Smuzhiyun 	{RES43602_XTAL_PU,		0x00280002},
841*4882a593Smuzhiyun 	{RES43602_RFLDO_PU,		0x00430005}
842*4882a593Smuzhiyun };
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm43012a0_res_depend_ds0)[] = {
845*4882a593Smuzhiyun 	{0, 0, 0, NULL}
846*4882a593Smuzhiyun };
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm43602_res_depend)[] = {
849*4882a593Smuzhiyun 	/* JIRA HW43602-131 : PCIe SERDES dependency problem */
850*4882a593Smuzhiyun 	{
851*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_SUBCORE_PWRSW) | PMURES_BIT(RES43602_SR_CLK_STABLE) |
852*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_SAVE_RESTORE)  | PMURES_BIT(RES43602_SR_SLEEP) |
853*4882a593Smuzhiyun 		PMURES_BIT(RES43602_LQ_START) | PMURES_BIT(RES43602_LQ_AVAIL) |
854*4882a593Smuzhiyun 		PMURES_BIT(RES43602_WL_CORE_RDY) | PMURES_BIT(RES43602_ILP_REQ) |
855*4882a593Smuzhiyun 		PMURES_BIT(RES43602_ALP_AVAIL) | PMURES_BIT(RES43602_RFLDO_PU) |
856*4882a593Smuzhiyun 		PMURES_BIT(RES43602_HT_START) | PMURES_BIT(RES43602_HT_AVAIL) |
857*4882a593Smuzhiyun 		PMURES_BIT(RES43602_MACPHY_CLKAVAIL),
858*4882a593Smuzhiyun 		RES_DEPEND_ADD,
859*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SERDES_PU),
860*4882a593Smuzhiyun 		NULL
861*4882a593Smuzhiyun 	},
862*4882a593Smuzhiyun 	/* set rsrc  7, 8, 9, 12, 13, 14 & 17 add (1<<10 | 1<<4 )] */
863*4882a593Smuzhiyun 	{
864*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_CLK_START) | PMURES_BIT(RES43602_SR_PHY_PWRSW) |
865*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_SUBCORE_PWRSW) | PMURES_BIT(RES43602_SR_CLK_STABLE) |
866*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_SAVE_RESTORE) | PMURES_BIT(RES43602_SR_SLEEP) |
867*4882a593Smuzhiyun 		PMURES_BIT(RES43602_WL_CORE_RDY),
868*4882a593Smuzhiyun 		RES_DEPEND_ADD,
869*4882a593Smuzhiyun 		PMURES_BIT(RES43602_XTALLDO_PU) | PMURES_BIT(RES43602_XTAL_PU),
870*4882a593Smuzhiyun 		NULL
871*4882a593Smuzhiyun 	},
872*4882a593Smuzhiyun 	/* set rsrc 11 add (1<<13 | 1<<12 | 1<<9 | 1<<8 | 1<<7 )] */
873*4882a593Smuzhiyun 	{
874*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PERST_OVR),
875*4882a593Smuzhiyun 		RES_DEPEND_ADD,
876*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_CLK_START) | PMURES_BIT(RES43602_SR_PHY_PWRSW) |
877*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_SUBCORE_PWRSW) | PMURES_BIT(RES43602_SR_CLK_STABLE) |
878*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_SAVE_RESTORE),
879*4882a593Smuzhiyun 		NULL
880*4882a593Smuzhiyun 	},
881*4882a593Smuzhiyun 	/* set rsrc 19, 21, 22, 23 & 24 remove ~(1<<16 | 1<<15 )] */
882*4882a593Smuzhiyun 	{
883*4882a593Smuzhiyun 		PMURES_BIT(RES43602_ALP_AVAIL) | PMURES_BIT(RES43602_RFLDO_PU) |
884*4882a593Smuzhiyun 		PMURES_BIT(RES43602_HT_START) | PMURES_BIT(RES43602_HT_AVAIL) |
885*4882a593Smuzhiyun 		PMURES_BIT(RES43602_MACPHY_CLKAVAIL),
886*4882a593Smuzhiyun 		RES_DEPEND_REMOVE,
887*4882a593Smuzhiyun 		PMURES_BIT(RES43602_LQ_START) | PMURES_BIT(RES43602_LQ_AVAIL),
888*4882a593Smuzhiyun 		NULL
889*4882a593Smuzhiyun 	}
890*4882a593Smuzhiyun };
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun #ifndef BCM_BOOTLOADER
893*4882a593Smuzhiyun /** switch off LPLDO for 12x12 package because it can cause a problem when chip is reset */
894*4882a593Smuzhiyun static const pmu_res_depend_t BCMATTACHDATA(bcm43602_12x12_res_depend)[] = {
895*4882a593Smuzhiyun 	/* set rsrc 19, 21, 22, 23 & 24 remove ~(1<<16 | 1<<15 )] */
896*4882a593Smuzhiyun 	{	/* resources no longer dependent on resource that is going to be removed */
897*4882a593Smuzhiyun 		PMURES_BIT(RES43602_LPLDO_PU)        | PMURES_BIT(RES43602_REGULATOR)        |
898*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PMU_SLEEP)       | PMURES_BIT(RES43602_RSVD_3)           |
899*4882a593Smuzhiyun 		PMURES_BIT(RES43602_XTALLDO_PU)      | PMURES_BIT(RES43602_SERDES_PU)        |
900*4882a593Smuzhiyun 		PMURES_BIT(RES43602_BBPLL_PWRSW_PU)  | PMURES_BIT(RES43602_SR_CLK_START)     |
901*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_PHY_PWRSW)    | PMURES_BIT(RES43602_SR_SUBCORE_PWRSW) |
902*4882a593Smuzhiyun 		PMURES_BIT(RES43602_XTAL_PU)         | PMURES_BIT(RES43602_PERST_OVR)        |
903*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_CLK_STABLE)   | PMURES_BIT(RES43602_SR_SAVE_RESTORE)  |
904*4882a593Smuzhiyun 		PMURES_BIT(RES43602_SR_SLEEP)        | PMURES_BIT(RES43602_LQ_START)         |
905*4882a593Smuzhiyun 		PMURES_BIT(RES43602_LQ_AVAIL)        | PMURES_BIT(RES43602_WL_CORE_RDY)      |
906*4882a593Smuzhiyun 		PMURES_BIT(RES43602_ILP_REQ)         | PMURES_BIT(RES43602_ALP_AVAIL)        |
907*4882a593Smuzhiyun 		PMURES_BIT(RES43602_RADIO_PU)        | PMURES_BIT(RES43602_RFLDO_PU)         |
908*4882a593Smuzhiyun 		PMURES_BIT(RES43602_HT_START)        | PMURES_BIT(RES43602_HT_AVAIL)         |
909*4882a593Smuzhiyun 		PMURES_BIT(RES43602_MACPHY_CLKAVAIL) | PMURES_BIT(RES43602_PARLDO_PU)        |
910*4882a593Smuzhiyun 		PMURES_BIT(RES43602_RSVD_26),
911*4882a593Smuzhiyun 		RES_DEPEND_REMOVE,
912*4882a593Smuzhiyun 		/* resource that is going to be removed */
913*4882a593Smuzhiyun 		PMURES_BIT(RES43602_LPLDO_PU),
914*4882a593Smuzhiyun 		NULL
915*4882a593Smuzhiyun 	}
916*4882a593Smuzhiyun };
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun static const pmu_res_depend_t BCMATTACHDATA(bcm43602_res_pciewar)[] = {
919*4882a593Smuzhiyun 	{
920*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PERST_OVR),
921*4882a593Smuzhiyun 		RES_DEPEND_ADD,
922*4882a593Smuzhiyun 		PMURES_BIT(RES43602_REGULATOR) |
923*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PMU_SLEEP) |
924*4882a593Smuzhiyun 		PMURES_BIT(RES43602_XTALLDO_PU) |
925*4882a593Smuzhiyun 		PMURES_BIT(RES43602_XTAL_PU) |
926*4882a593Smuzhiyun 		PMURES_BIT(RES43602_RADIO_PU),
927*4882a593Smuzhiyun 		NULL
928*4882a593Smuzhiyun 	},
929*4882a593Smuzhiyun 	{
930*4882a593Smuzhiyun 		PMURES_BIT(RES43602_WL_CORE_RDY),
931*4882a593Smuzhiyun 		RES_DEPEND_ADD,
932*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PERST_OVR),
933*4882a593Smuzhiyun 		NULL
934*4882a593Smuzhiyun 	},
935*4882a593Smuzhiyun 	{
936*4882a593Smuzhiyun 		PMURES_BIT(RES43602_LQ_START),
937*4882a593Smuzhiyun 		RES_DEPEND_ADD,
938*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PERST_OVR),
939*4882a593Smuzhiyun 		NULL
940*4882a593Smuzhiyun 	},
941*4882a593Smuzhiyun 	{
942*4882a593Smuzhiyun 		PMURES_BIT(RES43602_LQ_AVAIL),
943*4882a593Smuzhiyun 		RES_DEPEND_ADD,
944*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PERST_OVR),
945*4882a593Smuzhiyun 		NULL
946*4882a593Smuzhiyun 	},
947*4882a593Smuzhiyun 	{
948*4882a593Smuzhiyun 		PMURES_BIT(RES43602_ALP_AVAIL),
949*4882a593Smuzhiyun 		RES_DEPEND_ADD,
950*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PERST_OVR),
951*4882a593Smuzhiyun 		NULL
952*4882a593Smuzhiyun 	},
953*4882a593Smuzhiyun 	{
954*4882a593Smuzhiyun 		PMURES_BIT(RES43602_HT_START),
955*4882a593Smuzhiyun 		RES_DEPEND_ADD,
956*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PERST_OVR),
957*4882a593Smuzhiyun 		NULL
958*4882a593Smuzhiyun 	},
959*4882a593Smuzhiyun 	{
960*4882a593Smuzhiyun 		PMURES_BIT(RES43602_HT_AVAIL),
961*4882a593Smuzhiyun 		RES_DEPEND_ADD,
962*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PERST_OVR),
963*4882a593Smuzhiyun 		NULL
964*4882a593Smuzhiyun 	},
965*4882a593Smuzhiyun 	{
966*4882a593Smuzhiyun 		PMURES_BIT(RES43602_MACPHY_CLKAVAIL),
967*4882a593Smuzhiyun 		RES_DEPEND_ADD,
968*4882a593Smuzhiyun 		PMURES_BIT(RES43602_PERST_OVR),
969*4882a593Smuzhiyun 		NULL
970*4882a593Smuzhiyun 	}
971*4882a593Smuzhiyun };
972*4882a593Smuzhiyun #endif /* BCM_BOOTLOADER */
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4360B1_res_updown)[] = {
975*4882a593Smuzhiyun 	/* Need to change elements here, should get default values for this - 4360B1 */
976*4882a593Smuzhiyun 	{RES4360_XTAL_PU,               0x00430002}, /* Changed for 4360B1 */
977*4882a593Smuzhiyun };
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm4369a0_res_depend)[] = {
980*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_DUMMY),			RES_DEPEND_SET, 0x00000000, NULL},
981*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_ABUCK),			RES_DEPEND_SET, 0x00000005, NULL},
982*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PMU_SLEEP),			RES_DEPEND_SET, 0x00000001, NULL},
983*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MISCLDO),			RES_DEPEND_SET, 0x00000007, NULL},
984*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_LDO3P3),			RES_DEPEND_SET, 0x00000001, NULL},
985*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_FAST_LPO_AVAIL),		RES_DEPEND_SET, 0x00000005, NULL},
986*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_XTAL_PU),			RES_DEPEND_SET, 0x00000007, NULL},
987*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_XTAL_STABLE),		RES_DEPEND_SET, 0x00000047, NULL},
988*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PWRSW_DIG),			RES_DEPEND_SET, 0x060000cf, NULL},
989*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SR_DIG),			RES_DEPEND_SET, 0x060001cf, NULL},
990*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SLEEP_DIG),			RES_DEPEND_SET, 0x060003cf, NULL},
991*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PWRSW_AUX),			RES_DEPEND_SET, 0x040000cf, NULL},
992*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SR_AUX),			RES_DEPEND_SET, 0x040008cf, NULL},
993*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SLEEP_AUX),			RES_DEPEND_SET, 0x040018cf, NULL},
994*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PWRSW_MAIN),		RES_DEPEND_SET, 0x040000cf, NULL},
995*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SR_MAIN),			RES_DEPEND_SET, 0x040040cf, NULL},
996*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SLEEP_MAIN),		RES_DEPEND_SET, 0x0400c0cf, NULL},
997*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_DIG_CORE_RDY),		RES_DEPEND_SET, 0x060007cf, NULL},
998*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_CORE_RDY_AUX),		RES_DEPEND_SET, 0x040038cf, NULL},
999*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_ALP_AVAIL),			RES_DEPEND_SET, 0x060207cf, NULL},
1000*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_RADIO_AUX_PU),		RES_DEPEND_SET, 0x040438df, NULL},
1001*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MINIPMU_AUX_PU),		RES_DEPEND_SET, 0x041438df, NULL},
1002*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_CORE_RDY_MAIN),		RES_DEPEND_SET, 0x0401c0cf, NULL},
1003*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_RADIO_MAIN_PU),		RES_DEPEND_SET, 0x0441c0df, NULL},
1004*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MINIPMU_MAIN_PU),		RES_DEPEND_SET, 0x04c1c0df, NULL},
1005*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PCIE_EP_PU),		RES_DEPEND_SET, 0x040000cf, NULL},
1006*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_COLD_START_WAIT),		RES_DEPEND_SET, 0x0000000f, NULL},
1007*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_ARMHTAVAIL),		RES_DEPEND_SET, 0x060a07cf, NULL},
1008*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_HT_AVAIL),			RES_DEPEND_SET, 0x060a07cf, NULL},
1009*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MACPHY_AUX_CLK_AVAIL),	RES_DEPEND_SET, 0x163e3fdf, NULL},
1010*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MACPHY_MAIN_CLK_AVAIL),	RES_DEPEND_SET, 0x17cbc7df, NULL},
1011*4882a593Smuzhiyun };
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm4369a0_res_depend_fastlpo_pcie)[] = {
1014*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_DUMMY),			RES_DEPEND_SET, 0x00000000, NULL},
1015*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_ABUCK),			RES_DEPEND_SET, 0x00000005, NULL},
1016*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PMU_SLEEP),			RES_DEPEND_SET, 0x00000001, NULL},
1017*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MISCLDO),			RES_DEPEND_SET, 0x00000007, NULL},
1018*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_LDO3P3),			RES_DEPEND_SET, 0x00000001, NULL},
1019*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_FAST_LPO_AVAIL),		RES_DEPEND_SET, 0x00000005, NULL},
1020*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_XTAL_PU),			RES_DEPEND_SET, 0x00000007, NULL},
1021*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_XTAL_STABLE),		RES_DEPEND_SET, 0x00000047, NULL},
1022*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PWRSW_DIG),                 RES_DEPEND_SET, 0x060000ef, NULL},
1023*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SR_DIG),                    RES_DEPEND_SET, 0x060001ef, NULL},
1024*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SLEEP_DIG),                 RES_DEPEND_SET, 0x060003ef, NULL},
1025*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PWRSW_AUX),                 RES_DEPEND_SET, 0x040000ef, NULL},
1026*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SR_AUX),                    RES_DEPEND_SET, 0x040008ef, NULL},
1027*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SLEEP_AUX),                 RES_DEPEND_SET, 0x040018ef, NULL},
1028*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PWRSW_MAIN),                RES_DEPEND_SET, 0x040000ef, NULL},
1029*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SR_MAIN),                   RES_DEPEND_SET, 0x040040ef, NULL},
1030*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_SLEEP_MAIN),                RES_DEPEND_SET, 0x0400c0ef, NULL},
1031*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_DIG_CORE_RDY),              RES_DEPEND_SET, 0x060007ef, NULL},
1032*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_CORE_RDY_AUX),              RES_DEPEND_SET, 0x040038ef, NULL},
1033*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_ALP_AVAIL),                 RES_DEPEND_SET, 0x060207ef, NULL},
1034*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_RADIO_AUX_PU),              RES_DEPEND_SET, 0x040438ff, NULL},
1035*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MINIPMU_AUX_PU),            RES_DEPEND_SET, 0x041438ff, NULL},
1036*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_CORE_RDY_MAIN),             RES_DEPEND_SET, 0x0401c0ef, NULL},
1037*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_RADIO_MAIN_PU),             RES_DEPEND_SET, 0x0441c0ff, NULL},
1038*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MINIPMU_MAIN_PU),           RES_DEPEND_SET, 0x04c1c0ff, NULL},
1039*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_PCIE_EP_PU),                RES_DEPEND_SET, 0x0400002f, NULL},
1040*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_COLD_START_WAIT),           RES_DEPEND_SET, 0x0000002f, NULL},
1041*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_ARMHTAVAIL),                RES_DEPEND_SET, 0x060a07ef, NULL},
1042*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_HT_AVAIL),                  RES_DEPEND_SET, 0x060a07ef, NULL},
1043*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MACPHY_AUX_CLK_AVAIL),      RES_DEPEND_SET, 0x163e3fff, NULL},
1044*4882a593Smuzhiyun 	{PMURES_BIT(RES4369_MACPHY_MAIN_CLK_AVAIL),     RES_DEPEND_SET, 0x17cbc7ff, NULL},
1045*4882a593Smuzhiyun };
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4369a0_res_updown)[] = {
1048*4882a593Smuzhiyun 	{RES4369_DUMMY,                 0x00220022},
1049*4882a593Smuzhiyun 	{RES4369_ABUCK,                 0x00c80022},
1050*4882a593Smuzhiyun 	{RES4369_PMU_SLEEP,             0x00c80022},
1051*4882a593Smuzhiyun 	{RES4369_MISCLDO,               0x00bd0022},
1052*4882a593Smuzhiyun 	{RES4369_LDO3P3,                0x00bd0022},
1053*4882a593Smuzhiyun 	{RES4369_FAST_LPO_AVAIL,        0x01500022},
1054*4882a593Smuzhiyun 	{RES4369_XTAL_PU,               0x07d00022},
1055*4882a593Smuzhiyun 	{RES4369_XTAL_STABLE,           0x00220022},
1056*4882a593Smuzhiyun 	{RES4369_PWRSW_DIG,             0x02100087},
1057*4882a593Smuzhiyun 	{RES4369_SR_DIG,                0x02000200},
1058*4882a593Smuzhiyun 	{RES4369_SLEEP_DIG,             0x00220022},
1059*4882a593Smuzhiyun 	{RES4369_PWRSW_AUX,             0x03900087},
1060*4882a593Smuzhiyun 	{RES4369_SR_AUX,                0x01cc01cc},
1061*4882a593Smuzhiyun 	{RES4369_SLEEP_AUX,             0x00220022},
1062*4882a593Smuzhiyun 	{RES4369_PWRSW_MAIN,            0x03900087},
1063*4882a593Smuzhiyun 	{RES4369_SR_MAIN,               0x02000200},
1064*4882a593Smuzhiyun 	{RES4369_SLEEP_MAIN,            0x00220022},
1065*4882a593Smuzhiyun 	{RES4369_DIG_CORE_RDY,          0x00220044},
1066*4882a593Smuzhiyun 	{RES4369_CORE_RDY_AUX,          0x00220044},
1067*4882a593Smuzhiyun 	{RES4369_ALP_AVAIL,             0x00220044},
1068*4882a593Smuzhiyun 	{RES4369_RADIO_AUX_PU,          0x006e0022},
1069*4882a593Smuzhiyun 	{RES4369_MINIPMU_AUX_PU,        0x00460022},
1070*4882a593Smuzhiyun 	{RES4369_CORE_RDY_MAIN,         0x00220022},
1071*4882a593Smuzhiyun 	{RES4369_RADIO_MAIN_PU,         0x006e0022},
1072*4882a593Smuzhiyun 	{RES4369_MINIPMU_MAIN_PU,       0x00460022},
1073*4882a593Smuzhiyun 	{RES4369_PCIE_EP_PU,            0x02100087},
1074*4882a593Smuzhiyun 	{RES4369_COLD_START_WAIT,       0x00220022},
1075*4882a593Smuzhiyun 	{RES4369_ARMHTAVAIL,            0x00a80022},
1076*4882a593Smuzhiyun 	{RES4369_HT_AVAIL,              RES4369_HTAVAIL_VAL},
1077*4882a593Smuzhiyun 	{RES4369_MACPHY_AUX_CLK_AVAIL,  0x00640022},
1078*4882a593Smuzhiyun 	{RES4369_MACPHY_MAIN_CLK_AVAIL, 0x00640022},
1079*4882a593Smuzhiyun };
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4369a0_res_updown_fastlpo_pmu)[] = {
1082*4882a593Smuzhiyun 	{RES4369_DUMMY,                 0x00220022},
1083*4882a593Smuzhiyun 	{RES4369_ABUCK,                 0x00c80022},
1084*4882a593Smuzhiyun 	{RES4369_PMU_SLEEP,             0x00c80022},
1085*4882a593Smuzhiyun 	{RES4369_MISCLDO,               0x00bd0022},
1086*4882a593Smuzhiyun 	{RES4369_LDO3P3,                0x00bd0022},
1087*4882a593Smuzhiyun 	{RES4369_FAST_LPO_AVAIL,        0x01500022},
1088*4882a593Smuzhiyun 	{RES4369_XTAL_PU,               0x07d00022},
1089*4882a593Smuzhiyun 	{RES4369_XTAL_STABLE,           0x00220022},
1090*4882a593Smuzhiyun 	{RES4369_PWRSW_DIG,             0x02100087},
1091*4882a593Smuzhiyun 	{RES4369_SR_DIG,                0x02000200},
1092*4882a593Smuzhiyun 	{RES4369_SLEEP_DIG,             0x00220022},
1093*4882a593Smuzhiyun 	{RES4369_PWRSW_AUX,             0x03900087},
1094*4882a593Smuzhiyun 	{RES4369_SR_AUX,                0x01cc01cc},
1095*4882a593Smuzhiyun 	{RES4369_SLEEP_AUX,             0x00220022},
1096*4882a593Smuzhiyun 	{RES4369_PWRSW_MAIN,            0x03900087},
1097*4882a593Smuzhiyun 	{RES4369_SR_MAIN,               0x02000200},
1098*4882a593Smuzhiyun 	{RES4369_SLEEP_MAIN,            0x00220022},
1099*4882a593Smuzhiyun 	{RES4369_DIG_CORE_RDY,          0x00220044},
1100*4882a593Smuzhiyun 	{RES4369_CORE_RDY_AUX,          0x00220044},
1101*4882a593Smuzhiyun 	{RES4369_ALP_AVAIL,             0x00220044},
1102*4882a593Smuzhiyun 	{RES4369_RADIO_AUX_PU,          0x006e0022},
1103*4882a593Smuzhiyun 	{RES4369_MINIPMU_AUX_PU,        0x00460022},
1104*4882a593Smuzhiyun 	{RES4369_CORE_RDY_MAIN,         0x00220022},
1105*4882a593Smuzhiyun 	{RES4369_RADIO_MAIN_PU,         0x006e0022},
1106*4882a593Smuzhiyun 	{RES4369_MINIPMU_MAIN_PU,       0x00460022},
1107*4882a593Smuzhiyun 	{RES4369_PCIE_EP_PU,            0x01200087},
1108*4882a593Smuzhiyun 	{RES4369_COLD_START_WAIT,       0x00220022},
1109*4882a593Smuzhiyun 	{RES4369_ARMHTAVAIL,            0x00a80022},
1110*4882a593Smuzhiyun 	{RES4369_HT_AVAIL,              RES4369_HTAVAIL_VAL},
1111*4882a593Smuzhiyun 	{RES4369_MACPHY_AUX_CLK_AVAIL,  0x00640022},
1112*4882a593Smuzhiyun 	{RES4369_MACPHY_MAIN_CLK_AVAIL, 0x00640022},
1113*4882a593Smuzhiyun };
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4369b0_res_updown)[] = {
1116*4882a593Smuzhiyun 	{RES4369_DUMMY,                 0x00220022},
1117*4882a593Smuzhiyun 	{RES4369_ABUCK,                 0x00c80022},
1118*4882a593Smuzhiyun 	{RES4369_PMU_SLEEP,             0x00c80022},
1119*4882a593Smuzhiyun 	{RES4369_MISCLDO,               0x00bd0022},
1120*4882a593Smuzhiyun 	{RES4369_LDO3P3,                0x01ad0022},
1121*4882a593Smuzhiyun 	{RES4369_FAST_LPO_AVAIL,        0x01500022},
1122*4882a593Smuzhiyun 	{RES4369_XTAL_PU,               0x05dc0022},
1123*4882a593Smuzhiyun 	{RES4369_XTAL_STABLE,           0x00220022},
1124*4882a593Smuzhiyun 	{RES4369_PWRSW_DIG,             0x02100087},
1125*4882a593Smuzhiyun 	{RES4369_SR_DIG,                0x00A000A0},
1126*4882a593Smuzhiyun 	{RES4369_SLEEP_DIG,             0x00220022},
1127*4882a593Smuzhiyun 	{RES4369_PWRSW_AUX,             0x03900087},
1128*4882a593Smuzhiyun 	{RES4369_SR_AUX,                0x01400140},
1129*4882a593Smuzhiyun 	{RES4369_SLEEP_AUX,             0x00220022},
1130*4882a593Smuzhiyun 	{RES4369_PWRSW_MAIN,            0x03900087},
1131*4882a593Smuzhiyun 	{RES4369_SR_MAIN,               0x01A001A0},
1132*4882a593Smuzhiyun 	{RES4369_SLEEP_MAIN,            0x00220022},
1133*4882a593Smuzhiyun 	{RES4369_DIG_CORE_RDY,          0x00220044},
1134*4882a593Smuzhiyun 	{RES4369_CORE_RDY_AUX,          0x00220044},
1135*4882a593Smuzhiyun 	{RES4369_ALP_AVAIL,             0x00220044},
1136*4882a593Smuzhiyun 	{RES4369_RADIO_AUX_PU,          0x006e0022},
1137*4882a593Smuzhiyun 	{RES4369_MINIPMU_AUX_PU,        0x00460022},
1138*4882a593Smuzhiyun 	{RES4369_CORE_RDY_MAIN,         0x00220022},
1139*4882a593Smuzhiyun 	{RES4369_RADIO_MAIN_PU,         0x006e0022},
1140*4882a593Smuzhiyun 	{RES4369_MINIPMU_MAIN_PU,       0x00460022},
1141*4882a593Smuzhiyun 	{RES4369_PCIE_EP_PU,            0x02100087},
1142*4882a593Smuzhiyun 	{RES4369_COLD_START_WAIT,       0x00220022},
1143*4882a593Smuzhiyun 	{RES4369_ARMHTAVAIL,            0x00a80022},
1144*4882a593Smuzhiyun 	{RES4369_HT_AVAIL,              RES4369_HTAVAIL_VAL},
1145*4882a593Smuzhiyun 	{RES4369_MACPHY_AUX_CLK_AVAIL,  0x00640022},
1146*4882a593Smuzhiyun 	{RES4369_MACPHY_MAIN_CLK_AVAIL, 0x00640022},
1147*4882a593Smuzhiyun };
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4369b0_res_updown_fastlpo_pmu)[] = {
1150*4882a593Smuzhiyun 	{RES4369_DUMMY,                 0x00220022},
1151*4882a593Smuzhiyun 	{RES4369_ABUCK,                 0x00c80022},
1152*4882a593Smuzhiyun 	{RES4369_PMU_SLEEP,             0x00c80022},
1153*4882a593Smuzhiyun 	{RES4369_MISCLDO,               0x00bd0022},
1154*4882a593Smuzhiyun 	{RES4369_LDO3P3,                0x01ad0022},
1155*4882a593Smuzhiyun 	{RES4369_FAST_LPO_AVAIL,        0x01500022},
1156*4882a593Smuzhiyun 	{RES4369_XTAL_PU,               0x05dc0022},
1157*4882a593Smuzhiyun 	{RES4369_XTAL_STABLE,           0x00220022},
1158*4882a593Smuzhiyun 	{RES4369_PWRSW_DIG,             0x02100087},
1159*4882a593Smuzhiyun 	{RES4369_SR_DIG,                0x02000200},
1160*4882a593Smuzhiyun 	{RES4369_SLEEP_DIG,             0x00220022},
1161*4882a593Smuzhiyun 	{RES4369_PWRSW_AUX,             0x03900087},
1162*4882a593Smuzhiyun 	{RES4369_SR_AUX,                0x01cc01cc},
1163*4882a593Smuzhiyun 	{RES4369_SLEEP_AUX,             0x00220022},
1164*4882a593Smuzhiyun 	{RES4369_PWRSW_MAIN,            0x03900087},
1165*4882a593Smuzhiyun 	{RES4369_SR_MAIN,               0x02000200},
1166*4882a593Smuzhiyun 	{RES4369_SLEEP_MAIN,            0x00220022},
1167*4882a593Smuzhiyun 	{RES4369_DIG_CORE_RDY,          0x00220044},
1168*4882a593Smuzhiyun 	{RES4369_CORE_RDY_AUX,          0x00220044},
1169*4882a593Smuzhiyun 	{RES4369_ALP_AVAIL,             0x00220044},
1170*4882a593Smuzhiyun 	{RES4369_RADIO_AUX_PU,          0x006e0022},
1171*4882a593Smuzhiyun 	{RES4369_MINIPMU_AUX_PU,        0x00460022},
1172*4882a593Smuzhiyun 	{RES4369_CORE_RDY_MAIN,         0x00220022},
1173*4882a593Smuzhiyun 	{RES4369_RADIO_MAIN_PU,         0x006e0022},
1174*4882a593Smuzhiyun 	{RES4369_MINIPMU_MAIN_PU,       0x00460022},
1175*4882a593Smuzhiyun 	{RES4369_PCIE_EP_PU,            0x01200087},
1176*4882a593Smuzhiyun 	{RES4369_COLD_START_WAIT,       0x00220022},
1177*4882a593Smuzhiyun 	{RES4369_ARMHTAVAIL,            0x00a80022},
1178*4882a593Smuzhiyun 	{RES4369_HT_AVAIL,              RES4369_HTAVAIL_VAL},
1179*4882a593Smuzhiyun 	{RES4369_MACPHY_AUX_CLK_AVAIL,  0x00640022},
1180*4882a593Smuzhiyun 	{RES4369_MACPHY_MAIN_CLK_AVAIL, 0x00640022},
1181*4882a593Smuzhiyun };
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm4362_res_depend)[] = {
1184*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_DUMMY),                 RES_DEPEND_SET, 0x00000000, NULL},
1185*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_ABUCK),                 RES_DEPEND_SET, 0x00000005, NULL},
1186*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_PMU_SLEEP),             RES_DEPEND_SET, 0x00000001, NULL},
1187*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_MISCLDO_PU),            RES_DEPEND_SET, 0x00000007, NULL},
1188*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_LDO3P3_PU),             RES_DEPEND_SET, 0x00000005, NULL},
1189*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_FAST_LPO_AVAIL),        RES_DEPEND_SET, 0x00000005, NULL},
1190*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_XTAL_PU),               RES_DEPEND_SET, 0x00000007, NULL},
1191*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_XTAL_STABLE),           RES_DEPEND_SET, 0x00000047, NULL},
1192*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_PWRSW_DIG),             RES_DEPEND_SET, 0x060000cf, NULL},
1193*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_SR_DIG),                RES_DEPEND_SET, 0x060001cf, NULL},
1194*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_SLEEP_DIG),             RES_DEPEND_SET, 0x060003cf, NULL},
1195*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_PWRSW_AUX),             RES_DEPEND_SET, 0x040000cf, NULL},
1196*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_SR_AUX),                RES_DEPEND_SET, 0x040008cf, NULL},
1197*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_SLEEP_AUX),             RES_DEPEND_SET, 0x040018cf, NULL},
1198*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_PWRSW_MAIN),            RES_DEPEND_SET, 0x040000cf, NULL},
1199*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_SR_MAIN),               RES_DEPEND_SET, 0x040040cf, NULL},
1200*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_SLEEP_MAIN),            RES_DEPEND_SET, 0x0400c0cf, NULL},
1201*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_DIG_CORE_RDY),          RES_DEPEND_SET, 0x060007cf, NULL},
1202*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_CORE_RDY_AUX),          RES_DEPEND_SET, 0x040038cf, NULL},
1203*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_ALP_AVAIL),             RES_DEPEND_SET, 0x060207cf, NULL},
1204*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_RADIO_AUX_PU),          RES_DEPEND_SET, 0x040438df, NULL},
1205*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_MINIPMU_AUX_PU),        RES_DEPEND_SET, 0x041438df, NULL},
1206*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_CORE_RDY_MAIN),         RES_DEPEND_SET, 0x0401c0cf, NULL},
1207*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_RADIO_MAIN_PU),         RES_DEPEND_SET, 0x0441c0df, NULL},
1208*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_MINIPMU_MAIN_PU),       RES_DEPEND_SET, 0x04c1c0df, NULL},
1209*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_PCIE_EP_PU),            RES_DEPEND_SET, 0x040000cf, NULL},
1210*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_COLD_START_WAIT),       RES_DEPEND_SET, 0x0000000f, NULL},
1211*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_ARMHTAVAIL),            RES_DEPEND_SET, 0x060a07cf, NULL},
1212*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_HT_AVAIL),              RES_DEPEND_SET, 0x060a07cf, NULL},
1213*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_MACPHY_AUX_CLK_AVAIL),  RES_DEPEND_SET, 0x163e3fdf, NULL},
1214*4882a593Smuzhiyun 	{PMURES_BIT(RES4362_MACPHY_MAIN_CLK_AVAIL), RES_DEPEND_SET, 0x17cbc7df, NULL},
1215*4882a593Smuzhiyun };
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4362_res_updown)[] = {
1218*4882a593Smuzhiyun 	{RES4362_DUMMY,                 0x00220022},
1219*4882a593Smuzhiyun 	{RES4362_ABUCK,                 0x00c80022},
1220*4882a593Smuzhiyun 	{RES4362_PMU_SLEEP,             0x00c80022},
1221*4882a593Smuzhiyun 	{RES4362_MISCLDO_PU,            0x00bd0022},
1222*4882a593Smuzhiyun 	{RES4362_LDO3P3_PU,             0x01ad0022},
1223*4882a593Smuzhiyun 	{RES4362_FAST_LPO_AVAIL,        0x01500022},
1224*4882a593Smuzhiyun 	{RES4362_XTAL_PU,               0x05dc0022},
1225*4882a593Smuzhiyun 	{RES4362_XTAL_STABLE,           0x00220022},
1226*4882a593Smuzhiyun 	{RES4362_PWRSW_DIG,             0x009000ca},
1227*4882a593Smuzhiyun 	{RES4362_SR_DIG,                0x00A000A0},
1228*4882a593Smuzhiyun 	{RES4362_SLEEP_DIG,             0x00220022},
1229*4882a593Smuzhiyun 	{RES4362_PWRSW_AUX,             0x039000ca},
1230*4882a593Smuzhiyun 	{RES4362_SR_AUX,                0x01400140},
1231*4882a593Smuzhiyun 	{RES4362_SLEEP_AUX,             0x00220022},
1232*4882a593Smuzhiyun 	{RES4362_PWRSW_MAIN,            0x039000ca},
1233*4882a593Smuzhiyun 	{RES4362_SR_MAIN,               0x01a001a0},
1234*4882a593Smuzhiyun 	{RES4362_SLEEP_MAIN,            0x00220022},
1235*4882a593Smuzhiyun 	{RES4362_DIG_CORE_RDY,          0x00220044},
1236*4882a593Smuzhiyun 	{RES4362_CORE_RDY_AUX,          0x00220044},
1237*4882a593Smuzhiyun 	{RES4362_ALP_AVAIL,             0x00220044},
1238*4882a593Smuzhiyun 	{RES4362_RADIO_AUX_PU,          0x006e0022},
1239*4882a593Smuzhiyun 	{RES4362_MINIPMU_AUX_PU,        0x00460022},
1240*4882a593Smuzhiyun 	{RES4362_CORE_RDY_MAIN,         0x00220022},
1241*4882a593Smuzhiyun 	{RES4362_RADIO_MAIN_PU,         0x006e0022},
1242*4882a593Smuzhiyun 	{RES4362_MINIPMU_MAIN_PU,       0x00460022},
1243*4882a593Smuzhiyun 	{RES4362_PCIE_EP_PU,            0x009000ca},
1244*4882a593Smuzhiyun 	{RES4362_COLD_START_WAIT,       0x00220022},
1245*4882a593Smuzhiyun 	{RES4362_ARMHTAVAIL,            0x00a80022},
1246*4882a593Smuzhiyun 	{RES4362_HT_AVAIL,              0x00a80022},
1247*4882a593Smuzhiyun 	{RES4362_MACPHY_AUX_CLK_AVAIL,  0x00640022},
1248*4882a593Smuzhiyun 	{RES4362_MACPHY_MAIN_CLK_AVAIL, 0x00640022},
1249*4882a593Smuzhiyun };
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4378b0_res_updown)[] = {
1252*4882a593Smuzhiyun 	{RES4378_ABUCK,			0x00c80022},
1253*4882a593Smuzhiyun 	{RES4378_PMU_SLEEP,		0x011c0022},
1254*4882a593Smuzhiyun 	{RES4378_MISC_LDO,		0x00c80022},
1255*4882a593Smuzhiyun 	{RES4378_XTAL_PU,		0x05dc0022},
1256*4882a593Smuzhiyun 	{RES4378_SR_DIG,		0x00700070},
1257*4882a593Smuzhiyun 	{RES4378_SR_AUX,		0x01800180},
1258*4882a593Smuzhiyun 	{RES4378_SR_MAIN,		0x01a001a0},
1259*4882a593Smuzhiyun 	{RES4378_RADIO_AUX_PU,		0x006e0022},
1260*4882a593Smuzhiyun 	{RES4378_MINIPMU_AUX_PU,	0x00460022},
1261*4882a593Smuzhiyun 	{RES4378_RADIO_MAIN_PU,		0x006e0022},
1262*4882a593Smuzhiyun 	{RES4378_MINIPMU_MAIN_PU,	0x00460022},
1263*4882a593Smuzhiyun 	{RES4378_CORE_RDY_CB,		0x00220022},
1264*4882a593Smuzhiyun #ifdef BCMPCIE_TREFUP_HW_SUPPORT
1265*4882a593Smuzhiyun 	{RES4378_PWRSW_CB,              0x015e00ca},
1266*4882a593Smuzhiyun #endif
1267*4882a593Smuzhiyun 	{RES4378_MACPHY_AUX_CLK_AVAIL,	0x00640022},
1268*4882a593Smuzhiyun 	{RES4378_MACPHY_MAIN_CLK_AVAIL,	0x00640022},
1269*4882a593Smuzhiyun };
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm4378b0_res_depend)[] = {
1272*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_ABUCK),			RES_DEPEND_SET, 0x00000005, NULL},
1273*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_PMU_SLEEP),			RES_DEPEND_SET, 0x00000001, NULL},
1274*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_MISC_LDO),			RES_DEPEND_SET, 0x00000007, NULL},
1275*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_LDO3P3_PU),			RES_DEPEND_SET, 0x00000001, NULL},
1276*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_FAST_LPO_AVAIL),		RES_DEPEND_SET, 0x00000005, NULL},
1277*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_XTAL_PU),			RES_DEPEND_SET, 0x00000007, NULL},
1278*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_XTAL_STABLE),		RES_DEPEND_SET, 0x00000047, NULL},
1279*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_PWRSW_DIG),			RES_DEPEND_SET, 0x060000ef, NULL},
1280*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_SR_DIG),			RES_DEPEND_SET, 0x060001ef, NULL},
1281*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_SLEEP_DIG),			RES_DEPEND_SET, 0x060003ef, NULL},
1282*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_PWRSW_AUX),			RES_DEPEND_SET, 0x060000ef, NULL},
1283*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_SR_AUX),			RES_DEPEND_SET, 0x060008ef, NULL},
1284*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_SLEEP_AUX),			RES_DEPEND_SET, 0x060018ef, NULL},
1285*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_PWRSW_MAIN),		RES_DEPEND_SET, 0x060000ef, NULL},
1286*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_SR_MAIN),			RES_DEPEND_SET, 0x060040ef, NULL},
1287*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_SLEEP_MAIN),		RES_DEPEND_SET, 0x0600c0ef, NULL},
1288*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_CORE_RDY_DIG),		RES_DEPEND_SET, 0x060007ef, NULL},
1289*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_CORE_RDY_AUX),		RES_DEPEND_SET, 0x06023fef, NULL},
1290*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_ALP_AVAIL),			RES_DEPEND_SET, 0x000000c7, NULL},
1291*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_RADIO_AUX_PU),		RES_DEPEND_SET, 0x06063fff, NULL},
1292*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_MINIPMU_AUX_PU),		RES_DEPEND_SET, 0x06163fff, NULL},
1293*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_CORE_RDY_MAIN),		RES_DEPEND_SET, 0x0603c7ef, NULL},
1294*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_RADIO_MAIN_PU),		RES_DEPEND_SET, 0x0643c7ff, NULL},
1295*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_MINIPMU_MAIN_PU),		RES_DEPEND_SET, 0x06c3c7ff, NULL},
1296*4882a593Smuzhiyun #ifdef BCMPCIE_TREFUP_HW_SUPPORT
1297*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_CORE_RDY_CB),		RES_DEPEND_SET, 0x0400002f, NULL},
1298*4882a593Smuzhiyun #else
1299*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_CORE_RDY_CB),		RES_DEPEND_SET, 0x040000ef, NULL},
1300*4882a593Smuzhiyun #endif
1301*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_PWRSW_CB),			RES_DEPEND_SET, 0x0000002f, NULL},
1302*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_ARMHTAVAIL),		RES_DEPEND_SET, 0x000800c7, NULL},
1303*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_HT_AVAIL),			RES_DEPEND_SET, 0x000800c7, NULL},
1304*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_MACPHY_AUX_CLK_AVAIL),	RES_DEPEND_SET, 0x163e3fff, NULL},
1305*4882a593Smuzhiyun 	{PMURES_BIT(RES4378_MACPHY_MAIN_CLK_AVAIL),	RES_DEPEND_SET, 0x17cbc7ff, NULL},
1306*4882a593Smuzhiyun };
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4387b0_res_updown_qt)[] = {
1309*4882a593Smuzhiyun 	{RES4387_XTAL_PU,		0x012c0033},
1310*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		0x38993899},
1311*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		0x38993899},
1312*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		0x38993899},
1313*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		0x38993899},
1314*4882a593Smuzhiyun 	{RES4387_CORE_RDY_CB,		0x00960033},
1315*4882a593Smuzhiyun };
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4387b0_res_subst_trans_tmr_qt)[] = {
1318*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		0, 0x38993800},
1319*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		1, 0x36000600},
1320*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		2, 0x01000002},
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		0, 0x38993800},
1323*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		1, 0x36000600},
1324*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		2, 0x01000002},
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		0, 0x38993800},
1327*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		1, 0x36000600},
1328*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		2, 0x01000002},
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		0, 0x38993800},
1331*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		1, 0x36000600},
1332*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		2, 0x01000002},
1333*4882a593Smuzhiyun };
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4387b0_res_updown)[] = {
1336*4882a593Smuzhiyun 	{RES4387_PMU_SLEEP,		0x00960022},
1337*4882a593Smuzhiyun 	{RES4387_MISC_LDO,		0x00320022},
1338*4882a593Smuzhiyun 	{RES4387_XTAL_HQ,		0x00210021},
1339*4882a593Smuzhiyun 	{RES4387_XTAL_PU,		0x03e80033},
1340*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		0x04b002bc},
1341*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		0x060e03bc},
1342*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		0x060e03bc},
1343*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		0x060e03bc},
1344*4882a593Smuzhiyun 	{RES4387_CORE_RDY_CB,		0x000a0033},
1345*4882a593Smuzhiyun 	{RES4387_PWRSW_CB,		0x006400ca},
1346*4882a593Smuzhiyun };
1347*4882a593Smuzhiyun 
1348*4882a593Smuzhiyun static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4387b0_res_subst_trans_tmr)[] = {
1349*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		0, 0x04b002bc},
1350*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		1, 0x02500210},
1351*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		2, 0x00a00010},
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		0, 0x060e03ac},
1354*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		1, 0x028a0134},
1355*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		2, 0x00320002},
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		0, 0x060e03b2},
1358*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		1, 0x028a0134},
1359*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		2, 0x00320002},
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		0, 0x060e03b2},
1362*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		1, 0x028a0134},
1363*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		2, 0x00320002},
1364*4882a593Smuzhiyun };
1365*4882a593Smuzhiyun 
1366*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm4387b0_res_depend)[] = {
1367*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_DUMMY),			RES_DEPEND_SET,  0x0, NULL},
1368*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RESERVED_1),		RES_DEPEND_SET,  0x0, NULL},
1369*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PMU_SLEEP),			RES_DEPEND_SET,  0x1, NULL},
1370*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_MISC_LDO),			RES_DEPEND_SET,  0x5, NULL},
1371*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RESERVED_4),		RES_DEPEND_SET,  0x0, NULL},
1372*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_XTAL_HQ),			RES_DEPEND_SET,  0xc5, NULL},
1373*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_XTAL_PU),			RES_DEPEND_SET,  0x5, NULL},
1374*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_XTAL_STABLE),		RES_DEPEND_SET,  0x45, NULL},
1375*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_DIG),			RES_DEPEND_SET,  0x060000CD, NULL},
1376*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_BTMAIN),		RES_DEPEND_SET,  0xCD, NULL},
1377*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_BTSC),		RES_DEPEND_SET,  0xC5, NULL},
1378*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_AUX),			RES_DEPEND_SET,  0xCD, NULL},
1379*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_SCAN),		RES_DEPEND_SET,  0xCD, NULL},
1380*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_SCAN),		RES_DEPEND_SET,  0x060010CD, NULL},
1381*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_MAIN),		RES_DEPEND_SET,  0xCD, NULL},
1382*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RESERVED_15),		RES_DEPEND_SET,  0x0, NULL},
1383*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RESERVED_16),		RES_DEPEND_SET,  0x0, NULL},
1384*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_DIG),		RES_DEPEND_SET,  0x060001CD, NULL},
1385*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_AUX),		RES_DEPEND_SET,  0x060209CD, NULL},
1386*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_ALP_AVAIL),			RES_DEPEND_SET,  0xC5, NULL},
1387*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RADIO_PU_AUX),		RES_DEPEND_SET,  0x060609CD, NULL},
1388*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RADIO_PU_SCAN),		RES_DEPEND_SET,  0x060030CD, NULL},
1389*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_MAIN),		RES_DEPEND_SET,  0x060241CD, NULL},
1390*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RADIO_PU_MAIN),		RES_DEPEND_SET,  0x064241CD, NULL},
1391*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_MACPHY_CLK_SCAN),		RES_DEPEND_SET,  0x162830CD, NULL},
1392*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_CB),		RES_DEPEND_SET,  0x0400000D, NULL},
1393*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_CB),			RES_DEPEND_SET,  0x0000000D, NULL},
1394*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_ARMCLK_AVAIL),		RES_DEPEND_SET,  0x000800CD, NULL},
1395*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_HT_AVAIL),			RES_DEPEND_SET,  0x000800CD, NULL},
1396*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_MACPHY_CLK_AUX),		RES_DEPEND_SET,  0x161E09ED, NULL},
1397*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_MACPHY_CLK_MAIN),		RES_DEPEND_SET,  0x16CA41ED, NULL},
1398*4882a593Smuzhiyun };
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4387c0_res_updown_topoff)[] = {
1401*4882a593Smuzhiyun 	{RES4387_PMU_SLEEP,		0x02000022},
1402*4882a593Smuzhiyun 	{RES4387_MISC_LDO,		0x00320022},
1403*4882a593Smuzhiyun 	{RES4387_SERDES_AFE_RET,	0x00010001},
1404*4882a593Smuzhiyun 	{RES4387_XTAL_HQ,		0x00210021},
1405*4882a593Smuzhiyun 	{RES4387_XTAL_PU,		0x03e80033},
1406*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,	        0x00d20102},
1407*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,	        0x01c201e2},
1408*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,	        0x01020122},
1409*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,	        0x02220242},
1410*4882a593Smuzhiyun 	{RES4387_CORE_RDY_CB,		0x000a0033},
1411*4882a593Smuzhiyun 	{RES4387_PWRSW_CB,		0x006400ca},
1412*4882a593Smuzhiyun };
1413*4882a593Smuzhiyun 
1414*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4387c0_res_updown)[] = {
1415*4882a593Smuzhiyun #ifdef BCM_PMU_FLL_PU_MANAGE
1416*4882a593Smuzhiyun 	{RES4387_FAST_LPO_AVAIL,	0x00960001},
1417*4882a593Smuzhiyun #endif
1418*4882a593Smuzhiyun 	{RES4387_PMU_SLEEP,		0x00960022},
1419*4882a593Smuzhiyun 	{RES4387_MISC_LDO,		0x00320022},
1420*4882a593Smuzhiyun 	{RES4387_XTAL_HQ,		0x00210021},
1421*4882a593Smuzhiyun 	{RES4387_XTAL_PU,		0x03e80033},
1422*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,	        0x01320172},
1423*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,	        0x01c201e2},
1424*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,	        0x019201b2},
1425*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,	        0x02220242},
1426*4882a593Smuzhiyun 	{RES4387_CORE_RDY_CB,		0x000a0033},
1427*4882a593Smuzhiyun 	{RES4387_PWRSW_CB,		0x006400ca},
1428*4882a593Smuzhiyun };
1429*4882a593Smuzhiyun 
1430*4882a593Smuzhiyun static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4387c0_res_subst_trans_tmr)[] = {
1431*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		0, 0x01320142},
1432*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		1, 0x00e2005a},
1433*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		2, 0x00c20052},
1434*4882a593Smuzhiyun 	{RES4387_PWRSW_DIG,		3, 0x00020002},
1435*4882a593Smuzhiyun 
1436*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		0, 0x01c201b2},
1437*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		1, 0x0172005a},
1438*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		2, 0x01520052},
1439*4882a593Smuzhiyun 	{RES4387_PWRSW_AUX,		3, 0x00020002},
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		0, 0x02220212},
1442*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		1, 0x01d2005a},
1443*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		2, 0x01b20052},
1444*4882a593Smuzhiyun 	{RES4387_PWRSW_MAIN,		3, 0x00020002},
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		0, 0x01920182},
1447*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		1, 0x0142005a},
1448*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		2, 0x01220052},
1449*4882a593Smuzhiyun 	{RES4387_PWRSW_SCAN,		3, 0x00020002},
1450*4882a593Smuzhiyun };
1451*4882a593Smuzhiyun 
1452*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm4387c0_res_depend)[] = {
1453*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_DUMMY),			RES_DEPEND_SET,  0x0, NULL},
1454*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_FAST_LPO_AVAIL),		RES_DEPEND_SET,  0x0, NULL},
1455*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PMU_LP),			RES_DEPEND_SET,  0x1, NULL},
1456*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_MISC_LDO),			RES_DEPEND_SET,  0x5, NULL},
1457*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_SERDES_AFE_RET),		RES_DEPEND_SET,  0xD, NULL},
1458*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_XTAL_HQ),			RES_DEPEND_SET,  0xC5, NULL},
1459*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_XTAL_PU),			RES_DEPEND_SET,  0x5, NULL},
1460*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_XTAL_STABLE),		RES_DEPEND_SET,  0x45, NULL},
1461*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_DIG),			RES_DEPEND_SET,  0x060000DD, NULL},
1462*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_BTMAIN),		RES_DEPEND_SET,  0xCD, NULL},
1463*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_BTSC),		RES_DEPEND_SET,  0xC5, NULL},
1464*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_AUX),			RES_DEPEND_SET,  0xCD, NULL},
1465*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_SCAN),		RES_DEPEND_SET,  0xCD, NULL},
1466*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_SCAN),		RES_DEPEND_SET,  0x060010DD, NULL},
1467*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_MAIN),		RES_DEPEND_SET,  0xCD, NULL},
1468*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_XTAL_PM_CLK),		RES_DEPEND_SET,  0xC5, NULL},
1469*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RESERVED_16),		RES_DEPEND_SET,  0x0, NULL},
1470*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_DIG),		RES_DEPEND_SET,  0x060001DD, NULL},
1471*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_AUX),		RES_DEPEND_SET,  0x060209DD, NULL},
1472*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_ALP_AVAIL),			RES_DEPEND_SET,  0x80C5, NULL},
1473*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RADIO_PU_AUX),		RES_DEPEND_SET,  0x060609DD, NULL},
1474*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RADIO_PU_SCAN),		RES_DEPEND_SET,  0x060030DD, NULL},
1475*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_MAIN),		RES_DEPEND_SET,  0x060241DD, NULL},
1476*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_RADIO_PU_MAIN),		RES_DEPEND_SET,  0x064241DD, NULL},
1477*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_MACPHY_CLK_SCAN),		RES_DEPEND_SET,  0x1628B0DD, NULL},
1478*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_CORE_RDY_CB),		RES_DEPEND_SET,  0x0400001D, NULL},
1479*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_PWRSW_CB),			RES_DEPEND_SET,  0x0000001D, NULL},
1480*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_ARMCLK_AVAIL),		RES_DEPEND_SET,  0x000880CD, NULL},
1481*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_HT_AVAIL),			RES_DEPEND_SET,  0x000880CD, NULL},
1482*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_MACPHY_CLK_AUX),		RES_DEPEND_SET,  0x161E89FD, NULL},
1483*4882a593Smuzhiyun 	{PMURES_BIT(RES4387_MACPHY_CLK_MAIN),		RES_DEPEND_SET,  0x16CAC1FD, NULL},
1484*4882a593Smuzhiyun };
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4388a0_res_updown_qt)[] = {
1487*4882a593Smuzhiyun 	{RES4388_XTAL_PU,	0x012c0033},
1488*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,	0x38993899},
1489*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,	0x38993899},
1490*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,	0x38993899},
1491*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,	0x38993899},
1492*4882a593Smuzhiyun 	{RES4388_CORE_RDY_CB,	0x00960033},
1493*4882a593Smuzhiyun };
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4388a0_res_subst_trans_tmr_qt)[] = {
1496*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,	0, 0x38993800},
1497*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,	1, 0x36c00600},
1498*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,	2, 0x360005a0},
1499*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,	3, 0x01000002},
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,	0, 0x38993800},
1502*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,	1, 0x36c00600},
1503*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,	2, 0x360005a0},
1504*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,	3, 0x01000002},
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,	0, 0x38993800},
1507*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,	1, 0x36c00600},
1508*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,	2, 0x360005a0},
1509*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,	3, 0x01000002},
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,	0, 0x38993800},
1512*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,	1, 0x33c00600},
1513*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,	2, 0x330005a0},
1514*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,	3, 0x01000002},
1515*4882a593Smuzhiyun };
1516*4882a593Smuzhiyun 
1517*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4388a0_res_updown)[] = {
1518*4882a593Smuzhiyun #ifdef BCM_PMU_FLL_PU_MANAGE
1519*4882a593Smuzhiyun 	{RES4388_FAST_LPO_AVAIL,	0x00960001},
1520*4882a593Smuzhiyun #endif /* BCM_PMU_FLL_PU_MANAGE */
1521*4882a593Smuzhiyun 	{RES4388_PMU_LP,		0x00960022},
1522*4882a593Smuzhiyun 	{RES4388_MISC_LDO,		0x00320022},
1523*4882a593Smuzhiyun 	{RES4388_XTAL_HQ,		0x00210021},
1524*4882a593Smuzhiyun 	{RES4388_XTAL_PU,		0x03e80033},
1525*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,		0x042c0349},
1526*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,		0x0740046a},
1527*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,		0x03c802e8},
1528*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,		0x08080532},
1529*4882a593Smuzhiyun 	{RES4388_CORE_RDY_CB,		0x000a0033},
1530*4882a593Smuzhiyun 	{RES4388_PWRSW_CB,		0x006400ca},
1531*4882a593Smuzhiyun 	{RES4388_MACPHY_CLK_MAIN,	0x00860022},
1532*4882a593Smuzhiyun };
1533*4882a593Smuzhiyun 
1534*4882a593Smuzhiyun static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4388a0_res_subst_trans_tmr)[] = {
1535*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,	0, 0x0428033c},
1536*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,	1, 0x028c0210},
1537*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,	2, 0x01cc01b0},
1538*4882a593Smuzhiyun 	{RES4388_PWRSW_DIG,	3, 0x00a00010},
1539*4882a593Smuzhiyun 
1540*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,	0, 0x0740045a},
1541*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,	1, 0x03580202},
1542*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,	2, 0x02f801a2},
1543*4882a593Smuzhiyun 	{RES4388_PWRSW_AUX,	3, 0x00a00002},
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,	0, 0x08080522},
1546*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,	1, 0x04200202},
1547*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,	2, 0x03c001a2},
1548*4882a593Smuzhiyun 	{RES4388_PWRSW_MAIN,	3, 0x00a00002},
1549*4882a593Smuzhiyun 
1550*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,	0, 0x03c402d8},
1551*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,	1, 0x02280210},
1552*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,	2, 0x016801b0},
1553*4882a593Smuzhiyun 	{RES4388_PWRSW_SCAN,	3, 0x00a00010},
1554*4882a593Smuzhiyun };
1555*4882a593Smuzhiyun 
1556*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm4388a0_res_depend)[] = {
1557*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_DUMMY),		RES_DEPEND_SET, 0x00000000, NULL},
1558*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_FAST_LPO_AVAIL),	RES_DEPEND_SET, 0x00000000, NULL},
1559*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_PMU_LP),		RES_DEPEND_SET, 0x00000001, NULL},
1560*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_MISC_LDO),		RES_DEPEND_SET, 0x00000005, NULL},
1561*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_SERDES_AFE_RET),	RES_DEPEND_SET, 0x0000000d, NULL},
1562*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_XTAL_HQ),		RES_DEPEND_SET, 0x000000c5, NULL},
1563*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_XTAL_PU),		RES_DEPEND_SET, 0x00000005, NULL},
1564*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_XTAL_STABLE),	RES_DEPEND_SET, 0x00000045, NULL},
1565*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_PWRSW_DIG),		RES_DEPEND_SET, 0x060000dd, NULL},
1566*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_BTMC_TOP_RDY),	RES_DEPEND_SET, 0x000000cd, NULL},
1567*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_BTSC_TOP_RDY),	RES_DEPEND_SET, 0x000000c5, NULL},
1568*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_PWRSW_AUX),		RES_DEPEND_SET, 0x000000cd, NULL},
1569*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_PWRSW_SCAN),	RES_DEPEND_SET, 0x000000cd, NULL},
1570*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_CORE_RDY_SCAN),	RES_DEPEND_SET, 0x060211dd, NULL},
1571*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_PWRSW_MAIN),	RES_DEPEND_SET, 0x000000cd, NULL},
1572*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_RESERVED_15),	RES_DEPEND_SET, 0x00000000, NULL},
1573*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_RESERVED_16),	RES_DEPEND_SET, 0x00000000, NULL},
1574*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_CORE_RDY_DIG),	RES_DEPEND_SET, 0x060001dd, NULL},
1575*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_CORE_RDY_AUX),	RES_DEPEND_SET, 0x060209dd, NULL},
1576*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_ALP_AVAIL),		RES_DEPEND_SET, 0x000000c5, NULL},
1577*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_RADIO_PU_AUX),	RES_DEPEND_SET, 0x060609dd, NULL},
1578*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_RADIO_PU_SCAN),	RES_DEPEND_SET, 0x060231dd, NULL},
1579*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_CORE_RDY_MAIN),	RES_DEPEND_SET, 0x060241dd, NULL},
1580*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_RADIO_PU_MAIN),	RES_DEPEND_SET, 0x064241dd, NULL},
1581*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_MACPHY_CLK_SCAN),	RES_DEPEND_SET, 0x162a31fd, NULL},
1582*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_CORE_RDY_CB),	RES_DEPEND_SET, 0x040000dd, NULL},
1583*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_PWRSW_CB),		RES_DEPEND_SET, 0x000000dd, NULL},
1584*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_ARMCLKAVAIL),	RES_DEPEND_SET, 0x000800cd, NULL},
1585*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_HT_AVAIL),		RES_DEPEND_SET, 0x000800cd, NULL},
1586*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_MACPHY_CLK_AUX),	RES_DEPEND_SET, 0x161e09fd, NULL},
1587*4882a593Smuzhiyun 	{PMURES_BIT(RES4388_MACPHY_CLK_MAIN),	RES_DEPEND_SET, 0x16ca41fd, NULL},
1588*4882a593Smuzhiyun };
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4389b0_res_updown_qt)[] = {
1591*4882a593Smuzhiyun 	{RES4389_XTAL_PU,	0x012c0033},
1592*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,	0x38993899},
1593*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,	0x38993899},
1594*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,	0x38993899},
1595*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,	0x38993899},
1596*4882a593Smuzhiyun 	{RES4389_CORE_RDY_CB,	0x00960033},
1597*4882a593Smuzhiyun };
1598*4882a593Smuzhiyun 
1599*4882a593Smuzhiyun static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4389b0_res_subst_trans_tmr_qt)[] = {
1600*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,	0, 0x38993800},
1601*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,	1, 0x36c00600},
1602*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,	2, 0x360005a0},
1603*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,	3, 0x01000002},
1604*4882a593Smuzhiyun 
1605*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,	0, 0x38993800},
1606*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,	1, 0x36c00600},
1607*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,	2, 0x360005a0},
1608*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,	3, 0x01000002},
1609*4882a593Smuzhiyun 
1610*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,	0, 0x38993800},
1611*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,	1, 0x36c00600},
1612*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,	2, 0x360005a0},
1613*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,	3, 0x01000002},
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,	0, 0x38993800},
1616*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,	1, 0x33c00600},
1617*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,	2, 0x330005a0},
1618*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,	3, 0x01000002},
1619*4882a593Smuzhiyun };
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun static const pmu_res_updown_t BCMATTACHDATA(bcm4389b0_res_updown)[] = {
1622*4882a593Smuzhiyun #ifdef BCM_PMU_FLL_PU_MANAGE
1623*4882a593Smuzhiyun 	{RES4389_FAST_LPO_AVAIL,	0x001e0001},
1624*4882a593Smuzhiyun #endif /* BCM_PMU_FLL_PU_MANAGE */
1625*4882a593Smuzhiyun 	{RES4389_PMU_LP,		0x00960022},
1626*4882a593Smuzhiyun 	{RES4389_MISC_LDO,		0x00320022},
1627*4882a593Smuzhiyun 	{RES4389_XTAL_HQ,		0x00210021},
1628*4882a593Smuzhiyun 	{RES4389_XTAL_PU,		0x03e80033},
1629*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,		0x042c0349},
1630*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,		0x0740046a},
1631*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,		0x03c802e8},
1632*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,		0x08080532},
1633*4882a593Smuzhiyun 	{RES4389_CORE_RDY_CB,		0x000a0033},
1634*4882a593Smuzhiyun 	{RES4389_PWRSW_CB,		0x006400ca},
1635*4882a593Smuzhiyun 	{RES4389_MACPHY_CLK_MAIN,	0x00860022},
1636*4882a593Smuzhiyun };
1637*4882a593Smuzhiyun 
1638*4882a593Smuzhiyun static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4389b0_res_subst_trans_tmr)[] = {
1639*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,	0, 0x0428033c},
1640*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,	1, 0x028c0210},
1641*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,	2, 0x01cc01b0},
1642*4882a593Smuzhiyun 	{RES4389_PWRSW_DIG,	3, 0x00a00010},
1643*4882a593Smuzhiyun 
1644*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,	0, 0x0740045a},
1645*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,	1, 0x03580202},
1646*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,	2, 0x02f801a2},
1647*4882a593Smuzhiyun 	{RES4389_PWRSW_AUX,	3, 0x00a00002},
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,	0, 0x08080522},
1650*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,	1, 0x04200202},
1651*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,	2, 0x03c001a2},
1652*4882a593Smuzhiyun 	{RES4389_PWRSW_MAIN,	3, 0x00a00002},
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,	0, 0x03c402d8},
1655*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,	1, 0x02280210},
1656*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,	2, 0x016801b0},
1657*4882a593Smuzhiyun 	{RES4389_PWRSW_SCAN,	3, 0x00a00010},
1658*4882a593Smuzhiyun };
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun static pmu_res_depend_t BCMATTACHDATA(bcm4389b0_res_depend)[] = {
1661*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_DUMMY),		RES_DEPEND_SET, 0x00000000, NULL},
1662*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_FAST_LPO_AVAIL),	RES_DEPEND_SET, 0x00000000, NULL},
1663*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_PMU_LP),		RES_DEPEND_SET, 0x00000001, NULL},
1664*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_MISC_LDO),		RES_DEPEND_SET, 0x00000005, NULL},
1665*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_SERDES_AFE_RET),	RES_DEPEND_SET, 0x0000000d, NULL},
1666*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_XTAL_HQ),		RES_DEPEND_SET, 0x000000c5, NULL},
1667*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_XTAL_PU),		RES_DEPEND_SET, 0x00000005, NULL},
1668*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_XTAL_STABLE),	RES_DEPEND_SET, 0x00000045, NULL},
1669*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_PWRSW_DIG),		RES_DEPEND_SET, 0x060000dd, NULL},
1670*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_BTMC_TOP_RDY),	RES_DEPEND_SET, 0x000000cd, NULL},
1671*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_BTSC_TOP_RDY),	RES_DEPEND_SET, 0x000000c5, NULL},
1672*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_PWRSW_AUX),		RES_DEPEND_SET, 0x000000cd, NULL},
1673*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_PWRSW_SCAN),	RES_DEPEND_SET, 0x000000cd, NULL},
1674*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_CORE_RDY_SCAN),	RES_DEPEND_SET, 0x060211dd, NULL},
1675*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_PWRSW_MAIN),	RES_DEPEND_SET, 0x000000cd, NULL},
1676*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_RESERVED_15),	RES_DEPEND_SET, 0x00000000, NULL},
1677*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_RESERVED_16),	RES_DEPEND_SET, 0x00000000, NULL},
1678*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_CORE_RDY_DIG),	RES_DEPEND_SET, 0x060001dd, NULL},
1679*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_CORE_RDY_AUX),	RES_DEPEND_SET, 0x060209dd, NULL},
1680*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_ALP_AVAIL),		RES_DEPEND_SET, 0x000000c5, NULL},
1681*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_RADIO_PU_AUX),	RES_DEPEND_SET, 0x060609dd, NULL},
1682*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_RADIO_PU_SCAN),	RES_DEPEND_SET, 0x060231dd, NULL},
1683*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_CORE_RDY_MAIN),	RES_DEPEND_SET, 0x060241dd, NULL},
1684*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_RADIO_PU_MAIN),	RES_DEPEND_SET, 0x064241dd, NULL},
1685*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_MACPHY_CLK_SCAN),	RES_DEPEND_SET, 0x162a31fd, NULL},
1686*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_CORE_RDY_CB),	RES_DEPEND_SET, 0x040000dd, NULL},
1687*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_PWRSW_CB),		RES_DEPEND_SET, 0x000000dd, NULL},
1688*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_ARMCLKAVAIL),	RES_DEPEND_SET, 0x000800cd, NULL},
1689*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_HT_AVAIL),		RES_DEPEND_SET, 0x000800cd, NULL},
1690*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_MACPHY_CLK_AUX),	RES_DEPEND_SET, 0x161e09fd, NULL},
1691*4882a593Smuzhiyun 	{PMURES_BIT(RES4389_MACPHY_CLK_MAIN),	RES_DEPEND_SET, 0x16ca41fd, NULL},
1692*4882a593Smuzhiyun };
1693*4882a593Smuzhiyun 
1694*4882a593Smuzhiyun /** To enable avb timer clock feature */
si_pmu_avbtimer_enable(si_t * sih,osl_t * osh,bool set_flag)1695*4882a593Smuzhiyun void si_pmu_avbtimer_enable(si_t *sih, osl_t *osh, bool set_flag)
1696*4882a593Smuzhiyun {
1697*4882a593Smuzhiyun 	uint32 min_mask = 0, max_mask = 0;
1698*4882a593Smuzhiyun 	pmuregs_t *pmu;
1699*4882a593Smuzhiyun 	uint origidx;
1700*4882a593Smuzhiyun 
1701*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
1702*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
1703*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
1704*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
1705*4882a593Smuzhiyun 	} else {
1706*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
1707*4882a593Smuzhiyun 	}
1708*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM4360_CHIP_ID || CHIPID(sih->chip) == BCM43460_CHIP_ID) &&
1711*4882a593Smuzhiyun 		CHIPREV(sih->chiprev) >= 0x3) {
1712*4882a593Smuzhiyun 		int cst_ht = CST4360_RSRC_INIT_MODE(sih->chipst) & 0x1;
1713*4882a593Smuzhiyun 		if (cst_ht == 0) {
1714*4882a593Smuzhiyun 			/* Enable the AVB timers for proxd feature */
1715*4882a593Smuzhiyun 			min_mask = R_REG(osh, &pmu->min_res_mask);
1716*4882a593Smuzhiyun 			max_mask = R_REG(osh, &pmu->max_res_mask);
1717*4882a593Smuzhiyun 			if (set_flag) {
1718*4882a593Smuzhiyun 				max_mask |= PMURES_BIT(RES4360_AVB_PLL_PWRSW_PU);
1719*4882a593Smuzhiyun 				max_mask |= PMURES_BIT(RES4360_PCIE_TL_CLK_AVAIL);
1720*4882a593Smuzhiyun 				min_mask |= PMURES_BIT(RES4360_AVB_PLL_PWRSW_PU);
1721*4882a593Smuzhiyun 				min_mask |= PMURES_BIT(RES4360_PCIE_TL_CLK_AVAIL);
1722*4882a593Smuzhiyun 				W_REG(osh, &pmu->min_res_mask, min_mask);
1723*4882a593Smuzhiyun 				W_REG(osh, &pmu->max_res_mask, max_mask);
1724*4882a593Smuzhiyun 			} else {
1725*4882a593Smuzhiyun 				AND_REG(osh, &pmu->min_res_mask,
1726*4882a593Smuzhiyun 					~PMURES_BIT(RES4360_AVB_PLL_PWRSW_PU));
1727*4882a593Smuzhiyun 				AND_REG(osh, &pmu->min_res_mask,
1728*4882a593Smuzhiyun 					~PMURES_BIT(RES4360_PCIE_TL_CLK_AVAIL));
1729*4882a593Smuzhiyun 				AND_REG(osh, &pmu->max_res_mask,
1730*4882a593Smuzhiyun 					~PMURES_BIT(RES4360_AVB_PLL_PWRSW_PU));
1731*4882a593Smuzhiyun 				AND_REG(osh, &pmu->max_res_mask,
1732*4882a593Smuzhiyun 					~PMURES_BIT(RES4360_PCIE_TL_CLK_AVAIL));
1733*4882a593Smuzhiyun 			}
1734*4882a593Smuzhiyun 			/* Need to wait 100 millisecond for the uptime */
1735*4882a593Smuzhiyun 			OSL_DELAY(100);
1736*4882a593Smuzhiyun 		}
1737*4882a593Smuzhiyun 	}
1738*4882a593Smuzhiyun 
1739*4882a593Smuzhiyun 	/* Return to original core */
1740*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
1741*4882a593Smuzhiyun }
1742*4882a593Smuzhiyun 
1743*4882a593Smuzhiyun /**
1744*4882a593Smuzhiyun  * Determines min/max rsrc masks. Normally hardware contains these masks, and software reads the
1745*4882a593Smuzhiyun  * masks from hardware. Note that masks are sometimes dependent on chip straps.
1746*4882a593Smuzhiyun  */
1747*4882a593Smuzhiyun static void
si_pmu_res_masks(si_t * sih,uint32 * pmin,uint32 * pmax)1748*4882a593Smuzhiyun si_pmu_res_masks(si_t *sih, uint32 *pmin, uint32 *pmax)
1749*4882a593Smuzhiyun {
1750*4882a593Smuzhiyun 	uint32 min_mask = 0, max_mask = 0;
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun 	/* determine min/max rsrc masks */
1753*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
1754*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
1755*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
1756*4882a593Smuzhiyun 		if (CHIPREV(sih->chiprev) >= 0x4) {
1757*4882a593Smuzhiyun 			min_mask = 0x103;
1758*4882a593Smuzhiyun 		}
1759*4882a593Smuzhiyun 		/* Continue - Don't break */
1760*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
1761*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
1762*4882a593Smuzhiyun 		if (CHIPREV(sih->chiprev) >= 0x3) {
1763*4882a593Smuzhiyun 			/* PR 110203 */
1764*4882a593Smuzhiyun 			int cst_ht = CST4360_RSRC_INIT_MODE(sih->chipst) & 0x1;
1765*4882a593Smuzhiyun 			if (cst_ht == 0)
1766*4882a593Smuzhiyun 				max_mask = 0x1ff;
1767*4882a593Smuzhiyun 		}
1768*4882a593Smuzhiyun 		break;
1769*4882a593Smuzhiyun 
1770*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
1771*4882a593Smuzhiyun 		/* as a bare minimum, have ALP clock running */
1772*4882a593Smuzhiyun 		min_mask = PMURES_BIT(RES43602_LPLDO_PU)  | PMURES_BIT(RES43602_REGULATOR)      |
1773*4882a593Smuzhiyun 			PMURES_BIT(RES43602_PMU_SLEEP)    | PMURES_BIT(RES43602_XTALLDO_PU)     |
1774*4882a593Smuzhiyun 			PMURES_BIT(RES43602_SERDES_PU)    | PMURES_BIT(RES43602_BBPLL_PWRSW_PU) |
1775*4882a593Smuzhiyun 			PMURES_BIT(RES43602_SR_CLK_START) | PMURES_BIT(RES43602_SR_PHY_PWRSW)   |
1776*4882a593Smuzhiyun 			PMURES_BIT(RES43602_SR_SUBCORE_PWRSW) | PMURES_BIT(RES43602_XTAL_PU)    |
1777*4882a593Smuzhiyun 			PMURES_BIT(RES43602_PERST_OVR)    | PMURES_BIT(RES43602_SR_CLK_STABLE)  |
1778*4882a593Smuzhiyun 			PMURES_BIT(RES43602_SR_SAVE_RESTORE) | PMURES_BIT(RES43602_SR_SLEEP)    |
1779*4882a593Smuzhiyun 			PMURES_BIT(RES43602_LQ_START)     | PMURES_BIT(RES43602_LQ_AVAIL)       |
1780*4882a593Smuzhiyun 			PMURES_BIT(RES43602_WL_CORE_RDY)  |
1781*4882a593Smuzhiyun 			PMURES_BIT(RES43602_ALP_AVAIL);
1782*4882a593Smuzhiyun 
1783*4882a593Smuzhiyun 		if (sih->chippkg == BCM43602_12x12_PKG_ID) /* LPLDO WAR */
1784*4882a593Smuzhiyun 			min_mask &= ~PMURES_BIT(RES43602_LPLDO_PU);
1785*4882a593Smuzhiyun 
1786*4882a593Smuzhiyun 		max_mask = (1<<3) | min_mask          | PMURES_BIT(RES43602_RADIO_PU)        |
1787*4882a593Smuzhiyun 			PMURES_BIT(RES43602_RFLDO_PU) | PMURES_BIT(RES43602_HT_START)        |
1788*4882a593Smuzhiyun 			PMURES_BIT(RES43602_HT_AVAIL) | PMURES_BIT(RES43602_MACPHY_CLKAVAIL);
1789*4882a593Smuzhiyun 
1790*4882a593Smuzhiyun #if defined(SAVERESTORE)
1791*4882a593Smuzhiyun 		/* min_mask is updated after SR code is downloaded to txfifo */
1792*4882a593Smuzhiyun 		if (SR_ENAB() && sr_isenab(sih)) {
1793*4882a593Smuzhiyun 			ASSERT(sih->chippkg != BCM43602_12x12_PKG_ID);
1794*4882a593Smuzhiyun 			min_mask = PMURES_BIT(RES43602_LPLDO_PU);
1795*4882a593Smuzhiyun 		}
1796*4882a593Smuzhiyun #endif /* SAVERESTORE */
1797*4882a593Smuzhiyun 		break;
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
1800*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
1801*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
1802*4882a593Smuzhiyun 		/* Set the bits for all resources in the max mask except for the SR Engine */
1803*4882a593Smuzhiyun 		max_mask = 0x7FFFFFFF;
1804*4882a593Smuzhiyun 		break;
1805*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
1806*4882a593Smuzhiyun 		min_mask = 0x64fffff;
1807*4882a593Smuzhiyun #if defined(SAVERESTORE)
1808*4882a593Smuzhiyun 		if (SR_ENAB() && sr_isenab(sih)) {
1809*4882a593Smuzhiyun 			if (si_get_nvram_rfldo3p3_war(sih)) {
1810*4882a593Smuzhiyun 				min_mask = 0x0000011;
1811*4882a593Smuzhiyun 			} else {
1812*4882a593Smuzhiyun 				min_mask = 0x0000001;
1813*4882a593Smuzhiyun 			}
1814*4882a593Smuzhiyun 		}
1815*4882a593Smuzhiyun #endif /* SAVERESTORE */
1816*4882a593Smuzhiyun 		max_mask = 0x7FFFFFFF;
1817*4882a593Smuzhiyun 		break;
1818*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
1819*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
1820*4882a593Smuzhiyun 		min_mask = 0x064fffff;
1821*4882a593Smuzhiyun #if defined(SAVERESTORE)
1822*4882a593Smuzhiyun 		if (SR_ENAB()) {
1823*4882a593Smuzhiyun 			if (!sr_isenab(sih)) {
1824*4882a593Smuzhiyun 				min_mask = 0x064fffff;
1825*4882a593Smuzhiyun 			} else {
1826*4882a593Smuzhiyun 				min_mask = PMURES_BIT(RES4378_DUMMY);
1827*4882a593Smuzhiyun 			}
1828*4882a593Smuzhiyun 		}
1829*4882a593Smuzhiyun #endif /* SAVERESTORE */
1830*4882a593Smuzhiyun 		max_mask = 0x7FFFFFFF;
1831*4882a593Smuzhiyun 		break;
1832*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
1833*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
1834*4882a593Smuzhiyun 		min_mask = 0x64fffff;
1835*4882a593Smuzhiyun #if defined(SAVERESTORE)
1836*4882a593Smuzhiyun 		if (SR_ENAB()) {
1837*4882a593Smuzhiyun 			if (sr_isenab(sih)) {
1838*4882a593Smuzhiyun 				min_mask = PMURES_BIT(RES4387_DUMMY);
1839*4882a593Smuzhiyun 			} else {
1840*4882a593Smuzhiyun 				min_mask = pmu_corereg(sih, SI_CC_IDX, min_res_mask, 0, 0);
1841*4882a593Smuzhiyun 				if (PMU_FLL_PU_ENAB()) {
1842*4882a593Smuzhiyun 					min_mask |= PMURES_BIT(RES4387_FAST_LPO_AVAIL) |
1843*4882a593Smuzhiyun 						PMURES_BIT(RES4387_PMU_LP);
1844*4882a593Smuzhiyun 				}
1845*4882a593Smuzhiyun 			}
1846*4882a593Smuzhiyun 		}
1847*4882a593Smuzhiyun #endif /* SAVERESTORE */
1848*4882a593Smuzhiyun 
1849*4882a593Smuzhiyun 		max_mask = 0x7FFFFFFF;
1850*4882a593Smuzhiyun 		break;
1851*4882a593Smuzhiyun 
1852*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
1853*4882a593Smuzhiyun 		min_mask = 0x64fffff;
1854*4882a593Smuzhiyun #if defined(SAVERESTORE)
1855*4882a593Smuzhiyun 		if (SR_ENAB()) {
1856*4882a593Smuzhiyun 			if (sr_isenab(sih)) {
1857*4882a593Smuzhiyun 				min_mask = PMURES_BIT(RES4388_DUMMY);
1858*4882a593Smuzhiyun 			} else {
1859*4882a593Smuzhiyun 				min_mask = pmu_corereg(sih, SI_CC_IDX, min_res_mask, 0, 0);
1860*4882a593Smuzhiyun 				if (PMU_FLL_PU_ENAB()) {
1861*4882a593Smuzhiyun 					min_mask |= PMURES_BIT(RES4388_FAST_LPO_AVAIL) |
1862*4882a593Smuzhiyun 						PMURES_BIT(RES4388_PMU_LP);
1863*4882a593Smuzhiyun 				}
1864*4882a593Smuzhiyun 			}
1865*4882a593Smuzhiyun 		}
1866*4882a593Smuzhiyun #endif /* SAVERESTORE */
1867*4882a593Smuzhiyun 		max_mask = 0x7FFFFFFF;
1868*4882a593Smuzhiyun 		break;
1869*4882a593Smuzhiyun 
1870*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
1871*4882a593Smuzhiyun 		/*
1872*4882a593Smuzhiyun 		 * check later if this can be replaced with chip default value read from
1873*4882a593Smuzhiyun 		 * PMU register - min_res_mask and remove the code in SR_ENAB() portion
1874*4882a593Smuzhiyun 		 */
1875*4882a593Smuzhiyun 		min_mask = 0x64fffff;
1876*4882a593Smuzhiyun #if defined(SAVERESTORE)
1877*4882a593Smuzhiyun 		if (SR_ENAB()) {
1878*4882a593Smuzhiyun 			if (sr_isenab(sih)) {
1879*4882a593Smuzhiyun 				min_mask = PMURES_BIT(RES4389_DUMMY);
1880*4882a593Smuzhiyun 			} else {
1881*4882a593Smuzhiyun 				min_mask = pmu_corereg(sih, SI_CC_IDX, min_res_mask, 0, 0);
1882*4882a593Smuzhiyun 				if (PMU_FLL_PU_ENAB()) {
1883*4882a593Smuzhiyun 					min_mask |= PMURES_BIT(RES4389_FAST_LPO_AVAIL) |
1884*4882a593Smuzhiyun 						PMURES_BIT(RES4389_PMU_LP);
1885*4882a593Smuzhiyun 				}
1886*4882a593Smuzhiyun 			}
1887*4882a593Smuzhiyun 		}
1888*4882a593Smuzhiyun #endif /* SAVERESTORE */
1889*4882a593Smuzhiyun 		max_mask = 0x7FFFFFFF;
1890*4882a593Smuzhiyun 		break;
1891*4882a593Smuzhiyun 
1892*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
1893*4882a593Smuzhiyun 		min_mask = 0x64fffff;
1894*4882a593Smuzhiyun 		max_mask = 0x7FFFFFFF;
1895*4882a593Smuzhiyun 	break;
1896*4882a593Smuzhiyun 
1897*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
1898*4882a593Smuzhiyun 		min_mask = 0x64fffff;
1899*4882a593Smuzhiyun #if defined(SAVERESTORE)
1900*4882a593Smuzhiyun 		if (SR_ENAB() && sr_isenab(sih)) {
1901*4882a593Smuzhiyun 			min_mask = (PMURES_BIT(RES4362_DUMMY));
1902*4882a593Smuzhiyun 		}
1903*4882a593Smuzhiyun #endif /* SAVERESTORE */
1904*4882a593Smuzhiyun 		max_mask = 0x7FFFFFFF;
1905*4882a593Smuzhiyun 		break;
1906*4882a593Smuzhiyun 
1907*4882a593Smuzhiyun 	default:
1908*4882a593Smuzhiyun 		PMU_ERROR(("MIN and MAX mask is not programmed\n"));
1909*4882a593Smuzhiyun 		break;
1910*4882a593Smuzhiyun 	}
1911*4882a593Smuzhiyun 
1912*4882a593Smuzhiyun 	if (!FWSIGN_ENAB()) {
1913*4882a593Smuzhiyun 		/* nvram override */
1914*4882a593Smuzhiyun 		si_nvram_res_masks(sih, &min_mask, &max_mask);
1915*4882a593Smuzhiyun 	}
1916*4882a593Smuzhiyun 
1917*4882a593Smuzhiyun 	*pmin = min_mask;
1918*4882a593Smuzhiyun 	*pmax = max_mask;
1919*4882a593Smuzhiyun } /* si_pmu_res_masks */
1920*4882a593Smuzhiyun 
1921*4882a593Smuzhiyun /**
1922*4882a593Smuzhiyun  * resource dependencies can change because of the host interface
1923*4882a593Smuzhiyun  * selected, to work around an issue, or for more optimal power
1924*4882a593Smuzhiyun  * savings after tape out
1925*4882a593Smuzhiyun  */
1926*4882a593Smuzhiyun #ifdef DUAL_PMU_SEQUENCE
1927*4882a593Smuzhiyun static void
si_pmu_resdeptbl_upd(si_t * sih,osl_t * osh,pmuregs_t * pmu,const pmu_res_depend_t * restable,uint tablesz)1928*4882a593Smuzhiyun si_pmu_resdeptbl_upd(si_t *sih, osl_t *osh, pmuregs_t *pmu,
1929*4882a593Smuzhiyun 	const pmu_res_depend_t *restable, uint tablesz)
1930*4882a593Smuzhiyun #else
1931*4882a593Smuzhiyun static void
1932*4882a593Smuzhiyun BCMATTACHFN(si_pmu_resdeptbl_upd)(si_t *sih, osl_t *osh, pmuregs_t *pmu,
1933*4882a593Smuzhiyun 	const pmu_res_depend_t *restable, uint tablesz)
1934*4882a593Smuzhiyun #endif /* DUAL_PMU_SEQUENCE */
1935*4882a593Smuzhiyun {
1936*4882a593Smuzhiyun 	uint i, rsrcs;
1937*4882a593Smuzhiyun 
1938*4882a593Smuzhiyun 	if (tablesz == 0)
1939*4882a593Smuzhiyun 		return;
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun 	ASSERT(restable != NULL);
1942*4882a593Smuzhiyun 
1943*4882a593Smuzhiyun 	rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT;
1944*4882a593Smuzhiyun 	/* Program resource dependencies table */
1945*4882a593Smuzhiyun 	while (tablesz--) {
1946*4882a593Smuzhiyun 		if (restable[tablesz].filter != NULL &&
1947*4882a593Smuzhiyun 		    !(restable[tablesz].filter)(sih))
1948*4882a593Smuzhiyun 			continue;
1949*4882a593Smuzhiyun 		for (i = 0; i < rsrcs; i ++) {
1950*4882a593Smuzhiyun 			if ((restable[tablesz].res_mask &
1951*4882a593Smuzhiyun 			     PMURES_BIT(i)) == 0)
1952*4882a593Smuzhiyun 				continue;
1953*4882a593Smuzhiyun 			W_REG(osh, &pmu->res_table_sel, i);
1954*4882a593Smuzhiyun 			switch (restable[tablesz].action) {
1955*4882a593Smuzhiyun 				case RES_DEPEND_SET:
1956*4882a593Smuzhiyun 					PMU_MSG(("Changing rsrc %d res_dep_mask to 0x%x\n", i,
1957*4882a593Smuzhiyun 						restable[tablesz].depend_mask));
1958*4882a593Smuzhiyun 					W_REG(osh, &pmu->res_dep_mask,
1959*4882a593Smuzhiyun 					      restable[tablesz].depend_mask);
1960*4882a593Smuzhiyun 					break;
1961*4882a593Smuzhiyun 				case RES_DEPEND_ADD:
1962*4882a593Smuzhiyun 					PMU_MSG(("Adding 0x%x to rsrc %d res_dep_mask\n",
1963*4882a593Smuzhiyun 						restable[tablesz].depend_mask, i));
1964*4882a593Smuzhiyun 					OR_REG(osh, &pmu->res_dep_mask,
1965*4882a593Smuzhiyun 					       restable[tablesz].depend_mask);
1966*4882a593Smuzhiyun 					break;
1967*4882a593Smuzhiyun 				case RES_DEPEND_REMOVE:
1968*4882a593Smuzhiyun 					PMU_MSG(("Removing 0x%x from rsrc %d res_dep_mask\n",
1969*4882a593Smuzhiyun 						restable[tablesz].depend_mask, i));
1970*4882a593Smuzhiyun 					AND_REG(osh, &pmu->res_dep_mask,
1971*4882a593Smuzhiyun 						~restable[tablesz].depend_mask);
1972*4882a593Smuzhiyun 					break;
1973*4882a593Smuzhiyun 				default:
1974*4882a593Smuzhiyun 					ASSERT(0);
1975*4882a593Smuzhiyun 					break;
1976*4882a593Smuzhiyun 			}
1977*4882a593Smuzhiyun 		}
1978*4882a593Smuzhiyun 	}
1979*4882a593Smuzhiyun } /* si_pmu_resdeptbl_upd */
1980*4882a593Smuzhiyun 
1981*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_dep_table_fll_pu_fixup)1982*4882a593Smuzhiyun BCMATTACHFN(si_pmu_dep_table_fll_pu_fixup)(si_t *sih, osl_t *osh,
1983*4882a593Smuzhiyun 	pmu_res_depend_t *pmu_res_depend_table, uint pmu_res_depend_table_sz)
1984*4882a593Smuzhiyun {
1985*4882a593Smuzhiyun 	uint i;
1986*4882a593Smuzhiyun 
1987*4882a593Smuzhiyun 	if (!PMU_FLL_PU_ENAB()) {
1988*4882a593Smuzhiyun 		return;
1989*4882a593Smuzhiyun 	}
1990*4882a593Smuzhiyun 
1991*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
1992*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
1993*4882a593Smuzhiyun 		for (i = 0; i < pmu_res_depend_table_sz; i ++) {
1994*4882a593Smuzhiyun 			if (pmu_res_depend_table[i].res_mask ==
1995*4882a593Smuzhiyun 				PMURES_BIT(RES4387_FAST_LPO_AVAIL)) {
1996*4882a593Smuzhiyun 				pmu_res_depend_table[i].depend_mask = PMURES_BIT(RES4387_DUMMY) |
1997*4882a593Smuzhiyun 					PMURES_BIT(RES4387_PMU_LP);
1998*4882a593Smuzhiyun 			} else if ((pmu_res_depend_table[i].res_mask !=
1999*4882a593Smuzhiyun 					PMURES_BIT(RES4387_DUMMY)) &&
2000*4882a593Smuzhiyun 				(pmu_res_depend_table[i].res_mask !=
2001*4882a593Smuzhiyun 					PMURES_BIT(RES4387_PMU_LP)) &&
2002*4882a593Smuzhiyun 				(pmu_res_depend_table[i].res_mask !=
2003*4882a593Smuzhiyun 					PMURES_BIT(RES4387_RESERVED_16))) {
2004*4882a593Smuzhiyun 				pmu_res_depend_table[i].depend_mask |=
2005*4882a593Smuzhiyun 					PMURES_BIT(RES4387_FAST_LPO_AVAIL);
2006*4882a593Smuzhiyun 			}
2007*4882a593Smuzhiyun 		}
2008*4882a593Smuzhiyun 		break;
2009*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
2010*4882a593Smuzhiyun 		for (i = 0; i < pmu_res_depend_table_sz; i ++) {
2011*4882a593Smuzhiyun 			if (pmu_res_depend_table[i].res_mask ==
2012*4882a593Smuzhiyun 				PMURES_BIT(RES4388_FAST_LPO_AVAIL)) {
2013*4882a593Smuzhiyun 				pmu_res_depend_table[i].depend_mask = PMURES_BIT(RES4388_DUMMY) |
2014*4882a593Smuzhiyun 					PMURES_BIT(RES4388_PMU_LP);
2015*4882a593Smuzhiyun 			} else if ((pmu_res_depend_table[i].res_mask !=
2016*4882a593Smuzhiyun 					PMURES_BIT(RES4388_DUMMY)) &&
2017*4882a593Smuzhiyun 				(pmu_res_depend_table[i].res_mask !=
2018*4882a593Smuzhiyun 					PMURES_BIT(RES4388_PMU_LP)) &&
2019*4882a593Smuzhiyun 				(pmu_res_depend_table[i].res_mask !=
2020*4882a593Smuzhiyun 					PMURES_BIT(RES4388_RESERVED_15)) &&
2021*4882a593Smuzhiyun 				(pmu_res_depend_table[i].res_mask !=
2022*4882a593Smuzhiyun 					PMURES_BIT(RES4388_RESERVED_16))) {
2023*4882a593Smuzhiyun 				pmu_res_depend_table[i].depend_mask |=
2024*4882a593Smuzhiyun 					PMURES_BIT(RES4388_FAST_LPO_AVAIL);
2025*4882a593Smuzhiyun 			}
2026*4882a593Smuzhiyun 		}
2027*4882a593Smuzhiyun 		break;
2028*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
2029*4882a593Smuzhiyun 		for (i = 0; i < pmu_res_depend_table_sz; i ++) {
2030*4882a593Smuzhiyun 			if (pmu_res_depend_table[i].res_mask ==
2031*4882a593Smuzhiyun 				PMURES_BIT(RES4389_FAST_LPO_AVAIL)) {
2032*4882a593Smuzhiyun 				pmu_res_depend_table[i].depend_mask = PMURES_BIT(RES4389_DUMMY) |
2033*4882a593Smuzhiyun 					PMURES_BIT(RES4389_PMU_LP);
2034*4882a593Smuzhiyun 			} else if ((pmu_res_depend_table[i].res_mask !=
2035*4882a593Smuzhiyun 					PMURES_BIT(RES4389_DUMMY)) &&
2036*4882a593Smuzhiyun 				(pmu_res_depend_table[i].res_mask !=
2037*4882a593Smuzhiyun 					PMURES_BIT(RES4389_PMU_LP)) &&
2038*4882a593Smuzhiyun 				(pmu_res_depend_table[i].res_mask !=
2039*4882a593Smuzhiyun 					PMURES_BIT(RES4389_RESERVED_16))) {
2040*4882a593Smuzhiyun 				pmu_res_depend_table[i].depend_mask |=
2041*4882a593Smuzhiyun 					PMURES_BIT(RES4389_FAST_LPO_AVAIL);
2042*4882a593Smuzhiyun 			}
2043*4882a593Smuzhiyun 		}
2044*4882a593Smuzhiyun 		break;
2045*4882a593Smuzhiyun 	default:
2046*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_dep_table_fll_pu_fixup: unsupported chip!\n"));
2047*4882a593Smuzhiyun 		ASSERT(0);
2048*4882a593Smuzhiyun 		break;
2049*4882a593Smuzhiyun 	}
2050*4882a593Smuzhiyun }
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun /** Initialize PMU hardware resources. */
2053*4882a593Smuzhiyun void
BCMATTACHFN(si_pmu_res_init)2054*4882a593Smuzhiyun BCMATTACHFN(si_pmu_res_init)(si_t *sih, osl_t *osh)
2055*4882a593Smuzhiyun {
2056*4882a593Smuzhiyun 	pmuregs_t *pmu;
2057*4882a593Smuzhiyun 	uint origidx;
2058*4882a593Smuzhiyun 	const pmu_res_updown_t *pmu_res_updown_table = NULL;
2059*4882a593Smuzhiyun 	uint pmu_res_updown_table_sz = 0;
2060*4882a593Smuzhiyun 	const pmu_res_subst_trans_tmr_t *pmu_res_subst_trans_tmr_table = NULL;
2061*4882a593Smuzhiyun 	uint pmu_res_subst_trans_tmr_table_sz = 0;
2062*4882a593Smuzhiyun 	pmu_res_depend_t *pmu_res_depend_table = NULL;
2063*4882a593Smuzhiyun 	uint pmu_res_depend_table_sz = 0;
2064*4882a593Smuzhiyun #ifndef BCM_BOOTLOADER
2065*4882a593Smuzhiyun 	const pmu_res_depend_t *pmu_res_depend_pciewar_table[2] = {NULL, NULL};
2066*4882a593Smuzhiyun 	uint pmu_res_depend_pciewar_table_sz[2] = {0, 0};
2067*4882a593Smuzhiyun #endif /* BCM_BOOTLOADER */
2068*4882a593Smuzhiyun 	uint32 min_mask = 0, max_mask = 0;
2069*4882a593Smuzhiyun 	char name[8];
2070*4882a593Smuzhiyun 	const char *val;
2071*4882a593Smuzhiyun 	uint i, rsrcs;
2072*4882a593Smuzhiyun 	uint8   fastlpo_dis = fastlpo_dis_get();
2073*4882a593Smuzhiyun 	uint8   fastlpo_pcie_dis = fastlpo_pcie_dis_get();
2074*4882a593Smuzhiyun 
2075*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
2076*4882a593Smuzhiyun 
2077*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
2078*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
2079*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
2080*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
2081*4882a593Smuzhiyun 	} else {
2082*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
2083*4882a593Smuzhiyun 	}
2084*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	/*
2087*4882a593Smuzhiyun 	 * Hardware contains the resource updown and dependency tables. Only if a chip has a
2088*4882a593Smuzhiyun 	 * hardware problem, software tables can be used to override hardware tables.
2089*4882a593Smuzhiyun 	 */
2090*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
2091*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
2092*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
2093*4882a593Smuzhiyun 		if (CHIPREV(sih->chiprev) < 4) {
2094*4882a593Smuzhiyun 			pmu_res_updown_table = bcm4360_res_updown;
2095*4882a593Smuzhiyun 			pmu_res_updown_table_sz = ARRAYSIZE(bcm4360_res_updown);
2096*4882a593Smuzhiyun 		} else {
2097*4882a593Smuzhiyun 			/* FOR 4360B1 */
2098*4882a593Smuzhiyun 			pmu_res_updown_table = bcm4360B1_res_updown;
2099*4882a593Smuzhiyun 			pmu_res_updown_table_sz = ARRAYSIZE(bcm4360B1_res_updown);
2100*4882a593Smuzhiyun 		}
2101*4882a593Smuzhiyun 		break;
2102*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
2103*4882a593Smuzhiyun 		pmu_res_updown_table = bcm43602_res_updown;
2104*4882a593Smuzhiyun 		pmu_res_updown_table_sz = ARRAYSIZE(bcm43602_res_updown);
2105*4882a593Smuzhiyun 		pmu_res_depend_table = bcm43602_res_depend;
2106*4882a593Smuzhiyun 		pmu_res_depend_table_sz = ARRAYSIZE(bcm43602_res_depend);
2107*4882a593Smuzhiyun #ifndef BCM_BOOTLOADER
2108*4882a593Smuzhiyun 		pmu_res_depend_pciewar_table[0] = bcm43602_res_pciewar;
2109*4882a593Smuzhiyun 		pmu_res_depend_pciewar_table_sz[0] = ARRAYSIZE(bcm43602_res_pciewar);
2110*4882a593Smuzhiyun 		if (sih->chippkg == BCM43602_12x12_PKG_ID) { /* LPLDO WAR */
2111*4882a593Smuzhiyun 			pmu_res_depend_pciewar_table[1] = bcm43602_12x12_res_depend;
2112*4882a593Smuzhiyun 			pmu_res_depend_pciewar_table_sz[1] = ARRAYSIZE(bcm43602_12x12_res_depend);
2113*4882a593Smuzhiyun 		}
2114*4882a593Smuzhiyun #endif /* !BCM_BOOTLOADER */
2115*4882a593Smuzhiyun 		break;
2116*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
2117*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
2118*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
2119*4882a593Smuzhiyun 		pmu_res_updown_table = bcm43012a0_res_updown_ds0;
2120*4882a593Smuzhiyun 		pmu_res_updown_table_sz = ARRAYSIZE(bcm43012a0_res_updown_ds0);
2121*4882a593Smuzhiyun 		pmu_res_depend_table = bcm43012a0_res_depend_ds0;
2122*4882a593Smuzhiyun 		pmu_res_depend_table_sz = ARRAYSIZE(bcm43012a0_res_depend_ds0);
2123*4882a593Smuzhiyun 		break;
2124*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
2125*4882a593Smuzhiyun 		/* fastlpo_dis is override for PMU1M, updown times are updated accordingly
2126*4882a593Smuzhiyun 		 * if PMU 1M is enabled only Resource Up/Down times are changed
2127*4882a593Smuzhiyun 		 * Also the Up/Down times are different for A0 and B0
2128*4882a593Smuzhiyun 		 */
2129*4882a593Smuzhiyun 		if (fastlpo_dis) {
2130*4882a593Smuzhiyun 			/* Only Resource Up/Down times are different b/w A0 and B0 */
2131*4882a593Smuzhiyun 			if (CHIPREV(sih->chiprev) == 0) {
2132*4882a593Smuzhiyun 				pmu_res_updown_table = bcm4369a0_res_updown;
2133*4882a593Smuzhiyun 				pmu_res_updown_table_sz = ARRAYSIZE(bcm4369a0_res_updown);
2134*4882a593Smuzhiyun 			} else {
2135*4882a593Smuzhiyun 				pmu_res_updown_table = bcm4369b0_res_updown;
2136*4882a593Smuzhiyun 				pmu_res_updown_table_sz = ARRAYSIZE(bcm4369b0_res_updown);
2137*4882a593Smuzhiyun 			}
2138*4882a593Smuzhiyun 		} else {
2139*4882a593Smuzhiyun 			if (fastlpo_pcie_dis) {
2140*4882a593Smuzhiyun 				PMU_ERROR(("INVALID: PCIE 1MHz disabled but PMU 1MHz enabled\n"));
2141*4882a593Smuzhiyun 				ASSERT(0);
2142*4882a593Smuzhiyun 			}
2143*4882a593Smuzhiyun 			/* Only Resource Up/Down times are different b/w A0 and B0 */
2144*4882a593Smuzhiyun 			if (CHIPREV(sih->chiprev) == 0) {
2145*4882a593Smuzhiyun 				pmu_res_updown_table = bcm4369a0_res_updown_fastlpo_pmu;
2146*4882a593Smuzhiyun 				pmu_res_updown_table_sz =
2147*4882a593Smuzhiyun 					ARRAYSIZE(bcm4369a0_res_updown_fastlpo_pmu);
2148*4882a593Smuzhiyun 			} else {
2149*4882a593Smuzhiyun 				pmu_res_updown_table = bcm4369b0_res_updown_fastlpo_pmu;
2150*4882a593Smuzhiyun 				pmu_res_updown_table_sz =
2151*4882a593Smuzhiyun 					ARRAYSIZE(bcm4369b0_res_updown_fastlpo_pmu);
2152*4882a593Smuzhiyun 			}
2153*4882a593Smuzhiyun 		}
2154*4882a593Smuzhiyun 
2155*4882a593Smuzhiyun 		/* fastlpo_pcie_dis is override for PCIE1M, resource dependencies are updated
2156*4882a593Smuzhiyun 		 * if pcie 1M is enabled resource dependency are different
2157*4882a593Smuzhiyun 		 * for A0 and B0  chiprev there is no resource dependency change
2158*4882a593Smuzhiyun 		 */
2159*4882a593Smuzhiyun 		if (fastlpo_pcie_dis) {
2160*4882a593Smuzhiyun 			pmu_res_depend_table = bcm4369a0_res_depend;
2161*4882a593Smuzhiyun 			pmu_res_depend_table_sz = ARRAYSIZE(bcm4369a0_res_depend);
2162*4882a593Smuzhiyun 		} else {
2163*4882a593Smuzhiyun 			pmu_res_depend_table = bcm4369a0_res_depend_fastlpo_pcie;
2164*4882a593Smuzhiyun 			pmu_res_depend_table_sz = ARRAYSIZE(bcm4369a0_res_depend_fastlpo_pcie);
2165*4882a593Smuzhiyun 		}
2166*4882a593Smuzhiyun 		break;
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
2169*4882a593Smuzhiyun 		pmu_res_updown_table = bcm4362_res_updown;
2170*4882a593Smuzhiyun 		pmu_res_updown_table_sz = ARRAYSIZE(bcm4362_res_updown);
2171*4882a593Smuzhiyun 
2172*4882a593Smuzhiyun 		GCI_REG_NEW(sih, bt_smem_control1, (0xFF<<16), 0);
2173*4882a593Smuzhiyun 
2174*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL14,
2175*4882a593Smuzhiyun 			(PMU_CC14_MAIN_VDDB2VDDRET_UP_DLY_MASK |
2176*4882a593Smuzhiyun 			PMU_CC14_MAIN_VDDB2VDD_UP_DLY_MASK |
2177*4882a593Smuzhiyun 			PMU_CC14_AUX_VDDB2VDDRET_UP_DLY_MASK |
2178*4882a593Smuzhiyun 			PMU_CC14_AUX_VDDB2VDD_UP_DLY_MASK |
2179*4882a593Smuzhiyun 			PMU_CC14_PCIE_VDDB2VDDRET_UP_DLY_MASK |
2180*4882a593Smuzhiyun 			PMU_CC14_PCIE_VDDB2VDD_UP_DLY_MASK), 0);
2181*4882a593Smuzhiyun 
2182*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL15,
2183*4882a593Smuzhiyun 			(PMU_CC15_PCIE_VDDB_CURRENT_LIMIT_DELAY_MASK |
2184*4882a593Smuzhiyun 			PMU_CC15_PCIE_VDDB_FORCE_RPS_PWROK_DELAY_MASK), 0);
2185*4882a593Smuzhiyun 
2186*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL10,
2187*4882a593Smuzhiyun 			(PMU_CC10_PCIE_RESET0_CNT_SLOW_MASK |
2188*4882a593Smuzhiyun 			PMU_CC10_PCIE_RESET1_CNT_SLOW_MASK), 0);
2189*4882a593Smuzhiyun 
2190*4882a593Smuzhiyun 		GCI_REG_NEW(sih, bt_smem_control0, (0xF<<16), 0);
2191*4882a593Smuzhiyun 		GCI_REG_NEW(sih, bt_smem_control0, (0xF<<24), 0);
2192*4882a593Smuzhiyun 
2193*4882a593Smuzhiyun 		pmu_res_depend_table = bcm4362_res_depend;
2194*4882a593Smuzhiyun 		pmu_res_depend_table_sz = ARRAYSIZE(bcm4362_res_depend);
2195*4882a593Smuzhiyun 		break;
2196*4882a593Smuzhiyun 
2197*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
2198*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
2199*4882a593Smuzhiyun 		if (SR_ENAB()) {
2200*4882a593Smuzhiyun 			pmu_res_updown_table = bcm4378b0_res_updown;
2201*4882a593Smuzhiyun 			pmu_res_updown_table_sz = ARRAYSIZE(bcm4378b0_res_updown);
2202*4882a593Smuzhiyun 			pmu_res_depend_table = bcm4378b0_res_depend;
2203*4882a593Smuzhiyun 			pmu_res_depend_table_sz = ARRAYSIZE(bcm4378b0_res_depend);
2204*4882a593Smuzhiyun 		}
2205*4882a593Smuzhiyun 		break;
2206*4882a593Smuzhiyun 
2207*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
2208*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
2209*4882a593Smuzhiyun 		if (SR_ENAB()) {
2210*4882a593Smuzhiyun 			if (ISSIM_ENAB(sih)) {
2211*4882a593Smuzhiyun 				if (PMUREV(sih->pmurev) == 39) {
2212*4882a593Smuzhiyun 					pmu_res_updown_table = bcm4387c0_res_updown;
2213*4882a593Smuzhiyun 					pmu_res_updown_table_sz =
2214*4882a593Smuzhiyun 						ARRAYSIZE(bcm4387c0_res_updown);
2215*4882a593Smuzhiyun 
2216*4882a593Smuzhiyun 					pmu_res_subst_trans_tmr_table =
2217*4882a593Smuzhiyun 						bcm4387c0_res_subst_trans_tmr;
2218*4882a593Smuzhiyun 					pmu_res_subst_trans_tmr_table_sz =
2219*4882a593Smuzhiyun 						ARRAYSIZE(bcm4387c0_res_subst_trans_tmr);
2220*4882a593Smuzhiyun 
2221*4882a593Smuzhiyun 					pmu_res_depend_table = bcm4387c0_res_depend;
2222*4882a593Smuzhiyun 					pmu_res_depend_table_sz = ARRAYSIZE(bcm4387c0_res_depend);
2223*4882a593Smuzhiyun 				} else {
2224*4882a593Smuzhiyun 					pmu_res_updown_table = bcm4387b0_res_updown_qt;
2225*4882a593Smuzhiyun 					pmu_res_updown_table_sz =
2226*4882a593Smuzhiyun 						ARRAYSIZE(bcm4387b0_res_updown_qt);
2227*4882a593Smuzhiyun 
2228*4882a593Smuzhiyun 					pmu_res_subst_trans_tmr_table =
2229*4882a593Smuzhiyun 						bcm4387b0_res_subst_trans_tmr_qt;
2230*4882a593Smuzhiyun 					pmu_res_subst_trans_tmr_table_sz =
2231*4882a593Smuzhiyun 						ARRAYSIZE(bcm4387b0_res_subst_trans_tmr_qt);
2232*4882a593Smuzhiyun 
2233*4882a593Smuzhiyun 					pmu_res_depend_table = bcm4387b0_res_depend;
2234*4882a593Smuzhiyun 					pmu_res_depend_table_sz = ARRAYSIZE(bcm4387b0_res_depend);
2235*4882a593Smuzhiyun 				}
2236*4882a593Smuzhiyun 			} else {
2237*4882a593Smuzhiyun 				if (PMUREV(sih->pmurev) == 39) {
2238*4882a593Smuzhiyun 					if (BCMSRTOPOFF_ENAB()) {
2239*4882a593Smuzhiyun 						pmu_res_updown_table = bcm4387c0_res_updown_topoff;
2240*4882a593Smuzhiyun 						pmu_res_updown_table_sz =
2241*4882a593Smuzhiyun 							ARRAYSIZE(bcm4387c0_res_updown_topoff);
2242*4882a593Smuzhiyun 					} else {
2243*4882a593Smuzhiyun 						pmu_res_updown_table = bcm4387c0_res_updown;
2244*4882a593Smuzhiyun 						pmu_res_updown_table_sz =
2245*4882a593Smuzhiyun 							ARRAYSIZE(bcm4387c0_res_updown);
2246*4882a593Smuzhiyun 					}
2247*4882a593Smuzhiyun 
2248*4882a593Smuzhiyun 					pmu_res_subst_trans_tmr_table =
2249*4882a593Smuzhiyun 						bcm4387c0_res_subst_trans_tmr;
2250*4882a593Smuzhiyun 					pmu_res_subst_trans_tmr_table_sz =
2251*4882a593Smuzhiyun 						ARRAYSIZE(bcm4387c0_res_subst_trans_tmr);
2252*4882a593Smuzhiyun 
2253*4882a593Smuzhiyun 					pmu_res_depend_table = bcm4387c0_res_depend;
2254*4882a593Smuzhiyun 					pmu_res_depend_table_sz = ARRAYSIZE(bcm4387c0_res_depend);
2255*4882a593Smuzhiyun 
2256*4882a593Smuzhiyun 					if (PMU_FLL_PU_ENAB()) {
2257*4882a593Smuzhiyun 						si_pmu_dep_table_fll_pu_fixup(sih, osh,
2258*4882a593Smuzhiyun 							pmu_res_depend_table,
2259*4882a593Smuzhiyun 							pmu_res_depend_table_sz);
2260*4882a593Smuzhiyun 					}
2261*4882a593Smuzhiyun 				} else {
2262*4882a593Smuzhiyun 					pmu_res_updown_table = bcm4387b0_res_updown;
2263*4882a593Smuzhiyun 					pmu_res_updown_table_sz = ARRAYSIZE(bcm4387b0_res_updown);
2264*4882a593Smuzhiyun 
2265*4882a593Smuzhiyun 					pmu_res_subst_trans_tmr_table =
2266*4882a593Smuzhiyun 						bcm4387b0_res_subst_trans_tmr;
2267*4882a593Smuzhiyun 					pmu_res_subst_trans_tmr_table_sz =
2268*4882a593Smuzhiyun 						ARRAYSIZE(bcm4387b0_res_subst_trans_tmr);
2269*4882a593Smuzhiyun 
2270*4882a593Smuzhiyun 					pmu_res_depend_table = bcm4387b0_res_depend;
2271*4882a593Smuzhiyun 					pmu_res_depend_table_sz = ARRAYSIZE(bcm4387b0_res_depend);
2272*4882a593Smuzhiyun 				}
2273*4882a593Smuzhiyun 			}
2274*4882a593Smuzhiyun 		}
2275*4882a593Smuzhiyun 		break;
2276*4882a593Smuzhiyun 
2277*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
2278*4882a593Smuzhiyun 		if (SR_ENAB()) {
2279*4882a593Smuzhiyun 			if (ISSIM_ENAB(sih)) {
2280*4882a593Smuzhiyun 				pmu_res_updown_table = bcm4388a0_res_updown_qt;
2281*4882a593Smuzhiyun 				pmu_res_updown_table_sz = ARRAYSIZE(bcm4388a0_res_updown_qt);
2282*4882a593Smuzhiyun 
2283*4882a593Smuzhiyun 				pmu_res_subst_trans_tmr_table = bcm4388a0_res_subst_trans_tmr_qt;
2284*4882a593Smuzhiyun 				pmu_res_subst_trans_tmr_table_sz =
2285*4882a593Smuzhiyun 					ARRAYSIZE(bcm4388a0_res_subst_trans_tmr_qt);
2286*4882a593Smuzhiyun 			} else {
2287*4882a593Smuzhiyun 				pmu_res_updown_table = bcm4388a0_res_updown;
2288*4882a593Smuzhiyun 				pmu_res_updown_table_sz = ARRAYSIZE(bcm4388a0_res_updown);
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun 				pmu_res_subst_trans_tmr_table = bcm4388a0_res_subst_trans_tmr;
2291*4882a593Smuzhiyun 				pmu_res_subst_trans_tmr_table_sz =
2292*4882a593Smuzhiyun 					ARRAYSIZE(bcm4388a0_res_subst_trans_tmr);
2293*4882a593Smuzhiyun 			}
2294*4882a593Smuzhiyun 
2295*4882a593Smuzhiyun 			pmu_res_depend_table = bcm4388a0_res_depend;
2296*4882a593Smuzhiyun 			pmu_res_depend_table_sz = ARRAYSIZE(bcm4388a0_res_depend);
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun 			if (PMU_FLL_PU_ENAB()) {
2299*4882a593Smuzhiyun 				si_pmu_dep_table_fll_pu_fixup(sih, osh,
2300*4882a593Smuzhiyun 					pmu_res_depend_table,
2301*4882a593Smuzhiyun 					pmu_res_depend_table_sz);
2302*4882a593Smuzhiyun 			}
2303*4882a593Smuzhiyun 		}
2304*4882a593Smuzhiyun 		break;
2305*4882a593Smuzhiyun 
2306*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
2307*4882a593Smuzhiyun 		if (SR_ENAB()) {
2308*4882a593Smuzhiyun 			if (ISSIM_ENAB(sih)) {
2309*4882a593Smuzhiyun 				pmu_res_updown_table = bcm4389b0_res_updown_qt;
2310*4882a593Smuzhiyun 				pmu_res_updown_table_sz = ARRAYSIZE(bcm4389b0_res_updown_qt);
2311*4882a593Smuzhiyun 
2312*4882a593Smuzhiyun 				pmu_res_subst_trans_tmr_table = bcm4389b0_res_subst_trans_tmr_qt;
2313*4882a593Smuzhiyun 				pmu_res_subst_trans_tmr_table_sz =
2314*4882a593Smuzhiyun 					ARRAYSIZE(bcm4389b0_res_subst_trans_tmr_qt);
2315*4882a593Smuzhiyun 			} else {
2316*4882a593Smuzhiyun 				pmu_res_updown_table = bcm4389b0_res_updown;
2317*4882a593Smuzhiyun 				pmu_res_updown_table_sz = ARRAYSIZE(bcm4389b0_res_updown);
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun 				pmu_res_subst_trans_tmr_table = bcm4389b0_res_subst_trans_tmr;
2320*4882a593Smuzhiyun 				pmu_res_subst_trans_tmr_table_sz =
2321*4882a593Smuzhiyun 					ARRAYSIZE(bcm4389b0_res_subst_trans_tmr);
2322*4882a593Smuzhiyun 			}
2323*4882a593Smuzhiyun 
2324*4882a593Smuzhiyun 			pmu_res_depend_table = bcm4389b0_res_depend;
2325*4882a593Smuzhiyun 			pmu_res_depend_table_sz = ARRAYSIZE(bcm4389b0_res_depend);
2326*4882a593Smuzhiyun 			if (PMU_FLL_PU_ENAB()) {
2327*4882a593Smuzhiyun 				si_pmu_dep_table_fll_pu_fixup(sih, osh,
2328*4882a593Smuzhiyun 					pmu_res_depend_table, pmu_res_depend_table_sz);
2329*4882a593Smuzhiyun 			}
2330*4882a593Smuzhiyun 		}
2331*4882a593Smuzhiyun 		break;
2332*4882a593Smuzhiyun 
2333*4882a593Smuzhiyun 	default:
2334*4882a593Smuzhiyun 		break;
2335*4882a593Smuzhiyun 	}
2336*4882a593Smuzhiyun 
2337*4882a593Smuzhiyun 	/* Program up/down timers */
2338*4882a593Smuzhiyun 	while (pmu_res_updown_table_sz--) {
2339*4882a593Smuzhiyun 		ASSERT(pmu_res_updown_table != NULL);
2340*4882a593Smuzhiyun 		PMU_MSG(("Changing rsrc %d res_updn_timer to 0x%x\n",
2341*4882a593Smuzhiyun 		         pmu_res_updown_table[pmu_res_updown_table_sz].resnum,
2342*4882a593Smuzhiyun 		         pmu_res_updown_table[pmu_res_updown_table_sz].updown));
2343*4882a593Smuzhiyun 		W_REG(osh, &pmu->res_table_sel,
2344*4882a593Smuzhiyun 		      pmu_res_updown_table[pmu_res_updown_table_sz].resnum);
2345*4882a593Smuzhiyun 		W_REG(osh, &pmu->res_updn_timer,
2346*4882a593Smuzhiyun 		      pmu_res_updown_table[pmu_res_updown_table_sz].updown);
2347*4882a593Smuzhiyun 	}
2348*4882a593Smuzhiyun 
2349*4882a593Smuzhiyun 	if (!FWSIGN_ENAB()) {
2350*4882a593Smuzhiyun 		/* # resources */
2351*4882a593Smuzhiyun 		rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT;
2352*4882a593Smuzhiyun 
2353*4882a593Smuzhiyun 		/* Apply nvram overrides to up/down timers */
2354*4882a593Smuzhiyun 		for (i = 0; i < rsrcs; i ++) {
2355*4882a593Smuzhiyun 			uint32 r_val;
2356*4882a593Smuzhiyun 			snprintf(name, sizeof(name), rstr_rDt, i);
2357*4882a593Smuzhiyun 			if ((val = getvar(NULL, name)) == NULL)
2358*4882a593Smuzhiyun 				continue;
2359*4882a593Smuzhiyun 			r_val = (uint32)bcm_strtoul(val, NULL, 0);
2360*4882a593Smuzhiyun 			/* PMUrev = 13, pmu resource updown times are 12 bits(0:11 DT, 16:27 UT) */
2361*4882a593Smuzhiyun 			/* OLD values are 8 bits for UT/DT, handle the old nvram format */
2362*4882a593Smuzhiyun 			if (PMUREV(sih->pmurev) >= 13) {
2363*4882a593Smuzhiyun 				if (r_val < (1 << 16)) {
2364*4882a593Smuzhiyun 					uint16 up_time = (r_val >> 8) & 0xFF;
2365*4882a593Smuzhiyun 					r_val &= 0xFF;
2366*4882a593Smuzhiyun 					r_val |= (up_time << 16);
2367*4882a593Smuzhiyun 				}
2368*4882a593Smuzhiyun 			}
2369*4882a593Smuzhiyun 			PMU_MSG(("Applying %s=%s to rsrc %d res_updn_timer\n", name, val, i));
2370*4882a593Smuzhiyun 			W_REG(osh, &pmu->res_table_sel, (uint32)i);
2371*4882a593Smuzhiyun 			W_REG(osh, &pmu->res_updn_timer, r_val);
2372*4882a593Smuzhiyun 		}
2373*4882a593Smuzhiyun 	}
2374*4882a593Smuzhiyun 
2375*4882a593Smuzhiyun 	/* Program Rsrc Substate Transition Timer */
2376*4882a593Smuzhiyun 	while (pmu_res_subst_trans_tmr_table_sz --) {
2377*4882a593Smuzhiyun 		ASSERT(pmu_res_subst_trans_tmr_table != NULL);
2378*4882a593Smuzhiyun 		PMU_MSG(("Changing rsrc %d substate %d res_subst_trans_timer to 0x%x\n",
2379*4882a593Smuzhiyun 			pmu_res_subst_trans_tmr_table[pmu_res_subst_trans_tmr_table_sz].resnum,
2380*4882a593Smuzhiyun 			pmu_res_subst_trans_tmr_table[pmu_res_subst_trans_tmr_table_sz].substate,
2381*4882a593Smuzhiyun 			pmu_res_subst_trans_tmr_table[pmu_res_subst_trans_tmr_table_sz].tmr));
2382*4882a593Smuzhiyun 		W_REG(osh, &pmu->res_table_sel,
2383*4882a593Smuzhiyun 			pmu_res_subst_trans_tmr_table[pmu_res_subst_trans_tmr_table_sz].resnum |
2384*4882a593Smuzhiyun 			(pmu_res_subst_trans_tmr_table[pmu_res_subst_trans_tmr_table_sz].substate
2385*4882a593Smuzhiyun 			<< PMU_RES_SUBSTATE_SHIFT));
2386*4882a593Smuzhiyun 		W_REG(osh, &pmu->rsrc_substate_trans_tmr,
2387*4882a593Smuzhiyun 			pmu_res_subst_trans_tmr_table[pmu_res_subst_trans_tmr_table_sz].tmr);
2388*4882a593Smuzhiyun 	}
2389*4882a593Smuzhiyun 
2390*4882a593Smuzhiyun 	/* Program resource dependencies table */
2391*4882a593Smuzhiyun 	si_pmu_resdeptbl_upd(sih, osh, pmu, pmu_res_depend_table, pmu_res_depend_table_sz);
2392*4882a593Smuzhiyun 
2393*4882a593Smuzhiyun 	if (!FWSIGN_ENAB()) {
2394*4882a593Smuzhiyun 		/* Apply nvram overrides to dependencies masks */
2395*4882a593Smuzhiyun 		for (i = 0; i < rsrcs; i ++) {
2396*4882a593Smuzhiyun 			snprintf(name, sizeof(name), rstr_rDd, i);
2397*4882a593Smuzhiyun 			if ((val = getvar(NULL, name)) == NULL)
2398*4882a593Smuzhiyun 				continue;
2399*4882a593Smuzhiyun 			PMU_MSG(("Applying %s=%s to rsrc %d res_dep_mask\n", name, val, i));
2400*4882a593Smuzhiyun 			W_REG(osh, &pmu->res_table_sel, (uint32)i);
2401*4882a593Smuzhiyun 			W_REG(osh, &pmu->res_dep_mask, (uint32)bcm_strtoul(val, NULL, 0));
2402*4882a593Smuzhiyun 		}
2403*4882a593Smuzhiyun 	}
2404*4882a593Smuzhiyun 
2405*4882a593Smuzhiyun #if !defined(BCM_BOOTLOADER)
2406*4882a593Smuzhiyun 	/* Initial any chip interface dependent PMU rsrc by looking at the
2407*4882a593Smuzhiyun 	 * chipstatus register to figure the selected interface
2408*4882a593Smuzhiyun 	 */
2409*4882a593Smuzhiyun 	/* this should be a general change to cover all the chips.
2410*4882a593Smuzhiyun 	 * this also should validate the build where the dongle is
2411*4882a593Smuzhiyun 	 * built for SDIO but downloaded on PCIE dev
2412*4882a593Smuzhiyun 	 */
2413*4882a593Smuzhiyun 	if (BUSTYPE(sih->bustype) == PCI_BUS || BUSTYPE(sih->bustype) == SI_BUS) {
2414*4882a593Smuzhiyun 		bool is_pciedev = BCM43602_CHIP(sih->chip);
2415*4882a593Smuzhiyun 
2416*4882a593Smuzhiyun 		for (i = 0; i < ARRAYSIZE(pmu_res_depend_pciewar_table); i++) {
2417*4882a593Smuzhiyun 			if (is_pciedev && pmu_res_depend_pciewar_table[i] &&
2418*4882a593Smuzhiyun 			    pmu_res_depend_pciewar_table_sz[i]) {
2419*4882a593Smuzhiyun 				si_pmu_resdeptbl_upd(sih, osh, pmu,
2420*4882a593Smuzhiyun 					pmu_res_depend_pciewar_table[i],
2421*4882a593Smuzhiyun 					pmu_res_depend_pciewar_table_sz[i]);
2422*4882a593Smuzhiyun 			}
2423*4882a593Smuzhiyun 		}
2424*4882a593Smuzhiyun 	}
2425*4882a593Smuzhiyun #endif /* !BCM_BOOTLOADER */
2426*4882a593Smuzhiyun 	/* Determine min/max rsrc masks */
2427*4882a593Smuzhiyun 	si_pmu_res_masks(sih, &min_mask, &max_mask);
2428*4882a593Smuzhiyun 	/* Add min mask dependencies */
2429*4882a593Smuzhiyun 	min_mask |= si_pmu_res_deps(sih, osh, pmu, min_mask, FALSE);
2430*4882a593Smuzhiyun 
2431*4882a593Smuzhiyun #ifdef BCM_BOOTLOADER
2432*4882a593Smuzhiyun 	/* Apply nvram override to max mask */
2433*4882a593Smuzhiyun 	if ((val = getvar(NULL, "brmax")) != NULL) {
2434*4882a593Smuzhiyun 		PMU_MSG(("Applying brmax=%s to max_res_mask\n", val));
2435*4882a593Smuzhiyun 		max_mask = (uint32)bcm_strtoul(val, NULL, 0);
2436*4882a593Smuzhiyun 	}
2437*4882a593Smuzhiyun 
2438*4882a593Smuzhiyun 	/* Apply nvram override to min mask */
2439*4882a593Smuzhiyun 	if ((val = getvar(NULL, "brmin")) != NULL) {
2440*4882a593Smuzhiyun 		PMU_MSG(("Applying brmin=%s to min_res_mask\n", val));
2441*4882a593Smuzhiyun 		min_mask = (uint32)bcm_strtoul(val, NULL, 0);
2442*4882a593Smuzhiyun 	}
2443*4882a593Smuzhiyun #endif /* BCM_BOOTLOADER */
2444*4882a593Smuzhiyun 
2445*4882a593Smuzhiyun 	/* apply new PLL setting if is ALP strap (need to close out
2446*4882a593Smuzhiyun 	 * if possible apply if is HT strap)
2447*4882a593Smuzhiyun 	 */
2448*4882a593Smuzhiyun 	if (((CHIPID(sih->chip) == BCM4360_CHIP_ID) || (CHIPID(sih->chip) == BCM4352_CHIP_ID)) &&
2449*4882a593Smuzhiyun 	    (CHIPREV(sih->chiprev) < 4) &&
2450*4882a593Smuzhiyun 	    ((CST4360_RSRC_INIT_MODE(sih->chipst) & 1) == 0)) {
2451*4882a593Smuzhiyun 		/* BBPLL */
2452*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, ~0, 0x09048562);
2453*4882a593Smuzhiyun 		/* AVB PLL */
2454*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG14, ~0, 0x09048562);
2455*4882a593Smuzhiyun 		si_pmu_pllupd(sih);
2456*4882a593Smuzhiyun 	} else if (((CHIPID(sih->chip) == BCM4360_CHIP_ID) ||
2457*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM4352_CHIP_ID)) &&
2458*4882a593Smuzhiyun 		(CHIPREV(sih->chiprev) >= 4) &&
2459*4882a593Smuzhiyun 		((CST4360_RSRC_INIT_MODE(sih->chipst) & 1) == 0)) {
2460*4882a593Smuzhiyun 		/* Changes for 4360B1 */
2461*4882a593Smuzhiyun 
2462*4882a593Smuzhiyun 		/* Enable REFCLK bit 11 */
2463*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL1, 0x800, 0x800);
2464*4882a593Smuzhiyun 
2465*4882a593Smuzhiyun 		/* BBPLL */
2466*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, ~0, 0x080004e2);
2467*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG7, ~0, 0xE);
2468*4882a593Smuzhiyun 		/* AVB PLL */
2469*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG14, ~0, 0x080004e2);
2470*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG15, ~0, 0xE);
2471*4882a593Smuzhiyun 		si_pmu_pllupd(sih);
2472*4882a593Smuzhiyun 	}
2473*4882a593Smuzhiyun 	/* disable PLL open loop operation */
2474*4882a593Smuzhiyun 	si_pll_closeloop(sih);
2475*4882a593Smuzhiyun 
2476*4882a593Smuzhiyun 	if (max_mask) {
2477*4882a593Smuzhiyun 		/* Ensure there is no bit set in min_mask which is not set in max_mask */
2478*4882a593Smuzhiyun 		max_mask |= min_mask;
2479*4882a593Smuzhiyun 
2480*4882a593Smuzhiyun 		/* First set the bits which change from 0 to 1 in max, then update the
2481*4882a593Smuzhiyun 		 * min_mask register and then reset the bits which change from 1 to 0
2482*4882a593Smuzhiyun 		 * in max. This is required as the bit in MAX should never go to 0 when
2483*4882a593Smuzhiyun 		 * the corresponding bit in min is still 1. Similarly the bit in min cannot
2484*4882a593Smuzhiyun 		 * be 1 when the corresponding bit in max is still 0.
2485*4882a593Smuzhiyun 		 */
2486*4882a593Smuzhiyun 		OR_REG(osh, &pmu->max_res_mask, max_mask);
2487*4882a593Smuzhiyun 	} else {
2488*4882a593Smuzhiyun 		/* First set the bits which change from 0 to 1 in max, then update the
2489*4882a593Smuzhiyun 		 * min_mask register and then reset the bits which change from 1 to 0
2490*4882a593Smuzhiyun 		 * in max. This is required as the bit in MAX should never go to 0 when
2491*4882a593Smuzhiyun 		 * the corresponding bit in min is still 1. Similarly the bit in min cannot
2492*4882a593Smuzhiyun 		 * be 1 when the corresponding bit in max is still 0.
2493*4882a593Smuzhiyun 		 */
2494*4882a593Smuzhiyun 		if (min_mask)
2495*4882a593Smuzhiyun 			OR_REG(osh, &pmu->max_res_mask, min_mask);
2496*4882a593Smuzhiyun 	}
2497*4882a593Smuzhiyun 
2498*4882a593Smuzhiyun 	/* Program min resource mask */
2499*4882a593Smuzhiyun 	if (min_mask) {
2500*4882a593Smuzhiyun 		PMU_MSG(("Changing min_res_mask to 0x%x\n", min_mask));
2501*4882a593Smuzhiyun 		W_REG(osh, &pmu->min_res_mask, min_mask);
2502*4882a593Smuzhiyun 	}
2503*4882a593Smuzhiyun 
2504*4882a593Smuzhiyun 	/* Program max resource mask */
2505*4882a593Smuzhiyun 	if (max_mask) {
2506*4882a593Smuzhiyun 		PMU_MSG(("Changing max_res_mask to 0x%x\n", max_mask));
2507*4882a593Smuzhiyun 		W_REG(osh, &pmu->max_res_mask, max_mask);
2508*4882a593Smuzhiyun 	}
2509*4882a593Smuzhiyun #if defined(SAVERESTORE) && defined(LDO3P3_MIN_RES_MASK)
2510*4882a593Smuzhiyun 	if (SR_ENAB()) {
2511*4882a593Smuzhiyun 		/* Set the default state for LDO3P3 protection */
2512*4882a593Smuzhiyun 		if (getintvar(NULL, rstr_ldo_prot) == 1) {
2513*4882a593Smuzhiyun 			si_pmu_min_res_ldo3p3_set(sih, osh, TRUE);
2514*4882a593Smuzhiyun 		}
2515*4882a593Smuzhiyun 	}
2516*4882a593Smuzhiyun #endif /* SAVERESTORE && LDO3P3_MIN_RES_MASK */
2517*4882a593Smuzhiyun 
2518*4882a593Smuzhiyun 	/* request htavail thru pcie core */
2519*4882a593Smuzhiyun 	if (((CHIPID(sih->chip) == BCM4360_CHIP_ID) || (CHIPID(sih->chip) == BCM4352_CHIP_ID)) &&
2520*4882a593Smuzhiyun 	    (BUSTYPE(sih->bustype) == PCI_BUS) &&
2521*4882a593Smuzhiyun 	    (CHIPREV(sih->chiprev) < 4)) {
2522*4882a593Smuzhiyun 		uint32 pcie_clk_ctl_st;
2523*4882a593Smuzhiyun 
2524*4882a593Smuzhiyun 		pcie_clk_ctl_st = si_corereg(sih, 3, 0x1e0, 0, 0);
2525*4882a593Smuzhiyun 		si_corereg(sih, 3, 0x1e0, ~0, (pcie_clk_ctl_st | CCS_HTAREQ));
2526*4882a593Smuzhiyun 	}
2527*4882a593Smuzhiyun 
2528*4882a593Smuzhiyun 	si_pmu_wait_for_steady_state(sih, osh, pmu);
2529*4882a593Smuzhiyun 	/* Add some delay; allow resources to come up and settle. */
2530*4882a593Smuzhiyun 	OSL_DELAY(2000);
2531*4882a593Smuzhiyun 
2532*4882a593Smuzhiyun 	/* Return to original core */
2533*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
2534*4882a593Smuzhiyun } /* si_pmu_res_init */
2535*4882a593Smuzhiyun 
2536*4882a593Smuzhiyun /* setup pll and query clock speed */
2537*4882a593Smuzhiyun typedef struct {
2538*4882a593Smuzhiyun 	uint16	fref;	/* x-tal frequency in [hz] */
2539*4882a593Smuzhiyun 	uint8	xf;	/* x-tal index as contained in PMU control reg, see PMU programmers guide */
2540*4882a593Smuzhiyun 	uint8	p1div;
2541*4882a593Smuzhiyun 	uint8	p2div;
2542*4882a593Smuzhiyun 	uint8	ndiv_int;
2543*4882a593Smuzhiyun 	uint32	ndiv_frac;
2544*4882a593Smuzhiyun } pmu1_xtaltab0_t;
2545*4882a593Smuzhiyun 
2546*4882a593Smuzhiyun /* 'xf' values corresponding to the 'xf' definition in the PMU control register */
2547*4882a593Smuzhiyun /* unclear why this enum contains '_640_' since the PMU prog guide says nothing about that */
2548*4882a593Smuzhiyun enum xtaltab0_640 {
2549*4882a593Smuzhiyun 	XTALTAB0_640_12000K = 1,
2550*4882a593Smuzhiyun 	XTALTAB0_640_13000K,
2551*4882a593Smuzhiyun 	XTALTAB0_640_14400K,
2552*4882a593Smuzhiyun 	XTALTAB0_640_15360K,
2553*4882a593Smuzhiyun 	XTALTAB0_640_16200K,
2554*4882a593Smuzhiyun 	XTALTAB0_640_16800K,
2555*4882a593Smuzhiyun 	XTALTAB0_640_19200K,
2556*4882a593Smuzhiyun 	XTALTAB0_640_19800K,
2557*4882a593Smuzhiyun 	XTALTAB0_640_20000K,
2558*4882a593Smuzhiyun 	XTALTAB0_640_24000K, /* warning: unknown in PMU programmers guide. seems incorrect. */
2559*4882a593Smuzhiyun 	XTALTAB0_640_25000K,
2560*4882a593Smuzhiyun 	XTALTAB0_640_26000K,
2561*4882a593Smuzhiyun 	XTALTAB0_640_30000K,
2562*4882a593Smuzhiyun 	XTALTAB0_640_33600K, /* warning: unknown in PMU programmers guide. seems incorrect. */
2563*4882a593Smuzhiyun 	XTALTAB0_640_37400K,
2564*4882a593Smuzhiyun 	XTALTAB0_640_38400K, /* warning: unknown in PMU programmers guide. seems incorrect. */
2565*4882a593Smuzhiyun 	XTALTAB0_640_40000K,
2566*4882a593Smuzhiyun 	XTALTAB0_640_48000K, /* warning: unknown in PMU programmers guide. seems incorrect. */
2567*4882a593Smuzhiyun 	XTALTAB0_640_52000K
2568*4882a593Smuzhiyun };
2569*4882a593Smuzhiyun 
2570*4882a593Smuzhiyun /* the following table is based on 880Mhz fvco */
2571*4882a593Smuzhiyun static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_880)[] = {
2572*4882a593Smuzhiyun 	{12000,	1,	3,	22,	0x9,	0xFFFFEF},
2573*4882a593Smuzhiyun 	{13000,	2,	1,	6,	0xb,	0x483483},
2574*4882a593Smuzhiyun 	{14400,	3,	1,	10,	0xa,	0x1C71C7},
2575*4882a593Smuzhiyun 	{15360,	4,	1,	5,	0xb,	0x755555},
2576*4882a593Smuzhiyun 	{16200,	5,	1,	10,	0x5,	0x6E9E06},
2577*4882a593Smuzhiyun 	{16800,	6,	1,	10,	0x5,	0x3Cf3Cf},
2578*4882a593Smuzhiyun 	{19200,	7,	1,	4,	0xb,	0x755555},
2579*4882a593Smuzhiyun 	{19800,	8,	1,	11,	0x4,	0xA57EB},
2580*4882a593Smuzhiyun 	{20000,	9,	1,	11,	0x4,	0x0},
2581*4882a593Smuzhiyun 	{24000,	10,	3,	11,	0xa,	0x0},
2582*4882a593Smuzhiyun 	{25000,	11,	5,	16,	0xb,	0x0},
2583*4882a593Smuzhiyun 	{26000,	12,	1,	2,	0x10,	0xEC4EC4},
2584*4882a593Smuzhiyun 	{30000,	13,	3,	8,	0xb,	0x0},
2585*4882a593Smuzhiyun 	{33600,	14,	1,	2,	0xd,	0x186186},
2586*4882a593Smuzhiyun 	{38400,	15,	1,	2,	0xb,	0x755555},
2587*4882a593Smuzhiyun 	{40000,	16,	1,	2,	0xb,	0},
2588*4882a593Smuzhiyun 	{0,	0,	0,	0,	0,	0}
2589*4882a593Smuzhiyun };
2590*4882a593Smuzhiyun 
2591*4882a593Smuzhiyun /* indices into pmu1_xtaltab0_880[] */
2592*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_12000K	0
2593*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_13000K	1
2594*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_14400K	2
2595*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_15360K	3
2596*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_16200K	4
2597*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_16800K	5
2598*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_19200K	6
2599*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_19800K	7
2600*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_20000K	8
2601*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_24000K	9
2602*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_25000K	10
2603*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_26000K	11
2604*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_30000K	12
2605*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_37400K	13
2606*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_38400K	14
2607*4882a593Smuzhiyun #define PMU1_XTALTAB0_880_40000K	15
2608*4882a593Smuzhiyun 
2609*4882a593Smuzhiyun /* the following table is based on 1760Mhz fvco */
2610*4882a593Smuzhiyun static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_1760)[] = {
2611*4882a593Smuzhiyun 	{12000,	1,	3,	44,	0x9,	0xFFFFEF},
2612*4882a593Smuzhiyun 	{13000,	2,	1,	12,	0xb,	0x483483},
2613*4882a593Smuzhiyun 	{14400,	3,	1,	20,	0xa,	0x1C71C7},
2614*4882a593Smuzhiyun 	{15360,	4,	1,	10,	0xb,	0x755555},
2615*4882a593Smuzhiyun 	{16200,	5,	1,	20,	0x5,	0x6E9E06},
2616*4882a593Smuzhiyun 	{16800,	6,	1,	20,	0x5,	0x3Cf3Cf},
2617*4882a593Smuzhiyun 	{19200,	7,	1,	18,	0x5,	0x17B425},
2618*4882a593Smuzhiyun 	{19800,	8,	1,	22,	0x4,	0xA57EB},
2619*4882a593Smuzhiyun 	{20000,	9,	1,	22,	0x4,	0x0},
2620*4882a593Smuzhiyun 	{24000,	10,	3,	22,	0xa,	0x0},
2621*4882a593Smuzhiyun 	{25000,	11,	5,	32,	0xb,	0x0},
2622*4882a593Smuzhiyun 	{26000,	12,	1,	4,	0x10,	0xEC4EC4},
2623*4882a593Smuzhiyun 	{30000,	13,	3,	16,	0xb,	0x0},
2624*4882a593Smuzhiyun 	{38400,	14,	1,	10,	0x4,	0x955555},
2625*4882a593Smuzhiyun 	{40000,	15,	1,	4,	0xb,	0},
2626*4882a593Smuzhiyun 	{0,	0,	0,	0,	0,	0}
2627*4882a593Smuzhiyun };
2628*4882a593Smuzhiyun 
2629*4882a593Smuzhiyun #define XTAL_FREQ_24000MHZ		24000
2630*4882a593Smuzhiyun #define XTAL_FREQ_29985MHZ		29985
2631*4882a593Smuzhiyun #define XTAL_FREQ_30000MHZ		30000
2632*4882a593Smuzhiyun #define XTAL_FREQ_37400MHZ		37400
2633*4882a593Smuzhiyun #define XTAL_FREQ_48000MHZ		48000
2634*4882a593Smuzhiyun #define XTAL_FREQ_59970MHZ		59970
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun /* 'xf' values corresponding to the 'xf' definition in the PMU control register */
2637*4882a593Smuzhiyun /* unclear why this enum contains '_960_' since the PMU prog guide says nothing about that */
2638*4882a593Smuzhiyun enum xtaltab0_960 {
2639*4882a593Smuzhiyun 	XTALTAB0_960_12000K = 1,
2640*4882a593Smuzhiyun 	XTALTAB0_960_13000K,
2641*4882a593Smuzhiyun 	XTALTAB0_960_14400K,
2642*4882a593Smuzhiyun 	XTALTAB0_960_15360K,
2643*4882a593Smuzhiyun 	XTALTAB0_960_16200K,
2644*4882a593Smuzhiyun 	XTALTAB0_960_16800K,
2645*4882a593Smuzhiyun 	XTALTAB0_960_19200K,
2646*4882a593Smuzhiyun 	XTALTAB0_960_19800K,
2647*4882a593Smuzhiyun 	XTALTAB0_960_20000K,
2648*4882a593Smuzhiyun 	XTALTAB0_960_24000K, /* warning: unknown in PMU programmers guide. seems incorrect. */
2649*4882a593Smuzhiyun 	XTALTAB0_960_25000K,
2650*4882a593Smuzhiyun 	XTALTAB0_960_26000K,
2651*4882a593Smuzhiyun 	XTALTAB0_960_30000K,
2652*4882a593Smuzhiyun 	XTALTAB0_960_33600K, /* warning: unknown in PMU programmers guide. seems incorrect. */
2653*4882a593Smuzhiyun 	XTALTAB0_960_37400K,
2654*4882a593Smuzhiyun 	XTALTAB0_960_38400K, /* warning: unknown in PMU programmers guide. seems incorrect. */
2655*4882a593Smuzhiyun 	XTALTAB0_960_40000K,
2656*4882a593Smuzhiyun 	XTALTAB0_960_48000K, /* warning: unknown in PMU programmers guide. seems incorrect. */
2657*4882a593Smuzhiyun 	XTALTAB0_960_52000K,
2658*4882a593Smuzhiyun 	XTALTAB0_960_59970K
2659*4882a593Smuzhiyun };
2660*4882a593Smuzhiyun 
2661*4882a593Smuzhiyun /**
2662*4882a593Smuzhiyun  * given an x-tal frequency, this table specifies the PLL params to use to generate a 960Mhz output
2663*4882a593Smuzhiyun  * clock. This output clock feeds the clock divider network. The defines of the form
2664*4882a593Smuzhiyun  * PMU1_XTALTAB0_960_* index into this array.
2665*4882a593Smuzhiyun  */
2666*4882a593Smuzhiyun static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_960)[] = {
2667*4882a593Smuzhiyun /*	fref      xf     p1div   p2div  ndiv_int  ndiv_frac */
2668*4882a593Smuzhiyun 	{12000,   1,       1,      1,     0x50,   0x0     }, /* array index 0 */
2669*4882a593Smuzhiyun 	{13000,   2,       1,      1,     0x49,   0xD89D89},
2670*4882a593Smuzhiyun 	{14400,   3,       1,      1,     0x42,   0xAAAAAA},
2671*4882a593Smuzhiyun 	{15360,   4,       1,      1,     0x3E,   0x800000},
2672*4882a593Smuzhiyun 	{16200,   5,       1,      1,     0x3B,   0x425ED0},
2673*4882a593Smuzhiyun 	{16800,   6,       1,      1,     0x39,   0x249249},
2674*4882a593Smuzhiyun 	{19200,   7,       1,      1,     0x32,   0x0     },
2675*4882a593Smuzhiyun 	{19800,   8,       1,      1,     0x30,   0x7C1F07},
2676*4882a593Smuzhiyun 	{20000,   9,       1,      1,     0x30,   0x0     },
2677*4882a593Smuzhiyun 	{24000,   10,      1,      1,     0x28,   0x0     },
2678*4882a593Smuzhiyun 	{25000,   11,      1,      1,     0x26,   0x666666}, /* array index 10 */
2679*4882a593Smuzhiyun 	{26000,   12,      1,      1,     0x24,   0xEC4EC4},
2680*4882a593Smuzhiyun 	{30000,   13,      1,      1,     0x20,   0x0     },
2681*4882a593Smuzhiyun 	{33600,   14,      1,      1,     0x1C,   0x924924},
2682*4882a593Smuzhiyun 	{37400,   15,      2,      1,     0x33,   0x563EF9},
2683*4882a593Smuzhiyun 	{38400,   16,      2,      1,     0x32,   0x0	  },
2684*4882a593Smuzhiyun 	{40000,   17,      2,      1,     0x30,   0x0     },
2685*4882a593Smuzhiyun 	{48000,   18,      2,      1,     0x28,   0x0     },
2686*4882a593Smuzhiyun 	{52000,   19,      2,      1,     0x24,   0xEC4EC4}, /* array index 18 */
2687*4882a593Smuzhiyun 	{59970,   20,      0,      0,     0,      0       },
2688*4882a593Smuzhiyun 	/* TBD: will separate 59970 for 4387B0 for new pll scheme */
2689*4882a593Smuzhiyun 	{0,	      0,       0,      0,     0,      0	      }
2690*4882a593Smuzhiyun };
2691*4882a593Smuzhiyun 
2692*4882a593Smuzhiyun static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_4369_963)[] = {
2693*4882a593Smuzhiyun /*	fref      xf     p1div   NA  ndiv_int  ndiv_frac */
2694*4882a593Smuzhiyun 	{12000,   1,       1,      1,     0x50,   0x40000}, /* array index 0 */
2695*4882a593Smuzhiyun 	{13000,   2,       1,      1,     0x4A,   0x13B14},
2696*4882a593Smuzhiyun 	{14400,   3,       1,      1,     0x42,   0xE0000},
2697*4882a593Smuzhiyun 	{15360,   4,       1,      1,     0x3E,   0xB2000},
2698*4882a593Smuzhiyun 	{16200,   5,       1,      1,     0x3B,   0x71C72},
2699*4882a593Smuzhiyun 	{16800,   6,       1,      1,     0x39,   0x52492},
2700*4882a593Smuzhiyun 	{19200,   7,       1,      1,     0x32,   0x28000},
2701*4882a593Smuzhiyun 	{19800,   8,       1,      1,     0x30,   0xA2E8C},
2702*4882a593Smuzhiyun 	{20000,   9,       1,      1,     0x30,   0x26666},
2703*4882a593Smuzhiyun 	{24000,   10,      1,      1,     0x28,   0x20000},
2704*4882a593Smuzhiyun 	{25000,   11,      1,      1,     0x26,   0x851EC}, /* array index 10 */
2705*4882a593Smuzhiyun 	{26000,   12,      1,      1,     0x25,   0x09D8A},
2706*4882a593Smuzhiyun 	{30000,   13,      1,      1,     0x20,   0x1999A},
2707*4882a593Smuzhiyun 	{33600,   14,      1,      1,     0x1C,   0xA9249},
2708*4882a593Smuzhiyun 	{37400,   15,      1,      1,     0x19,   0xBFA86},
2709*4882a593Smuzhiyun 	{38400,   16,      1,      1,     0x19,   0x14000},
2710*4882a593Smuzhiyun 	{40000,   17,      1,      1,     0x18,   0x13333},
2711*4882a593Smuzhiyun 	{48000,   18,      1,      1,     0x14,   0x10000},
2712*4882a593Smuzhiyun 	{52000,   19,      1,      1,     0x12,   0x84EC5}, /* array index 18 */
2713*4882a593Smuzhiyun 	{0,	      0,       0,      0,     0,      0	     }
2714*4882a593Smuzhiyun };
2715*4882a593Smuzhiyun 
2716*4882a593Smuzhiyun static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_4362_963)[] = {
2717*4882a593Smuzhiyun /*	fref      xf     p1div   NA  ndiv_int  ndiv_frac */
2718*4882a593Smuzhiyun 	{12000,   1,       1,      1,     0x50,   0x40000}, /* array index 0 */
2719*4882a593Smuzhiyun 	{13000,   2,       1,      1,     0x4A,   0x13B14},
2720*4882a593Smuzhiyun 	{14400,   3,       1,      1,     0x42,   0xE0000},
2721*4882a593Smuzhiyun 	{15360,   4,       1,      1,     0x3E,   0xB2000},
2722*4882a593Smuzhiyun 	{16200,   5,       1,      1,     0x3B,   0x71C72},
2723*4882a593Smuzhiyun 	{16800,   6,       1,      1,     0x39,   0x52492},
2724*4882a593Smuzhiyun 	{19200,   7,       1,      1,     0x32,   0x28000},
2725*4882a593Smuzhiyun 	{19800,   8,       1,      1,     0x30,   0xA2E8C},
2726*4882a593Smuzhiyun 	{20000,   9,       1,      1,     0x30,   0x26666},
2727*4882a593Smuzhiyun 	{24000,   10,      1,      1,     0x28,   0x20000},
2728*4882a593Smuzhiyun 	{25000,   11,      1,      1,     0x26,   0x851EC}, /* array index 10 */
2729*4882a593Smuzhiyun 	{26000,   12,      1,      1,     0x25,   0x09D8A},
2730*4882a593Smuzhiyun 	{30000,   13,      1,      1,     0x20,   0x1999A},
2731*4882a593Smuzhiyun 	{33600,   14,      1,      1,     0x1C,   0xA9249},
2732*4882a593Smuzhiyun 	{37400,   15,      1,      1,     0x19,   0xBFA86},
2733*4882a593Smuzhiyun 	{38400,   16,      1,      1,     0x19,   0x14000},
2734*4882a593Smuzhiyun 	{40000,   17,      1,      1,     0x18,   0x13333},
2735*4882a593Smuzhiyun 	{48000,   18,      1,      1,     0x14,   0x10000},
2736*4882a593Smuzhiyun 	{52000,   19,      1,      1,     0x12,   0x84EC5}, /* array index 18 */
2737*4882a593Smuzhiyun 	{0,	      0,       0,      0,     0,      0	     }
2738*4882a593Smuzhiyun };
2739*4882a593Smuzhiyun 
2740*4882a593Smuzhiyun /* Indices into array pmu1_xtaltab0_960[]. Keep array and these defines synchronized. */
2741*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_12000K	0
2742*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_13000K	1
2743*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_14400K	2
2744*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_15360K	3
2745*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_16200K	4
2746*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_16800K	5
2747*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_19200K	6
2748*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_19800K	7
2749*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_20000K	8
2750*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_24000K	9
2751*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_25000K	10
2752*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_26000K	11
2753*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_30000K	12
2754*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_33600K	13
2755*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_37400K	14
2756*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_38400K	15
2757*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_40000K	16
2758*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_48000K	17
2759*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_52000K	18
2760*4882a593Smuzhiyun #define PMU1_XTALTAB0_960_59970K	19
2761*4882a593Smuzhiyun 
2762*4882a593Smuzhiyun #define PMU15_XTALTAB0_12000K	0
2763*4882a593Smuzhiyun #define PMU15_XTALTAB0_20000K	1
2764*4882a593Smuzhiyun #define PMU15_XTALTAB0_26000K	2
2765*4882a593Smuzhiyun #define PMU15_XTALTAB0_37400K	3
2766*4882a593Smuzhiyun #define PMU15_XTALTAB0_52000K	4
2767*4882a593Smuzhiyun #define PMU15_XTALTAB0_END	5
2768*4882a593Smuzhiyun 
2769*4882a593Smuzhiyun /* For having the pllcontrol data (info)
2770*4882a593Smuzhiyun  * The table with the values of the registers will have one - one mapping.
2771*4882a593Smuzhiyun  */
2772*4882a593Smuzhiyun typedef struct {
2773*4882a593Smuzhiyun 	uint16	clock;	/**< x-tal frequency in [KHz] */
2774*4882a593Smuzhiyun 	uint8	mode;	/**< spur mode */
2775*4882a593Smuzhiyun 	uint8	xf;	/**< corresponds with xf bitfield in PMU control register */
2776*4882a593Smuzhiyun } pllctrl_data_t;
2777*4882a593Smuzhiyun 
2778*4882a593Smuzhiyun /*  *****************************  tables for 43012a0 *********************** */
2779*4882a593Smuzhiyun 
2780*4882a593Smuzhiyun /**
2781*4882a593Smuzhiyun  * PLL control register table giving info about the xtal supported for 43012
2782*4882a593Smuzhiyun  * There should be a one to one mapping between pmu1_pllctrl_tab_43012_960mhz[] and this table.
2783*4882a593Smuzhiyun  */
2784*4882a593Smuzhiyun static const pllctrl_data_t(pmu1_xtaltab0_43012)[] = {
2785*4882a593Smuzhiyun /*       clock  mode xf */
2786*4882a593Smuzhiyun 	{37400, 0,   XTALTAB0_960_37400K},
2787*4882a593Smuzhiyun 	{37400,	100, XTALTAB0_960_37400K},
2788*4882a593Smuzhiyun 	{26000, 0,   XTALTAB0_960_26000K},
2789*4882a593Smuzhiyun 	{24000, 0,   XTALTAB0_960_24000K}
2790*4882a593Smuzhiyun };
2791*4882a593Smuzhiyun 
2792*4882a593Smuzhiyun /*
2793*4882a593Smuzhiyun There should be a one to one mapping between pmu1_pllctrl_tab_43012_640mhz[]
2794*4882a593Smuzhiyun * and this table. PLL control5 register is related to HSIC which is not supported in 43012
2795*4882a593Smuzhiyun * Use a safe DCO code=56 by default, Across PVT openloop VCO Max=320MHz, Min=100
2796*4882a593Smuzhiyun * Mhz
2797*4882a593Smuzhiyun */
2798*4882a593Smuzhiyun #ifdef BCMQT
2799*4882a593Smuzhiyun static const uint32 (pmu1_pllctrl_tab_43012_1600mhz)[] = {
2800*4882a593Smuzhiyun /* Fvco is taken as 160.1 */
2801*4882a593Smuzhiyun /*	 PLL 0	     PLL 1	 PLL 2	     PLL 3	 PLL 4	     PLL 5		  */
2802*4882a593Smuzhiyun 	0x072fe811, 0x00800000, 0x00000000, 0x038051e8, 0x00000000, 0x00000000,
2803*4882a593Smuzhiyun 	0x0e5fd422, 0x00800000,	0x00000000, 0x000011e8,	0x00000000, 0x00000000
2804*4882a593Smuzhiyun };
2805*4882a593Smuzhiyun #else
2806*4882a593Smuzhiyun static const uint32 (pmu1_pllctrl_tab_43012_1600mhz)[] = {
2807*4882a593Smuzhiyun /* Fvco is taken as 160.1 */
2808*4882a593Smuzhiyun /*	 PLL 0	     PLL 1	 PLL 2	     PLL 3	 PLL 4  */
2809*4882a593Smuzhiyun 	0x07df2411, 0x00800000, 0x00000000, 0x038051e8, 0x00000000,
2810*4882a593Smuzhiyun 	0x0e5fd422, 0x00800000, 0x00000000, 0x000011e8, 0x00000000,
2811*4882a593Smuzhiyun 	0x1d89dc12, 0x00800000, 0x00000000, 0x06d04de8, 0x00000000,
2812*4882a593Smuzhiyun 	0x072fe828, 0x00800000, 0x00000000, 0x06d04de8, 0x00000000
2813*4882a593Smuzhiyun };
2814*4882a593Smuzhiyun #endif /* BCMQT */
2815*4882a593Smuzhiyun /*  ************************  tables for 43012a0 END *********************** */
2816*4882a593Smuzhiyun 
2817*4882a593Smuzhiyun /*  *****************************  tables for 4369a0 *********************** */
2818*4882a593Smuzhiyun /* should get real value from hardware guys */
2819*4882a593Smuzhiyun /**
2820*4882a593Smuzhiyun  * PLL control register table giving info about the xtal supported for 4369
2821*4882a593Smuzhiyun  * There should be a one to one mapping between pmu1_pllctrl_tab_4369_960mhz[] and this table.
2822*4882a593Smuzhiyun  * Even though macro suggests XTALTAB0_960_37400K --> BBPLL VCO is set to 963MHz
2823*4882a593Smuzhiyun  */
2824*4882a593Smuzhiyun static const pllctrl_data_t BCMATTACHDATA(pmu1_xtaltab0_4369)[] = {
2825*4882a593Smuzhiyun /*       clock  mode xf */
2826*4882a593Smuzhiyun 	{37400, 0,   XTALTAB0_960_37400K}
2827*4882a593Smuzhiyun };
2828*4882a593Smuzhiyun 
2829*4882a593Smuzhiyun /**
2830*4882a593Smuzhiyun  * PLL control register table giving info about the xtal supported for 4369.
2831*4882a593Smuzhiyun  * There should be a one to one mapping between pmu1_pllctrl_tab_4369_963mhz[] and this table.
2832*4882a593Smuzhiyun  */
2833*4882a593Smuzhiyun 
2834*4882a593Smuzhiyun /* For 4369, 960.1MHz BBPLL freq is chosen to avoid the spurs
2835*4882a593Smuzhiyun * freq table : pll1 : fvco 960.1M, pll2 for arm : 400 MHz
2836*4882a593Smuzhiyun */
2837*4882a593Smuzhiyun #define PMU_PLL3_4369B0_DEFAULT	0x006ABF86
2838*4882a593Smuzhiyun static const uint32	BCMATTACHDATA(pmu1_pllctrl_tab_4369_960p1mhz)[] = {
2839*4882a593Smuzhiyun /* Default values for unused registers 4-7 as sw loop execution will go for 8 times */
2840*4882a593Smuzhiyun /* Fvco is taken as 963M */
2841*4882a593Smuzhiyun /*	PLL 0  PLL 1   PLL 2   PLL 3   PLL 4   PLL 5  PLL 6  PLL 7   PLL 8   PLL 9   PLL 10 */
2842*4882a593Smuzhiyun 	0x15000000, 0x06050603, 0x01910806, PMU_PLL3_4369B0_DEFAULT,
2843*4882a593Smuzhiyun 	0x00000000, 0x32800000, 0xC7AE00A9, 0x40800000,
2844*4882a593Smuzhiyun 	0x00000000, 0x00000000, 0x00000000
2845*4882a593Smuzhiyun };
2846*4882a593Smuzhiyun 
2847*4882a593Smuzhiyun /*  ************************  tables for 4369a0 END *********************** */
2848*4882a593Smuzhiyun 
2849*4882a593Smuzhiyun /*  *****************************  tables for 4362a0 *********************** */
2850*4882a593Smuzhiyun /* should get real value from hardware guys */
2851*4882a593Smuzhiyun /**
2852*4882a593Smuzhiyun  * PLL control register table giving info about the xtal supported for 4362
2853*4882a593Smuzhiyun  * There should be a one to one mapping between pmu1_pllctrl_tab_4362_960mhz[] and this table.
2854*4882a593Smuzhiyun  * Even though macro suggests XTALTAB0_960_37400K --> BBPLL VCO is set to 963MHz
2855*4882a593Smuzhiyun  */
2856*4882a593Smuzhiyun static const pllctrl_data_t BCMATTACHDATA(pmu1_xtaltab0_4362)[] = {
2857*4882a593Smuzhiyun /*       clock  mode xf */
2858*4882a593Smuzhiyun 	{37400, 0,   XTALTAB0_960_37400K}
2859*4882a593Smuzhiyun };
2860*4882a593Smuzhiyun 
2861*4882a593Smuzhiyun /* For 4362, 960.1MHz BBPLL freq is chosen to avoid the spurs
2862*4882a593Smuzhiyun * freq table : pll1 : fvco 960.1M, pll2 for arm : 400 MHz
2863*4882a593Smuzhiyun */
2864*4882a593Smuzhiyun /* This freq actually around 960.123 */
2865*4882a593Smuzhiyun #define PMU_PLL3_4362A0_DEFAULT	0x006ABF86
2866*4882a593Smuzhiyun 
2867*4882a593Smuzhiyun static const uint32	BCMATTACHDATA(pmu1_pllctrl_tab_4362_960p1mhz)[] = {
2868*4882a593Smuzhiyun /* Default values for unused registers 4-7 as sw loop execution will go for 8 times */
2869*4882a593Smuzhiyun /* Fvco is taken as 963M */
2870*4882a593Smuzhiyun /*	PLL 0  PLL 1   PLL 2   PLL 3   PLL 4   PLL 5  PLL 6  PLL 7   PLL 8   PLL 9   PLL 10 */
2871*4882a593Smuzhiyun 	0x15000000, 0x06050603, 0x01910806, PMU_PLL3_4362A0_DEFAULT,
2872*4882a593Smuzhiyun 	0x00000000, 0x32800000, 0xC7AE00A9, 0x40800000,
2873*4882a593Smuzhiyun 	0x00000000, 0x00000000, 0x00000000
2874*4882a593Smuzhiyun };
2875*4882a593Smuzhiyun 
2876*4882a593Smuzhiyun /*  ************************  tables for 4362a0 END *********************** */
2877*4882a593Smuzhiyun 
2878*4882a593Smuzhiyun /*  *****************************  tables for 4389 *********************** */
2879*4882a593Smuzhiyun static const pllctrl_data_t BCMATTACHDATA(pmu1_xtaltab0_4389)[] = {
2880*4882a593Smuzhiyun /*       clock               mode xf */
2881*4882a593Smuzhiyun 	{XTAL_FREQ_59970MHZ, 0,   XTALTAB0_960_59970K}
2882*4882a593Smuzhiyun };
2883*4882a593Smuzhiyun 
2884*4882a593Smuzhiyun static const uint32 BCMATTACHDATA(pmu1_pllctrl_tab_4389_963mhz)[] = {
2885*4882a593Smuzhiyun /* Default values for all registers */
2886*4882a593Smuzhiyun /* Fvco (BBPLL) is taken as 963M */
2887*4882a593Smuzhiyun /*	PLL 0  PLL 1   PLL 2   PLL 3   PLL 4   PLL 5  PLL 6  PLL 7   PLL 8   PLL 9   PLL 10 */
2888*4882a593Smuzhiyun 	0x29d00000, 0x30100c03, 0x00240c06, 0x597ff060,
2889*4882a593Smuzhiyun 	0x00000000, 0x00000800, 0x00321d3a, 0x000551ff,
2890*4882a593Smuzhiyun 	0x00000000, 0x10000000, 0x00000000
2891*4882a593Smuzhiyun };
2892*4882a593Smuzhiyun 
2893*4882a593Smuzhiyun /*  ************************  tables for 4389 END *********************** */
2894*4882a593Smuzhiyun 
2895*4882a593Smuzhiyun /** returns a table that instructs how to program the BBPLL for a particular xtal frequency */
2896*4882a593Smuzhiyun static const pmu1_xtaltab0_t *
BCMPOSTTRAPFN(si_pmu1_xtaltab0)2897*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu1_xtaltab0)(si_t *sih)
2898*4882a593Smuzhiyun {
2899*4882a593Smuzhiyun #ifdef BCMDBG_PMU
2900*4882a593Smuzhiyun 	char chn[8];
2901*4882a593Smuzhiyun #endif
2902*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
2903*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
2904*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
2905*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
2906*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
2907*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
2908*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
2909*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
2910*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
2911*4882a593Smuzhiyun 		return pmu1_xtaltab0_960;
2912*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
2913*4882a593Smuzhiyun 		return pmu1_xtaltab0_4369_963;
2914*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
2915*4882a593Smuzhiyun 		return pmu1_xtaltab0_4362_963;
2916*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
2917*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
2918*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
2919*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
2920*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
2921*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
2922*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
2923*4882a593Smuzhiyun 		return pmu1_xtaltab0_960;
2924*4882a593Smuzhiyun 	default:
2925*4882a593Smuzhiyun 		PMU_MSG(("si_pmu1_xtaltab0: Unknown chipid %s\n", bcm_chipname(sih->chip, chn, 8)));
2926*4882a593Smuzhiyun 		break;
2927*4882a593Smuzhiyun 	}
2928*4882a593Smuzhiyun 	ASSERT(0);
2929*4882a593Smuzhiyun 	return NULL;
2930*4882a593Smuzhiyun } /* si_pmu1_xtaltab0 */
2931*4882a593Smuzhiyun 
2932*4882a593Smuzhiyun /** returns chip specific PLL settings for default xtal frequency and VCO output frequency */
2933*4882a593Smuzhiyun static const pmu1_xtaltab0_t *
BCMPOSTTRAPFN(si_pmu1_xtaldef0)2934*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu1_xtaldef0)(si_t *sih)
2935*4882a593Smuzhiyun {
2936*4882a593Smuzhiyun #ifdef BCMDBG_PMU
2937*4882a593Smuzhiyun 	char chn[8];
2938*4882a593Smuzhiyun #endif
2939*4882a593Smuzhiyun 
2940*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
2941*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
2942*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
2943*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
2944*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
2945*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
2946*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
2947*4882a593Smuzhiyun 		/* Default to 37400Khz */
2948*4882a593Smuzhiyun 		return &pmu1_xtaltab0_960[PMU1_XTALTAB0_960_37400K];
2949*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
2950*4882a593Smuzhiyun 		/* Default to 24000Khz */
2951*4882a593Smuzhiyun 		return &pmu1_xtaltab0_960[PMU1_XTALTAB0_960_24000K];
2952*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
2953*4882a593Smuzhiyun 		return &pmu1_xtaltab0_960[PMU1_XTALTAB0_960_40000K];
2954*4882a593Smuzhiyun 
2955*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
2956*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
2957*4882a593Smuzhiyun 		return &pmu1_xtaltab0_960[PMU1_XTALTAB0_960_37400K];
2958*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
2959*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
2960*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
2961*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
2962*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
2963*4882a593Smuzhiyun 		return &pmu1_xtaltab0_960[PMU1_XTALTAB0_960_59970K];
2964*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
2965*4882a593Smuzhiyun 		return &pmu1_xtaltab0_4369_963[PMU1_XTALTAB0_960_37400K];
2966*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
2967*4882a593Smuzhiyun 		return &pmu1_xtaltab0_4362_963[PMU1_XTALTAB0_960_37400K];
2968*4882a593Smuzhiyun 	default:
2969*4882a593Smuzhiyun 		PMU_MSG(("si_pmu1_xtaldef0: Unknown chipid %s\n", bcm_chipname(sih->chip, chn, 8)));
2970*4882a593Smuzhiyun 		break;
2971*4882a593Smuzhiyun 	}
2972*4882a593Smuzhiyun 	ASSERT(0);
2973*4882a593Smuzhiyun 	return NULL;
2974*4882a593Smuzhiyun } /* si_pmu1_xtaldef0 */
2975*4882a593Smuzhiyun 
2976*4882a593Smuzhiyun static uint32 fvco_4360 = 0;
2977*4882a593Smuzhiyun 
2978*4882a593Smuzhiyun /**
2979*4882a593Smuzhiyun  * store the val on init, then if func is called during normal operation
2980*4882a593Smuzhiyun  * don't touch core regs anymore
2981*4882a593Smuzhiyun  */
2982*4882a593Smuzhiyun static uint32
BCMPOSTTRAPFN(si_pmu_pll1_fvco_4360)2983*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_pll1_fvco_4360)(si_t *sih, osl_t *osh)
2984*4882a593Smuzhiyun {
2985*4882a593Smuzhiyun 	uint32 xf, ndiv_int, ndiv_frac, fvco, pll_reg, p1_div_scale;
2986*4882a593Smuzhiyun 	uint32 r_high, r_low, int_part, frac_part, rounding_const;
2987*4882a593Smuzhiyun 	uint8 p1_div;
2988*4882a593Smuzhiyun 	uint origidx = 0;
2989*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
2990*4882a593Smuzhiyun 
2991*4882a593Smuzhiyun 	if (fvco_4360) {
2992*4882a593Smuzhiyun 		printf("si_pmu_pll1_fvco_4360:attempt to query fvco during normal operation\n");
2993*4882a593Smuzhiyun 		/* this will insure that the func is called only once upon init */
2994*4882a593Smuzhiyun 		return fvco_4360;
2995*4882a593Smuzhiyun 	}
2996*4882a593Smuzhiyun 
2997*4882a593Smuzhiyun 	/* Remember original core before switch to chipc */
2998*4882a593Smuzhiyun 	si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
2999*4882a593Smuzhiyun 
3000*4882a593Smuzhiyun 	xf = si_pmu_alp_clock(sih, osh)/1000;
3001*4882a593Smuzhiyun 
3002*4882a593Smuzhiyun 	/* pll reg 10 , p1div, ndif_mode, ndiv_int */
3003*4882a593Smuzhiyun 	pll_reg = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG10, 0, 0);
3004*4882a593Smuzhiyun 	p1_div = pll_reg & 0xf;
3005*4882a593Smuzhiyun 	ndiv_int = (pll_reg >> 7)  & 0x1f;
3006*4882a593Smuzhiyun 
3007*4882a593Smuzhiyun 	/* pllctrl11 */
3008*4882a593Smuzhiyun 	pll_reg = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG11, 0, 0);
3009*4882a593Smuzhiyun 	ndiv_frac = pll_reg & 0xfffff;
3010*4882a593Smuzhiyun 
3011*4882a593Smuzhiyun 	int_part = xf * ndiv_int;
3012*4882a593Smuzhiyun 
3013*4882a593Smuzhiyun 	rounding_const = 1 << (BBPLL_NDIV_FRAC_BITS - 1);
3014*4882a593Smuzhiyun 	math_uint64_multiple_add(&r_high, &r_low, ndiv_frac, xf, rounding_const);
3015*4882a593Smuzhiyun 	math_uint64_right_shift(&frac_part, r_high, r_low, BBPLL_NDIV_FRAC_BITS);
3016*4882a593Smuzhiyun 
3017*4882a593Smuzhiyun 	if (!p1_div) {
3018*4882a593Smuzhiyun 		PMU_ERROR(("p1_div calc returned 0! [%d]\n", __LINE__));
3019*4882a593Smuzhiyun 		ROMMABLE_ASSERT(0);
3020*4882a593Smuzhiyun 	}
3021*4882a593Smuzhiyun 
3022*4882a593Smuzhiyun 	if (p1_div == 0) {
3023*4882a593Smuzhiyun 		ASSERT(p1_div != 0);
3024*4882a593Smuzhiyun 		p1_div_scale = 0;
3025*4882a593Smuzhiyun 	} else
3026*4882a593Smuzhiyun 
3027*4882a593Smuzhiyun 	p1_div_scale = (1 << P1_DIV_SCALE_BITS) / p1_div;
3028*4882a593Smuzhiyun 	rounding_const = 1 << (P1_DIV_SCALE_BITS - 1);
3029*4882a593Smuzhiyun 
3030*4882a593Smuzhiyun 	math_uint64_multiple_add(&r_high, &r_low, (int_part + frac_part),
3031*4882a593Smuzhiyun 		p1_div_scale, rounding_const);
3032*4882a593Smuzhiyun 	math_uint64_right_shift(&fvco, r_high, r_low, P1_DIV_SCALE_BITS);
3033*4882a593Smuzhiyun 
3034*4882a593Smuzhiyun 	/* Return to original core */
3035*4882a593Smuzhiyun 	si_restore_core(sih, origidx, &intr_val);
3036*4882a593Smuzhiyun 
3037*4882a593Smuzhiyun 	fvco_4360 = fvco;
3038*4882a593Smuzhiyun 	return fvco;
3039*4882a593Smuzhiyun } /* si_pmu_pll1_fvco_4360 */
3040*4882a593Smuzhiyun 
3041*4882a593Smuzhiyun /**
3042*4882a593Smuzhiyun  * Specific to 43012 and calculate the FVCO frequency from XTAL freq
3043*4882a593Smuzhiyun  *  Returns the FCVO frequency in [khz] units
3044*4882a593Smuzhiyun  */
3045*4882a593Smuzhiyun static uint32
BCMPOSTTRAPFN(si_pmu_pll1_fvco_43012)3046*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_pll1_fvco_43012)(si_t *sih, osl_t *osh)
3047*4882a593Smuzhiyun {
3048*4882a593Smuzhiyun 	uint32 xf, ndiv_int, ndiv_frac, fvco, pll_reg, p1_div_scale;
3049*4882a593Smuzhiyun 	uint32 r_high, r_low, int_part, frac_part, rounding_const;
3050*4882a593Smuzhiyun 	uint8 p_div;
3051*4882a593Smuzhiyun 	chipcregs_t *cc;
3052*4882a593Smuzhiyun 	uint origidx = 0;
3053*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
3054*4882a593Smuzhiyun 
3055*4882a593Smuzhiyun 	/* Remember original core before switch to chipc */
3056*4882a593Smuzhiyun 	cc = (chipcregs_t *)si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
3057*4882a593Smuzhiyun 	ASSERT(cc != NULL);
3058*4882a593Smuzhiyun 	BCM_REFERENCE(cc);
3059*4882a593Smuzhiyun 
3060*4882a593Smuzhiyun 	xf = si_pmu_alp_clock(sih, osh)/1000;
3061*4882a593Smuzhiyun 
3062*4882a593Smuzhiyun 	pll_reg = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG0, 0, 0);
3063*4882a593Smuzhiyun 
3064*4882a593Smuzhiyun 	ndiv_int = (pll_reg & PMU43012_PLL0_PC0_NDIV_INT_MASK) >>
3065*4882a593Smuzhiyun 			PMU43012_PLL0_PC0_NDIV_INT_SHIFT;
3066*4882a593Smuzhiyun 
3067*4882a593Smuzhiyun 	ndiv_frac = (pll_reg & PMU43012_PLL0_PC0_NDIV_FRAC_MASK) >>
3068*4882a593Smuzhiyun 			PMU43012_PLL0_PC0_NDIV_FRAC_SHIFT;
3069*4882a593Smuzhiyun 
3070*4882a593Smuzhiyun 	pll_reg = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG3, 0, 0);
3071*4882a593Smuzhiyun 
3072*4882a593Smuzhiyun 	p_div = (pll_reg & PMU43012_PLL0_PC3_PDIV_MASK) >>
3073*4882a593Smuzhiyun 			PMU43012_PLL0_PC3_PDIV_SHIFT;
3074*4882a593Smuzhiyun 
3075*4882a593Smuzhiyun 	/* If the p_div value read from PLL control register is zero,
3076*4882a593Smuzhiyun 	* then return default FVCO value instead of computing the FVCO frequency
3077*4882a593Smuzhiyun 	* using XTAL frequency
3078*4882a593Smuzhiyun 	*/
3079*4882a593Smuzhiyun 	if (!p_div) {
3080*4882a593Smuzhiyun 		PMU_ERROR(("pll control register read failed [%d]\n", __LINE__));
3081*4882a593Smuzhiyun 		ROMMABLE_ASSERT(0);
3082*4882a593Smuzhiyun 		fvco = 0;
3083*4882a593Smuzhiyun 		goto done;
3084*4882a593Smuzhiyun 	}
3085*4882a593Smuzhiyun 	/* Actual expression is as below */
3086*4882a593Smuzhiyun 	/* fvco1 = ((xf * (1/p1_div)) * (ndiv_int + (ndiv_frac /(1 << 20)))); */
3087*4882a593Smuzhiyun 
3088*4882a593Smuzhiyun 	int_part = xf * ndiv_int;
3089*4882a593Smuzhiyun 	rounding_const = 1 << (PMU43012_PLL_NDIV_FRAC_BITS - 1);
3090*4882a593Smuzhiyun 	math_uint64_multiple_add(&r_high, &r_low, ndiv_frac, xf, rounding_const);
3091*4882a593Smuzhiyun 	math_uint64_right_shift(&frac_part, r_high, r_low, PMU43012_PLL_NDIV_FRAC_BITS);
3092*4882a593Smuzhiyun 
3093*4882a593Smuzhiyun 	p1_div_scale = (1 << PMU43012_PLL_P_DIV_SCALE_BITS) / p_div;
3094*4882a593Smuzhiyun 	rounding_const = 1 << (PMU43012_PLL_P_DIV_SCALE_BITS - 1);
3095*4882a593Smuzhiyun 
3096*4882a593Smuzhiyun 	math_uint64_multiple_add(&r_high, &r_low, (int_part + frac_part),
3097*4882a593Smuzhiyun 		p1_div_scale, rounding_const);
3098*4882a593Smuzhiyun 	math_uint64_right_shift(&fvco, r_high, r_low, PMU43012_PLL_P_DIV_SCALE_BITS);
3099*4882a593Smuzhiyun 
3100*4882a593Smuzhiyun done:
3101*4882a593Smuzhiyun 	/* Return to original core */
3102*4882a593Smuzhiyun 	si_restore_core(sih, origidx, &intr_val);
3103*4882a593Smuzhiyun 	return fvco;
3104*4882a593Smuzhiyun } /* si_pmu_pll1_fvco_43012 */
3105*4882a593Smuzhiyun 
3106*4882a593Smuzhiyun /** returns chip specific default BaseBand pll fvco frequency in [khz] units */
3107*4882a593Smuzhiyun static uint32
BCMPOSTTRAPFN(si_pmu1_pllfvco0)3108*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu1_pllfvco0)(si_t *sih)
3109*4882a593Smuzhiyun {
3110*4882a593Smuzhiyun #ifdef BCMDBG_PMU
3111*4882a593Smuzhiyun 	char chn[8];
3112*4882a593Smuzhiyun #endif
3113*4882a593Smuzhiyun 
3114*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
3115*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
3116*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
3117*4882a593Smuzhiyun 		return FVCO_960;
3118*4882a593Smuzhiyun 
3119*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
3120*4882a593Smuzhiyun 		return FVCO_960;
3121*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
3122*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
3123*4882a593Smuzhiyun 	{
3124*4882a593Smuzhiyun 		osl_t *osh;
3125*4882a593Smuzhiyun 		osh = si_osh(sih);
3126*4882a593Smuzhiyun 		return si_pmu_pll1_fvco_4360(sih, osh);
3127*4882a593Smuzhiyun 	}
3128*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
3129*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
3130*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
3131*4882a593Smuzhiyun 	{
3132*4882a593Smuzhiyun 		osl_t *osh;
3133*4882a593Smuzhiyun 		osh = si_osh(sih);
3134*4882a593Smuzhiyun 		return si_pmu_pll1_fvco_43012(sih, osh);
3135*4882a593Smuzhiyun 	}
3136*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
3137*4882a593Smuzhiyun 		return FVCO_960p1;
3138*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
3139*4882a593Smuzhiyun 		return FVCO_960p1;
3140*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
3141*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
3142*4882a593Smuzhiyun 		return FVCO_960p1;
3143*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
3144*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
3145*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
3146*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
3147*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
3148*4882a593Smuzhiyun 		return FVCO_963p01;
3149*4882a593Smuzhiyun 	default:
3150*4882a593Smuzhiyun 		PMU_MSG(("si_pmu1_pllfvco0: Unknown chipid %s\n", bcm_chipname(sih->chip, chn, 8)));
3151*4882a593Smuzhiyun 		break;
3152*4882a593Smuzhiyun 	}
3153*4882a593Smuzhiyun 	ASSERT(0);
3154*4882a593Smuzhiyun 	return 0;
3155*4882a593Smuzhiyun } /* si_pmu1_pllfvco0 */
3156*4882a593Smuzhiyun 
3157*4882a593Smuzhiyun /**
3158*4882a593Smuzhiyun  * returns chip specific default pll fvco frequency in [khz] units
3159*4882a593Smuzhiyun  */
3160*4882a593Smuzhiyun static uint32
BCMPOSTTRAPFN(si_pmu1_pllfvco0_pll2)3161*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu1_pllfvco0_pll2)(si_t *sih)
3162*4882a593Smuzhiyun {
3163*4882a593Smuzhiyun #ifdef BCMDBG_PMU
3164*4882a593Smuzhiyun 	char chn[8];
3165*4882a593Smuzhiyun #endif
3166*4882a593Smuzhiyun 
3167*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
3168*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
3169*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
3170*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
3171*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
3172*4882a593Smuzhiyun 		return si_get_armpllclkfreq(sih) * 1000;
3173*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
3174*4882a593Smuzhiyun 		return SI_INFO(sih)->armpllclkfreq ? si_get_armpllclkfreq(sih) * 1000 : FVCO_1002p8;
3175*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
3176*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
3177*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
3178*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
3179*4882a593Smuzhiyun 		return FVCO_400;
3180*4882a593Smuzhiyun 	default:
3181*4882a593Smuzhiyun 		PMU_MSG(("si_pmu1_pllfvco0_pll2 : Unknown chipid %s\n",
3182*4882a593Smuzhiyun 				bcm_chipname(sih->chip, chn, 8)));
3183*4882a593Smuzhiyun 		ASSERT(0);
3184*4882a593Smuzhiyun 		break;
3185*4882a593Smuzhiyun 	}
3186*4882a593Smuzhiyun 	return 0;
3187*4882a593Smuzhiyun } /* si_pmu1_pllfvco0_pll2 */
3188*4882a593Smuzhiyun 
3189*4882a593Smuzhiyun /** query alp/xtal clock frequency */
3190*4882a593Smuzhiyun static uint32
BCMPOSTTRAPFN(si_pmu1_alpclk0)3191*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu1_alpclk0)(si_t *sih, osl_t *osh, pmuregs_t *pmu)
3192*4882a593Smuzhiyun {
3193*4882a593Smuzhiyun 	const pmu1_xtaltab0_t *xt;
3194*4882a593Smuzhiyun 	uint32 xf;
3195*4882a593Smuzhiyun 	uint8 xtdiv = 1;
3196*4882a593Smuzhiyun 
3197*4882a593Smuzhiyun 	BCM_REFERENCE(sih);
3198*4882a593Smuzhiyun 
3199*4882a593Smuzhiyun 	/* Find the frequency in the table */
3200*4882a593Smuzhiyun 	xf = (R_REG(osh, &pmu->pmucontrol) & PCTL_XTALFREQ_MASK) >>
3201*4882a593Smuzhiyun 	        PCTL_XTALFREQ_SHIFT;
3202*4882a593Smuzhiyun 	for (xt = si_pmu1_xtaltab0(sih); xt != NULL && xt->fref != 0; xt ++)
3203*4882a593Smuzhiyun 		if (xt->xf == xf)
3204*4882a593Smuzhiyun 			break;
3205*4882a593Smuzhiyun 	/* Could not find it so assign a default value */
3206*4882a593Smuzhiyun 	if (xt == NULL || xt->fref == 0)
3207*4882a593Smuzhiyun 		xt = si_pmu1_xtaldef0(sih);
3208*4882a593Smuzhiyun 	ASSERT(xt != NULL && xt->fref != 0);
3209*4882a593Smuzhiyun 
3210*4882a593Smuzhiyun 	switch (CHIPID(sih->chip))
3211*4882a593Smuzhiyun 	{
3212*4882a593Smuzhiyun 		case BCM4385_CHIP_GRPID:
3213*4882a593Smuzhiyun 		case BCM4387_CHIP_GRPID:
3214*4882a593Smuzhiyun 		case BCM4388_CHIP_GRPID:
3215*4882a593Smuzhiyun 		case BCM4389_CHIP_GRPID:
3216*4882a593Smuzhiyun 		case BCM4397_CHIP_GRPID:
3217*4882a593Smuzhiyun 			/* xtalfreq for 4378B0 is 59.97 MHz and
3218*4882a593Smuzhiyun 			 * but ALP clk is xtal / 2 (29.985 MHz) by default.
3219*4882a593Smuzhiyun 			 */
3220*4882a593Smuzhiyun 			xtdiv = 2;
3221*4882a593Smuzhiyun 			break;
3222*4882a593Smuzhiyun 		default:
3223*4882a593Smuzhiyun 			break;
3224*4882a593Smuzhiyun 	}
3225*4882a593Smuzhiyun 
3226*4882a593Smuzhiyun 	return (xt->fref * 1000) / xtdiv;
3227*4882a593Smuzhiyun }
3228*4882a593Smuzhiyun 
3229*4882a593Smuzhiyun /**
3230*4882a593Smuzhiyun  * Before the PLL is switched off, the HT clocks need to be deactivated, and reactivated
3231*4882a593Smuzhiyun  * when the PLL is switched on again.
3232*4882a593Smuzhiyun  * This function returns the chip specific HT clock resources (HT and MACPHY clocks).
3233*4882a593Smuzhiyun  */
3234*4882a593Smuzhiyun static uint32
si_pmu_htclk_mask(si_t * sih)3235*4882a593Smuzhiyun si_pmu_htclk_mask(si_t *sih)
3236*4882a593Smuzhiyun {
3237*4882a593Smuzhiyun 	/* chip specific bit position of various resources */
3238*4882a593Smuzhiyun 	rsc_per_chip_t *rsc = si_pmu_get_rsc_positions(sih);
3239*4882a593Smuzhiyun 
3240*4882a593Smuzhiyun 	uint32 ht_req = (PMURES_BIT(rsc->ht_avail) | PMURES_BIT(rsc->macphy_clkavail));
3241*4882a593Smuzhiyun 
3242*4882a593Smuzhiyun 	switch (CHIPID(sih->chip))
3243*4882a593Smuzhiyun 	{
3244*4882a593Smuzhiyun 		CASE_BCM43602_CHIP:
3245*4882a593Smuzhiyun 		case BCM43012_CHIP_ID:
3246*4882a593Smuzhiyun 		case BCM43013_CHIP_ID:
3247*4882a593Smuzhiyun 		case BCM43014_CHIP_ID:
3248*4882a593Smuzhiyun 		case BCM4369_CHIP_GRPID:
3249*4882a593Smuzhiyun 		case BCM4362_CHIP_GRPID:
3250*4882a593Smuzhiyun 		case BCM4376_CHIP_GRPID:
3251*4882a593Smuzhiyun 		case BCM4378_CHIP_GRPID:
3252*4882a593Smuzhiyun 		case BCM4385_CHIP_GRPID:
3253*4882a593Smuzhiyun 		case BCM4387_CHIP_GRPID:
3254*4882a593Smuzhiyun 		case BCM4388_CHIP_GRPID:
3255*4882a593Smuzhiyun 		case BCM4389_CHIP_GRPID:
3256*4882a593Smuzhiyun 		case BCM4397_CHIP_GRPID:
3257*4882a593Smuzhiyun 			ht_req |= PMURES_BIT(rsc->ht_start);
3258*4882a593Smuzhiyun 			break;
3259*4882a593Smuzhiyun 		default:
3260*4882a593Smuzhiyun 			ASSERT(0);
3261*4882a593Smuzhiyun 			break;
3262*4882a593Smuzhiyun 	}
3263*4882a593Smuzhiyun 
3264*4882a593Smuzhiyun 	return ht_req;
3265*4882a593Smuzhiyun } /* si_pmu_htclk_mask */
3266*4882a593Smuzhiyun 
3267*4882a593Smuzhiyun /** returns ALP frequency in [Hz] */
3268*4882a593Smuzhiyun static uint32
BCMATTACHFN(si_pmu_def_alp_clock)3269*4882a593Smuzhiyun BCMATTACHFN(si_pmu_def_alp_clock)(si_t *sih, osl_t *osh)
3270*4882a593Smuzhiyun {
3271*4882a593Smuzhiyun 	uint32 clock = ALP_CLOCK;
3272*4882a593Smuzhiyun 
3273*4882a593Smuzhiyun 	BCM_REFERENCE(osh);
3274*4882a593Smuzhiyun 
3275*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
3276*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
3277*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
3278*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
3279*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
3280*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
3281*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
3282*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
3283*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
3284*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
3285*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
3286*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
3287*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
3288*4882a593Smuzhiyun 
3289*4882a593Smuzhiyun #ifdef UNRELEASEDCHIP
3290*4882a593Smuzhiyun #endif
3291*4882a593Smuzhiyun 
3292*4882a593Smuzhiyun 		clock = 37400*1000;
3293*4882a593Smuzhiyun 		break;
3294*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
3295*4882a593Smuzhiyun 		clock = 40000 * 1000;
3296*4882a593Smuzhiyun 		break;
3297*4882a593Smuzhiyun 	}
3298*4882a593Smuzhiyun 
3299*4882a593Smuzhiyun 	return clock;
3300*4882a593Smuzhiyun }
3301*4882a593Smuzhiyun 
3302*4882a593Smuzhiyun /**
3303*4882a593Smuzhiyun  * The BBPLL register set needs to be reprogrammed because the x-tal frequency is not known at
3304*4882a593Smuzhiyun  * compile time, or a different spur mode is selected. This function writes appropriate values into
3305*4882a593Smuzhiyun  * the BBPLL registers. It returns the 'xf', corresponding to the 'xf' bitfield in the PMU control
3306*4882a593Smuzhiyun  * register.
3307*4882a593Smuzhiyun  *     'xtal'             : xtal frequency in [KHz]
3308*4882a593Smuzhiyun  *     'pllctrlreg_update': contains info on what entries to use in 'pllctrlreg_val' for the given
3309*4882a593Smuzhiyun  *                          x-tal frequency and spur mode
3310*4882a593Smuzhiyun  *     'pllctrlreg_val'   : contains a superset of the BBPLL values to write
3311*4882a593Smuzhiyun  *
3312*4882a593Smuzhiyun  * Note: if pmu is NULL, this function returns xf, without programming PLL registers.
3313*4882a593Smuzhiyun  * This function is only called for pmu1_ type chips, perhaps we should rename it.
3314*4882a593Smuzhiyun  */
3315*4882a593Smuzhiyun static uint8
si_pmu_pllctrlreg_update(si_t * sih,osl_t * osh,pmuregs_t * pmu,uint32 xtal,uint8 spur_mode,const pllctrl_data_t * pllctrlreg_update,uint32 array_size,const uint32 * pllctrlreg_val)3316*4882a593Smuzhiyun si_pmu_pllctrlreg_update(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 xtal,
3317*4882a593Smuzhiyun             uint8 spur_mode, const pllctrl_data_t *pllctrlreg_update, uint32 array_size,
3318*4882a593Smuzhiyun             const uint32 *pllctrlreg_val)
3319*4882a593Smuzhiyun {
3320*4882a593Smuzhiyun 	uint8 indx, reg_offset, xf = 0;
3321*4882a593Smuzhiyun 	uint8 pll_ctrlcnt = 0;
3322*4882a593Smuzhiyun 
3323*4882a593Smuzhiyun 	ASSERT(pllctrlreg_update);
3324*4882a593Smuzhiyun 
3325*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 5) {
3326*4882a593Smuzhiyun 		pll_ctrlcnt = (sih->pmucaps & PCAP5_PC_MASK) >> PCAP5_PC_SHIFT;
3327*4882a593Smuzhiyun 	} else {
3328*4882a593Smuzhiyun 		pll_ctrlcnt = (sih->pmucaps & PCAP_PC_MASK) >> PCAP_PC_SHIFT;
3329*4882a593Smuzhiyun 	}
3330*4882a593Smuzhiyun 
3331*4882a593Smuzhiyun 	/* Program the PLL control register if the xtal value matches with the table entry value */
3332*4882a593Smuzhiyun 	for (indx = 0; indx < array_size; indx++) {
3333*4882a593Smuzhiyun 		/* If the entry does not match the xtal and spur_mode just continue the loop */
3334*4882a593Smuzhiyun 		if (!((pllctrlreg_update[indx].clock == (uint16)xtal) &&
3335*4882a593Smuzhiyun 			(pllctrlreg_update[indx].mode == spur_mode)))
3336*4882a593Smuzhiyun 			continue;
3337*4882a593Smuzhiyun 		/*
3338*4882a593Smuzhiyun 		 * Don't program the PLL registers if register base is NULL.
3339*4882a593Smuzhiyun 		 * If NULL just return the xref.
3340*4882a593Smuzhiyun 		 */
3341*4882a593Smuzhiyun 		if (pmu) {
3342*4882a593Smuzhiyun 			for (reg_offset = 0; reg_offset < pll_ctrlcnt; reg_offset++) {
3343*4882a593Smuzhiyun 				si_pmu_pllcontrol(sih, reg_offset, ~0,
3344*4882a593Smuzhiyun 					pllctrlreg_val[indx*pll_ctrlcnt + reg_offset]);
3345*4882a593Smuzhiyun 			}
3346*4882a593Smuzhiyun 
3347*4882a593Smuzhiyun 			/* for 4369, arm clk cycle can be set from nvram - default is 400 MHz */
3348*4882a593Smuzhiyun 			if ((BCM4369_CHIP(sih->chip) || BCM4362_CHIP(sih->chip)) &&
3349*4882a593Smuzhiyun 				(pll_ctrlcnt > PMU1_PLL0_PLLCTL6)) {
3350*4882a593Smuzhiyun 				si_pmu_pll6val_armclk_calc(osh, pmu,
3351*4882a593Smuzhiyun 					si_get_armpllclkfreq(sih), xtal, TRUE);
3352*4882a593Smuzhiyun 			}
3353*4882a593Smuzhiyun 		}
3354*4882a593Smuzhiyun 		xf = pllctrlreg_update[indx].xf;
3355*4882a593Smuzhiyun 		break;
3356*4882a593Smuzhiyun 	}
3357*4882a593Smuzhiyun 	return xf;
3358*4882a593Smuzhiyun } /* si_pmu_pllctrlreg_update */
3359*4882a593Smuzhiyun 
3360*4882a593Smuzhiyun /*
3361*4882a593Smuzhiyun  * Calculate p1div, ndiv_int, ndiv_frac for clock ratio.
3362*4882a593Smuzhiyun  * Input: fvco, xtal
3363*4882a593Smuzhiyun  * Output: ndiv_int, ndiv_frac
3364*4882a593Smuzhiyun  * Returns: p1div
3365*4882a593Smuzhiyun  *
3366*4882a593Smuzhiyun  */
3367*4882a593Smuzhiyun uint8
si_pmu_pll28nm_calc_ndiv(uint32 fvco,uint32 xtal,uint32 * ndiv_int,uint32 * ndiv_frac)3368*4882a593Smuzhiyun si_pmu_pll28nm_calc_ndiv(uint32 fvco, uint32 xtal, uint32 *ndiv_int, uint32 *ndiv_frac)
3369*4882a593Smuzhiyun {
3370*4882a593Smuzhiyun 	uint8 p1div;
3371*4882a593Smuzhiyun 	uint32 temp_high, temp_low;
3372*4882a593Smuzhiyun 	ASSERT(xtal <= 0xFFFFFFFF / 1000);
3373*4882a593Smuzhiyun 	p1div = 1 + (uint8) ((xtal * 1000) / 54000000UL);
3374*4882a593Smuzhiyun 	*ndiv_int = (fvco * p1div) / xtal;
3375*4882a593Smuzhiyun 	/* nfrac = 20 */
3376*4882a593Smuzhiyun 	/* ndiv_frac = (uint32) (((uint64) (fvco * p1div - xtal * ndiv_int) * (1 << 20)) / xtal) */
3377*4882a593Smuzhiyun 	math_uint64_multiple_add(&temp_high, &temp_low, fvco * p1div - xtal * (*ndiv_int), 1 << 20,
3378*4882a593Smuzhiyun 		0);
3379*4882a593Smuzhiyun 	math_uint64_divide(ndiv_frac, temp_high, temp_low, xtal);
3380*4882a593Smuzhiyun 	return p1div;
3381*4882a593Smuzhiyun }
3382*4882a593Smuzhiyun 
3383*4882a593Smuzhiyun void
si_pmu_armpll_freq_upd(si_t * sih,uint8 p1div,uint32 ndiv_int,uint32 ndiv_frac)3384*4882a593Smuzhiyun si_pmu_armpll_freq_upd(si_t *sih, uint8 p1div, uint32 ndiv_int, uint32 ndiv_frac)
3385*4882a593Smuzhiyun {
3386*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
3387*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
3388*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, PMU4388_ARMPLL_I_NDIV_INT_MASK,
3389*4882a593Smuzhiyun 			ndiv_int << PMU4388_ARMPLL_I_NDIV_INT_SHIFT);
3390*4882a593Smuzhiyun 		si_pmu_pllupd(sih);
3391*4882a593Smuzhiyun 		break;
3392*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
3393*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, PMU4389_ARMPLL_I_NDIV_INT_MASK,
3394*4882a593Smuzhiyun 			ndiv_int << PMU4389_ARMPLL_I_NDIV_INT_SHIFT);
3395*4882a593Smuzhiyun 		si_pmu_pllupd(sih);
3396*4882a593Smuzhiyun 		break;
3397*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
3398*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG5, PMU4369_PLL1_PC5_P1DIV_MASK,
3399*4882a593Smuzhiyun 			((p1div >> PMU4369_P1DIV_LO_SHIFT) << PMU4369_PLL1_PC5_P1DIV_SHIFT));
3400*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, PMU4369_PLL1_PC6_P1DIV_MASK,
3401*4882a593Smuzhiyun 			(p1div >> PMU4369_P1DIV_HI_SHIFT));
3402*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, PMU4369_PLL1_PC6_NDIV_INT_MASK,
3403*4882a593Smuzhiyun 			ndiv_int << PMU4369_PLL1_PC6_NDIV_INT_SHIFT);
3404*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, PMU4369_PLL1_PC6_NDIV_FRAC_MASK,
3405*4882a593Smuzhiyun 			ndiv_frac << PMU4369_PLL1_PC6_NDIV_FRAC_SHIFT);
3406*4882a593Smuzhiyun 		si_pmu_pllupd(sih);
3407*4882a593Smuzhiyun 		break;
3408*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
3409*4882a593Smuzhiyun 		/* 4362/69 PLL definitions are same. so reusing definitions */
3410*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG5, PMU4369_PLL1_PC5_P1DIV_MASK,
3411*4882a593Smuzhiyun 			((p1div >> PMU4369_P1DIV_LO_SHIFT) << PMU4369_PLL1_PC5_P1DIV_SHIFT));
3412*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, PMU4369_PLL1_PC6_P1DIV_MASK,
3413*4882a593Smuzhiyun 			(p1div >> PMU4369_P1DIV_HI_SHIFT));
3414*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, PMU4369_PLL1_PC6_NDIV_INT_MASK,
3415*4882a593Smuzhiyun 			ndiv_int << PMU4369_PLL1_PC6_NDIV_INT_SHIFT);
3416*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6, PMU4369_PLL1_PC6_NDIV_FRAC_MASK,
3417*4882a593Smuzhiyun 			ndiv_frac << PMU4369_PLL1_PC6_NDIV_FRAC_SHIFT);
3418*4882a593Smuzhiyun 		si_pmu_pllupd(sih);
3419*4882a593Smuzhiyun 		break;
3420*4882a593Smuzhiyun 	default:
3421*4882a593Smuzhiyun 		ASSERT(0);
3422*4882a593Smuzhiyun 		break;
3423*4882a593Smuzhiyun 	}
3424*4882a593Smuzhiyun }
3425*4882a593Smuzhiyun 
3426*4882a593Smuzhiyun void
si_pmu_bbpll_freq_upd(si_t * sih,uint8 p1div,uint32 ndiv_int,uint32 ndiv_frac)3427*4882a593Smuzhiyun si_pmu_bbpll_freq_upd(si_t *sih, uint8 p1div, uint32 ndiv_int, uint32 ndiv_frac)
3428*4882a593Smuzhiyun {
3429*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
3430*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
3431*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
3432*4882a593Smuzhiyun 		/* PLL Control 2 Register are the same for 4368, 4369 */
3433*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2, PMU4369_PLL0_PC2_PDIV_MASK, p1div);
3434*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2, PMU4369_PLL0_PC2_NDIV_INT_MASK,
3435*4882a593Smuzhiyun 			ndiv_int << PMU4369_PLL0_PC2_NDIV_INT_SHIFT);
3436*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2, PMU4369_PLL0_PC3_NDIV_FRAC_MASK,
3437*4882a593Smuzhiyun 			ndiv_frac << PMU4369_PLL0_PC3_NDIV_FRAC_SHIFT);
3438*4882a593Smuzhiyun 		si_pmu_pllupd(sih);
3439*4882a593Smuzhiyun 		break;
3440*4882a593Smuzhiyun 	default:
3441*4882a593Smuzhiyun 		ASSERT(0);
3442*4882a593Smuzhiyun 		break;
3443*4882a593Smuzhiyun 	}
3444*4882a593Smuzhiyun }
3445*4882a593Smuzhiyun 
3446*4882a593Smuzhiyun void
si_pmu_armpll_chmdiv_upd(si_t * sih,uint32 ch0_mdiv,uint32 ch1_mdiv)3447*4882a593Smuzhiyun si_pmu_armpll_chmdiv_upd(si_t *sih, uint32 ch0_mdiv, uint32 ch1_mdiv)
3448*4882a593Smuzhiyun {
3449*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
3450*4882a593Smuzhiyun 	default:
3451*4882a593Smuzhiyun 		ASSERT(0);
3452*4882a593Smuzhiyun 		break;
3453*4882a593Smuzhiyun 	}
3454*4882a593Smuzhiyun }
3455*4882a593Smuzhiyun 
3456*4882a593Smuzhiyun static bool
si_pmu_armpll_write_required(si_t * sih,uint32 xtal)3457*4882a593Smuzhiyun si_pmu_armpll_write_required(si_t *sih, uint32 xtal)
3458*4882a593Smuzhiyun {
3459*4882a593Smuzhiyun 	uint32 def_xtal = 0;
3460*4882a593Smuzhiyun 	uint32 def_armclk_mhz = 0;
3461*4882a593Smuzhiyun 	uint32 armclk_mhz = si_get_armpllclkfreq(sih);
3462*4882a593Smuzhiyun 
3463*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
3464*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
3465*4882a593Smuzhiyun 		def_xtal = XTAL_FREQ_37400MHZ;
3466*4882a593Smuzhiyun 		def_armclk_mhz = ARMPLL_FREQ_400MHZ;
3467*4882a593Smuzhiyun 		break;
3468*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
3469*4882a593Smuzhiyun 		def_xtal = XTAL_FREQ_59970MHZ;
3470*4882a593Smuzhiyun 		def_armclk_mhz = ARMPLL_FREQ_1000MHZ;
3471*4882a593Smuzhiyun 		break;
3472*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
3473*4882a593Smuzhiyun 		def_xtal = XTAL_FREQ_59970MHZ;
3474*4882a593Smuzhiyun 		def_armclk_mhz = ARMPLL_FREQ_1000MHZ;
3475*4882a593Smuzhiyun 		break;
3476*4882a593Smuzhiyun 	default:
3477*4882a593Smuzhiyun 		break;
3478*4882a593Smuzhiyun 	}
3479*4882a593Smuzhiyun 
3480*4882a593Smuzhiyun 	/*
3481*4882a593Smuzhiyun 	 * If programmed xtalfreq is same as xtal, no need to enable pll write. Check for
3482*4882a593Smuzhiyun 	 * armclk and xtalfreq instead of comparing calculated value and pll register value.
3483*4882a593Smuzhiyun 	 */
3484*4882a593Smuzhiyun 	return (((armclk_mhz == def_armclk_mhz) && (xtal == def_xtal)) ? FALSE : TRUE);
3485*4882a593Smuzhiyun }
3486*4882a593Smuzhiyun 
3487*4882a593Smuzhiyun /**
3488*4882a593Smuzhiyun  * Chip-specific overrides to PLLCONTROL registers during init. If certain conditions (dependent on
3489*4882a593Smuzhiyun  * x-tal frequency and current ALP frequency) are met, an update of the PLL is required.
3490*4882a593Smuzhiyun  *
3491*4882a593Smuzhiyun  * This takes less precedence over OTP PLLCONTROL overrides.
3492*4882a593Smuzhiyun  * If update_required=FALSE, it returns TRUE if a update is about to occur.
3493*4882a593Smuzhiyun  * No write happens.
3494*4882a593Smuzhiyun  *
3495*4882a593Smuzhiyun  * Return value: TRUE if the BBPLL registers 'update' field should be written by the caller.
3496*4882a593Smuzhiyun  *
3497*4882a593Smuzhiyun  * This function is only called for pmu1_ type chips, perhaps we should rename it.
3498*4882a593Smuzhiyun  */
3499*4882a593Smuzhiyun static bool
BCMATTACHFN(si_pmu_update_pllcontrol)3500*4882a593Smuzhiyun BCMATTACHFN(si_pmu_update_pllcontrol)(si_t *sih, osl_t *osh, uint32 xtal, bool update_required)
3501*4882a593Smuzhiyun {
3502*4882a593Smuzhiyun 	pmuregs_t *pmu;
3503*4882a593Smuzhiyun 	uint origidx;
3504*4882a593Smuzhiyun 	bool write_en = FALSE;
3505*4882a593Smuzhiyun 	uint8 xf = 0;
3506*4882a593Smuzhiyun 	const pmu1_xtaltab0_t *xt;
3507*4882a593Smuzhiyun 	uint32 tmp;
3508*4882a593Smuzhiyun 	const pllctrl_data_t *pllctrlreg_update = NULL;
3509*4882a593Smuzhiyun 	uint32 array_size = 0;
3510*4882a593Smuzhiyun 	/* points at a set of PLL register values to write for a given x-tal frequency: */
3511*4882a593Smuzhiyun 	const uint32 *pllctrlreg_val = NULL;
3512*4882a593Smuzhiyun 	uint8 ndiv_mode = PMU1_PLL0_PC2_NDIV_MODE_MASH;
3513*4882a593Smuzhiyun 	uint32 xtalfreq = 0;
3514*4882a593Smuzhiyun 	uint32 ndiv_int;
3515*4882a593Smuzhiyun 	uint32 ndiv_frac;
3516*4882a593Smuzhiyun 	uint8 pdiv;
3517*4882a593Smuzhiyun 
3518*4882a593Smuzhiyun 	BCM_REFERENCE(ndiv_int);
3519*4882a593Smuzhiyun 	BCM_REFERENCE(ndiv_frac);
3520*4882a593Smuzhiyun 	BCM_REFERENCE(pdiv);
3521*4882a593Smuzhiyun 	/* If there is OTP or NVRAM entry for xtalfreq, program the
3522*4882a593Smuzhiyun 	 * PLL control register even if it is default xtal.
3523*4882a593Smuzhiyun 	 */
3524*4882a593Smuzhiyun 	xtalfreq = getintvar(NULL, rstr_xtalfreq);
3525*4882a593Smuzhiyun 	/* CASE1 */
3526*4882a593Smuzhiyun 	if (xtalfreq) {
3527*4882a593Smuzhiyun 		write_en = TRUE;
3528*4882a593Smuzhiyun 		xtal = xtalfreq;
3529*4882a593Smuzhiyun 	} else {
3530*4882a593Smuzhiyun 		/* There is NO OTP value */
3531*4882a593Smuzhiyun 		if (xtal) {
3532*4882a593Smuzhiyun 			/* CASE2: If the xtal value was calculated, program the PLL control
3533*4882a593Smuzhiyun 			 * registers only if it is not default xtal value.
3534*4882a593Smuzhiyun 			 */
3535*4882a593Smuzhiyun 			if (xtal != (si_pmu_def_alp_clock(sih, osh)/1000))
3536*4882a593Smuzhiyun 				write_en = TRUE;
3537*4882a593Smuzhiyun 		} else {
3538*4882a593Smuzhiyun 			/* CASE3: If the xtal obtained is "0", ie., clock is not measured, then
3539*4882a593Smuzhiyun 			 * leave the PLL control register as it is but program the xf in
3540*4882a593Smuzhiyun 			 * pmucontrol register with the default xtal value.
3541*4882a593Smuzhiyun 			 */
3542*4882a593Smuzhiyun 			xtal = si_pmu_def_alp_clock(sih, osh)/1000;
3543*4882a593Smuzhiyun 		}
3544*4882a593Smuzhiyun 	}
3545*4882a593Smuzhiyun 
3546*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
3547*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
3548*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
3549*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
3550*4882a593Smuzhiyun 		pllctrlreg_update = pmu1_xtaltab0_43012;
3551*4882a593Smuzhiyun 		array_size = ARRAYSIZE(pmu1_xtaltab0_43012);
3552*4882a593Smuzhiyun 		pllctrlreg_val = pmu1_pllctrl_tab_43012_1600mhz;
3553*4882a593Smuzhiyun 		break;
3554*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
3555*4882a593Smuzhiyun 		pllctrlreg_update = pmu1_xtaltab0_4369;
3556*4882a593Smuzhiyun 		array_size = ARRAYSIZE(pmu1_xtaltab0_4369);
3557*4882a593Smuzhiyun 		pllctrlreg_val = pmu1_pllctrl_tab_4369_960p1mhz;
3558*4882a593Smuzhiyun 		/* default pll programming be true, later based on need disable it */
3559*4882a593Smuzhiyun 		write_en = TRUE;
3560*4882a593Smuzhiyun 		break;
3561*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
3562*4882a593Smuzhiyun 		pllctrlreg_update = pmu1_xtaltab0_4362;
3563*4882a593Smuzhiyun 		array_size = ARRAYSIZE(pmu1_xtaltab0_4362);
3564*4882a593Smuzhiyun 		pllctrlreg_val = pmu1_pllctrl_tab_4362_960p1mhz;
3565*4882a593Smuzhiyun 		/* default pll programming be true, later based on need disable it */
3566*4882a593Smuzhiyun 		write_en = TRUE;
3567*4882a593Smuzhiyun 		break;
3568*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
3569*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
3570*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
3571*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
3572*4882a593Smuzhiyun 		/* TBD : bypass PLL programming, So use chip default values */
3573*4882a593Smuzhiyun 		pllctrlreg_update = NULL;
3574*4882a593Smuzhiyun 		array_size = 0;
3575*4882a593Smuzhiyun 		pllctrlreg_val = NULL;
3576*4882a593Smuzhiyun 		write_en = FALSE;
3577*4882a593Smuzhiyun 		break;
3578*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
3579*4882a593Smuzhiyun 		/* TBD : bypass PLL programming, So use chip default values */
3580*4882a593Smuzhiyun 		pllctrlreg_update = NULL;
3581*4882a593Smuzhiyun 		array_size = 0;
3582*4882a593Smuzhiyun 		pllctrlreg_val = NULL;
3583*4882a593Smuzhiyun 		write_en = FALSE;
3584*4882a593Smuzhiyun 		break;
3585*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
3586*4882a593Smuzhiyun 		pllctrlreg_update = pmu1_xtaltab0_4389;
3587*4882a593Smuzhiyun 		array_size = ARRAYSIZE(pmu1_xtaltab0_4389);
3588*4882a593Smuzhiyun 		pllctrlreg_val = pmu1_pllctrl_tab_4389_963mhz;
3589*4882a593Smuzhiyun 		break;
3590*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
3591*4882a593Smuzhiyun 		/*
3592*4882a593Smuzhiyun 		 * 43602 has only 1 x-tal value, possibly insert case when an other BBPLL
3593*4882a593Smuzhiyun 		 * frequency than 960Mhz is required (e.g., for spur avoidance)
3594*4882a593Smuzhiyun 		 */
3595*4882a593Smuzhiyun 		 /* fall through */
3596*4882a593Smuzhiyun 	default:
3597*4882a593Smuzhiyun 		/* write_en is FALSE in this case. So returns from the function */
3598*4882a593Smuzhiyun 		write_en = FALSE;
3599*4882a593Smuzhiyun 		break;
3600*4882a593Smuzhiyun 	}
3601*4882a593Smuzhiyun 
3602*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
3603*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
3604*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
3605*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
3606*4882a593Smuzhiyun 	} else {
3607*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
3608*4882a593Smuzhiyun 	}
3609*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
3610*4882a593Smuzhiyun 
3611*4882a593Smuzhiyun 	/* Check if the table has PLL control register values for the requested xtal */
3612*4882a593Smuzhiyun 	if (!update_required && pllctrlreg_update) {
3613*4882a593Smuzhiyun 		/* Here the chipcommon register base is passed as NULL, so that we just get
3614*4882a593Smuzhiyun 		 * the xf for the xtal being programmed but don't program the registers now
3615*4882a593Smuzhiyun 		 * as the PLL is not yet turned OFF.
3616*4882a593Smuzhiyun 		 */
3617*4882a593Smuzhiyun 		xf = si_pmu_pllctrlreg_update(sih, osh, NULL, xtal, 0, pllctrlreg_update,
3618*4882a593Smuzhiyun 			array_size, pllctrlreg_val);
3619*4882a593Smuzhiyun 
3620*4882a593Smuzhiyun 		/* Program the PLL based on the xtal value. */
3621*4882a593Smuzhiyun 		if (xf != 0) {
3622*4882a593Smuzhiyun 			/* Write XtalFreq. Set the divisor also. */
3623*4882a593Smuzhiyun 			tmp = R_REG(osh, &pmu->pmucontrol) &
3624*4882a593Smuzhiyun 				~(PCTL_ILP_DIV_MASK | PCTL_XTALFREQ_MASK);
3625*4882a593Smuzhiyun 			tmp |= (((((xtal + 127) / 128) - 1) << PCTL_ILP_DIV_SHIFT) &
3626*4882a593Smuzhiyun 				PCTL_ILP_DIV_MASK) |
3627*4882a593Smuzhiyun 				((xf << PCTL_XTALFREQ_SHIFT) & PCTL_XTALFREQ_MASK);
3628*4882a593Smuzhiyun 			W_REG(osh, &pmu->pmucontrol, tmp);
3629*4882a593Smuzhiyun 		} else {
3630*4882a593Smuzhiyun 			write_en = FALSE;
3631*4882a593Smuzhiyun 			if (!FWSIGN_ENAB()) {
3632*4882a593Smuzhiyun 				printf(rstr_Invalid_Unsupported_xtal_value_D, xtal);
3633*4882a593Smuzhiyun 			}
3634*4882a593Smuzhiyun 		}
3635*4882a593Smuzhiyun 
3636*4882a593Smuzhiyun 		write_en = si_pmu_armpll_write_required(sih, xtal);
3637*4882a593Smuzhiyun 	}
3638*4882a593Smuzhiyun 
3639*4882a593Smuzhiyun 	/* If its a check sequence or if there is nothing to write, return here */
3640*4882a593Smuzhiyun 	if ((update_required == FALSE) || (write_en == FALSE)) {
3641*4882a593Smuzhiyun 		goto exit;
3642*4882a593Smuzhiyun 	}
3643*4882a593Smuzhiyun 
3644*4882a593Smuzhiyun 	/* Update the PLL control register based on the xtal used. */
3645*4882a593Smuzhiyun 	if (pllctrlreg_val) {
3646*4882a593Smuzhiyun 		si_pmu_pllctrlreg_update(sih, osh, pmu, xtal, 0, pllctrlreg_update, array_size,
3647*4882a593Smuzhiyun 			pllctrlreg_val);
3648*4882a593Smuzhiyun 	}
3649*4882a593Smuzhiyun 
3650*4882a593Smuzhiyun 	/* Chip specific changes to PLL Control registers is done here. */
3651*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
3652*4882a593Smuzhiyun 	case BCM4388_CHIP_ID: {
3653*4882a593Smuzhiyun 		uint32 armclk_mhz = si_get_armpllclkfreq(sih);
3654*4882a593Smuzhiyun 		uint32 vco_freq = (armclk_mhz * PMU4388_APLL_PDIV * 1000);
3655*4882a593Smuzhiyun 
3656*4882a593Smuzhiyun 		ASSERT(vco_freq <= FVCO_3200);
3657*4882a593Smuzhiyun 
3658*4882a593Smuzhiyun 		/*
3659*4882a593Smuzhiyun 		 * ndiv_init = Fvco / Frefeff
3660*4882a593Smuzhiyun 		 * Frefeff = Fref / pdiv
3661*4882a593Smuzhiyun 		 * Fref = xtal / 2
3662*4882a593Smuzhiyun 		 * pdiv = 3
3663*4882a593Smuzhiyun 		 *
3664*4882a593Smuzhiyun 		 * ndiv_init = ((Fvco * pdiv * 1000000) / ((xtal * 1000) / 2)
3665*4882a593Smuzhiyun 		 */
3666*4882a593Smuzhiyun 		ndiv_int = (vco_freq / (xtal / 2));
3667*4882a593Smuzhiyun 		si_pmu_armpll_freq_upd(sih, 0, ndiv_int, 0);
3668*4882a593Smuzhiyun 		break;
3669*4882a593Smuzhiyun 	}
3670*4882a593Smuzhiyun 
3671*4882a593Smuzhiyun 	case BCM4389_CHIP_ID: {
3672*4882a593Smuzhiyun 		uint32 armclk_mhz = si_get_armpllclkfreq(sih);
3673*4882a593Smuzhiyun 		uint32 vco_freq = (armclk_mhz * PMU4389_APLL_PDIV * 1000);
3674*4882a593Smuzhiyun 
3675*4882a593Smuzhiyun 		ASSERT(vco_freq <= FVCO_3200);
3676*4882a593Smuzhiyun 
3677*4882a593Smuzhiyun 		/*
3678*4882a593Smuzhiyun 		 * ndiv_init = Fvco / Frefeff
3679*4882a593Smuzhiyun 		 * Frefeff = Fref / pdiv
3680*4882a593Smuzhiyun 		 * Fref = xtal / 2
3681*4882a593Smuzhiyun 		 * pdiv = 3
3682*4882a593Smuzhiyun 		 *
3683*4882a593Smuzhiyun 		 * ndiv_init = ((Fvco * pdiv * 1000000) / ((xtal * 1000) / 2)
3684*4882a593Smuzhiyun 		 */
3685*4882a593Smuzhiyun 		ndiv_int = (vco_freq / (xtal / 2));
3686*4882a593Smuzhiyun 		si_pmu_armpll_freq_upd(sih, 0, ndiv_int, 0);
3687*4882a593Smuzhiyun 		break;
3688*4882a593Smuzhiyun 	}
3689*4882a593Smuzhiyun 
3690*4882a593Smuzhiyun 	default:
3691*4882a593Smuzhiyun 		break;
3692*4882a593Smuzhiyun 	}
3693*4882a593Smuzhiyun 
3694*4882a593Smuzhiyun 	/* Program the PLL based on the xtal value. */
3695*4882a593Smuzhiyun 	if (xtal != 0) {
3696*4882a593Smuzhiyun 		/* Find the frequency in the table */
3697*4882a593Smuzhiyun 		for (xt = si_pmu1_xtaltab0(sih); xt != NULL && xt->fref != 0; xt ++)
3698*4882a593Smuzhiyun 			if (xt->fref == xtal) {
3699*4882a593Smuzhiyun 				break;
3700*4882a593Smuzhiyun 			}
3701*4882a593Smuzhiyun 
3702*4882a593Smuzhiyun 		/* Check current PLL state, bail out if it has been programmed or
3703*4882a593Smuzhiyun 		 * we don't know how to program it. But we might still have some programming
3704*4882a593Smuzhiyun 		 * like changing the ARM clock, etc. So cannot return from here.
3705*4882a593Smuzhiyun 		 */
3706*4882a593Smuzhiyun 		if (xt == NULL || xt->fref == 0) {
3707*4882a593Smuzhiyun 			goto exit;
3708*4882a593Smuzhiyun 		}
3709*4882a593Smuzhiyun 
3710*4882a593Smuzhiyun 		/* If the PLL is already programmed exit from here. */
3711*4882a593Smuzhiyun 		if (((R_REG(osh, &pmu->pmucontrol) &
3712*4882a593Smuzhiyun 			PCTL_XTALFREQ_MASK) >> PCTL_XTALFREQ_SHIFT) == xt->xf) {
3713*4882a593Smuzhiyun 			goto exit;
3714*4882a593Smuzhiyun 		}
3715*4882a593Smuzhiyun 
3716*4882a593Smuzhiyun 		PMU_MSG(("XTAL %d.%d MHz (%d)\n", xtal / 1000, xtal % 1000, xt->xf));
3717*4882a593Smuzhiyun 		PMU_MSG(("Programming PLL for %d.%d MHz\n", xt->fref / 1000, xt->fref % 1000));
3718*4882a593Smuzhiyun 
3719*4882a593Smuzhiyun 		if (BCM4389_CHIP(sih->chip)) {
3720*4882a593Smuzhiyun 			/* Write ndiv_int to pllcontrol[6] */
3721*4882a593Smuzhiyun 			tmp = ((xt->ndiv_int << PMU4389_ARMPLL_I_NDIV_INT_SHIFT)
3722*4882a593Smuzhiyun 				& PMU4389_ARMPLL_I_NDIV_INT_MASK);
3723*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6,
3724*4882a593Smuzhiyun 				(PMU4389_ARMPLL_I_NDIV_INT_MASK), tmp);
3725*4882a593Smuzhiyun 		} else if (BCM4388_CHIP(sih->chip)) {
3726*4882a593Smuzhiyun 			/* Write ndiv_int to pllcontrol[6] */
3727*4882a593Smuzhiyun 			tmp = ((xt->ndiv_int << PMU4388_ARMPLL_I_NDIV_INT_SHIFT)
3728*4882a593Smuzhiyun 				& PMU4388_ARMPLL_I_NDIV_INT_MASK);
3729*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG6,
3730*4882a593Smuzhiyun 				(PMU4388_ARMPLL_I_NDIV_INT_MASK), tmp);
3731*4882a593Smuzhiyun 		} else if (BCM4369_CHIP(sih->chip) ||
3732*4882a593Smuzhiyun 				BCM4362_CHIP(sih->chip) ||
3733*4882a593Smuzhiyun 				FALSE) {
3734*4882a593Smuzhiyun 			/* Write pdiv (Actually it is mapped to p1div in the struct)
3735*4882a593Smuzhiyun 			 to pllcontrol[2]
3736*4882a593Smuzhiyun 			 */
3737*4882a593Smuzhiyun 			tmp = ((xt->p1div << PMU4369_PLL0_PC2_PDIV_SHIFT) &
3738*4882a593Smuzhiyun 				PMU4369_PLL0_PC2_PDIV_MASK);
3739*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2,
3740*4882a593Smuzhiyun 				(PMU4369_PLL0_PC2_PDIV_MASK), tmp);
3741*4882a593Smuzhiyun 
3742*4882a593Smuzhiyun 			/* Write ndiv_int to pllcontrol[2] */
3743*4882a593Smuzhiyun 			tmp = ((xt->ndiv_int << PMU4369_PLL0_PC2_NDIV_INT_SHIFT)
3744*4882a593Smuzhiyun 					& PMU4369_PLL0_PC2_NDIV_INT_MASK);
3745*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2,
3746*4882a593Smuzhiyun 				(PMU4369_PLL0_PC2_NDIV_INT_MASK), tmp);
3747*4882a593Smuzhiyun 
3748*4882a593Smuzhiyun 			/* Write ndiv_frac to pllcontrol[3] */
3749*4882a593Smuzhiyun 			tmp = ((xt->ndiv_frac << PMU4369_PLL0_PC3_NDIV_FRAC_SHIFT) &
3750*4882a593Smuzhiyun 				PMU4369_PLL0_PC3_NDIV_FRAC_MASK);
3751*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG3,
3752*4882a593Smuzhiyun 				PMU4369_PLL0_PC3_NDIV_FRAC_MASK, tmp);
3753*4882a593Smuzhiyun 		} else {
3754*4882a593Smuzhiyun 			/* Write p1div and p2div to pllcontrol[0] */
3755*4882a593Smuzhiyun 			tmp = ((xt->p1div << PMU1_PLL0_PC0_P1DIV_SHIFT) &
3756*4882a593Smuzhiyun 				PMU1_PLL0_PC0_P1DIV_MASK) |
3757*4882a593Smuzhiyun 				((xt->p2div << PMU1_PLL0_PC0_P2DIV_SHIFT) &
3758*4882a593Smuzhiyun 				PMU1_PLL0_PC0_P2DIV_MASK);
3759*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG0,
3760*4882a593Smuzhiyun 				(PMU1_PLL0_PC0_P1DIV_MASK | PMU1_PLL0_PC0_P2DIV_MASK), tmp);
3761*4882a593Smuzhiyun 
3762*4882a593Smuzhiyun 			/* Write ndiv_int and ndiv_mode to pllcontrol[2] */
3763*4882a593Smuzhiyun 			tmp = ((xt->ndiv_int << PMU1_PLL0_PC2_NDIV_INT_SHIFT)
3764*4882a593Smuzhiyun 					& PMU1_PLL0_PC2_NDIV_INT_MASK) |
3765*4882a593Smuzhiyun 					((ndiv_mode << PMU1_PLL0_PC2_NDIV_MODE_SHIFT)
3766*4882a593Smuzhiyun 					& PMU1_PLL0_PC2_NDIV_MODE_MASK);
3767*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2,
3768*4882a593Smuzhiyun 				(PMU1_PLL0_PC2_NDIV_INT_MASK | PMU1_PLL0_PC2_NDIV_MODE_MASK), tmp);
3769*4882a593Smuzhiyun 			/* Write ndiv_frac to pllcontrol[3] */
3770*4882a593Smuzhiyun 			tmp = ((xt->ndiv_frac << PMU1_PLL0_PC3_NDIV_FRAC_SHIFT) &
3771*4882a593Smuzhiyun 				PMU1_PLL0_PC3_NDIV_FRAC_MASK);
3772*4882a593Smuzhiyun 			si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG3,
3773*4882a593Smuzhiyun 				PMU1_PLL0_PC3_NDIV_FRAC_MASK, tmp);
3774*4882a593Smuzhiyun 		}
3775*4882a593Smuzhiyun 
3776*4882a593Smuzhiyun 		/* Write XtalFreq. Set the divisor also. */
3777*4882a593Smuzhiyun 		tmp = R_REG(osh, &pmu->pmucontrol) &
3778*4882a593Smuzhiyun 			~(PCTL_ILP_DIV_MASK | PCTL_XTALFREQ_MASK);
3779*4882a593Smuzhiyun 		tmp |= (((((xt->fref + 127) / 128) - 1) << PCTL_ILP_DIV_SHIFT) &
3780*4882a593Smuzhiyun 			PCTL_ILP_DIV_MASK) |
3781*4882a593Smuzhiyun 			((xt->xf << PCTL_XTALFREQ_SHIFT) & PCTL_XTALFREQ_MASK);
3782*4882a593Smuzhiyun 		W_REG(osh, &pmu->pmucontrol, tmp);
3783*4882a593Smuzhiyun 	}
3784*4882a593Smuzhiyun 
3785*4882a593Smuzhiyun exit:
3786*4882a593Smuzhiyun 	/* Return to original core */
3787*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
3788*4882a593Smuzhiyun 
3789*4882a593Smuzhiyun 	return write_en;
3790*4882a593Smuzhiyun } /* si_pmu_update_pllcontrol */
3791*4882a593Smuzhiyun 
3792*4882a593Smuzhiyun /* returns current value of PMUTimer.
3793*4882a593Smuzhiyun 	also taking care of PR88659 by multiple reads.
3794*4882a593Smuzhiyun */
3795*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_get_pmutimer)3796*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_get_pmutimer)(si_t *sih)
3797*4882a593Smuzhiyun {
3798*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
3799*4882a593Smuzhiyun 	pmuregs_t *pmu;
3800*4882a593Smuzhiyun 	uint origidx;
3801*4882a593Smuzhiyun 	uint32 start;
3802*4882a593Smuzhiyun 	BCM_REFERENCE(sih);
3803*4882a593Smuzhiyun 
3804*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
3805*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
3806*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
3807*4882a593Smuzhiyun 	} else {
3808*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
3809*4882a593Smuzhiyun 	}
3810*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
3811*4882a593Smuzhiyun 
3812*4882a593Smuzhiyun 	start = R_REG(osh, &pmu->pmutimer);
3813*4882a593Smuzhiyun 	if (start != R_REG(osh, &pmu->pmutimer))
3814*4882a593Smuzhiyun 		start = R_REG(osh, &pmu->pmutimer);
3815*4882a593Smuzhiyun 
3816*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
3817*4882a593Smuzhiyun 
3818*4882a593Smuzhiyun 	return (start);
3819*4882a593Smuzhiyun }
3820*4882a593Smuzhiyun 
3821*4882a593Smuzhiyun /* Get current pmu time API */
3822*4882a593Smuzhiyun uint32
si_cur_pmu_time(si_t * sih)3823*4882a593Smuzhiyun si_cur_pmu_time(si_t *sih)
3824*4882a593Smuzhiyun {
3825*4882a593Smuzhiyun 	uint origidx;
3826*4882a593Smuzhiyun 	uint32 pmu_time;
3827*4882a593Smuzhiyun 
3828*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
3829*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
3830*4882a593Smuzhiyun 
3831*4882a593Smuzhiyun 	pmu_time = si_pmu_get_pmutimer(sih);
3832*4882a593Smuzhiyun 
3833*4882a593Smuzhiyun 	/* Return to original core */
3834*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
3835*4882a593Smuzhiyun 	return (pmu_time);
3836*4882a593Smuzhiyun }
3837*4882a593Smuzhiyun 
3838*4882a593Smuzhiyun /**
3839*4882a593Smuzhiyun  * returns
3840*4882a593Smuzhiyun  * a) diff between a 'prev' value of pmu timer and current value
3841*4882a593Smuzhiyun  * b) the current pmutime value in 'prev'
3842*4882a593Smuzhiyun  *  So, 'prev' is an IO parameter.
3843*4882a593Smuzhiyun  */
3844*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_get_pmutime_diff)3845*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_get_pmutime_diff)(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 *prev)
3846*4882a593Smuzhiyun {
3847*4882a593Smuzhiyun 	uint32 pmutime_diff = 0, pmutime_val = 0;
3848*4882a593Smuzhiyun 	uint32 prev_val = *prev;
3849*4882a593Smuzhiyun 	BCM_REFERENCE(osh);
3850*4882a593Smuzhiyun 	BCM_REFERENCE(pmu);
3851*4882a593Smuzhiyun 	/* read current value */
3852*4882a593Smuzhiyun 	pmutime_val = si_pmu_get_pmutimer(sih);
3853*4882a593Smuzhiyun 	/* diff btween prev and current value, take on wraparound case as well. */
3854*4882a593Smuzhiyun 	pmutime_diff = (pmutime_val >= prev_val) ?
3855*4882a593Smuzhiyun 		(pmutime_val - prev_val) :
3856*4882a593Smuzhiyun 		(~prev_val + pmutime_val + 1);
3857*4882a593Smuzhiyun 	*prev = pmutime_val;
3858*4882a593Smuzhiyun 	return pmutime_diff;
3859*4882a593Smuzhiyun }
3860*4882a593Smuzhiyun 
3861*4882a593Smuzhiyun /**
3862*4882a593Smuzhiyun  * wait for usec for the res_pending register to change.
3863*4882a593Smuzhiyun  * NOTE: usec SHOULD be > 32uS
3864*4882a593Smuzhiyun  * if cond = TRUE, res_pending will be read until it becomes == 0;
3865*4882a593Smuzhiyun  * If cond = FALSE, res_pending will be read until it becomes != 0;
3866*4882a593Smuzhiyun  * returns TRUE if timedout.
3867*4882a593Smuzhiyun  * returns elapsed time in this loop in elapsed_time
3868*4882a593Smuzhiyun  */
3869*4882a593Smuzhiyun bool
BCMPOSTTRAPFN(si_pmu_wait_for_res_pending)3870*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_wait_for_res_pending)(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint usec,
3871*4882a593Smuzhiyun 	bool cond, uint32 *elapsed_time)
3872*4882a593Smuzhiyun {
3873*4882a593Smuzhiyun 	/* add 32uSec more */
3874*4882a593Smuzhiyun 	uint countdown = usec;
3875*4882a593Smuzhiyun 	uint32 pmutime_prev = 0, pmutime_elapsed = 0, res_pend;
3876*4882a593Smuzhiyun 	bool pending = FALSE;
3877*4882a593Smuzhiyun 
3878*4882a593Smuzhiyun 	/* store current time */
3879*4882a593Smuzhiyun 	pmutime_prev = si_pmu_get_pmutimer(sih);
3880*4882a593Smuzhiyun 	while (1) {
3881*4882a593Smuzhiyun 		res_pend = R_REG(osh, &pmu->res_pending);
3882*4882a593Smuzhiyun 
3883*4882a593Smuzhiyun 		/* based on the condition, check */
3884*4882a593Smuzhiyun 		if (cond == TRUE) {
3885*4882a593Smuzhiyun 			if (res_pend == 0) break;
3886*4882a593Smuzhiyun 		} else {
3887*4882a593Smuzhiyun 			if (res_pend != 0) break;
3888*4882a593Smuzhiyun 		}
3889*4882a593Smuzhiyun 
3890*4882a593Smuzhiyun 		/* if required time over */
3891*4882a593Smuzhiyun 		if ((pmutime_elapsed * PMU_US_STEPS) >= countdown) {
3892*4882a593Smuzhiyun 			/* timeout. so return as still pending */
3893*4882a593Smuzhiyun 			pending = TRUE;
3894*4882a593Smuzhiyun 			break;
3895*4882a593Smuzhiyun 		}
3896*4882a593Smuzhiyun 
3897*4882a593Smuzhiyun 		/* get elapsed time after adding diff between prev and current
3898*4882a593Smuzhiyun 		* pmutimer value
3899*4882a593Smuzhiyun 		*/
3900*4882a593Smuzhiyun 		pmutime_elapsed += si_pmu_get_pmutime_diff(sih, osh, pmu, &pmutime_prev);
3901*4882a593Smuzhiyun 	}
3902*4882a593Smuzhiyun 
3903*4882a593Smuzhiyun 	*elapsed_time = pmutime_elapsed * PMU_US_STEPS;
3904*4882a593Smuzhiyun 	return pending;
3905*4882a593Smuzhiyun } /* si_pmu_wait_for_res_pending */
3906*4882a593Smuzhiyun 
3907*4882a593Smuzhiyun /**
3908*4882a593Smuzhiyun  *	The algorithm for pending check is that,
3909*4882a593Smuzhiyun  *	step1: 	wait till (res_pending !=0) OR pmu_max_trans_timeout.
3910*4882a593Smuzhiyun  *			if max_trans_timeout, flag error and exit.
3911*4882a593Smuzhiyun  *			wait for 1 ILP clk [64uS] based on pmu timer,
3912*4882a593Smuzhiyun  *			polling to see if res_pending again goes high.
3913*4882a593Smuzhiyun  *			if res_pending again goes high, go back to step1.
3914*4882a593Smuzhiyun  *	Note: res_pending is checked repeatedly because, in between switching
3915*4882a593Smuzhiyun  *	of dependent
3916*4882a593Smuzhiyun  *	resources, res_pending resets to 0 for a short duration of time before
3917*4882a593Smuzhiyun  *	it becomes 1 again.
3918*4882a593Smuzhiyun  *	Note: return 0 is GOOD, 1 is BAD [mainly timeout].
3919*4882a593Smuzhiyun  */
3920*4882a593Smuzhiyun int
BCMPOSTTRAPFN(si_pmu_wait_for_steady_state)3921*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_wait_for_steady_state)(si_t *sih, osl_t *osh, pmuregs_t *pmu)
3922*4882a593Smuzhiyun {
3923*4882a593Smuzhiyun 	si_info_t *sii = SI_INFO(sih);
3924*4882a593Smuzhiyun 	int stat = 0;
3925*4882a593Smuzhiyun 	bool timedout = FALSE;
3926*4882a593Smuzhiyun 	uint32 elapsed = 0, pmutime_total_elapsed = 0;
3927*4882a593Smuzhiyun 	uint32 pmutime_prev;
3928*4882a593Smuzhiyun 
3929*4882a593Smuzhiyun 	sii->res_pend_count = 0;
3930*4882a593Smuzhiyun 
3931*4882a593Smuzhiyun 	pmutime_prev = si_pmu_get_pmutimer(sih);
3932*4882a593Smuzhiyun 
3933*4882a593Smuzhiyun 	while (1) {
3934*4882a593Smuzhiyun 		/* wait until all resources are settled down [till res_pending becomes 0] */
3935*4882a593Smuzhiyun 		timedout = si_pmu_wait_for_res_pending(sih, osh, pmu,
3936*4882a593Smuzhiyun 			PMU_MAX_TRANSITION_DLY, TRUE, &elapsed);
3937*4882a593Smuzhiyun 
3938*4882a593Smuzhiyun 		sii->res_state[sii->res_pend_count].low_time =
3939*4882a593Smuzhiyun 			si_pmu_get_pmutime_diff(sih, osh, pmu, &pmutime_prev);
3940*4882a593Smuzhiyun 		sii->res_state[sii->res_pend_count].low = R_REG(osh, &pmu->res_pending);
3941*4882a593Smuzhiyun 
3942*4882a593Smuzhiyun 		if (timedout) {
3943*4882a593Smuzhiyun 			stat = 1;
3944*4882a593Smuzhiyun 			break;
3945*4882a593Smuzhiyun 		}
3946*4882a593Smuzhiyun 
3947*4882a593Smuzhiyun 		pmutime_total_elapsed += elapsed;
3948*4882a593Smuzhiyun 		/* wait to check if any resource comes back to non-zero indicating
3949*4882a593Smuzhiyun 		* that it pends again. The res_pending goes 0 for 1 ILP clock before
3950*4882a593Smuzhiyun 		* getting set for next resource in the sequence , so if res_pending
3951*4882a593Smuzhiyun 		* is 0 for more than 1 ILP clk it means nothing is pending
3952*4882a593Smuzhiyun 		* to indicate some pending dependency.
3953*4882a593Smuzhiyun 		*/
3954*4882a593Smuzhiyun 		pmutime_prev = R_REG(osh, &pmu->pmutimer);
3955*4882a593Smuzhiyun 		timedout = si_pmu_wait_for_res_pending(sih, osh, pmu,
3956*4882a593Smuzhiyun 			64, FALSE, &elapsed);
3957*4882a593Smuzhiyun 
3958*4882a593Smuzhiyun 		pmutime_total_elapsed += elapsed;
3959*4882a593Smuzhiyun 
3960*4882a593Smuzhiyun 		sii->res_state[sii->res_pend_count].high_time =
3961*4882a593Smuzhiyun 			si_pmu_get_pmutime_diff(sih, osh, pmu, &pmutime_prev);
3962*4882a593Smuzhiyun 		sii->res_state[sii->res_pend_count].high = R_REG(osh, &pmu->res_pending);
3963*4882a593Smuzhiyun 
3964*4882a593Smuzhiyun 		/* Here, we can also check timedout, but we make sure that,
3965*4882a593Smuzhiyun 		* we read the res_pending again.
3966*4882a593Smuzhiyun 		*/
3967*4882a593Smuzhiyun 
3968*4882a593Smuzhiyun 		if (timedout) {
3969*4882a593Smuzhiyun 			stat = 0;
3970*4882a593Smuzhiyun 			break;
3971*4882a593Smuzhiyun 		}
3972*4882a593Smuzhiyun 
3973*4882a593Smuzhiyun 		/* Total wait time for all the waits above added should be
3974*4882a593Smuzhiyun 		* less than  PMU_MAX_TRANSITION_DLY
3975*4882a593Smuzhiyun 		*/
3976*4882a593Smuzhiyun 		if (pmutime_total_elapsed >= PMU_MAX_TRANSITION_DLY) {
3977*4882a593Smuzhiyun 			/* timeout. so return as still pending */
3978*4882a593Smuzhiyun 			stat = 1;
3979*4882a593Smuzhiyun 			break;
3980*4882a593Smuzhiyun 		}
3981*4882a593Smuzhiyun 
3982*4882a593Smuzhiyun 		sii->res_pend_count++;
3983*4882a593Smuzhiyun 		sii->res_pend_count %= RES_PEND_STATS_COUNT;
3984*4882a593Smuzhiyun 		pmutime_prev = R_REG(osh, &pmu->pmutimer);
3985*4882a593Smuzhiyun 	}
3986*4882a593Smuzhiyun 	return stat;
3987*4882a593Smuzhiyun } /* si_pmu_wait_for_steady_state */
3988*4882a593Smuzhiyun 
3989*4882a593Smuzhiyun static uint32
si_pmu_pll_delay_43012(si_t * sih,uint32 delay_us,uint32 poll)3990*4882a593Smuzhiyun si_pmu_pll_delay_43012(si_t *sih, uint32 delay_us, uint32 poll)
3991*4882a593Smuzhiyun {
3992*4882a593Smuzhiyun 	uint32 delay = 0;
3993*4882a593Smuzhiyun 
3994*4882a593Smuzhiyun 	/* In case of NIC builds, we can use OSL_DELAY() for 1 us delay. But in case of DONGLE
3995*4882a593Smuzhiyun 	 * builds, we can't rely on the OSL_DELAY() as it is internally relying on HT clock and
3996*4882a593Smuzhiyun 	 * we are calling this function when ALP clock is present.
3997*4882a593Smuzhiyun 	 */
3998*4882a593Smuzhiyun #if defined(DONGLEBUILD)
3999*4882a593Smuzhiyun 	uint32 initial, current;
4000*4882a593Smuzhiyun 
4001*4882a593Smuzhiyun 	initial = get_arm_cyclecount();
4002*4882a593Smuzhiyun 	while (delay < delay_us) {
4003*4882a593Smuzhiyun 		if (poll == 1) {
4004*4882a593Smuzhiyun 			if (si_gci_chipstatus(sih, GCI_CHIPSTATUS_07) &
4005*4882a593Smuzhiyun 					GCI43012_CHIPSTATUS_07_BBPLL_LOCK_MASK) {
4006*4882a593Smuzhiyun 				goto exit;
4007*4882a593Smuzhiyun 			}
4008*4882a593Smuzhiyun 		}
4009*4882a593Smuzhiyun 		current = get_arm_cyclecount();
4010*4882a593Smuzhiyun 		delay = ((current - initial) * 1000) / si_xtalfreq(sih);
4011*4882a593Smuzhiyun 	}
4012*4882a593Smuzhiyun #else
4013*4882a593Smuzhiyun 	for (delay = 0; delay < delay_us; delay++) {
4014*4882a593Smuzhiyun 		if (poll == 1) {
4015*4882a593Smuzhiyun 			if (si_gci_chipstatus(sih, GCI_CHIPSTATUS_07) &
4016*4882a593Smuzhiyun 					GCI43012_CHIPSTATUS_07_BBPLL_LOCK_MASK) {
4017*4882a593Smuzhiyun 				goto exit;
4018*4882a593Smuzhiyun 			}
4019*4882a593Smuzhiyun 		}
4020*4882a593Smuzhiyun 		OSL_DELAY(1);
4021*4882a593Smuzhiyun 	}
4022*4882a593Smuzhiyun #endif /* BCMDONGLEHOST */
4023*4882a593Smuzhiyun 
4024*4882a593Smuzhiyun 	if (poll == 1) {
4025*4882a593Smuzhiyun 		PMU_ERROR(("si_pmu_pll_delay_43012: PLL not locked!"));
4026*4882a593Smuzhiyun 		ASSERT(0);
4027*4882a593Smuzhiyun 	}
4028*4882a593Smuzhiyun exit:
4029*4882a593Smuzhiyun 	return delay;
4030*4882a593Smuzhiyun }
4031*4882a593Smuzhiyun 
4032*4882a593Smuzhiyun static void
si_pmu_pll_on_43012(si_t * sih,osl_t * osh,pmuregs_t * pmu,bool openloop_cal)4033*4882a593Smuzhiyun si_pmu_pll_on_43012(si_t *sih, osl_t *osh, pmuregs_t *pmu, bool openloop_cal)
4034*4882a593Smuzhiyun {
4035*4882a593Smuzhiyun 	uint32 rsrc_ht, total_time = 0;
4036*4882a593Smuzhiyun 
4037*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4, PMUCCTL04_43012_FORCE_BBPLL_PWROFF, 0);
4038*4882a593Smuzhiyun 	total_time += si_pmu_pll_delay_43012(sih, 2, 0);
4039*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4, PMUCCTL04_43012_FORCE_BBPLL_ISOONHIGH |
4040*4882a593Smuzhiyun 			PMUCCTL04_43012_FORCE_BBPLL_PWRDN, 0);
4041*4882a593Smuzhiyun 	total_time += si_pmu_pll_delay_43012(sih, 2, 0);
4042*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4, PMUCCTL04_43012_FORCE_BBPLL_ARESET, 0);
4043*4882a593Smuzhiyun 
4044*4882a593Smuzhiyun 	rsrc_ht = R_REG(osh, &pmu->res_state) &
4045*4882a593Smuzhiyun 			((1 << RES43012_HT_AVAIL) | (1 << RES43012_HT_START));
4046*4882a593Smuzhiyun 
4047*4882a593Smuzhiyun 	if (rsrc_ht)
4048*4882a593Smuzhiyun 	{
4049*4882a593Smuzhiyun 		/* Wait for PLL to lock in close-loop */
4050*4882a593Smuzhiyun 		total_time += si_pmu_pll_delay_43012(sih, 200, 1);
4051*4882a593Smuzhiyun 	}
4052*4882a593Smuzhiyun 	else {
4053*4882a593Smuzhiyun 		/* Wait for 1 us for the open-loop clock to start */
4054*4882a593Smuzhiyun 		total_time += si_pmu_pll_delay_43012(sih, 1, 0);
4055*4882a593Smuzhiyun 	}
4056*4882a593Smuzhiyun 
4057*4882a593Smuzhiyun 	if (!openloop_cal) {
4058*4882a593Smuzhiyun 		/* Allow clk to be used if its not calibration */
4059*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL4, PMUCCTL04_43012_FORCE_BBPLL_DRESET, 0);
4060*4882a593Smuzhiyun 		total_time += si_pmu_pll_delay_43012(sih, 1, 0);
4061*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL4, PMUCCTL04_43012_DISABLE_LQ_AVAIL, 0);
4062*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL4, PMUCCTL04_43012_DISABLE_HT_AVAIL, 0);
4063*4882a593Smuzhiyun 	}
4064*4882a593Smuzhiyun 
4065*4882a593Smuzhiyun 	PMU_MSG(("si_pmu_pll_on_43012: time taken: %d us\n", total_time));
4066*4882a593Smuzhiyun }
4067*4882a593Smuzhiyun 
4068*4882a593Smuzhiyun static void
si_pmu_pll_off_43012(si_t * sih,osl_t * osh,pmuregs_t * pmu)4069*4882a593Smuzhiyun si_pmu_pll_off_43012(si_t *sih, osl_t *osh, pmuregs_t *pmu)
4070*4882a593Smuzhiyun {
4071*4882a593Smuzhiyun 	uint32 total_time = 0;
4072*4882a593Smuzhiyun 	BCM_REFERENCE(osh);
4073*4882a593Smuzhiyun 	BCM_REFERENCE(pmu);
4074*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
4075*4882a593Smuzhiyun 			PMUCCTL04_43012_DISABLE_LQ_AVAIL | PMUCCTL04_43012_DISABLE_HT_AVAIL,
4076*4882a593Smuzhiyun 			PMUCCTL04_43012_DISABLE_LQ_AVAIL | PMUCCTL04_43012_DISABLE_HT_AVAIL);
4077*4882a593Smuzhiyun 	total_time += si_pmu_pll_delay_43012(sih, 1, 0);
4078*4882a593Smuzhiyun 
4079*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
4080*4882a593Smuzhiyun 			(PMUCCTL04_43012_FORCE_BBPLL_ARESET | PMUCCTL04_43012_FORCE_BBPLL_DRESET |
4081*4882a593Smuzhiyun 			PMUCCTL04_43012_FORCE_BBPLL_PWRDN |PMUCCTL04_43012_FORCE_BBPLL_ISOONHIGH),
4082*4882a593Smuzhiyun 			(PMUCCTL04_43012_FORCE_BBPLL_ARESET | PMUCCTL04_43012_FORCE_BBPLL_DRESET |
4083*4882a593Smuzhiyun 			PMUCCTL04_43012_FORCE_BBPLL_PWRDN |PMUCCTL04_43012_FORCE_BBPLL_ISOONHIGH));
4084*4882a593Smuzhiyun 	total_time += si_pmu_pll_delay_43012(sih, 1, 0);
4085*4882a593Smuzhiyun 
4086*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
4087*4882a593Smuzhiyun 			PMUCCTL04_43012_FORCE_BBPLL_PWROFF,
4088*4882a593Smuzhiyun 			PMUCCTL04_43012_FORCE_BBPLL_PWROFF);
4089*4882a593Smuzhiyun 
4090*4882a593Smuzhiyun 	PMU_MSG(("si_pmu_pll_off_43012: time taken: %d us\n", total_time));
4091*4882a593Smuzhiyun }
4092*4882a593Smuzhiyun 
4093*4882a593Smuzhiyun /** Turn Off the PLL - Required before setting the PLL registers */
4094*4882a593Smuzhiyun static void
si_pmu_pll_off(si_t * sih,osl_t * osh,pmuregs_t * pmu,uint32 * min_mask,uint32 * max_mask,uint32 * clk_ctl_st)4095*4882a593Smuzhiyun si_pmu_pll_off(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 *min_mask,
4096*4882a593Smuzhiyun 	uint32 *max_mask, uint32 *clk_ctl_st)
4097*4882a593Smuzhiyun {
4098*4882a593Smuzhiyun 	uint32 ht_req;
4099*4882a593Smuzhiyun 
4100*4882a593Smuzhiyun 	/* Save the original register values */
4101*4882a593Smuzhiyun 	*min_mask = R_REG(osh, &pmu->min_res_mask);
4102*4882a593Smuzhiyun 	*max_mask = R_REG(osh, &pmu->max_res_mask);
4103*4882a593Smuzhiyun 	*clk_ctl_st = si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0);
4104*4882a593Smuzhiyun 
4105*4882a593Smuzhiyun 	ht_req = si_pmu_htclk_mask(sih);
4106*4882a593Smuzhiyun 	if (ht_req == 0)
4107*4882a593Smuzhiyun 		return;
4108*4882a593Smuzhiyun 
4109*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
4110*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
4111*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID) ||
4112*4882a593Smuzhiyun 		(BCM4369_CHIP(sih->chip)) ||
4113*4882a593Smuzhiyun 		(BCM4362_CHIP(sih->chip)) ||
4114*4882a593Smuzhiyun 		(BCM4376_CHIP(sih->chip)) ||
4115*4882a593Smuzhiyun 		(BCM4378_CHIP(sih->chip)) ||
4116*4882a593Smuzhiyun 		(BCM4385_CHIP(sih->chip)) ||
4117*4882a593Smuzhiyun 		(BCM4387_CHIP(sih->chip)) ||
4118*4882a593Smuzhiyun 		(BCM4388_CHIP(sih->chip)) ||
4119*4882a593Smuzhiyun 		(BCM4389_CHIP(sih->chip)) ||
4120*4882a593Smuzhiyun 		BCM43602_CHIP(sih->chip) ||
4121*4882a593Smuzhiyun 		0) {
4122*4882a593Smuzhiyun 		/*
4123*4882a593Smuzhiyun 		* If HT_AVAIL is not set, wait to see if any resources are availing HT.
4124*4882a593Smuzhiyun 		*/
4125*4882a593Smuzhiyun 		if (((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4126*4882a593Smuzhiyun 			& CCS_HTAVAIL) != CCS_HTAVAIL))
4127*4882a593Smuzhiyun 			si_pmu_wait_for_steady_state(sih, osh, pmu);
4128*4882a593Smuzhiyun 	} else {
4129*4882a593Smuzhiyun 		OR_REG(osh,  &pmu->max_res_mask, ht_req);
4130*4882a593Smuzhiyun 		/* wait for HT to be ready before taking the HT away...HT could be coming up... */
4131*4882a593Smuzhiyun 		SPINWAIT(((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4132*4882a593Smuzhiyun 			& CCS_HTAVAIL) != CCS_HTAVAIL), PMU_MAX_TRANSITION_DLY);
4133*4882a593Smuzhiyun 		ASSERT((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4134*4882a593Smuzhiyun 			& CCS_HTAVAIL));
4135*4882a593Smuzhiyun 	}
4136*4882a593Smuzhiyun 
4137*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
4138*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
4139*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID)) {
4140*4882a593Smuzhiyun 		si_pmu_pll_off_43012(sih, osh, pmu);
4141*4882a593Smuzhiyun 	} else {
4142*4882a593Smuzhiyun 		AND_REG(osh, &pmu->min_res_mask, ~ht_req);
4143*4882a593Smuzhiyun 		AND_REG(osh, &pmu->max_res_mask, ~ht_req);
4144*4882a593Smuzhiyun 
4145*4882a593Smuzhiyun 		SPINWAIT(((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4146*4882a593Smuzhiyun 			& CCS_HTAVAIL) == CCS_HTAVAIL), PMU_MAX_TRANSITION_DLY);
4147*4882a593Smuzhiyun 		ASSERT(!(si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4148*4882a593Smuzhiyun 			& CCS_HTAVAIL));
4149*4882a593Smuzhiyun 		OSL_DELAY(100);
4150*4882a593Smuzhiyun 	}
4151*4882a593Smuzhiyun } /* si_pmu_pll_off */
4152*4882a593Smuzhiyun 
4153*4882a593Smuzhiyun /* below function are for BBPLL parallel purpose */
4154*4882a593Smuzhiyun /** Turn Off the PLL - Required before setting the PLL registers */
4155*4882a593Smuzhiyun void
si_pmu_pll_off_PARR(si_t * sih,osl_t * osh,uint32 * min_mask,uint32 * max_mask,uint32 * clk_ctl_st)4156*4882a593Smuzhiyun si_pmu_pll_off_PARR(si_t *sih, osl_t *osh, uint32 *min_mask,
4157*4882a593Smuzhiyun uint32 *max_mask, uint32 *clk_ctl_st)
4158*4882a593Smuzhiyun {
4159*4882a593Smuzhiyun 	pmuregs_t *pmu;
4160*4882a593Smuzhiyun 	uint origidx;
4161*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
4162*4882a593Smuzhiyun 	uint32 ht_req;
4163*4882a593Smuzhiyun 
4164*4882a593Smuzhiyun 	/* Block ints and save current core */
4165*4882a593Smuzhiyun 	si_introff(sih, &intr_val);
4166*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
4167*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
4168*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
4169*4882a593Smuzhiyun 	} else {
4170*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
4171*4882a593Smuzhiyun 	}
4172*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
4173*4882a593Smuzhiyun 
4174*4882a593Smuzhiyun 	/* Save the original register values */
4175*4882a593Smuzhiyun 	*min_mask = R_REG(osh, &pmu->min_res_mask);
4176*4882a593Smuzhiyun 	*max_mask = R_REG(osh, &pmu->max_res_mask);
4177*4882a593Smuzhiyun 	*clk_ctl_st = si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0);
4178*4882a593Smuzhiyun 	ht_req = si_pmu_htclk_mask(sih);
4179*4882a593Smuzhiyun 	if (ht_req == 0) {
4180*4882a593Smuzhiyun 		/* Return to original core */
4181*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
4182*4882a593Smuzhiyun 		si_intrrestore(sih, &intr_val);
4183*4882a593Smuzhiyun 		return;
4184*4882a593Smuzhiyun 	}
4185*4882a593Smuzhiyun 
4186*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
4187*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
4188*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID) ||
4189*4882a593Smuzhiyun 		(BCM4369_CHIP(sih->chip)) ||
4190*4882a593Smuzhiyun 		(BCM4362_CHIP(sih->chip)) ||
4191*4882a593Smuzhiyun 		(BCM4376_CHIP(sih->chip)) ||
4192*4882a593Smuzhiyun 		(BCM4378_CHIP(sih->chip)) ||
4193*4882a593Smuzhiyun 		(BCM4385_CHIP(sih->chip)) ||
4194*4882a593Smuzhiyun 		(BCM4387_CHIP(sih->chip)) ||
4195*4882a593Smuzhiyun 		(BCM4388_CHIP(sih->chip)) ||
4196*4882a593Smuzhiyun 		(BCM4389_CHIP(sih->chip)) ||
4197*4882a593Smuzhiyun 		(BCM4397_CHIP(sih->chip)) ||
4198*4882a593Smuzhiyun 		(BCM43602_CHIP(sih->chip)) ||
4199*4882a593Smuzhiyun 		0) {
4200*4882a593Smuzhiyun 		/*
4201*4882a593Smuzhiyun 		* If HT_AVAIL is not set, wait to see if any resources are availing HT.
4202*4882a593Smuzhiyun 		*/
4203*4882a593Smuzhiyun 		if (((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4204*4882a593Smuzhiyun 			& CCS_HTAVAIL)
4205*4882a593Smuzhiyun 			!= CCS_HTAVAIL))
4206*4882a593Smuzhiyun 			si_pmu_wait_for_steady_state(sih, osh, pmu);
4207*4882a593Smuzhiyun 	} else {
4208*4882a593Smuzhiyun 		OR_REG(osh, &pmu->max_res_mask, ht_req);
4209*4882a593Smuzhiyun 		/* wait for HT to be ready before taking the HT away...HT could be coming up... */
4210*4882a593Smuzhiyun 		SPINWAIT(((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4211*4882a593Smuzhiyun 			& CCS_HTAVAIL) != CCS_HTAVAIL), PMU_MAX_TRANSITION_DLY);
4212*4882a593Smuzhiyun 		ASSERT((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4213*4882a593Smuzhiyun 			& CCS_HTAVAIL));
4214*4882a593Smuzhiyun 	}
4215*4882a593Smuzhiyun 
4216*4882a593Smuzhiyun 	AND_REG(osh, &pmu->min_res_mask, ~ht_req);
4217*4882a593Smuzhiyun 	AND_REG(osh, &pmu->max_res_mask, ~ht_req);
4218*4882a593Smuzhiyun 
4219*4882a593Smuzhiyun 	/* Return to original core */
4220*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
4221*4882a593Smuzhiyun 	si_intrrestore(sih, &intr_val);
4222*4882a593Smuzhiyun } /* si_pmu_pll_off_PARR */
4223*4882a593Smuzhiyun 
4224*4882a593Smuzhiyun /** Turn ON/restore the PLL based on the mask received */
4225*4882a593Smuzhiyun static void
si_pmu_pll_on(si_t * sih,osl_t * osh,pmuregs_t * pmu,uint32 min_mask_mask,uint32 max_mask_mask,uint32 clk_ctl_st_mask)4226*4882a593Smuzhiyun si_pmu_pll_on(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 min_mask_mask,
4227*4882a593Smuzhiyun 	uint32 max_mask_mask, uint32 clk_ctl_st_mask)
4228*4882a593Smuzhiyun {
4229*4882a593Smuzhiyun 	uint32 ht_req;
4230*4882a593Smuzhiyun 
4231*4882a593Smuzhiyun 	ht_req = si_pmu_htclk_mask(sih);
4232*4882a593Smuzhiyun 	if (ht_req == 0)
4233*4882a593Smuzhiyun 		return;
4234*4882a593Smuzhiyun 
4235*4882a593Smuzhiyun 	max_mask_mask &= ht_req;
4236*4882a593Smuzhiyun 	min_mask_mask &= ht_req;
4237*4882a593Smuzhiyun 
4238*4882a593Smuzhiyun 	if (max_mask_mask != 0)
4239*4882a593Smuzhiyun 		OR_REG(osh, &pmu->max_res_mask, max_mask_mask);
4240*4882a593Smuzhiyun 
4241*4882a593Smuzhiyun 	if (min_mask_mask != 0)
4242*4882a593Smuzhiyun 		OR_REG(osh, &pmu->min_res_mask, min_mask_mask);
4243*4882a593Smuzhiyun 
4244*4882a593Smuzhiyun 	if (clk_ctl_st_mask & CCS_HTAVAIL) {
4245*4882a593Smuzhiyun 		/* Wait for HT_AVAIL to come back */
4246*4882a593Smuzhiyun 		SPINWAIT(((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4247*4882a593Smuzhiyun 			& CCS_HTAVAIL) != CCS_HTAVAIL), PMU_MAX_TRANSITION_DLY);
4248*4882a593Smuzhiyun 		ASSERT((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4249*4882a593Smuzhiyun 		& CCS_HTAVAIL));
4250*4882a593Smuzhiyun 	}
4251*4882a593Smuzhiyun 
4252*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
4253*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
4254*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID)) {
4255*4882a593Smuzhiyun 		si_pmu_pll_on_43012(sih, osh, pmu, 0);
4256*4882a593Smuzhiyun 	}
4257*4882a593Smuzhiyun }
4258*4882a593Smuzhiyun 
4259*4882a593Smuzhiyun /**
4260*4882a593Smuzhiyun  * Set up PLL registers in the PMU as per the (optional) OTP values, or, if no OTP values are
4261*4882a593Smuzhiyun  * present, optionally update with POR override values contained in firmware. Enables the BBPLL
4262*4882a593Smuzhiyun  * when done.
4263*4882a593Smuzhiyun  */
4264*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu1_pllinit1)4265*4882a593Smuzhiyun BCMATTACHFN(si_pmu1_pllinit1)(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 xtal)
4266*4882a593Smuzhiyun {
4267*4882a593Smuzhiyun 	char name[16];
4268*4882a593Smuzhiyun 	const char *otp_val;
4269*4882a593Smuzhiyun 	uint8 i, otp_entry_found = FALSE;
4270*4882a593Smuzhiyun 	uint32 pll_ctrlcnt;
4271*4882a593Smuzhiyun 	uint32 min_mask = 0, max_mask = 0, clk_ctl_st = 0;
4272*4882a593Smuzhiyun #if defined(BTOVERPCIE) && !defined(BTOVERPCIE_DISABLED)
4273*4882a593Smuzhiyun 	uint32 otpval = 0, regval = 0;
4274*4882a593Smuzhiyun #endif /* defined(BTOVERPCIE) && !defined(BTOVERPCIE_DISABLED) */
4275*4882a593Smuzhiyun 
4276*4882a593Smuzhiyun 	if (!FWSIGN_ENAB()) {
4277*4882a593Smuzhiyun 		if (PMUREV(sih->pmurev) >= 5) {
4278*4882a593Smuzhiyun 			pll_ctrlcnt = (sih->pmucaps & PCAP5_PC_MASK) >> PCAP5_PC_SHIFT;
4279*4882a593Smuzhiyun 		} else {
4280*4882a593Smuzhiyun 			pll_ctrlcnt = (sih->pmucaps & PCAP_PC_MASK) >> PCAP_PC_SHIFT;
4281*4882a593Smuzhiyun 		}
4282*4882a593Smuzhiyun 
4283*4882a593Smuzhiyun 		/* Check if there is any otp enter for PLLcontrol registers */
4284*4882a593Smuzhiyun 		for (i = 0; i < pll_ctrlcnt; i++) {
4285*4882a593Smuzhiyun 			snprintf(name, sizeof(name), rstr_pllD, i);
4286*4882a593Smuzhiyun 			if ((otp_val = getvar(NULL, name)) == NULL)
4287*4882a593Smuzhiyun 				continue;
4288*4882a593Smuzhiyun 
4289*4882a593Smuzhiyun 			/* If OTP entry is found for PLL register, then turn off the PLL
4290*4882a593Smuzhiyun 			 * and set the status of the OTP entry accordingly.
4291*4882a593Smuzhiyun 			 */
4292*4882a593Smuzhiyun 			otp_entry_found = TRUE;
4293*4882a593Smuzhiyun 			break;
4294*4882a593Smuzhiyun 		}
4295*4882a593Smuzhiyun 	}
4296*4882a593Smuzhiyun 
4297*4882a593Smuzhiyun 	/* If no OTP parameter is found and no chip-specific updates are needed, return. */
4298*4882a593Smuzhiyun 	if ((otp_entry_found == FALSE) &&
4299*4882a593Smuzhiyun 		(si_pmu_update_pllcontrol(sih, osh, xtal, FALSE) == FALSE)) {
4300*4882a593Smuzhiyun #if defined(BTOVERPCIE) && !defined(BTOVERPCIE_DISABLED)
4301*4882a593Smuzhiyun 		/*
4302*4882a593Smuzhiyun 		 * For 4369/4362 PLL3 could be prorammed by BT, check the value is default and not
4303*4882a593Smuzhiyun 		 * overrided by BT
4304*4882a593Smuzhiyun 		 */
4305*4882a593Smuzhiyun 		if ((BCM4369_CHIP(sih->chip) || BCM4362_CHIP(sih->chip)) &&
4306*4882a593Smuzhiyun 			(regval = si_pmu_pllcontrol(sih, 3, 0, 0)) != PMU_PLL3_4369B0_DEFAULT) {
4307*4882a593Smuzhiyun 			PMU_ERROR(("Default PLL3 value 0x%x is not same as programmed"
4308*4882a593Smuzhiyun 						"value 0x%x\n", PMU_PLL3_4369B0_DEFAULT, regval));
4309*4882a593Smuzhiyun 			hnd_gcisem_set_err(GCI_PLL_LOCK_SEM);
4310*4882a593Smuzhiyun 			return;
4311*4882a593Smuzhiyun 		}
4312*4882a593Smuzhiyun 
4313*4882a593Smuzhiyun 		/* Update SW_READY bit indicating WLAN is ready and verified PLL3 */
4314*4882a593Smuzhiyun 		si_gci_output(sih, GCI_ECI_SW1(GCI_WLAN_IP_ID), GCI_SWREADY, GCI_SWREADY);
4315*4882a593Smuzhiyun #endif /* defined(BTOVERPCIE) && !defined(BTOVERPCIE_DISABLED) */
4316*4882a593Smuzhiyun 		return;
4317*4882a593Smuzhiyun 	}
4318*4882a593Smuzhiyun 
4319*4882a593Smuzhiyun #if defined(BTOVERPCIE) && !defined(BTOVERPCIE_DISABLED)
4320*4882a593Smuzhiyun 	if ((hnd_gcisem_acquire(GCI_PLL_LOCK_SEM, TRUE, GCI_PLL_LOCK_SEM_TIMEOUT) != BCME_OK)) {
4321*4882a593Smuzhiyun 		PMU_ERROR(("Failed to get GCI PLL Lock semaphore...\n"));
4322*4882a593Smuzhiyun 		hnd_gcisem_set_err(GCI_PLL_LOCK_SEM);
4323*4882a593Smuzhiyun 		return;
4324*4882a593Smuzhiyun 	}
4325*4882a593Smuzhiyun 
4326*4882a593Smuzhiyun 	/* Skip BB PLL programming if BT has already done it, which is indicated by SW_READY bit */
4327*4882a593Smuzhiyun 	if (si_gci_input(sih, GCI_ECI_SW1(GCI_BT_IP_ID)) & GCI_SWREADY) {
4328*4882a593Smuzhiyun 		PMU_MSG(("PLL is already programmed\n"));
4329*4882a593Smuzhiyun 
4330*4882a593Smuzhiyun 		/* Program ARM PLL only if xtalfreq(pllctrl6) programmed is different from xtal */
4331*4882a593Smuzhiyun 		if (si_pmu_update_pllcontrol(sih, osh, xtal, FALSE)) {
4332*4882a593Smuzhiyun 			/* Make sure PLL is off */
4333*4882a593Smuzhiyun 			si_pmu_pll_off(sih, osh, pmu, &min_mask, &max_mask, &clk_ctl_st);
4334*4882a593Smuzhiyun 
4335*4882a593Smuzhiyun 			/* for 4369, arm clk cycle can be set from nvram - default is 400 MHz */
4336*4882a593Smuzhiyun 			if ((BCM4369_CHIP(sih->chip) || BCM4362_CHIP(sih->chip)) &&
4337*4882a593Smuzhiyun 				(pll_ctrlcnt > PMU1_PLL0_PLLCTL6)) {
4338*4882a593Smuzhiyun 				PMU_MSG(("Programming ARM CLK\n"));
4339*4882a593Smuzhiyun 				si_pmu_pll6val_armclk_calc(osh, pmu,
4340*4882a593Smuzhiyun 					si_get_armpllclkfreq(sih), xtal, TRUE);
4341*4882a593Smuzhiyun 			}
4342*4882a593Smuzhiyun 
4343*4882a593Smuzhiyun 			/* Flush ('update') the deferred pll control registers writes */
4344*4882a593Smuzhiyun 			if (PMUREV(sih->pmurev) >= 2)
4345*4882a593Smuzhiyun 				OR_REG(osh, &pmu->pmucontrol, PCTL_PLL_PLLCTL_UPD);
4346*4882a593Smuzhiyun 
4347*4882a593Smuzhiyun 			/* Restore back the register values. This ensures PLL remains on if it
4348*4882a593Smuzhiyun 			 * was originally on and remains off if it was originally off.
4349*4882a593Smuzhiyun 			 */
4350*4882a593Smuzhiyun 			si_pmu_pll_on(sih, osh, pmu, min_mask, max_mask, clk_ctl_st);
4351*4882a593Smuzhiyun 		}
4352*4882a593Smuzhiyun 
4353*4882a593Smuzhiyun 		snprintf(name, sizeof(name), rstr_pllD, 3);
4354*4882a593Smuzhiyun 		if ((otp_val = getvar(NULL, name)) != NULL) {
4355*4882a593Smuzhiyun 			otpval = (uint32)bcm_strtoul(otp_val, NULL, 0);
4356*4882a593Smuzhiyun 			if ((regval = si_pmu_pllcontrol(sih, 3, 0, 0)) != otpval) {
4357*4882a593Smuzhiyun 				PMU_ERROR(("PLL3 programming value 0x%x is not same as programmed"
4358*4882a593Smuzhiyun 					"value 0x%x\n", otpval, regval));
4359*4882a593Smuzhiyun 				hnd_gcisem_set_err(GCI_PLL_LOCK_SEM);
4360*4882a593Smuzhiyun 			}
4361*4882a593Smuzhiyun 		}
4362*4882a593Smuzhiyun 		goto done;
4363*4882a593Smuzhiyun 	}
4364*4882a593Smuzhiyun #endif /* defined(BTOVERPCIE) && !defined(BTOVERPCIE_DISABLED) */
4365*4882a593Smuzhiyun 
4366*4882a593Smuzhiyun 	/* Make sure PLL is off */
4367*4882a593Smuzhiyun 	si_pmu_pll_off(sih, osh, pmu, &min_mask, &max_mask, &clk_ctl_st);
4368*4882a593Smuzhiyun 
4369*4882a593Smuzhiyun 	/* Update any chip-specific PLL registers. Does not write PLL 'update' bit yet. */
4370*4882a593Smuzhiyun 	si_pmu_update_pllcontrol(sih, osh, xtal, TRUE);
4371*4882a593Smuzhiyun 
4372*4882a593Smuzhiyun 	/* Update the PLL register if there is a OTP entry for PLL registers */
4373*4882a593Smuzhiyun 	si_pmu_otp_pllcontrol(sih, osh);
4374*4882a593Smuzhiyun 
4375*4882a593Smuzhiyun 	/* Flush ('update') the deferred pll control registers writes */
4376*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 2)
4377*4882a593Smuzhiyun 		OR_REG(osh, &pmu->pmucontrol, PCTL_PLL_PLLCTL_UPD);
4378*4882a593Smuzhiyun 
4379*4882a593Smuzhiyun 	/* Restore back the register values. This ensures PLL remains on if it
4380*4882a593Smuzhiyun 	 * was originally on and remains off if it was originally off.
4381*4882a593Smuzhiyun 	 */
4382*4882a593Smuzhiyun 	si_pmu_pll_on(sih, osh, pmu, min_mask, max_mask, clk_ctl_st);
4383*4882a593Smuzhiyun 
4384*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
4385*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
4386*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID)) {
4387*4882a593Smuzhiyun 		uint32 origidx;
4388*4882a593Smuzhiyun 		/* PMU clock stretch to be decreased to 8 for HT and ALP
4389*4882a593Smuzhiyun 		* to reduce DS0 current during high traffic
4390*4882a593Smuzhiyun 		*/
4391*4882a593Smuzhiyun 		W_REG(osh, &pmu->clkstretch, CSTRETCH_REDUCE_8);
4392*4882a593Smuzhiyun 
4393*4882a593Smuzhiyun 		/* SDIOD to request for ALP
4394*4882a593Smuzhiyun 		* to reduce DS0 current during high traffic
4395*4882a593Smuzhiyun 		*/
4396*4882a593Smuzhiyun 		origidx = si_coreidx(sih);
4397*4882a593Smuzhiyun 		si_setcore(sih, SDIOD_CORE_ID, 0);
4398*4882a593Smuzhiyun 		/* Clear the Bit 8 for ALP REQUEST change */
4399*4882a593Smuzhiyun 		si_wrapperreg(sih, AI_OOBSELOUTB30, (AI_OOBSEL_MASK << AI_OOBSEL_1_SHIFT),
4400*4882a593Smuzhiyun 			OOB_B_ALP_REQUEST << AI_OOBSEL_1_SHIFT);
4401*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
4402*4882a593Smuzhiyun 	}
4403*4882a593Smuzhiyun 
4404*4882a593Smuzhiyun #if defined(BTOVERPCIE) && !defined(BTOVERPCIE_DISABLED)
4405*4882a593Smuzhiyun done:
4406*4882a593Smuzhiyun 	/* Update SW_READY bit indicating WLAN is done programming PLL registers */
4407*4882a593Smuzhiyun 	si_gci_output(sih, GCI_ECI_SW1(GCI_WLAN_IP_ID), GCI_SWREADY, GCI_SWREADY);
4408*4882a593Smuzhiyun 	if ((hnd_gcisem_release(GCI_PLL_LOCK_SEM) != BCME_OK)) {
4409*4882a593Smuzhiyun 		PMU_ERROR(("Failed to release GCI PLL Lock semaphore...\n"));
4410*4882a593Smuzhiyun 		hnd_gcisem_set_err(GCI_PLL_LOCK_SEM);
4411*4882a593Smuzhiyun 	}
4412*4882a593Smuzhiyun #endif /* defined(BTOVERPCIE) && !defined(BTOVERPCIE_DISABLED) */
4413*4882a593Smuzhiyun } /* si_pmu1_pllinit1 */
4414*4882a593Smuzhiyun 
4415*4882a593Smuzhiyun #if defined(EDV)
4416*4882a593Smuzhiyun /* returns backplane clk programmed in pll cntl 1 */
4417*4882a593Smuzhiyun /* WHY NOT JUST CALL si_pmu_si_clock()? */
si_pmu_get_backplaneclkspeed(si_t * sih)4418*4882a593Smuzhiyun uint32 si_pmu_get_backplaneclkspeed(si_t *sih)
4419*4882a593Smuzhiyun {
4420*4882a593Smuzhiyun 	uint32 FVCO;
4421*4882a593Smuzhiyun 	uint32 tmp, mdiv = 1;
4422*4882a593Smuzhiyun 
4423*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
4424*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
4425*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
4426*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
4427*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
4428*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
4429*4882a593Smuzhiyun 		return si_pmu_bpclk_4387(sih);
4430*4882a593Smuzhiyun 	default:
4431*4882a593Smuzhiyun 		break;
4432*4882a593Smuzhiyun 	}
4433*4882a593Smuzhiyun 
4434*4882a593Smuzhiyun 	FVCO =  si_pmu1_pllfvco0(sih);
4435*4882a593Smuzhiyun 
4436*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
4437*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
4438*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
4439*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
4440*4882a593Smuzhiyun 		tmp = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG1, 0, 0);
4441*4882a593Smuzhiyun 		mdiv = (tmp & PMU1_PLL0_PC1_M4DIV_MASK) >> PMU1_PLL0_PC1_M4DIV_SHIFT;
4442*4882a593Smuzhiyun 		break;
4443*4882a593Smuzhiyun 	default:
4444*4882a593Smuzhiyun 		ASSERT(FALSE);
4445*4882a593Smuzhiyun 		break;
4446*4882a593Smuzhiyun 	}
4447*4882a593Smuzhiyun 	return FVCO / mdiv * 1000u;
4448*4882a593Smuzhiyun }
4449*4882a593Smuzhiyun 
4450*4882a593Smuzhiyun /* Update backplane clock speed */
4451*4882a593Smuzhiyun void
si_pmu_update_backplane_clock(si_t * sih,osl_t * osh,uint reg,uint32 mask,uint32 val)4452*4882a593Smuzhiyun si_pmu_update_backplane_clock(si_t *sih, osl_t *osh, uint reg, uint32 mask, uint32 val)
4453*4882a593Smuzhiyun {
4454*4882a593Smuzhiyun 
4455*4882a593Smuzhiyun 	pmuregs_t *pmu;
4456*4882a593Smuzhiyun 	uint origidx;
4457*4882a593Smuzhiyun 	uint32 max_mask = 0, min_mask = 0, clk_ctl_st = 0;
4458*4882a593Smuzhiyun 
4459*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
4460*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
4461*4882a593Smuzhiyun 
4462*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
4463*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
4464*4882a593Smuzhiyun 	} else {
4465*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
4466*4882a593Smuzhiyun 	}
4467*4882a593Smuzhiyun 
4468*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
4469*4882a593Smuzhiyun 
4470*4882a593Smuzhiyun 	/* Make sure PLL is off */
4471*4882a593Smuzhiyun 	si_pmu_pll_off(sih, osh, pmu, &min_mask, &max_mask, &clk_ctl_st);
4472*4882a593Smuzhiyun 
4473*4882a593Smuzhiyun 	si_pmu_pllcontrol(sih, reg, mask, val);
4474*4882a593Smuzhiyun 
4475*4882a593Smuzhiyun 	/* Flush ('update') the deferred pll control registers writes */
4476*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 2)
4477*4882a593Smuzhiyun 		OR_REG(osh, &pmu->pmucontrol, PCTL_PLL_PLLCTL_UPD);
4478*4882a593Smuzhiyun 
4479*4882a593Smuzhiyun 	/* Restore back the register values. This ensures PLL remains on if it
4480*4882a593Smuzhiyun 	 * was originally on and remains off if it was originally off.
4481*4882a593Smuzhiyun 	 */
4482*4882a593Smuzhiyun 	si_pmu_pll_on(sih, osh, pmu, min_mask, max_mask, clk_ctl_st);
4483*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
4484*4882a593Smuzhiyun }
4485*4882a593Smuzhiyun #endif /* si_pmu_update_backplane_clock */
4486*4882a593Smuzhiyun 
4487*4882a593Smuzhiyun /**
4488*4882a593Smuzhiyun  * returns the backplane clock frequency.
4489*4882a593Smuzhiyun  * Does this by determining current Fvco and the setting of the
4490*4882a593Smuzhiyun  * clock divider that leads up to the backplane. Returns value in [Hz] units.
4491*4882a593Smuzhiyun  */
4492*4882a593Smuzhiyun static uint32
BCMPOSTTRAPFN(si_pmu_bpclk_4387)4493*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_bpclk_4387)(si_t *sih)
4494*4882a593Smuzhiyun {
4495*4882a593Smuzhiyun 	uint32 tmp, mdiv;
4496*4882a593Smuzhiyun 	uint32 FVCO;	/* in [khz] units */
4497*4882a593Smuzhiyun 
4498*4882a593Smuzhiyun 	FVCO = si_pmu1_pllfvco0(sih);
4499*4882a593Smuzhiyun 
4500*4882a593Smuzhiyun 	tmp = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2, 0, 0);
4501*4882a593Smuzhiyun 	mdiv = (tmp & PMU4387_PLL0_PC2_ICH3_MDIV_MASK);
4502*4882a593Smuzhiyun 	ASSERT(mdiv != 0);
4503*4882a593Smuzhiyun 
4504*4882a593Smuzhiyun 	return FVCO / mdiv * 1000;
4505*4882a593Smuzhiyun }
4506*4882a593Smuzhiyun 
4507*4882a593Smuzhiyun /**
4508*4882a593Smuzhiyun  * returns the CPU clock frequency. Does this by determining current Fvco and the setting of the
4509*4882a593Smuzhiyun  * clock divider that leads up to the ARM. Returns value in [Hz] units.
4510*4882a593Smuzhiyun  */
4511*4882a593Smuzhiyun static uint32
BCMPOSTTRAPFN(si_pmu1_cpuclk0)4512*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu1_cpuclk0)(si_t *sih, osl_t *osh, pmuregs_t *pmu)
4513*4882a593Smuzhiyun {
4514*4882a593Smuzhiyun 	uint32 tmp, mdiv = 1;
4515*4882a593Smuzhiyun #ifdef BCMDBG
4516*4882a593Smuzhiyun 	uint32 ndiv_int, ndiv_frac, p2div, p1div, fvco;
4517*4882a593Smuzhiyun 	uint32 fref;
4518*4882a593Smuzhiyun #endif
4519*4882a593Smuzhiyun #ifdef BCMDBG_PMU
4520*4882a593Smuzhiyun 	char chn[8];
4521*4882a593Smuzhiyun #endif
4522*4882a593Smuzhiyun 	uint32 FVCO;	/* in [khz] units */
4523*4882a593Smuzhiyun 
4524*4882a593Smuzhiyun 	FVCO = si_pmu1_pllfvco0(sih);
4525*4882a593Smuzhiyun 
4526*4882a593Smuzhiyun 	if (BCM43602_CHIP(sih->chip) &&
4527*4882a593Smuzhiyun #ifdef DONGLEBUILD
4528*4882a593Smuzhiyun #ifdef __arm__
4529*4882a593Smuzhiyun 	    (si_arm_clockratio(sih, 0) == 1) &&
4530*4882a593Smuzhiyun #endif
4531*4882a593Smuzhiyun #endif /* DONGLEBUILD */
4532*4882a593Smuzhiyun 		TRUE) {
4533*4882a593Smuzhiyun 		/* CR4 running on backplane_clk */
4534*4882a593Smuzhiyun 		return si_pmu_si_clock(sih, osh);	/* in [hz] units */
4535*4882a593Smuzhiyun 	}
4536*4882a593Smuzhiyun 
4537*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
4538*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
4539*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
4540*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
4541*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
4542*4882a593Smuzhiyun 		/* Read m6div from pllcontrol[5] */
4543*4882a593Smuzhiyun 		tmp = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG5, 0, 0);
4544*4882a593Smuzhiyun 		mdiv = (tmp & PMU1_PLL0_PC2_M6DIV_MASK) >> PMU1_PLL0_PC2_M6DIV_SHIFT;
4545*4882a593Smuzhiyun 		break;
4546*4882a593Smuzhiyun #ifdef DONGLEBUILD
4547*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
4548*4882a593Smuzhiyun #ifdef __arm__
4549*4882a593Smuzhiyun 		ASSERT(si_arm_clockratio(sih, 0) == 2);
4550*4882a593Smuzhiyun #endif
4551*4882a593Smuzhiyun 		/* CR4 running on armcr4_clk (Ch5). Read 'bbpll_i_m5div' from pllctl[5] */
4552*4882a593Smuzhiyun 		tmp = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG5, 0, 0);
4553*4882a593Smuzhiyun 		mdiv = (tmp & PMU1_PLL0_PC2_M5DIV_MASK) >> PMU1_PLL0_PC2_M5DIV_SHIFT;
4554*4882a593Smuzhiyun 		break;
4555*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
4556*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
4557*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
4558*4882a593Smuzhiyun 		/* mdiv is not supported for 43012 and FVCO frequency should be divided by 2 */
4559*4882a593Smuzhiyun 		mdiv = 2;
4560*4882a593Smuzhiyun 		break;
4561*4882a593Smuzhiyun #endif /* DONGLEBUILD */
4562*4882a593Smuzhiyun 
4563*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
4564*4882a593Smuzhiyun 		tmp = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG1, 0, 0);
4565*4882a593Smuzhiyun 		mdiv = (tmp & PMU1_PLL0_PC1_M4DIV_MASK) >> PMU1_PLL0_PC1_M4DIV_SHIFT;
4566*4882a593Smuzhiyun 		break;
4567*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
4568*4882a593Smuzhiyun 		tmp = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG1, 0, 0);
4569*4882a593Smuzhiyun 		mdiv = (tmp & PMU1_PLL0_PC1_M4DIV_MASK) >> PMU1_PLL0_PC1_M4DIV_SHIFT;
4570*4882a593Smuzhiyun 		break;
4571*4882a593Smuzhiyun 
4572*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
4573*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
4574*4882a593Smuzhiyun 		tmp = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG1, 0, 0);
4575*4882a593Smuzhiyun 		mdiv = (tmp & PMU1_PLL0_PC1_M4DIV_MASK) >> PMU1_PLL0_PC1_M4DIV_SHIFT;
4576*4882a593Smuzhiyun 		break;
4577*4882a593Smuzhiyun 
4578*4882a593Smuzhiyun 	default:
4579*4882a593Smuzhiyun 		PMU_MSG(("si_pmu1_cpuclk0: Unknown chipid %s\n", bcm_chipname(sih->chip, chn, 8)));
4580*4882a593Smuzhiyun 		ASSERT(0);
4581*4882a593Smuzhiyun 		break;
4582*4882a593Smuzhiyun 	}
4583*4882a593Smuzhiyun 
4584*4882a593Smuzhiyun 	ASSERT(mdiv != 0);
4585*4882a593Smuzhiyun 
4586*4882a593Smuzhiyun #ifdef BCMDBG
4587*4882a593Smuzhiyun 	/* Read p2div/p1div from pllcontrol[0] */
4588*4882a593Smuzhiyun 	tmp = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG0, 0, 0);
4589*4882a593Smuzhiyun 	p2div = (tmp & PMU1_PLL0_PC0_P2DIV_MASK) >> PMU1_PLL0_PC0_P2DIV_SHIFT;
4590*4882a593Smuzhiyun 	p1div = (tmp & PMU1_PLL0_PC0_P1DIV_MASK) >> PMU1_PLL0_PC0_P1DIV_SHIFT;
4591*4882a593Smuzhiyun 
4592*4882a593Smuzhiyun 	/* Calculate fvco based on xtal freq and ndiv and pdiv */
4593*4882a593Smuzhiyun 	tmp = PMU1_PLL0_PLLCTL2;
4594*4882a593Smuzhiyun 
4595*4882a593Smuzhiyun 	tmp = si_pmu_pllcontrol(sih, tmp, 0, 0);
4596*4882a593Smuzhiyun 
4597*4882a593Smuzhiyun 	if (BCM4362_CHIP(sih->chip) ||
4598*4882a593Smuzhiyun 		BCM4369_CHIP(sih->chip)) {
4599*4882a593Smuzhiyun 		p2div = 1;
4600*4882a593Smuzhiyun 		p1div = (tmp & PMU4369_PLL0_PC2_PDIV_MASK) >> PMU4369_PLL0_PC2_PDIV_SHIFT;
4601*4882a593Smuzhiyun 		ndiv_int = (tmp & PMU4369_PLL0_PC2_NDIV_INT_MASK) >>
4602*4882a593Smuzhiyun 					PMU4369_PLL0_PC2_NDIV_INT_SHIFT;
4603*4882a593Smuzhiyun 	} else if (BCM4378_CHIP(sih->chip) || BCM4376_CHIP(sih->chip)) {
4604*4882a593Smuzhiyun 		p2div = 1;
4605*4882a593Smuzhiyun 		p1div = (tmp & PMU4378_PLL0_PC2_P1DIV_MASK) >> PMU4378_PLL0_PC2_P1DIV_SHIFT;
4606*4882a593Smuzhiyun 		ndiv_int = (tmp & PMU4378_PLL0_PC2_NDIV_INT_MASK) >>
4607*4882a593Smuzhiyun 					PMU4378_PLL0_PC2_NDIV_INT_SHIFT;
4608*4882a593Smuzhiyun 	} else {
4609*4882a593Smuzhiyun 		ndiv_int = (tmp & PMU1_PLL0_PC2_NDIV_INT_MASK) >> PMU1_PLL0_PC2_NDIV_INT_SHIFT;
4610*4882a593Smuzhiyun 	}
4611*4882a593Smuzhiyun 
4612*4882a593Smuzhiyun 	ASSERT(p1div != 0);
4613*4882a593Smuzhiyun 
4614*4882a593Smuzhiyun 	tmp = PMU1_PLL0_PLLCTL3;
4615*4882a593Smuzhiyun 
4616*4882a593Smuzhiyun 	tmp = si_pmu_pllcontrol(sih, tmp, 0, 0);
4617*4882a593Smuzhiyun 
4618*4882a593Smuzhiyun 	if (BCM4369_CHIP(sih->chip) || BCM4362_CHIP(sih->chip) ||
4619*4882a593Smuzhiyun 	    BCM4376_CHIP(sih->chip) ||
4620*4882a593Smuzhiyun 	    BCM4378_CHIP(sih->chip) ||
4621*4882a593Smuzhiyun 	    FALSE) {
4622*4882a593Smuzhiyun 			ndiv_frac =
4623*4882a593Smuzhiyun 				(tmp & PMU4369_PLL0_PC3_NDIV_FRAC_MASK) >>
4624*4882a593Smuzhiyun 				PMU4369_PLL0_PC3_NDIV_FRAC_SHIFT;
4625*4882a593Smuzhiyun 		fref = si_pmu1_alpclk0(sih, osh, pmu) / 1000; /* [KHz] */
4626*4882a593Smuzhiyun 
4627*4882a593Smuzhiyun 		fvco = (fref * ndiv_int) << 8;
4628*4882a593Smuzhiyun 		fvco += (fref * ((ndiv_frac & 0xfffff) >> 4)) >> 8;
4629*4882a593Smuzhiyun 		fvco >>= 8;
4630*4882a593Smuzhiyun 		fvco *= p1div;
4631*4882a593Smuzhiyun 		fvco /= 1000;
4632*4882a593Smuzhiyun 		fvco *= 1000;
4633*4882a593Smuzhiyun 	} else {
4634*4882a593Smuzhiyun 		ndiv_frac =
4635*4882a593Smuzhiyun 			(tmp & PMU1_PLL0_PC3_NDIV_FRAC_MASK) >> PMU1_PLL0_PC3_NDIV_FRAC_SHIFT;
4636*4882a593Smuzhiyun 
4637*4882a593Smuzhiyun 		fref = si_pmu1_alpclk0(sih, osh, pmu) / 1000;
4638*4882a593Smuzhiyun 
4639*4882a593Smuzhiyun 		fvco = (fref * ndiv_int) << 8;
4640*4882a593Smuzhiyun 		fvco += (fref * (ndiv_frac >> 12)) >> 4;
4641*4882a593Smuzhiyun 		fvco += (fref * (ndiv_frac & 0xfff)) >> 12;
4642*4882a593Smuzhiyun 		fvco >>= 8;
4643*4882a593Smuzhiyun 		fvco *= p2div;
4644*4882a593Smuzhiyun 		fvco /= p1div;
4645*4882a593Smuzhiyun 		fvco /= 1000;
4646*4882a593Smuzhiyun 		fvco *= 1000;
4647*4882a593Smuzhiyun 	}
4648*4882a593Smuzhiyun 
4649*4882a593Smuzhiyun 	PMU_MSG(("si_pmu1_cpuclk0: ndiv_int %u ndiv_frac %u p2div %u p1div %u fvco %u\n",
4650*4882a593Smuzhiyun 	         ndiv_int, ndiv_frac, p2div, p1div, fvco));
4651*4882a593Smuzhiyun 
4652*4882a593Smuzhiyun 	FVCO = fvco;
4653*4882a593Smuzhiyun #endif	/* BCMDBG */
4654*4882a593Smuzhiyun 
4655*4882a593Smuzhiyun 	return FVCO / mdiv * 1000; /* Return CPU clock in [Hz] */
4656*4882a593Smuzhiyun } /* si_pmu1_cpuclk0 */
4657*4882a593Smuzhiyun 
4658*4882a593Smuzhiyun /**
4659*4882a593Smuzhiyun  * BCM4369/4378/4387 specific function returning the CPU clock frequency.
4660*4882a593Smuzhiyun  * Does this by determining current Fvco and the setting of the clock divider that leads up to
4661*4882a593Smuzhiyun  * the ARM.
4662*4882a593Smuzhiyun  * Returns value in [Hz] units.
4663*4882a593Smuzhiyun  */
4664*4882a593Smuzhiyun static uint32
BCMPOSTTRAPFN(si_pmu1_cpuclk0_pll2)4665*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu1_cpuclk0_pll2)(si_t *sih)
4666*4882a593Smuzhiyun {
4667*4882a593Smuzhiyun 	uint32 FVCO = si_pmu1_pllfvco0_pll2(sih);	/* in [khz] units */
4668*4882a593Smuzhiyun 
4669*4882a593Smuzhiyun 	/* Return ARM/SB clock */
4670*4882a593Smuzhiyun 	return FVCO * 1000;
4671*4882a593Smuzhiyun } /* si_pmu1_cpuclk0_pll2 */
4672*4882a593Smuzhiyun 
4673*4882a593Smuzhiyun /**
4674*4882a593Smuzhiyun  * Returns the MAC clock frequency. Called when e.g. MAC clk frequency has to change because of
4675*4882a593Smuzhiyun  * interference mitigation.
4676*4882a593Smuzhiyun  */
4677*4882a593Smuzhiyun uint32
si_mac_clk(si_t * sih,osl_t * osh)4678*4882a593Smuzhiyun si_mac_clk(si_t *sih, osl_t *osh)
4679*4882a593Smuzhiyun {
4680*4882a593Smuzhiyun 	uint8 mdiv2 = 0;
4681*4882a593Smuzhiyun 	uint32 mac_clk = 0;
4682*4882a593Smuzhiyun 	chipcregs_t *cc;
4683*4882a593Smuzhiyun 	uint origidx;
4684*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
4685*4882a593Smuzhiyun #ifdef BCMDBG_PMU
4686*4882a593Smuzhiyun 	char chn[8];
4687*4882a593Smuzhiyun #endif
4688*4882a593Smuzhiyun 
4689*4882a593Smuzhiyun 	uint32 FVCO = si_pmu1_pllfvco0(sih);	/* in [khz] units */
4690*4882a593Smuzhiyun 
4691*4882a593Smuzhiyun 	BCM_REFERENCE(osh);
4692*4882a593Smuzhiyun 
4693*4882a593Smuzhiyun 	/* Remember original core before switch to chipc */
4694*4882a593Smuzhiyun 	cc = (chipcregs_t *)si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
4695*4882a593Smuzhiyun 	ASSERT(cc != NULL);
4696*4882a593Smuzhiyun 	BCM_REFERENCE(cc);
4697*4882a593Smuzhiyun 
4698*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
4699*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
4700*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
4701*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
4702*4882a593Smuzhiyun 		mdiv2 = 2;
4703*4882a593Smuzhiyun 		mac_clk = FVCO / mdiv2;
4704*4882a593Smuzhiyun 		break;
4705*4882a593Smuzhiyun 	default:
4706*4882a593Smuzhiyun 		PMU_MSG(("si_mac_clk: Unknown chipid %s\n",
4707*4882a593Smuzhiyun 			bcm_chipname(CHIPID(sih->chip), chn, 8)));
4708*4882a593Smuzhiyun 		ASSERT(0);
4709*4882a593Smuzhiyun 		break;
4710*4882a593Smuzhiyun 	}
4711*4882a593Smuzhiyun 
4712*4882a593Smuzhiyun 	/* Return to original core */
4713*4882a593Smuzhiyun 	si_restore_core(sih, origidx, &intr_val);
4714*4882a593Smuzhiyun 
4715*4882a593Smuzhiyun 	return mac_clk;
4716*4882a593Smuzhiyun } /* si_mac_clk */
4717*4882a593Smuzhiyun 
4718*4882a593Smuzhiyun /* 4387 pll MAC channel divisor - for ftm */
4719*4882a593Smuzhiyun static uint32
si_pmu_macdiv_4387(si_t * sih)4720*4882a593Smuzhiyun si_pmu_macdiv_4387(si_t *sih)
4721*4882a593Smuzhiyun {
4722*4882a593Smuzhiyun 	uint32 tmp, mdiv;
4723*4882a593Smuzhiyun 
4724*4882a593Smuzhiyun 	/* TODO: when it's needed return different MAC clock freq.
4725*4882a593Smuzhiyun 	 * for different MAC/slice!
4726*4882a593Smuzhiyun 	 */
4727*4882a593Smuzhiyun 	tmp = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG1, 0, 0);
4728*4882a593Smuzhiyun 	mdiv = (tmp & PMU4387_PLL0_PC1_ICH2_MDIV_MASK) >> PMU4387_PLL0_PC1_ICH2_MDIV_SHIFT;
4729*4882a593Smuzhiyun 	ASSERT(mdiv != 0);
4730*4882a593Smuzhiyun 
4731*4882a593Smuzhiyun 	return mdiv;
4732*4882a593Smuzhiyun }
4733*4882a593Smuzhiyun 
4734*4882a593Smuzhiyun /** Get chip's FVCO and PLLCTRL1 register value */
4735*4882a593Smuzhiyun int
si_pmu_fvco_macdiv(si_t * sih,uint32 * fvco,uint32 * div)4736*4882a593Smuzhiyun si_pmu_fvco_macdiv(si_t *sih, uint32 *fvco, uint32 *div)
4737*4882a593Smuzhiyun {
4738*4882a593Smuzhiyun 	chipcregs_t *cc;
4739*4882a593Smuzhiyun 	uint origidx;
4740*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
4741*4882a593Smuzhiyun 	int err = BCME_OK;
4742*4882a593Smuzhiyun #ifdef BCMDBG_PMU
4743*4882a593Smuzhiyun 	char chn[8];
4744*4882a593Smuzhiyun #endif
4745*4882a593Smuzhiyun 
4746*4882a593Smuzhiyun 	if (fvco)
4747*4882a593Smuzhiyun 		*fvco = si_pmu1_pllfvco0(sih)/1000;
4748*4882a593Smuzhiyun 
4749*4882a593Smuzhiyun 	/* Remember original core before switch to chipc */
4750*4882a593Smuzhiyun 	cc = (chipcregs_t *)si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
4751*4882a593Smuzhiyun 	ASSERT(cc != NULL);
4752*4882a593Smuzhiyun 	BCM_REFERENCE(cc);
4753*4882a593Smuzhiyun 
4754*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
4755*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
4756*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
4757*4882a593Smuzhiyun 		if (div)
4758*4882a593Smuzhiyun 			*div = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG12, 0, 0) &
4759*4882a593Smuzhiyun 				PMU1_PLL0_PC1_M1DIV_MASK;
4760*4882a593Smuzhiyun 		break;
4761*4882a593Smuzhiyun 
4762*4882a593Smuzhiyun 	case BCM43602_CHIP_ID:
4763*4882a593Smuzhiyun 		if (div) {
4764*4882a593Smuzhiyun 			*div = (si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG4, 0, 0) &
4765*4882a593Smuzhiyun 				PMU1_PLL0_PC1_M3DIV_MASK) >> PMU1_PLL0_PC1_M3DIV_SHIFT;
4766*4882a593Smuzhiyun 		}
4767*4882a593Smuzhiyun 		break;
4768*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
4769*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
4770*4882a593Smuzhiyun 		if (div) {
4771*4882a593Smuzhiyun 			*div = (si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL1, 0, 0)
4772*4882a593Smuzhiyun 				& PMU1_PLL0_PC1_M4DIV_MASK) >> PMU1_PLL0_PC1_M4DIV_SHIFT;
4773*4882a593Smuzhiyun 		}
4774*4882a593Smuzhiyun 		break;
4775*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
4776*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
4777*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
4778*4882a593Smuzhiyun 		 /* mDIV is not supported for 43012 & divisor value is always 2 */
4779*4882a593Smuzhiyun 		if (div)
4780*4882a593Smuzhiyun 			*div = 2;
4781*4882a593Smuzhiyun 		break;
4782*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
4783*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
4784*4882a593Smuzhiyun 		if (div) {
4785*4882a593Smuzhiyun 			*div = (si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL1, 0, 0)
4786*4882a593Smuzhiyun 				& PMU1_PLL0_PC1_M4DIV_MASK) >> PMU1_PLL0_PC1_M4DIV_SHIFT;
4787*4882a593Smuzhiyun 		}
4788*4882a593Smuzhiyun 		break;
4789*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
4790*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
4791*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
4792*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
4793*4882a593Smuzhiyun 		if (div) {
4794*4882a593Smuzhiyun 			*div = si_pmu_macdiv_4387(sih);
4795*4882a593Smuzhiyun 		}
4796*4882a593Smuzhiyun 		break;
4797*4882a593Smuzhiyun 	default:
4798*4882a593Smuzhiyun 		PMU_MSG(("si_mac_clk: Unknown chipid %s\n", bcm_chipname(sih->chip, chn, 8)));
4799*4882a593Smuzhiyun 		err = BCME_ERROR;
4800*4882a593Smuzhiyun 	}
4801*4882a593Smuzhiyun 
4802*4882a593Smuzhiyun 	/* Return to original core */
4803*4882a593Smuzhiyun 	si_restore_core(sih, origidx, &intr_val);
4804*4882a593Smuzhiyun 
4805*4882a593Smuzhiyun 	return err;
4806*4882a593Smuzhiyun }
4807*4882a593Smuzhiyun 
4808*4882a593Smuzhiyun /** Return TRUE if scan retention memory's sleep/pm signal was asserted */
4809*4882a593Smuzhiyun bool
BCMPOSTTRAPFN(si_pmu_reset_ret_sleep_log)4810*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_reset_ret_sleep_log)(si_t *sih, osl_t *osh)
4811*4882a593Smuzhiyun {
4812*4882a593Smuzhiyun 	pmuregs_t *pmu;
4813*4882a593Smuzhiyun 	uint origidx;
4814*4882a593Smuzhiyun 	uint32 ret_ctl;
4815*4882a593Smuzhiyun 	bool was_sleep = FALSE;
4816*4882a593Smuzhiyun 
4817*4882a593Smuzhiyun 	/* Remember original core before switch to chipc */
4818*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
4819*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
4820*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
4821*4882a593Smuzhiyun 	} else {
4822*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
4823*4882a593Smuzhiyun 	}
4824*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
4825*4882a593Smuzhiyun 
4826*4882a593Smuzhiyun 	ret_ctl = R_REG(osh, &pmu->retention_ctl);
4827*4882a593Smuzhiyun 	if (ret_ctl & RCTL_MEM_RET_SLEEP_LOG_MASK) {
4828*4882a593Smuzhiyun 		W_REG(osh, &pmu->retention_ctl, ret_ctl);
4829*4882a593Smuzhiyun 		was_sleep = TRUE;
4830*4882a593Smuzhiyun 	}
4831*4882a593Smuzhiyun 
4832*4882a593Smuzhiyun 	/* Return to original core */
4833*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
4834*4882a593Smuzhiyun 
4835*4882a593Smuzhiyun 	return was_sleep;
4836*4882a593Smuzhiyun }
4837*4882a593Smuzhiyun 
4838*4882a593Smuzhiyun /** Return TRUE if pmu rsrc XTAL_PU was de-asserted */
4839*4882a593Smuzhiyun bool
BCMPOSTTRAPFN(si_pmu_reset_chip_sleep_log)4840*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_reset_chip_sleep_log)(si_t *sih, osl_t *osh)
4841*4882a593Smuzhiyun {
4842*4882a593Smuzhiyun 	pmuregs_t *pmu;
4843*4882a593Smuzhiyun 	uint origidx;
4844*4882a593Smuzhiyun 	bool was_sleep = FALSE;
4845*4882a593Smuzhiyun 
4846*4882a593Smuzhiyun 	/* Remember original core before switch to chipc */
4847*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
4848*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
4849*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
4850*4882a593Smuzhiyun 	} else {
4851*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
4852*4882a593Smuzhiyun 	}
4853*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
4854*4882a593Smuzhiyun 
4855*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 36) {
4856*4882a593Smuzhiyun 		uint32 pmu_int_sts = R_REG(osh, &pmu->pmuintstatus);
4857*4882a593Smuzhiyun 		if (pmu_int_sts & PMU_INT_STAT_RSRC_EVENT_INT0_MASK) {
4858*4882a593Smuzhiyun 			/* write 1 to clear the status */
4859*4882a593Smuzhiyun 			W_REG(osh, &pmu->pmuintstatus, PMU_INT_STAT_RSRC_EVENT_INT0_MASK);
4860*4882a593Smuzhiyun 			was_sleep = TRUE;
4861*4882a593Smuzhiyun 		}
4862*4882a593Smuzhiyun 	} else {
4863*4882a593Smuzhiyun 		was_sleep = si_pmu_reset_ret_sleep_log(sih, osh);
4864*4882a593Smuzhiyun 	}
4865*4882a593Smuzhiyun 
4866*4882a593Smuzhiyun 	/* Return to original core */
4867*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
4868*4882a593Smuzhiyun 
4869*4882a593Smuzhiyun 	return was_sleep;
4870*4882a593Smuzhiyun }
4871*4882a593Smuzhiyun 
4872*4882a593Smuzhiyun /* For 43602a0 MCH2/MCH5 boards: power up PA Reference LDO */
4873*4882a593Smuzhiyun void
si_pmu_switch_on_PARLDO(si_t * sih,osl_t * osh)4874*4882a593Smuzhiyun si_pmu_switch_on_PARLDO(si_t *sih, osl_t *osh)
4875*4882a593Smuzhiyun {
4876*4882a593Smuzhiyun 	uint32 mask;
4877*4882a593Smuzhiyun 	pmuregs_t *pmu;
4878*4882a593Smuzhiyun 	uint origidx;
4879*4882a593Smuzhiyun 
4880*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
4881*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
4882*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
4883*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
4884*4882a593Smuzhiyun 	} else {
4885*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
4886*4882a593Smuzhiyun 	}
4887*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
4888*4882a593Smuzhiyun 
4889*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
4890*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
4891*4882a593Smuzhiyun 		mask = R_REG(osh, &pmu->min_res_mask) | PMURES_BIT(RES43602_PARLDO_PU);
4892*4882a593Smuzhiyun 		W_REG(osh, &pmu->min_res_mask, mask);
4893*4882a593Smuzhiyun 		mask = R_REG(osh, &pmu->max_res_mask) | PMURES_BIT(RES43602_PARLDO_PU);
4894*4882a593Smuzhiyun 		W_REG(osh, &pmu->max_res_mask, mask);
4895*4882a593Smuzhiyun 		break;
4896*4882a593Smuzhiyun 	default:
4897*4882a593Smuzhiyun 		break;
4898*4882a593Smuzhiyun 	}
4899*4882a593Smuzhiyun 	/* Return to original core */
4900*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
4901*4882a593Smuzhiyun }
4902*4882a593Smuzhiyun 
4903*4882a593Smuzhiyun /* For 43602a0 MCH2/MCH5 boards: power off PA Reference LDO */
4904*4882a593Smuzhiyun void
si_pmu_switch_off_PARLDO(si_t * sih,osl_t * osh)4905*4882a593Smuzhiyun si_pmu_switch_off_PARLDO(si_t *sih, osl_t *osh)
4906*4882a593Smuzhiyun {
4907*4882a593Smuzhiyun 	uint32 mask;
4908*4882a593Smuzhiyun 	pmuregs_t *pmu;
4909*4882a593Smuzhiyun 	uint origidx;
4910*4882a593Smuzhiyun 
4911*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
4912*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
4913*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
4914*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
4915*4882a593Smuzhiyun 	} else {
4916*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
4917*4882a593Smuzhiyun 	}
4918*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
4919*4882a593Smuzhiyun 
4920*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
4921*4882a593Smuzhiyun 	case BCM43602_CHIP_ID:
4922*4882a593Smuzhiyun 	case BCM43462_CHIP_ID:
4923*4882a593Smuzhiyun 		mask = R_REG(osh, &pmu->min_res_mask) & ~PMURES_BIT(RES43602_PARLDO_PU);
4924*4882a593Smuzhiyun 		W_REG(osh, &pmu->min_res_mask, mask);
4925*4882a593Smuzhiyun 		mask = R_REG(osh, &pmu->max_res_mask) & ~PMURES_BIT(RES43602_PARLDO_PU);
4926*4882a593Smuzhiyun 		W_REG(osh, &pmu->max_res_mask, mask);
4927*4882a593Smuzhiyun 		break;
4928*4882a593Smuzhiyun 	default:
4929*4882a593Smuzhiyun 		break;
4930*4882a593Smuzhiyun 	}
4931*4882a593Smuzhiyun 	/* Return to original core */
4932*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
4933*4882a593Smuzhiyun }
4934*4882a593Smuzhiyun 
4935*4882a593Smuzhiyun /**
4936*4882a593Smuzhiyun  * Change VCO frequency (slightly), e.g. to avoid PHY errors due to spurs.
4937*4882a593Smuzhiyun  */
4938*4882a593Smuzhiyun static void
BCMATTACHFN(si_set_bb_vcofreq_frac)4939*4882a593Smuzhiyun BCMATTACHFN(si_set_bb_vcofreq_frac)(si_t *sih, osl_t *osh, int vcofreq, int frac, int xtalfreq)
4940*4882a593Smuzhiyun {
4941*4882a593Smuzhiyun 	uint32 vcofreq_withfrac, p1div, ndiv_int, fraca, ndiv_mode, reg;
4942*4882a593Smuzhiyun 	/* shifts / masks for PMU PLL control register #2 : */
4943*4882a593Smuzhiyun 	uint32 ndiv_int_shift, ndiv_mode_shift, p1div_shift, pllctrl2_mask;
4944*4882a593Smuzhiyun 	/* shifts / masks for PMU PLL control register #3 : */
4945*4882a593Smuzhiyun 	uint32 pllctrl3_mask;
4946*4882a593Smuzhiyun 	BCM_REFERENCE(osh);
4947*4882a593Smuzhiyun 
4948*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM4360_CHIP_ID) ||
4949*4882a593Smuzhiyun 	    (CHIPID(sih->chip) == BCM43460_CHIP_ID) ||
4950*4882a593Smuzhiyun 	    (CHIPID(sih->chip) == BCM43526_CHIP_ID) ||
4951*4882a593Smuzhiyun 	    (CHIPID(sih->chip) == BCM4352_CHIP_ID) ||
4952*4882a593Smuzhiyun 	    BCM43602_CHIP(sih->chip)) {
4953*4882a593Smuzhiyun 		if (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
4954*4882a593Smuzhiyun 			& CCS_HTAVAIL) {
4955*4882a593Smuzhiyun 			PMU_MSG(("HTAVAIL is set, so not updating BBPLL Frequency \n"));
4956*4882a593Smuzhiyun 			return;
4957*4882a593Smuzhiyun 		}
4958*4882a593Smuzhiyun 
4959*4882a593Smuzhiyun 		ndiv_int_shift = 7;
4960*4882a593Smuzhiyun 		ndiv_mode_shift = 4;
4961*4882a593Smuzhiyun 		p1div_shift = 0;
4962*4882a593Smuzhiyun 		pllctrl2_mask = 0xffffffff;
4963*4882a593Smuzhiyun 		pllctrl3_mask = 0xffffffff;
4964*4882a593Smuzhiyun 	} else {
4965*4882a593Smuzhiyun 		/* put more chips here */
4966*4882a593Smuzhiyun 		PMU_ERROR(("si_set_bb_vcofreq_frac: only work on 4360, 4352\n"));
4967*4882a593Smuzhiyun 		return;
4968*4882a593Smuzhiyun 	}
4969*4882a593Smuzhiyun 
4970*4882a593Smuzhiyun 	vcofreq_withfrac = vcofreq * 10000 + frac;
4971*4882a593Smuzhiyun 	p1div = 0x1;
4972*4882a593Smuzhiyun 	ndiv_int = vcofreq / xtalfreq;
4973*4882a593Smuzhiyun 	ndiv_mode = (vcofreq_withfrac % (xtalfreq * 10000)) ? 3 : 0;
4974*4882a593Smuzhiyun 	PMU_ERROR(("ChangeVCO => vco:%d, xtalF:%d, frac: %d, ndivMode: %d, ndivint: %d\n",
4975*4882a593Smuzhiyun 		vcofreq, xtalfreq, frac, ndiv_mode, ndiv_int));
4976*4882a593Smuzhiyun 
4977*4882a593Smuzhiyun 	reg = (ndiv_int << ndiv_int_shift) |
4978*4882a593Smuzhiyun 	      (ndiv_mode << ndiv_mode_shift) |
4979*4882a593Smuzhiyun 	      (p1div << p1div_shift);
4980*4882a593Smuzhiyun 	PMU_ERROR(("Data written into the PLL_CNTRL_ADDR2: %08x\n", reg));
4981*4882a593Smuzhiyun 	si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2, pllctrl2_mask, reg);
4982*4882a593Smuzhiyun 
4983*4882a593Smuzhiyun 	if (ndiv_mode) {
4984*4882a593Smuzhiyun 		/* frac = (vcofreq_withfrac % (xtalfreq * 10000)) * 2^24) / (xtalfreq * 10000) */
4985*4882a593Smuzhiyun 		uint32 r1, r0;
4986*4882a593Smuzhiyun 		math_uint64_multiple_add(
4987*4882a593Smuzhiyun 			&r1, &r0, vcofreq_withfrac % (xtalfreq * 10000), 1 << 24, 0);
4988*4882a593Smuzhiyun 		math_uint64_divide(&fraca, r1, r0, xtalfreq * 10000);
4989*4882a593Smuzhiyun 		PMU_ERROR(("Data written into the PLL_CNTRL_ADDR3 (Fractional): %08x\n", fraca));
4990*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG3, pllctrl3_mask, fraca);
4991*4882a593Smuzhiyun 	}
4992*4882a593Smuzhiyun 
4993*4882a593Smuzhiyun 	si_pmu_pllupd(sih);
4994*4882a593Smuzhiyun } /* si_set_bb_vcofreq_frac */
4995*4882a593Smuzhiyun 
4996*4882a593Smuzhiyun /**
4997*4882a593Smuzhiyun  * given x-tal frequency, returns BaseBand vcofreq with fraction in 100Hz
4998*4882a593Smuzhiyun  * @param   xtalfreq In [Mhz] units.
4999*4882a593Smuzhiyun  * @return           In [100Hz] units.
5000*4882a593Smuzhiyun  */
5001*4882a593Smuzhiyun uint32
si_pmu_get_bb_vcofreq(si_t * sih,osl_t * osh,int xtalfreq)5002*4882a593Smuzhiyun si_pmu_get_bb_vcofreq(si_t *sih, osl_t *osh, int xtalfreq)
5003*4882a593Smuzhiyun {
5004*4882a593Smuzhiyun 	uint32  ndiv_int,	/* 9 bits integer divider */
5005*4882a593Smuzhiyun 		ndiv_mode,
5006*4882a593Smuzhiyun 		frac = 0,	/* 24 bits fractional divider */
5007*4882a593Smuzhiyun 		p1div;		/* predivider: divides x-tal freq */
5008*4882a593Smuzhiyun 	uint32 xtal1, vcofrac = 0, vcofreq;
5009*4882a593Smuzhiyun 	uint32 r1, r0, reg;
5010*4882a593Smuzhiyun 
5011*4882a593Smuzhiyun 	BCM_REFERENCE(osh);
5012*4882a593Smuzhiyun 
5013*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM4360_CHIP_ID) ||
5014*4882a593Smuzhiyun 	    (CHIPID(sih->chip) == BCM43460_CHIP_ID) ||
5015*4882a593Smuzhiyun 	    (CHIPID(sih->chip) == BCM43526_CHIP_ID) ||
5016*4882a593Smuzhiyun 	    (CHIPID(sih->chip) == BCM4352_CHIP_ID) ||
5017*4882a593Smuzhiyun 	    BCM43602_CHIP(sih->chip)) {
5018*4882a593Smuzhiyun 		reg = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2, 0, 0);
5019*4882a593Smuzhiyun 		ndiv_int = reg >> 7;
5020*4882a593Smuzhiyun 		ndiv_mode = (reg >> 4) & 7;
5021*4882a593Smuzhiyun 		p1div = 1; /* do not divide x-tal frequency */
5022*4882a593Smuzhiyun 
5023*4882a593Smuzhiyun 		if (ndiv_mode)
5024*4882a593Smuzhiyun 			frac = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG3, 0, 0);
5025*4882a593Smuzhiyun 	} else if ((BCM4369_CHIP(sih->chip) &&
5026*4882a593Smuzhiyun 			CST4369_CHIPMODE_PCIE(sih->chipst)) ||
5027*4882a593Smuzhiyun 			BCM4376_CHIP(sih->chip) ||
5028*4882a593Smuzhiyun 			BCM4378_CHIP(sih->chip) ||
5029*4882a593Smuzhiyun 			(BCM4362_CHIP(sih->chip) &&
5030*4882a593Smuzhiyun 			CST4362_CHIPMODE_PCIE(sih->chipst))) {
5031*4882a593Smuzhiyun 		reg = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG2, 0, 0);
5032*4882a593Smuzhiyun 		ndiv_int = reg >> 20;
5033*4882a593Smuzhiyun 		p1div = (reg >> 16) & 0xf;
5034*4882a593Smuzhiyun 		frac = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG3, 0, 0) & 0x00fffff;
5035*4882a593Smuzhiyun 		ndiv_mode = 1;
5036*4882a593Smuzhiyun 	} else {
5037*4882a593Smuzhiyun 		/* put more chips here */
5038*4882a593Smuzhiyun 		PMU_ERROR(("si_pmu_get_bb_vcofreq: only work on 4360, 4352, 4369, 4378\n"));
5039*4882a593Smuzhiyun 		ASSERT(FALSE);
5040*4882a593Smuzhiyun 		return 0;
5041*4882a593Smuzhiyun 	}
5042*4882a593Smuzhiyun 
5043*4882a593Smuzhiyun 	xtal1 = 10000 * xtalfreq / p1div;		/* in [100Hz] units */
5044*4882a593Smuzhiyun 
5045*4882a593Smuzhiyun 	if (ndiv_mode) {
5046*4882a593Smuzhiyun 		/* vcofreq fraction = (xtal1 * frac + (1 << 23)) / (1 << 24);
5047*4882a593Smuzhiyun 		 * handle overflow
5048*4882a593Smuzhiyun 		 */
5049*4882a593Smuzhiyun 		math_uint64_multiple_add(&r1, &r0, xtal1, frac, 1 << 23);
5050*4882a593Smuzhiyun 		vcofrac = (r1 << 8) | (r0 >> 24);
5051*4882a593Smuzhiyun 	}
5052*4882a593Smuzhiyun 
5053*4882a593Smuzhiyun 	if (ndiv_int == 0) {
5054*4882a593Smuzhiyun 		ASSERT(0);
5055*4882a593Smuzhiyun 		return 0;
5056*4882a593Smuzhiyun 	}
5057*4882a593Smuzhiyun 
5058*4882a593Smuzhiyun 	if ((int)xtal1 > (int)((0xffffffff - vcofrac) / ndiv_int)) {
5059*4882a593Smuzhiyun 		PMU_ERROR(("si_pmu_get_bb_vcofreq: xtalfreq is too big, %d\n", xtalfreq));
5060*4882a593Smuzhiyun 		return 0;
5061*4882a593Smuzhiyun 	}
5062*4882a593Smuzhiyun 
5063*4882a593Smuzhiyun 	vcofreq = xtal1 * ndiv_int + vcofrac;
5064*4882a593Smuzhiyun 	return vcofreq;
5065*4882a593Smuzhiyun } /* si_pmu_get_bb_vcofreq */
5066*4882a593Smuzhiyun 
5067*4882a593Smuzhiyun /** Enable PMU 1Mhz clock */
5068*4882a593Smuzhiyun static void
si_pmu_enb_slow_clk(si_t * sih,osl_t * osh,uint32 xtalfreq)5069*4882a593Smuzhiyun si_pmu_enb_slow_clk(si_t *sih, osl_t *osh, uint32 xtalfreq)
5070*4882a593Smuzhiyun {
5071*4882a593Smuzhiyun 	uint32 val;
5072*4882a593Smuzhiyun 	pmuregs_t *pmu;
5073*4882a593Smuzhiyun 	uint origidx;
5074*4882a593Smuzhiyun 
5075*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) < 24) {
5076*4882a593Smuzhiyun 		PMU_ERROR(("si_pmu_enb_slow_clk: Not supported %d\n", PMUREV(sih->pmurev)));
5077*4882a593Smuzhiyun 		return;
5078*4882a593Smuzhiyun 	}
5079*4882a593Smuzhiyun 
5080*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5081*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5082*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5083*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5084*4882a593Smuzhiyun 	} else {
5085*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5086*4882a593Smuzhiyun 	}
5087*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5088*4882a593Smuzhiyun 
5089*4882a593Smuzhiyun 	/* twiki PmuRev30, OneMhzToggleEn:31, AlpPeriod[23:0] */
5090*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 38) {
5091*4882a593Smuzhiyun 		/* Use AlpPeriod[23:0] only chip default value for PmuRev >= 38 chips
5092*4882a593Smuzhiyun 		 *  eg. ROUND(POWER(2,26) / (55.970 / 2 MHz) for 4387/4385, etc
5093*4882a593Smuzhiyun 		 */
5094*4882a593Smuzhiyun 		val = R_REG(osh, &pmu->slowclkperiod) | PMU30_ALPCLK_ONEMHZ_ENAB;
5095*4882a593Smuzhiyun 	} else {
5096*4882a593Smuzhiyun 		if (PMUREV(sih->pmurev) >= 30) {
5097*4882a593Smuzhiyun 			/* AlpPeriod = ROUND(POWER(2,26)/ALP_CLK_FREQ_IN_MHz,0) */
5098*4882a593Smuzhiyun 			/* Calculation will be accurate for only one decimal of xtal (like 37.4),
5099*4882a593Smuzhiyun 			* and will not be accurate for more than one decimal
5100*4882a593Smuzhiyun 			* of xtal freq (like 37.43)
5101*4882a593Smuzhiyun 			* Also no rounding is done on final result
5102*4882a593Smuzhiyun 			*/
5103*4882a593Smuzhiyun 			ROMMABLE_ASSERT((xtalfreq/100)*100 == xtalfreq);
5104*4882a593Smuzhiyun 			val = (((1 << 26)*10)/(xtalfreq/100));
5105*4882a593Smuzhiyun 			/* set the 32 bit to enable OneMhzToggle
5106*4882a593Smuzhiyun 			* -usec wide toggle signal will be generated
5107*4882a593Smuzhiyun 			*/
5108*4882a593Smuzhiyun 			val |= PMU30_ALPCLK_ONEMHZ_ENAB;
5109*4882a593Smuzhiyun 		} else { /* twiki PmuRev24, OneMhzToggleEn:16, AlpPeriod[15:0] */
5110*4882a593Smuzhiyun 			if (xtalfreq == 37400) {
5111*4882a593Smuzhiyun 				val = 0x101B6;
5112*4882a593Smuzhiyun 			} else if (xtalfreq == 40000) {
5113*4882a593Smuzhiyun 				val = 0x10199;
5114*4882a593Smuzhiyun 			} else {
5115*4882a593Smuzhiyun 				PMU_ERROR(("si_pmu_enb_slow_clk: xtalfreq is not supported, %d\n",
5116*4882a593Smuzhiyun 					xtalfreq));
5117*4882a593Smuzhiyun 				/* Return to original core */
5118*4882a593Smuzhiyun 				si_setcoreidx(sih, origidx);
5119*4882a593Smuzhiyun 				return;
5120*4882a593Smuzhiyun 			}
5121*4882a593Smuzhiyun 		}
5122*4882a593Smuzhiyun 	}
5123*4882a593Smuzhiyun 
5124*4882a593Smuzhiyun 	W_REG(osh, &pmu->slowclkperiod, val);
5125*4882a593Smuzhiyun 
5126*4882a593Smuzhiyun 	/* Return to original core */
5127*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5128*4882a593Smuzhiyun }
5129*4882a593Smuzhiyun 
5130*4882a593Smuzhiyun /**
5131*4882a593Smuzhiyun  * Initializes PLL given an x-tal frequency.
5132*4882a593Smuzhiyun  * Calls si_pmuX_pllinitY() type of functions, where the reasoning behind 'X' and 'Y' is historical
5133*4882a593Smuzhiyun  * rather than logical.
5134*4882a593Smuzhiyun  *
5135*4882a593Smuzhiyun  * xtalfreq : x-tal frequency in [KHz]
5136*4882a593Smuzhiyun  */
5137*4882a593Smuzhiyun void
BCMATTACHFN(si_pmu_pll_init)5138*4882a593Smuzhiyun BCMATTACHFN(si_pmu_pll_init)(si_t *sih, osl_t *osh, uint xtalfreq)
5139*4882a593Smuzhiyun {
5140*4882a593Smuzhiyun 	pmuregs_t *pmu;
5141*4882a593Smuzhiyun 	uint origidx;
5142*4882a593Smuzhiyun #ifdef BCMDBG_PMU
5143*4882a593Smuzhiyun 	char chn[8];
5144*4882a593Smuzhiyun #endif
5145*4882a593Smuzhiyun 	BCM_REFERENCE(pmu1_xtaltab0_880);
5146*4882a593Smuzhiyun 	BCM_REFERENCE(pmu1_xtaltab0_1760);
5147*4882a593Smuzhiyun 
5148*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
5149*4882a593Smuzhiyun 
5150*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5151*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5152*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5153*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5154*4882a593Smuzhiyun 	} else {
5155*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5156*4882a593Smuzhiyun 	}
5157*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5158*4882a593Smuzhiyun 
5159*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
5160*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
5161*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
5162*4882a593Smuzhiyun 	case BCM4352_CHIP_ID: {
5163*4882a593Smuzhiyun 		if (CHIPREV(sih->chiprev) > 2)
5164*4882a593Smuzhiyun 			si_set_bb_vcofreq_frac(sih, osh, 960, 98, 40);
5165*4882a593Smuzhiyun 		break;
5166*4882a593Smuzhiyun 	}
5167*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
5168*4882a593Smuzhiyun 		si_set_bb_vcofreq_frac(sih, osh, 960, 98, 40);
5169*4882a593Smuzhiyun 		break;
5170*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
5171*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
5172*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
5173*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
5174*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
5175*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
5176*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
5177*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
5178*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
5179*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
5180*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
5181*4882a593Smuzhiyun 		si_pmu1_pllinit1(sih, osh, pmu, xtalfreq); /* nvram PLL overrides + enables PLL */
5182*4882a593Smuzhiyun 		break;
5183*4882a593Smuzhiyun 	default:
5184*4882a593Smuzhiyun 		PMU_MSG(("No PLL init done for chip %s rev %d pmurev %d\n",
5185*4882a593Smuzhiyun 		         bcm_chipname(
5186*4882a593Smuzhiyun 			 CHIPID(sih->chip), chn, 8), CHIPREV(sih->chiprev), PMUREV(sih->pmurev)));
5187*4882a593Smuzhiyun 		break;
5188*4882a593Smuzhiyun 	}
5189*4882a593Smuzhiyun 
5190*4882a593Smuzhiyun #ifdef BCMDBG_FORCEHT
5191*4882a593Smuzhiyun 	si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), CCS_FORCEHT, CCS_FORCEHT)
5192*4882a593Smuzhiyun #endif
5193*4882a593Smuzhiyun 
5194*4882a593Smuzhiyun 	si_pmu_enb_slow_clk(sih, osh, xtalfreq);
5195*4882a593Smuzhiyun 
5196*4882a593Smuzhiyun 	/* Return to original core */
5197*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5198*4882a593Smuzhiyun } /* si_pmu_pll_init */
5199*4882a593Smuzhiyun 
5200*4882a593Smuzhiyun /** get alp clock frequency in [Hz] units */
5201*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_alp_clock)5202*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_alp_clock)(si_t *sih, osl_t *osh)
5203*4882a593Smuzhiyun {
5204*4882a593Smuzhiyun 	pmuregs_t *pmu;
5205*4882a593Smuzhiyun 	uint origidx;
5206*4882a593Smuzhiyun 	uint32 clock = ALP_CLOCK;
5207*4882a593Smuzhiyun #ifdef BCMDBG_PMU
5208*4882a593Smuzhiyun 	char chn[8];
5209*4882a593Smuzhiyun #endif
5210*4882a593Smuzhiyun 
5211*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
5212*4882a593Smuzhiyun 
5213*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5214*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5215*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5216*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5217*4882a593Smuzhiyun 	} else {
5218*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5219*4882a593Smuzhiyun 	}
5220*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5221*4882a593Smuzhiyun 
5222*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
5223*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
5224*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
5225*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
5226*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
5227*4882a593Smuzhiyun 		if (sih->chipst & CST4360_XTAL_40MZ)
5228*4882a593Smuzhiyun 			clock = 40000 * 1000;
5229*4882a593Smuzhiyun 		else
5230*4882a593Smuzhiyun 			clock = 20000 * 1000;
5231*4882a593Smuzhiyun 		break;
5232*4882a593Smuzhiyun 
5233*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
5234*4882a593Smuzhiyun 		/* always 40Mhz */
5235*4882a593Smuzhiyun 		clock = 40000 * 1000;
5236*4882a593Smuzhiyun 		break;
5237*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
5238*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
5239*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
5240*4882a593Smuzhiyun #ifndef BCMSDIOLITE
5241*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
5242*4882a593Smuzhiyun #endif /* BCMSDIOLITE */
5243*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
5244*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
5245*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
5246*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
5247*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
5248*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
5249*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
5250*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
5251*4882a593Smuzhiyun 		clock = si_pmu1_alpclk0(sih, osh, pmu);
5252*4882a593Smuzhiyun 		break;
5253*4882a593Smuzhiyun #ifdef BCMSDIOLITE
5254*4882a593Smuzhiyun 	case BCM4369_CHIP_ID:
5255*4882a593Smuzhiyun 		/* always 25Mhz */
5256*4882a593Smuzhiyun 		clock = 25000 * 1000;
5257*4882a593Smuzhiyun 		break;
5258*4882a593Smuzhiyun #endif /* BCMSDIOLITE */
5259*4882a593Smuzhiyun 	default:
5260*4882a593Smuzhiyun 		PMU_MSG(("No ALP clock specified "
5261*4882a593Smuzhiyun 			"for chip %s rev %d pmurev %d, using default %d Hz\n",
5262*4882a593Smuzhiyun 			bcm_chipname(
5263*4882a593Smuzhiyun 			CHIPID(sih->chip), chn, 8), CHIPREV(sih->chiprev),
5264*4882a593Smuzhiyun 			PMUREV(sih->pmurev), clock));
5265*4882a593Smuzhiyun 		break;
5266*4882a593Smuzhiyun 	}
5267*4882a593Smuzhiyun 
5268*4882a593Smuzhiyun 	/* Return to original core */
5269*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5270*4882a593Smuzhiyun 
5271*4882a593Smuzhiyun 	return clock; /* in [Hz] units */
5272*4882a593Smuzhiyun } /* si_pmu_alp_clock */
5273*4882a593Smuzhiyun 
5274*4882a593Smuzhiyun /**
5275*4882a593Smuzhiyun  * Find the output of the "m" pll divider given pll controls that start with
5276*4882a593Smuzhiyun  * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
5277*4882a593Smuzhiyun  */
5278*4882a593Smuzhiyun static uint32
BCMPOSTTRAPFN(si_pmu5_clock)5279*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu5_clock)(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint pll0, uint m)
5280*4882a593Smuzhiyun {
5281*4882a593Smuzhiyun 	uint32 tmp, div, ndiv, p1, p2, fc;
5282*4882a593Smuzhiyun 
5283*4882a593Smuzhiyun 	if ((pll0 & 3) || (pll0 > PMU4716_MAINPLL_PLL0)) {
5284*4882a593Smuzhiyun 		PMU_ERROR(("si_pmu5_clock: Bad pll0: %d\n", pll0));
5285*4882a593Smuzhiyun 		return 0;
5286*4882a593Smuzhiyun 	}
5287*4882a593Smuzhiyun 
5288*4882a593Smuzhiyun 	/* Strictly there is an m5 divider, but I'm not sure we use it */
5289*4882a593Smuzhiyun 	if ((m == 0) || (m > 4)) {
5290*4882a593Smuzhiyun 		PMU_ERROR(("si_pmu5_clock: Bad m divider: %d\n", m));
5291*4882a593Smuzhiyun 		return 0;
5292*4882a593Smuzhiyun 	}
5293*4882a593Smuzhiyun 
5294*4882a593Smuzhiyun 	W_REG(osh, &pmu->pllcontrol_addr, pll0 + PMU5_PLL_P1P2_OFF);
5295*4882a593Smuzhiyun 	(void)R_REG(osh, &pmu->pllcontrol_addr);
5296*4882a593Smuzhiyun 	tmp = R_REG(osh, &pmu->pllcontrol_data);
5297*4882a593Smuzhiyun 	p1 = (tmp & PMU5_PLL_P1_MASK) >> PMU5_PLL_P1_SHIFT;
5298*4882a593Smuzhiyun 	p2 = (tmp & PMU5_PLL_P2_MASK) >> PMU5_PLL_P2_SHIFT;
5299*4882a593Smuzhiyun 
5300*4882a593Smuzhiyun 	W_REG(osh, &pmu->pllcontrol_addr, pll0 + PMU5_PLL_M14_OFF);
5301*4882a593Smuzhiyun 	(void)R_REG(osh, &pmu->pllcontrol_addr);
5302*4882a593Smuzhiyun 	tmp = R_REG(osh, &pmu->pllcontrol_data);
5303*4882a593Smuzhiyun 	div = (tmp >> ((m - 1) * PMU5_PLL_MDIV_WIDTH)) & PMU5_PLL_MDIV_MASK;
5304*4882a593Smuzhiyun 
5305*4882a593Smuzhiyun 	W_REG(osh, &pmu->pllcontrol_addr, pll0 + PMU5_PLL_NM5_OFF);
5306*4882a593Smuzhiyun 	(void)R_REG(osh, &pmu->pllcontrol_addr);
5307*4882a593Smuzhiyun 	tmp = R_REG(osh, &pmu->pllcontrol_data);
5308*4882a593Smuzhiyun 	ndiv = (tmp & PMU5_PLL_NDIV_MASK) >> PMU5_PLL_NDIV_SHIFT;
5309*4882a593Smuzhiyun 
5310*4882a593Smuzhiyun 	/* Do calculation in Mhz */
5311*4882a593Smuzhiyun 	fc = si_pmu_alp_clock(sih, osh) / 1000000;
5312*4882a593Smuzhiyun 	fc = (p1 * ndiv * fc) / p2;
5313*4882a593Smuzhiyun 
5314*4882a593Smuzhiyun 	PMU_NONE(("si_pmu5_clock: p1=%d, p2=%d, ndiv=%d(0x%x), m%d=%d; fc=%d, clock=%d\n",
5315*4882a593Smuzhiyun 	          p1, p2, ndiv, ndiv, m, div, fc, fc / div));
5316*4882a593Smuzhiyun 
5317*4882a593Smuzhiyun 	/* Return clock in Hertz */
5318*4882a593Smuzhiyun 	return ((fc / div) * 1000000);
5319*4882a593Smuzhiyun } /* si_pmu5_clock */
5320*4882a593Smuzhiyun 
5321*4882a593Smuzhiyun /**
5322*4882a593Smuzhiyun  * Get backplane clock frequency, returns a value in [hz] units.
5323*4882a593Smuzhiyun  * For designs that feed the same clock to both backplane and CPU just return the CPU clock speed.
5324*4882a593Smuzhiyun  */
5325*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_si_clock)5326*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_si_clock)(si_t *sih, osl_t *osh)
5327*4882a593Smuzhiyun {
5328*4882a593Smuzhiyun 	pmuregs_t *pmu;
5329*4882a593Smuzhiyun 	uint origidx;
5330*4882a593Smuzhiyun 	uint32 clock = HT_CLOCK;	/* in [hz] units */
5331*4882a593Smuzhiyun #ifdef BCMDBG_PMU
5332*4882a593Smuzhiyun 	char chn[8];
5333*4882a593Smuzhiyun #endif
5334*4882a593Smuzhiyun 
5335*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
5336*4882a593Smuzhiyun 
5337*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5338*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5339*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5340*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5341*4882a593Smuzhiyun 	} else {
5342*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5343*4882a593Smuzhiyun 	}
5344*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5345*4882a593Smuzhiyun 
5346*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
5347*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
5348*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
5349*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
5350*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
5351*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
5352*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
5353*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
5354*4882a593Smuzhiyun 		clock = si_pmu1_cpuclk0(sih, osh, pmu);
5355*4882a593Smuzhiyun 		break;
5356*4882a593Smuzhiyun 
5357*4882a593Smuzhiyun 	CASE_BCM43602_CHIP: {
5358*4882a593Smuzhiyun 			uint32 mdiv;
5359*4882a593Smuzhiyun 			/* Ch3 is connected to backplane_clk. Read 'bbpll_i_m3div' from pllctl[4] */
5360*4882a593Smuzhiyun 			mdiv = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG4, 0, 0);
5361*4882a593Smuzhiyun 			mdiv = (mdiv & PMU1_PLL0_PC1_M3DIV_MASK) >> PMU1_PLL0_PC1_M3DIV_SHIFT;
5362*4882a593Smuzhiyun 			ASSERT(mdiv != 0);
5363*4882a593Smuzhiyun 			clock = si_pmu1_pllfvco0(sih) / mdiv * 1000;
5364*4882a593Smuzhiyun 			break;
5365*4882a593Smuzhiyun 		}
5366*4882a593Smuzhiyun 
5367*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
5368*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
5369*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
5370*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
5371*4882a593Smuzhiyun 		clock = si_pmu1_cpuclk0(sih, osh, pmu);
5372*4882a593Smuzhiyun 		break;
5373*4882a593Smuzhiyun 
5374*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
5375*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
5376*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
5377*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
5378*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
5379*4882a593Smuzhiyun 		clock = si_pmu_bpclk_4387(sih);
5380*4882a593Smuzhiyun 		break;
5381*4882a593Smuzhiyun 
5382*4882a593Smuzhiyun 	default:
5383*4882a593Smuzhiyun 		PMU_MSG(("No backplane clock specified "
5384*4882a593Smuzhiyun 			"for chip %s rev %d pmurev %d, using default %d Hz\n",
5385*4882a593Smuzhiyun 			bcm_chipname(
5386*4882a593Smuzhiyun 			CHIPID(sih->chip), chn, 8), CHIPREV(sih->chiprev),
5387*4882a593Smuzhiyun 			PMUREV(sih->pmurev), clock));
5388*4882a593Smuzhiyun 		break;
5389*4882a593Smuzhiyun 	}
5390*4882a593Smuzhiyun 
5391*4882a593Smuzhiyun 	/* Return to original core */
5392*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5393*4882a593Smuzhiyun 
5394*4882a593Smuzhiyun 	return clock;
5395*4882a593Smuzhiyun } /* si_pmu_si_clock */
5396*4882a593Smuzhiyun 
5397*4882a593Smuzhiyun /** returns CPU clock frequency in [hz] units */
5398*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_cpu_clock)5399*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_cpu_clock)(si_t *sih, osl_t *osh)
5400*4882a593Smuzhiyun {
5401*4882a593Smuzhiyun 	pmuregs_t *pmu;
5402*4882a593Smuzhiyun 	uint origidx;
5403*4882a593Smuzhiyun 	uint32 clock;	/* in [hz] units */
5404*4882a593Smuzhiyun 
5405*4882a593Smuzhiyun 	uint32 tmp;
5406*4882a593Smuzhiyun 	uint32 armclk_offcnt, armclk_oncnt;
5407*4882a593Smuzhiyun 
5408*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
5409*4882a593Smuzhiyun 
5410*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5411*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5412*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5413*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5414*4882a593Smuzhiyun 	} else {
5415*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5416*4882a593Smuzhiyun 	}
5417*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5418*4882a593Smuzhiyun 
5419*4882a593Smuzhiyun 	if (BCM4369_CHIP(sih->chip) ||
5420*4882a593Smuzhiyun 		BCM4376_CHIP(sih->chip) ||
5421*4882a593Smuzhiyun 		BCM4378_CHIP(sih->chip) ||
5422*4882a593Smuzhiyun 		BCM4385_CHIP(sih->chip) ||
5423*4882a593Smuzhiyun 		BCM4387_CHIP(sih->chip) ||
5424*4882a593Smuzhiyun 		BCM4388_CHIP(sih->chip) ||
5425*4882a593Smuzhiyun 		BCM4389_CHIP(sih->chip) ||
5426*4882a593Smuzhiyun 		BCM4397_CHIP(sih->chip) ||
5427*4882a593Smuzhiyun 		BCM4362_CHIP(sih->chip)) {
5428*4882a593Smuzhiyun 		clock = si_pmu1_cpuclk0_pll2(sih); /* for chips with separate CPU PLL */
5429*4882a593Smuzhiyun 	} else if ((PMUREV(sih->pmurev) >= 5) &&
5430*4882a593Smuzhiyun 		!((CHIPID(sih->chip) == BCM4360_CHIP_ID) ||
5431*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM4352_CHIP_ID) ||
5432*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43526_CHIP_ID) ||
5433*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43460_CHIP_ID) ||
5434*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
5435*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
5436*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID) ||
5437*4882a593Smuzhiyun 		0)) {
5438*4882a593Smuzhiyun 		uint pll = PMU4716_MAINPLL_PLL0;
5439*4882a593Smuzhiyun 
5440*4882a593Smuzhiyun 		if (BCM43602_CHIP(sih->chip)) {
5441*4882a593Smuzhiyun 			clock = si_pmu1_cpuclk0(sih, osh, pmu);
5442*4882a593Smuzhiyun 		} else {
5443*4882a593Smuzhiyun 			clock = si_pmu5_clock(sih, osh, pmu, pll, PMU5_MAINPLL_CPU);
5444*4882a593Smuzhiyun 		}
5445*4882a593Smuzhiyun 	} else {
5446*4882a593Smuzhiyun 		clock = si_pmu_si_clock(sih, osh);
5447*4882a593Smuzhiyun 	}
5448*4882a593Smuzhiyun 
5449*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
5450*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
5451*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID)) {
5452*4882a593Smuzhiyun 		/* Fout = (on_count + 1) * Fin/(on_count + 1 + off_count)
5453*4882a593Smuzhiyun 		* ARM clock using Fast divider calculation
5454*4882a593Smuzhiyun 		* Fin = FVCO/2
5455*4882a593Smuzhiyun 		*/
5456*4882a593Smuzhiyun 		tmp = si_pmu_chipcontrol(sih, PMU1_PLL0_CHIPCTL1, 0, 0);
5457*4882a593Smuzhiyun 		armclk_offcnt =
5458*4882a593Smuzhiyun 			(tmp & CCTL_43012_ARM_OFFCOUNT_MASK) >> CCTL_43012_ARM_OFFCOUNT_SHIFT;
5459*4882a593Smuzhiyun 		armclk_oncnt =
5460*4882a593Smuzhiyun 			(tmp & CCTL_43012_ARM_ONCOUNT_MASK) >> CCTL_43012_ARM_ONCOUNT_SHIFT;
5461*4882a593Smuzhiyun 		clock = (armclk_oncnt + 1) * clock/(armclk_oncnt + 1 + armclk_offcnt);
5462*4882a593Smuzhiyun 	}
5463*4882a593Smuzhiyun 
5464*4882a593Smuzhiyun 	/* Return to original core */
5465*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5466*4882a593Smuzhiyun 	return clock;
5467*4882a593Smuzhiyun } /* si_pmu_cpu_clock */
5468*4882a593Smuzhiyun 
5469*4882a593Smuzhiyun #ifdef __ARM_ARCH_7A__
5470*4882a593Smuzhiyun static uint32
si_pmu_mem_ca7clock(si_t * sih,osl_t * osh)5471*4882a593Smuzhiyun si_pmu_mem_ca7clock(si_t *sih, osl_t *osh)
5472*4882a593Smuzhiyun {
5473*4882a593Smuzhiyun 	uint32 clock = 0;
5474*4882a593Smuzhiyun 	int8 mdiv = 1;
5475*4882a593Smuzhiyun 	uint idx = si_coreidx(sih);
5476*4882a593Smuzhiyun 	bool fastclk;
5477*4882a593Smuzhiyun 	ca7regs_t *regs = si_setcore(sih, ARMCA7_CORE_ID, 0);
5478*4882a593Smuzhiyun 
5479*4882a593Smuzhiyun 	if (regs == NULL) {
5480*4882a593Smuzhiyun 		goto end;
5481*4882a593Smuzhiyun 	}
5482*4882a593Smuzhiyun 
5483*4882a593Smuzhiyun 	fastclk = ((R_REG(osh, ARMREG(regs, clk_ctl_st)) & CCS_ARMFASTCLOCKREQ) != 0);
5484*4882a593Smuzhiyun 
5485*4882a593Smuzhiyun 	if (fastclk) {
5486*4882a593Smuzhiyun 		uint32 fvco = si_pmu_pll28nm_fvco(sih);
5487*4882a593Smuzhiyun 		if (si_corerev(sih) >= 7) {
5488*4882a593Smuzhiyun 			mdiv = (R_REG(osh, ARMREG(regs, corecontrol)) & ACC_CLOCKRATIO_MASK) >>
5489*4882a593Smuzhiyun 				ACC_CLOCKRATIO_SHIFT;
5490*4882a593Smuzhiyun 		} else {
5491*4882a593Smuzhiyun 			ASSERT(0);
5492*4882a593Smuzhiyun 		}
5493*4882a593Smuzhiyun 
5494*4882a593Smuzhiyun 		if (mdiv == 0) {
5495*4882a593Smuzhiyun 			ASSERT(0);
5496*4882a593Smuzhiyun 			clock = 0;
5497*4882a593Smuzhiyun 		} else {
5498*4882a593Smuzhiyun 			clock = (fvco / mdiv);
5499*4882a593Smuzhiyun 		}
5500*4882a593Smuzhiyun 	} else {
5501*4882a593Smuzhiyun 		clock = si_pmu_si_clock(sih, osh);
5502*4882a593Smuzhiyun 	}
5503*4882a593Smuzhiyun 
5504*4882a593Smuzhiyun end:
5505*4882a593Smuzhiyun 	si_setcoreidx(sih, idx);
5506*4882a593Smuzhiyun 	return clock;
5507*4882a593Smuzhiyun 
5508*4882a593Smuzhiyun }
5509*4882a593Smuzhiyun #endif /* __ARM_ARCH_7A__ */
5510*4882a593Smuzhiyun 
5511*4882a593Smuzhiyun /** get memory clock frequency, which is the same as the HT clock for newer chips. Returns [Hz]. */
5512*4882a593Smuzhiyun uint32
BCMINITFN(si_pmu_mem_clock)5513*4882a593Smuzhiyun BCMINITFN(si_pmu_mem_clock)(si_t *sih, osl_t *osh)
5514*4882a593Smuzhiyun {
5515*4882a593Smuzhiyun 	pmuregs_t *pmu;
5516*4882a593Smuzhiyun 	uint origidx;
5517*4882a593Smuzhiyun 	uint32 clock;
5518*4882a593Smuzhiyun 
5519*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
5520*4882a593Smuzhiyun 
5521*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5522*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5523*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5524*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5525*4882a593Smuzhiyun 	} else {
5526*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5527*4882a593Smuzhiyun 	}
5528*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5529*4882a593Smuzhiyun 
5530*4882a593Smuzhiyun 	if ((PMUREV(sih->pmurev) >= 5) &&
5531*4882a593Smuzhiyun 		!((BCM4369_CHIP(sih->chip)) ||
5532*4882a593Smuzhiyun 		(BCM4362_CHIP(sih->chip)) ||
5533*4882a593Smuzhiyun 		BCM43602_CHIP(sih->chip) ||
5534*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
5535*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
5536*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID) ||
5537*4882a593Smuzhiyun 		BCM4376_CHIP(sih->chip) ||
5538*4882a593Smuzhiyun 		BCM4378_CHIP(sih->chip) ||
5539*4882a593Smuzhiyun 		BCM4387_CHIP(sih->chip) ||
5540*4882a593Smuzhiyun 		BCM4388_CHIP(sih->chip) ||
5541*4882a593Smuzhiyun 		BCM4389_CHIP(sih->chip) ||
5542*4882a593Smuzhiyun 		BCM4397_CHIP(sih->chip) ||
5543*4882a593Smuzhiyun 		0)) {
5544*4882a593Smuzhiyun 		uint pll = PMU4716_MAINPLL_PLL0;
5545*4882a593Smuzhiyun 
5546*4882a593Smuzhiyun 		clock = si_pmu5_clock(sih, osh, pmu, pll, PMU5_MAINPLL_MEM);
5547*4882a593Smuzhiyun 	} else {
5548*4882a593Smuzhiyun #ifdef __ARM_ARCH_7A__
5549*4882a593Smuzhiyun 		clock = si_pmu_mem_ca7clock(sih, osh);
5550*4882a593Smuzhiyun #else /* !__ARM_ARCH_7A__ */
5551*4882a593Smuzhiyun 		clock = si_pmu_si_clock(sih, osh); /* mem clk same as backplane clk */
5552*4882a593Smuzhiyun #endif /* __ARM_ARCH_7A__ */
5553*4882a593Smuzhiyun 	}
5554*4882a593Smuzhiyun 	/* Return to original core */
5555*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5556*4882a593Smuzhiyun 	return clock;
5557*4882a593Smuzhiyun } /* si_pmu_mem_clock */
5558*4882a593Smuzhiyun 
5559*4882a593Smuzhiyun /*
5560*4882a593Smuzhiyun  * ilpcycles per sec are now calculated during CPU init in a new way
5561*4882a593Smuzhiyun  * for better accuracy.  We set it here for compatability.
5562*4882a593Smuzhiyun  *
5563*4882a593Smuzhiyun  * On platforms that do not do this we resort to the old way.
5564*4882a593Smuzhiyun  */
5565*4882a593Smuzhiyun 
5566*4882a593Smuzhiyun #define ILP_CALC_DUR	10	/* ms, make sure 1000 can be divided by it. */
5567*4882a593Smuzhiyun 
5568*4882a593Smuzhiyun static uint32 ilpcycles_per_sec = 0;
5569*4882a593Smuzhiyun 
5570*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_pmu_ilp_clock_set)5571*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_ilp_clock_set)(uint32 cycles_per_sec)
5572*4882a593Smuzhiyun {
5573*4882a593Smuzhiyun 	ilpcycles_per_sec = cycles_per_sec;
5574*4882a593Smuzhiyun }
5575*4882a593Smuzhiyun 
5576*4882a593Smuzhiyun /**
5577*4882a593Smuzhiyun  * Measure ILP clock frequency. Returns a value in [Hz] units.
5578*4882a593Smuzhiyun  *
5579*4882a593Smuzhiyun  * The variable ilpcycles_per_sec is used to store the ILP clock speed. The value
5580*4882a593Smuzhiyun  * is calculated when the function is called the first time and then cached.
5581*4882a593Smuzhiyun  * The change in PMU timer count is measured across a delay of ILP_CALC_DUR msec.
5582*4882a593Smuzhiyun  * Before the first time the function is called, one must make sure the HT clock is
5583*4882a593Smuzhiyun  * turned on and used to feed the CPU and that OSL_DELAY() is calibrated.
5584*4882a593Smuzhiyun  */
5585*4882a593Smuzhiyun uint32
BCMINITFN(si_pmu_ilp_clock)5586*4882a593Smuzhiyun BCMINITFN(si_pmu_ilp_clock)(si_t *sih, osl_t *osh)
5587*4882a593Smuzhiyun {
5588*4882a593Smuzhiyun 	if (ISSIM_ENAB(sih))
5589*4882a593Smuzhiyun 		return ILP_CLOCK;
5590*4882a593Smuzhiyun 
5591*4882a593Smuzhiyun 	if (ilpcycles_per_sec == 0) {
5592*4882a593Smuzhiyun 		uint32 start, end, delta;
5593*4882a593Smuzhiyun 		pmuregs_t *pmu;
5594*4882a593Smuzhiyun 		uint origidx = si_coreidx(sih);
5595*4882a593Smuzhiyun 
5596*4882a593Smuzhiyun 		if (AOB_ENAB(sih)) {
5597*4882a593Smuzhiyun 			pmu = si_setcore(sih, PMU_CORE_ID, 0);
5598*4882a593Smuzhiyun 		} else {
5599*4882a593Smuzhiyun 			pmu = si_setcoreidx(sih, SI_CC_IDX);
5600*4882a593Smuzhiyun 		}
5601*4882a593Smuzhiyun 		ASSERT(pmu != NULL);
5602*4882a593Smuzhiyun 		start = R_REG(osh, &pmu->pmutimer);
5603*4882a593Smuzhiyun 		/* PR88659: verify pmutimer reads */
5604*4882a593Smuzhiyun 		if (start != R_REG(osh, &pmu->pmutimer))
5605*4882a593Smuzhiyun 			start = R_REG(osh, &pmu->pmutimer);
5606*4882a593Smuzhiyun 		OSL_DELAY(ILP_CALC_DUR * 1000);
5607*4882a593Smuzhiyun 		end = R_REG(osh, &pmu->pmutimer);
5608*4882a593Smuzhiyun 		if (end != R_REG(osh, &pmu->pmutimer))
5609*4882a593Smuzhiyun 			end = R_REG(osh, &pmu->pmutimer);
5610*4882a593Smuzhiyun 		delta = end - start;
5611*4882a593Smuzhiyun 		ilpcycles_per_sec = delta * (1000 / ILP_CALC_DUR);
5612*4882a593Smuzhiyun 		/* Return to original core */
5613*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
5614*4882a593Smuzhiyun 	}
5615*4882a593Smuzhiyun 
5616*4882a593Smuzhiyun 	ASSERT(ilpcycles_per_sec != 0);
5617*4882a593Smuzhiyun 	return ilpcycles_per_sec;
5618*4882a593Smuzhiyun }
5619*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
5620*4882a593Smuzhiyun 
5621*4882a593Smuzhiyun /**
5622*4882a593Smuzhiyun  * Reads/writes a chipcontrol reg. Performes core switching if required, at function exit the
5623*4882a593Smuzhiyun  * original core is restored. Depending on chip type, read/writes to chipcontrol regs in CC core
5624*4882a593Smuzhiyun  * (older chips) or to chipcontrol regs in PMU core (later chips).
5625*4882a593Smuzhiyun  */
5626*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_chipcontrol)5627*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_chipcontrol)(si_t *sih, uint reg, uint32 mask, uint32 val)
5628*4882a593Smuzhiyun {
5629*4882a593Smuzhiyun 	pmu_corereg(sih, SI_CC_IDX, chipcontrol_addr, ~0, reg);
5630*4882a593Smuzhiyun 	return pmu_corereg(sih, SI_CC_IDX, chipcontrol_data, mask, val);
5631*4882a593Smuzhiyun }
5632*4882a593Smuzhiyun 
5633*4882a593Smuzhiyun /**
5634*4882a593Smuzhiyun  * Reads/writes a voltage regulator (vreg) register. Performes core switching if required, at
5635*4882a593Smuzhiyun  * function exit the original core is restored. Depending on chip type, writes to regulator regs
5636*4882a593Smuzhiyun  * in CC core (older chips) or to regulator regs in PMU core (later chips).
5637*4882a593Smuzhiyun  */
5638*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_vreg_control)5639*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_vreg_control)(si_t *sih, uint reg, uint32 mask, uint32 val)
5640*4882a593Smuzhiyun {
5641*4882a593Smuzhiyun 	pmu_corereg(sih, SI_CC_IDX, regcontrol_addr, ~0, reg);
5642*4882a593Smuzhiyun 	return pmu_corereg(sih, SI_CC_IDX, regcontrol_data, mask, val);
5643*4882a593Smuzhiyun }
5644*4882a593Smuzhiyun 
5645*4882a593Smuzhiyun /**
5646*4882a593Smuzhiyun  * Reads/writes a PLL control register. Performes core switching if required, at function exit the
5647*4882a593Smuzhiyun  * original core is restored. Depending on chip type, writes to PLL control regs in CC core (older
5648*4882a593Smuzhiyun  * chips) or to PLL control regs in PMU core (later chips).
5649*4882a593Smuzhiyun  */
5650*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_pllcontrol)5651*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_pllcontrol)(si_t *sih, uint reg, uint32 mask, uint32 val)
5652*4882a593Smuzhiyun {
5653*4882a593Smuzhiyun 	pmu_corereg(sih, SI_CC_IDX, pllcontrol_addr, ~0, reg);
5654*4882a593Smuzhiyun 	return pmu_corereg(sih, SI_CC_IDX, pllcontrol_data, mask, val);
5655*4882a593Smuzhiyun }
5656*4882a593Smuzhiyun 
5657*4882a593Smuzhiyun /**
5658*4882a593Smuzhiyun  * Balance between stable SDIO operation and power consumption is achieved using this function.
5659*4882a593Smuzhiyun  * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this
5660*4882a593Smuzhiyun  * function should read the VDDIO itself to select the correct table. For now it has been solved
5661*4882a593Smuzhiyun  * with the 'BCM_SDIO_VDDIO' preprocessor constant.
5662*4882a593Smuzhiyun  *
5663*4882a593Smuzhiyun  * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if
5664*4882a593Smuzhiyun  *		    hardware supports this), if no hw support drive strength is not programmed.
5665*4882a593Smuzhiyun  */
5666*4882a593Smuzhiyun void
BCMINITFN(si_sdiod_drive_strength_init)5667*4882a593Smuzhiyun BCMINITFN(si_sdiod_drive_strength_init)(si_t *sih, osl_t *osh, uint32 drivestrength)
5668*4882a593Smuzhiyun {
5669*4882a593Smuzhiyun 	/*
5670*4882a593Smuzhiyun 	 * Note:
5671*4882a593Smuzhiyun 	 * This function used to set the SDIO drive strength via PMU_CHIPCTL1 for the
5672*4882a593Smuzhiyun 	 * 43143, 4330, 4334, 4336, 43362 chips.  These chips are now no longer supported, so
5673*4882a593Smuzhiyun 	 * the code has been deleted.
5674*4882a593Smuzhiyun 	 * Newer chips have the SDIO drive strength setting via a GCI Chip Control register,
5675*4882a593Smuzhiyun 	 * but the bit definitions are chip-specific.  We are keeping this function available
5676*4882a593Smuzhiyun 	 * (accessed via DHD 'sdiod_drive' IOVar) in case these newer chips need to provide access.
5677*4882a593Smuzhiyun 	 */
5678*4882a593Smuzhiyun 	UNUSED_PARAMETER(sih);
5679*4882a593Smuzhiyun 	UNUSED_PARAMETER(osh);
5680*4882a593Smuzhiyun 	UNUSED_PARAMETER(drivestrength);
5681*4882a593Smuzhiyun }
5682*4882a593Smuzhiyun 
5683*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
5684*4882a593Smuzhiyun /** initialize PMU */
5685*4882a593Smuzhiyun void
BCMATTACHFN(si_pmu_init)5686*4882a593Smuzhiyun BCMATTACHFN(si_pmu_init)(si_t *sih, osl_t *osh)
5687*4882a593Smuzhiyun {
5688*4882a593Smuzhiyun 	pmuregs_t *pmu;
5689*4882a593Smuzhiyun 	uint origidx;
5690*4882a593Smuzhiyun 
5691*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
5692*4882a593Smuzhiyun 
5693*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5694*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5695*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5696*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5697*4882a593Smuzhiyun 	} else {
5698*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5699*4882a593Smuzhiyun 	}
5700*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5701*4882a593Smuzhiyun 
5702*4882a593Smuzhiyun #if defined(BT_WLAN_REG_ON_WAR)
5703*4882a593Smuzhiyun 	si_pmu_reg_on_war_ext_wake_perst_clear(sih);
5704*4882a593Smuzhiyun 	si_pmu_reg_on_war_ext_wake_perst_set(sih);
5705*4882a593Smuzhiyun #endif /* BT_WLAN_REG_ON_WAR */
5706*4882a593Smuzhiyun 
5707*4882a593Smuzhiyun 	/* Feature is added in PMU rev. 1 but doesn't work until rev. 2 */
5708*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) == 1)
5709*4882a593Smuzhiyun 		AND_REG(osh, &pmu->pmucontrol, ~PCTL_NOILP_ON_WAIT);
5710*4882a593Smuzhiyun 	else if (PMUREV(sih->pmurev) >= 2)
5711*4882a593Smuzhiyun 		OR_REG(osh, &pmu->pmucontrol, PCTL_NOILP_ON_WAIT);
5712*4882a593Smuzhiyun 
5713*4882a593Smuzhiyun 	/* Changes from PMU revision 26 are not included in revision 27 */
5714*4882a593Smuzhiyun 	if ((PMUREV(sih->pmurev) >= 26) && (PMUREV(sih->pmurev) != 27)) {
5715*4882a593Smuzhiyun 		uint32 val = PMU_INTC_ALP_REQ | PMU_INTC_HT_REQ | PMU_INTC_HQ_REQ;
5716*4882a593Smuzhiyun 		pmu_corereg(sih, SI_CC_IDX, pmuintctrl0, val, val);
5717*4882a593Smuzhiyun 
5718*4882a593Smuzhiyun 		val = RSRC_INTR_MASK_TIMER_INT_0;
5719*4882a593Smuzhiyun 		pmu_corereg(sih, SI_CC_IDX, pmuintmask0, val, val);
5720*4882a593Smuzhiyun 		(void)pmu_corereg(sih, SI_CC_IDX, pmuintmask0, 0, 0);
5721*4882a593Smuzhiyun 	}
5722*4882a593Smuzhiyun 
5723*4882a593Smuzhiyun 	/* Return to original core */
5724*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5725*4882a593Smuzhiyun }
5726*4882a593Smuzhiyun 
5727*4882a593Smuzhiyun uint32
si_pmu_rsrc_macphy_clk_deps(si_t * sih,osl_t * osh,int macunit)5728*4882a593Smuzhiyun si_pmu_rsrc_macphy_clk_deps(si_t *sih, osl_t *osh, int macunit)
5729*4882a593Smuzhiyun {
5730*4882a593Smuzhiyun 	uint32 deps = 0;
5731*4882a593Smuzhiyun 	rsc_per_chip_t *rsc;
5732*4882a593Smuzhiyun 	uint origidx;
5733*4882a593Smuzhiyun 	pmuregs_t *pmu = NULL;
5734*4882a593Smuzhiyun 	uint8 rsc_num;
5735*4882a593Smuzhiyun 
5736*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5737*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5738*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5739*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5740*4882a593Smuzhiyun 	} else {
5741*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5742*4882a593Smuzhiyun 	}
5743*4882a593Smuzhiyun 
5744*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5745*4882a593Smuzhiyun 
5746*4882a593Smuzhiyun 	rsc = si_pmu_get_rsc_positions(sih);
5747*4882a593Smuzhiyun 	if (macunit == 0) {
5748*4882a593Smuzhiyun 		rsc_num = rsc->macphy_clkavail;
5749*4882a593Smuzhiyun 	} else if (macunit == 1) {
5750*4882a593Smuzhiyun 		rsc_num = rsc->macphy_aux_clkavail;
5751*4882a593Smuzhiyun 	} else if (macunit == 2) {
5752*4882a593Smuzhiyun 		rsc_num = rsc->macphy_scan_clkavail;
5753*4882a593Smuzhiyun 	} else {
5754*4882a593Smuzhiyun 		PMU_ERROR(("si_pmu_rsrc_macphy_clk_deps: slice %d is not supported\n", macunit));
5755*4882a593Smuzhiyun 		rsc_num = NO_SUCH_RESOURCE;	/* to satisfy the compiler */
5756*4882a593Smuzhiyun 		ASSERT(0);
5757*4882a593Smuzhiyun 	}
5758*4882a593Smuzhiyun 	deps = si_pmu_res_deps(sih, osh, pmu, PMURES_BIT(rsc_num), TRUE);
5759*4882a593Smuzhiyun 	deps |= PMURES_BIT(rsc_num);
5760*4882a593Smuzhiyun 
5761*4882a593Smuzhiyun 	/* Return to original core */
5762*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5763*4882a593Smuzhiyun 
5764*4882a593Smuzhiyun 	return deps;
5765*4882a593Smuzhiyun }
5766*4882a593Smuzhiyun 
5767*4882a593Smuzhiyun void
si_pmu_set_mac_rsrc_req_sc(si_t * sih,osl_t * osh)5768*4882a593Smuzhiyun si_pmu_set_mac_rsrc_req_sc(si_t *sih, osl_t *osh)
5769*4882a593Smuzhiyun {
5770*4882a593Smuzhiyun 	uint32 deps = 0;
5771*4882a593Smuzhiyun 	rsc_per_chip_t *rsc;
5772*4882a593Smuzhiyun 	uint origidx;
5773*4882a593Smuzhiyun 	pmuregs_t *pmu = NULL;
5774*4882a593Smuzhiyun 	uint32 rsrc = 0;
5775*4882a593Smuzhiyun 
5776*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5777*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5778*4882a593Smuzhiyun 	pmu = si_setcore(sih, PMU_CORE_ID, 0);
5779*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5780*4882a593Smuzhiyun 
5781*4882a593Smuzhiyun 	rsc = si_pmu_get_rsc_positions(sih);
5782*4882a593Smuzhiyun 
5783*4882a593Smuzhiyun 	rsrc = (PMURES_BIT(rsc->macphy_scan_clkavail) |
5784*4882a593Smuzhiyun 		PMURES_BIT(rsc->dig_ready));
5785*4882a593Smuzhiyun 
5786*4882a593Smuzhiyun 	deps = si_pmu_res_deps(sih, osh, pmu, rsrc, TRUE);
5787*4882a593Smuzhiyun 	deps |= rsrc;
5788*4882a593Smuzhiyun 
5789*4882a593Smuzhiyun 	W_REG(osh, &pmu->mac_res_req_timer2, PMU32_MAC_SCAN_RSRC_REQ_TIMER);
5790*4882a593Smuzhiyun 	W_REG(osh, &pmu->mac_res_req_mask2, deps);
5791*4882a593Smuzhiyun 
5792*4882a593Smuzhiyun 	/* Return to original core */
5793*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5794*4882a593Smuzhiyun }
5795*4882a593Smuzhiyun 
5796*4882a593Smuzhiyun uint32
BCMATTACHFN(si_pmu_rsrc_ht_avail_clk_deps)5797*4882a593Smuzhiyun BCMATTACHFN(si_pmu_rsrc_ht_avail_clk_deps)(si_t *sih, osl_t *osh)
5798*4882a593Smuzhiyun {
5799*4882a593Smuzhiyun 	uint32 deps;
5800*4882a593Smuzhiyun 	rsc_per_chip_t *rsc;
5801*4882a593Smuzhiyun 	uint origidx;
5802*4882a593Smuzhiyun 	pmuregs_t *pmu = NULL;
5803*4882a593Smuzhiyun 
5804*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5805*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5806*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5807*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5808*4882a593Smuzhiyun 	} else {
5809*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5810*4882a593Smuzhiyun 	}
5811*4882a593Smuzhiyun 
5812*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5813*4882a593Smuzhiyun 
5814*4882a593Smuzhiyun 	rsc = si_pmu_get_rsc_positions(sih);
5815*4882a593Smuzhiyun 	deps = si_pmu_res_deps(sih, osh, pmu, PMURES_BIT(rsc->ht_avail), FALSE);
5816*4882a593Smuzhiyun 	deps |= PMURES_BIT(rsc->ht_avail);
5817*4882a593Smuzhiyun 
5818*4882a593Smuzhiyun 	/* Return to original core */
5819*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5820*4882a593Smuzhiyun 
5821*4882a593Smuzhiyun 	return deps;
5822*4882a593Smuzhiyun }
5823*4882a593Smuzhiyun 
5824*4882a593Smuzhiyun uint32
BCMATTACHFN(si_pmu_rsrc_cb_ready_deps)5825*4882a593Smuzhiyun BCMATTACHFN(si_pmu_rsrc_cb_ready_deps)(si_t *sih, osl_t *osh)
5826*4882a593Smuzhiyun {
5827*4882a593Smuzhiyun 	uint32 deps;
5828*4882a593Smuzhiyun 	rsc_per_chip_t *rsc;
5829*4882a593Smuzhiyun 	uint origidx;
5830*4882a593Smuzhiyun 	pmuregs_t *pmu = NULL;
5831*4882a593Smuzhiyun 
5832*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5833*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5834*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5835*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5836*4882a593Smuzhiyun 	} else {
5837*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5838*4882a593Smuzhiyun 	}
5839*4882a593Smuzhiyun 
5840*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5841*4882a593Smuzhiyun 
5842*4882a593Smuzhiyun 	rsc = si_pmu_get_rsc_positions(sih);
5843*4882a593Smuzhiyun 	if (rsc->cb_ready == NO_SUCH_RESOURCE) {
5844*4882a593Smuzhiyun 		deps = 0;
5845*4882a593Smuzhiyun 	} else {
5846*4882a593Smuzhiyun 		deps = si_pmu_res_deps(sih, osh, pmu, PMURES_BIT(rsc->cb_ready), FALSE);
5847*4882a593Smuzhiyun 		deps |= PMURES_BIT(rsc->cb_ready);
5848*4882a593Smuzhiyun 	}
5849*4882a593Smuzhiyun 
5850*4882a593Smuzhiyun 	/* Return to original core */
5851*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5852*4882a593Smuzhiyun 
5853*4882a593Smuzhiyun 	return deps;
5854*4882a593Smuzhiyun }
5855*4882a593Smuzhiyun 
5856*4882a593Smuzhiyun void
si_pmu_set_mac_rsrc_req(si_t * sih,int macunit)5857*4882a593Smuzhiyun si_pmu_set_mac_rsrc_req(si_t *sih, int macunit)
5858*4882a593Smuzhiyun {
5859*4882a593Smuzhiyun 	pmuregs_t *pmu;
5860*4882a593Smuzhiyun 	uint origidx;
5861*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
5862*4882a593Smuzhiyun 
5863*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
5864*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
5865*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5866*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
5867*4882a593Smuzhiyun 	} else {
5868*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
5869*4882a593Smuzhiyun 	}
5870*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
5871*4882a593Smuzhiyun 
5872*4882a593Smuzhiyun 	if (macunit == 0) {
5873*4882a593Smuzhiyun 		W_REG(osh, &pmu->mac_res_req_timer, PMU32_MAC_MAIN_RSRC_REQ_TIMER);
5874*4882a593Smuzhiyun 		W_REG(osh, &pmu->mac_res_req_mask, si_pmu_rsrc_macphy_clk_deps(sih, osh, macunit));
5875*4882a593Smuzhiyun 	} else if (macunit == 1) {
5876*4882a593Smuzhiyun 		W_REG(osh, &pmu->mac_res_req_timer1, PMU32_MAC_AUX_RSRC_REQ_TIMER);
5877*4882a593Smuzhiyun 		W_REG(osh, &pmu->mac_res_req_mask1, si_pmu_rsrc_macphy_clk_deps(sih, osh, macunit));
5878*4882a593Smuzhiyun 	} else if (macunit == 2) {
5879*4882a593Smuzhiyun 		W_REG(osh, &pmu->mac_res_req_timer2, PMU32_MAC_SCAN_RSRC_REQ_TIMER);
5880*4882a593Smuzhiyun 		W_REG(osh, &pmu->mac_res_req_mask2, si_pmu_rsrc_macphy_clk_deps(sih, osh, macunit));
5881*4882a593Smuzhiyun 	}
5882*4882a593Smuzhiyun 
5883*4882a593Smuzhiyun 	/* Return to original core */
5884*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
5885*4882a593Smuzhiyun }
5886*4882a593Smuzhiyun 
5887*4882a593Smuzhiyun /**
5888*4882a593Smuzhiyun  * Return worst case up time in [ILP cycles] for the given resource.
5889*4882a593Smuzhiyun  *
5890*4882a593Smuzhiyun  * Example use case: the d11 core needs to be programmed with the max time it
5891*4882a593Smuzhiyun  * takes to make the HT clock available.
5892*4882a593Smuzhiyun  *
5893*4882a593Smuzhiyun  * need to check circular dependancies and prevent dead recursion.
5894*4882a593Smuzhiyun  */
5895*4882a593Smuzhiyun static uint
BCMINITFN(si_pmu_res_uptime)5896*4882a593Smuzhiyun BCMINITFN(si_pmu_res_uptime)(si_t *sih, osl_t *osh,
5897*4882a593Smuzhiyun 	pmuregs_t *pmu, uint8 rsrc, bool pmu_fast_trans_en)
5898*4882a593Smuzhiyun {
5899*4882a593Smuzhiyun 	uint32 deps;
5900*4882a593Smuzhiyun 	uint uptime, i, dup, dmax, uptrans, ret;
5901*4882a593Smuzhiyun 	uint32 min_mask = 0;
5902*4882a593Smuzhiyun #ifndef SR_DEBUG
5903*4882a593Smuzhiyun 	uint32 max_mask = 0;
5904*4882a593Smuzhiyun #endif /* SR_DEBUG */
5905*4882a593Smuzhiyun 
5906*4882a593Smuzhiyun 	/* uptime of resource 'rsrc' */
5907*4882a593Smuzhiyun 	W_REG(osh, &pmu->res_table_sel, rsrc);
5908*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 30)
5909*4882a593Smuzhiyun 		uptime = (R_REG(osh, &pmu->res_updn_timer) >> 16) & 0x7fff;
5910*4882a593Smuzhiyun 	else if (PMUREV(sih->pmurev) >= 13)
5911*4882a593Smuzhiyun 		uptime = (R_REG(osh, &pmu->res_updn_timer) >> 16) & 0x3ff;
5912*4882a593Smuzhiyun 	else
5913*4882a593Smuzhiyun 		uptime = (R_REG(osh, &pmu->res_updn_timer) >> 8) & 0xff;
5914*4882a593Smuzhiyun 
5915*4882a593Smuzhiyun 	/* direct dependencies of resource 'rsrc' */
5916*4882a593Smuzhiyun 	deps = si_pmu_res_deps(sih, osh, pmu, PMURES_BIT(rsrc), FALSE);
5917*4882a593Smuzhiyun 	for (i = 0; i <= PMURES_MAX_RESNUM; i ++) {
5918*4882a593Smuzhiyun 		if (!(deps & PMURES_BIT(i)))
5919*4882a593Smuzhiyun 			continue;
5920*4882a593Smuzhiyun 		deps &= ~si_pmu_res_deps(sih, osh, pmu, PMURES_BIT(i), TRUE);
5921*4882a593Smuzhiyun 	}
5922*4882a593Smuzhiyun #ifndef SR_DEBUG
5923*4882a593Smuzhiyun 	si_pmu_res_masks(sih, &min_mask, &max_mask);
5924*4882a593Smuzhiyun #else
5925*4882a593Smuzhiyun 	/* Recalculate fast pwr up delay if min res mask/max res mask has changed */
5926*4882a593Smuzhiyun 	min_mask = R_REG(osh, &pmu->min_res_mask);
5927*4882a593Smuzhiyun #endif /* SR_DEBUG */
5928*4882a593Smuzhiyun 	deps &= ~min_mask;
5929*4882a593Smuzhiyun 
5930*4882a593Smuzhiyun 	/* max uptime of direct dependencies */
5931*4882a593Smuzhiyun 	dmax = 0;
5932*4882a593Smuzhiyun 	for (i = 0; i <= PMURES_MAX_RESNUM; i ++) {
5933*4882a593Smuzhiyun 		if (!(deps & PMURES_BIT(i)))
5934*4882a593Smuzhiyun 			continue;
5935*4882a593Smuzhiyun 		dup = si_pmu_res_uptime(sih, osh, pmu, (uint8)i, pmu_fast_trans_en);
5936*4882a593Smuzhiyun 		if (dmax < dup)
5937*4882a593Smuzhiyun 			dmax = dup;
5938*4882a593Smuzhiyun 	}
5939*4882a593Smuzhiyun 
5940*4882a593Smuzhiyun 	PMU_MSG(("si_pmu_res_uptime: rsrc %u uptime %u(deps 0x%08x uptime %u)\n",
5941*4882a593Smuzhiyun 	         rsrc, uptime, deps, dmax));
5942*4882a593Smuzhiyun 
5943*4882a593Smuzhiyun 	uptrans = pmu_fast_trans_en ? 0 : PMURES_UP_TRANSITION;
5944*4882a593Smuzhiyun 	ret = uptime + dmax + uptrans;
5945*4882a593Smuzhiyun 	return ret;
5946*4882a593Smuzhiyun }
5947*4882a593Smuzhiyun 
5948*4882a593Smuzhiyun /* Return dependencies (direct or all/indirect) for the given resources */
5949*4882a593Smuzhiyun /* need to check circular dependencies and prevent dead recursion */
5950*4882a593Smuzhiyun static uint32
si_pmu_res_deps(si_t * sih,osl_t * osh,pmuregs_t * pmu,uint32 rsrcs,bool all)5951*4882a593Smuzhiyun si_pmu_res_deps(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 rsrcs, bool all)
5952*4882a593Smuzhiyun {
5953*4882a593Smuzhiyun 	uint32 deps = 0;
5954*4882a593Smuzhiyun 	uint32 i;
5955*4882a593Smuzhiyun 
5956*4882a593Smuzhiyun 	for (i = 0; i <= PMURES_MAX_RESNUM; i ++) {
5957*4882a593Smuzhiyun 		if (!(rsrcs & PMURES_BIT(i)))
5958*4882a593Smuzhiyun 			continue;
5959*4882a593Smuzhiyun 		W_REG(osh, &pmu->res_table_sel, i);
5960*4882a593Smuzhiyun 		deps |= R_REG(osh, &pmu->res_dep_mask);
5961*4882a593Smuzhiyun 	}
5962*4882a593Smuzhiyun 
5963*4882a593Smuzhiyun 	return !all ? deps : (deps ? (deps | si_pmu_res_deps(sih, osh, pmu, deps, TRUE)) : 0);
5964*4882a593Smuzhiyun }
5965*4882a593Smuzhiyun 
5966*4882a593Smuzhiyun static bool
si_pmu_otp_is_ready(si_t * sih)5967*4882a593Smuzhiyun si_pmu_otp_is_ready(si_t *sih)
5968*4882a593Smuzhiyun {
5969*4882a593Smuzhiyun 	uint32 otps = 0u;
5970*4882a593Smuzhiyun 
5971*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
5972*4882a593Smuzhiyun 		otps = si_corereg(sih, si_findcoreidx(sih, GCI_CORE_ID, 0u),
5973*4882a593Smuzhiyun 			OFFSETOF(gciregs_t, otpstatus), 0u, 0u);
5974*4882a593Smuzhiyun 	} else {
5975*4882a593Smuzhiyun 		otps = si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, otpstatus), 0u, 0u);
5976*4882a593Smuzhiyun 	}
5977*4882a593Smuzhiyun 	return !!(otps & OTPS_READY);
5978*4882a593Smuzhiyun }
5979*4882a593Smuzhiyun 
5980*4882a593Smuzhiyun static bool
si_pmu_otp_is_ready_and_wait(si_t * sih,bool on)5981*4882a593Smuzhiyun si_pmu_otp_is_ready_and_wait(si_t *sih, bool on)
5982*4882a593Smuzhiyun {
5983*4882a593Smuzhiyun 	SPINWAIT((si_pmu_otp_is_ready(sih) != on), 3000u);
5984*4882a593Smuzhiyun 
5985*4882a593Smuzhiyun 	if (si_pmu_otp_is_ready(sih) != on) {
5986*4882a593Smuzhiyun 		PMU_ERROR(("OTP ready bit not %s after wait\n", (on ? "Set" : "Clear")));
5987*4882a593Smuzhiyun 		OSL_SYS_HALT();
5988*4882a593Smuzhiyun 	}
5989*4882a593Smuzhiyun 
5990*4882a593Smuzhiyun 	return si_pmu_otp_is_ready(sih) == on;
5991*4882a593Smuzhiyun }
5992*4882a593Smuzhiyun 
5993*4882a593Smuzhiyun /**
5994*4882a593Smuzhiyun  * OTP is powered down/up as a means of resetting it, or for saving current when OTP is unused.
5995*4882a593Smuzhiyun  * OTP is powered up/down through PMU resources.
5996*4882a593Smuzhiyun  * OTP will turn OFF only if its not in the dependency of any "higher" rsrc in min_res_mask
5997*4882a593Smuzhiyun  */
5998*4882a593Smuzhiyun void
si_pmu_otp_power(si_t * sih,osl_t * osh,bool on,uint32 * min_res_mask)5999*4882a593Smuzhiyun si_pmu_otp_power(si_t *sih, osl_t *osh, bool on, uint32* min_res_mask)
6000*4882a593Smuzhiyun {
6001*4882a593Smuzhiyun 	pmuregs_t *pmu;
6002*4882a593Smuzhiyun 	uint origidx;
6003*4882a593Smuzhiyun 	uint32 rsrcs = 0;	/* rsrcs to turn on/off OTP power */
6004*4882a593Smuzhiyun 	rsc_per_chip_t *rsc;	/* chip specific resource bit positions */
6005*4882a593Smuzhiyun 
6006*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
6007*4882a593Smuzhiyun 
6008*4882a593Smuzhiyun 	/* Don't do anything if OTP is disabled */
6009*4882a593Smuzhiyun 	if (si_is_otp_disabled(sih)) {
6010*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_otp_power: OTP is disabled\n"));
6011*4882a593Smuzhiyun 		return;
6012*4882a593Smuzhiyun 	}
6013*4882a593Smuzhiyun 
6014*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
6015*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
6016*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
6017*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
6018*4882a593Smuzhiyun 	} else {
6019*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
6020*4882a593Smuzhiyun 	}
6021*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
6022*4882a593Smuzhiyun 
6023*4882a593Smuzhiyun 	/*
6024*4882a593Smuzhiyun 	 * OTP can't be power cycled by toggling OTP_PU for always on OTP chips. For now
6025*4882a593Smuzhiyun 	 * corerev 45 is the only one that has always on OTP.
6026*4882a593Smuzhiyun 	 * Instead, the chipc register OTPCtrl1 (Offset 0xF4) bit 25 (forceOTPpwrDis) is used.
6027*4882a593Smuzhiyun 	 * Please refer to http://hwnbu-twiki.broadcom.com/bin/view/Mwgroup/ChipcommonRev45
6028*4882a593Smuzhiyun 	 */
6029*4882a593Smuzhiyun 	if (CCREV(sih->ccrev) == 45) {
6030*4882a593Smuzhiyun 		uint32 otpctrl1;
6031*4882a593Smuzhiyun 		otpctrl1 = si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, otpcontrol1), 0, 0);
6032*4882a593Smuzhiyun 		if (on)
6033*4882a593Smuzhiyun 			otpctrl1 &= ~OTPC_FORCE_PWR_OFF;
6034*4882a593Smuzhiyun 		else
6035*4882a593Smuzhiyun 			otpctrl1 |= OTPC_FORCE_PWR_OFF;
6036*4882a593Smuzhiyun 		si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, otpcontrol1), ~0, otpctrl1);
6037*4882a593Smuzhiyun 		/* Return to original core */
6038*4882a593Smuzhiyun 		si_setcoreidx(sih, origidx);
6039*4882a593Smuzhiyun 		return;
6040*4882a593Smuzhiyun 	}
6041*4882a593Smuzhiyun 
6042*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
6043*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
6044*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
6045*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
6046*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
6047*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
6048*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
6049*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
6050*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
6051*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
6052*4882a593Smuzhiyun 
6053*4882a593Smuzhiyun #ifdef UNRELEASEDCHIP
6054*4882a593Smuzhiyun #endif
6055*4882a593Smuzhiyun 
6056*4882a593Smuzhiyun 		rsc = si_pmu_get_rsc_positions(sih);
6057*4882a593Smuzhiyun 		rsrcs = PMURES_BIT(rsc->otp_pu);
6058*4882a593Smuzhiyun 		break;
6059*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
6060*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
6061*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
6062*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
6063*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
6064*4882a593Smuzhiyun 		si_gci_direct(sih, GCI_OFFSETOF(sih, otpcontrol), OTPC_FORCE_OTP_PWR_DIS,
6065*4882a593Smuzhiyun 			on ? 0u : OTPC_FORCE_OTP_PWR_DIS);
6066*4882a593Smuzhiyun 		if (!si_pmu_otp_is_ready_and_wait(sih, on)) {
6067*4882a593Smuzhiyun 			PMU_MSG(("OTP ready bit not %s after wait\n", (on ? "ON" : "OFF")));
6068*4882a593Smuzhiyun 		}
6069*4882a593Smuzhiyun 		break;
6070*4882a593Smuzhiyun 	default:
6071*4882a593Smuzhiyun 		break;
6072*4882a593Smuzhiyun 	}
6073*4882a593Smuzhiyun 
6074*4882a593Smuzhiyun 	if (rsrcs != 0) {
6075*4882a593Smuzhiyun 		bool on_check = FALSE; /* Stores otp_ready state */
6076*4882a593Smuzhiyun 		uint32 min_mask = 0;
6077*4882a593Smuzhiyun 
6078*4882a593Smuzhiyun 		/* Turn on/off the power */
6079*4882a593Smuzhiyun 		if (on) {
6080*4882a593Smuzhiyun 			min_mask = R_REG(osh, &pmu->min_res_mask);
6081*4882a593Smuzhiyun 			*min_res_mask = min_mask;
6082*4882a593Smuzhiyun 
6083*4882a593Smuzhiyun 			min_mask |= rsrcs;
6084*4882a593Smuzhiyun 			min_mask |= si_pmu_res_deps(sih, osh, pmu, min_mask, TRUE);
6085*4882a593Smuzhiyun 			on_check = TRUE;
6086*4882a593Smuzhiyun 			/* Assuming max rsc mask defines OTP_PU, so not programming max */
6087*4882a593Smuzhiyun 			PMU_MSG(("Adding rsrc 0x%x to min_res_mask\n", min_mask));
6088*4882a593Smuzhiyun 			W_REG(osh, &pmu->min_res_mask, min_mask);
6089*4882a593Smuzhiyun 			si_pmu_wait_for_steady_state(sih, osh, pmu);
6090*4882a593Smuzhiyun 			OSL_DELAY(1000);
6091*4882a593Smuzhiyun 			SPINWAIT(!(R_REG(osh, &pmu->res_state) & rsrcs),
6092*4882a593Smuzhiyun 				PMU_MAX_TRANSITION_DLY);
6093*4882a593Smuzhiyun 			ASSERT(R_REG(osh, &pmu->res_state) & rsrcs);
6094*4882a593Smuzhiyun 		} else {
6095*4882a593Smuzhiyun 			/*
6096*4882a593Smuzhiyun 			 * Restore back the min_res_mask,
6097*4882a593Smuzhiyun 			 * but keep OTP powered off if allowed by dependencies
6098*4882a593Smuzhiyun 			 */
6099*4882a593Smuzhiyun 			if (*min_res_mask)
6100*4882a593Smuzhiyun 				min_mask = *min_res_mask;
6101*4882a593Smuzhiyun 			else
6102*4882a593Smuzhiyun 				min_mask = R_REG(osh, &pmu->min_res_mask);
6103*4882a593Smuzhiyun 
6104*4882a593Smuzhiyun 			min_mask &= ~rsrcs;
6105*4882a593Smuzhiyun 			/*
6106*4882a593Smuzhiyun 			 * OTP rsrc can be cleared only if its not
6107*4882a593Smuzhiyun 			 * in the dependency of any "higher" rsrc in min_res_mask
6108*4882a593Smuzhiyun 			 */
6109*4882a593Smuzhiyun 			min_mask |= si_pmu_res_deps(sih, osh, pmu, min_mask, TRUE);
6110*4882a593Smuzhiyun 			on_check = ((min_mask & rsrcs) != 0);
6111*4882a593Smuzhiyun 
6112*4882a593Smuzhiyun 			PMU_MSG(("Removing rsrc 0x%x from min_res_mask\n", min_mask));
6113*4882a593Smuzhiyun 			W_REG(osh, &pmu->min_res_mask, min_mask);
6114*4882a593Smuzhiyun 			si_pmu_wait_for_steady_state(sih, osh, pmu);
6115*4882a593Smuzhiyun 		}
6116*4882a593Smuzhiyun 
6117*4882a593Smuzhiyun 		if (!si_pmu_otp_is_ready_and_wait(sih, on_check)) {
6118*4882a593Smuzhiyun 			PMU_MSG(("OTP ready bit not %s after wait\n", (on_check ? "ON" : "OFF")));
6119*4882a593Smuzhiyun 		}
6120*4882a593Smuzhiyun #ifdef NOT_YET
6121*4882a593Smuzhiyun 		/*
6122*4882a593Smuzhiyun 		 * FIXME: Temporarily disabling OTPS_READY ASSERT check. Right now ASSERT in
6123*4882a593Smuzhiyun 		 * ROM is enabled only for 4389B0/C0. Therefore this change anyway will not
6124*4882a593Smuzhiyun 		 * affect other chips. Once the correct spin-wait value is updated by the
6125*4882a593Smuzhiyun 		 * HW team, then this ASSERT will be enabled back.
6126*4882a593Smuzhiyun 		 */
6127*4882a593Smuzhiyun 		ASSERT(si_pmu_otp_is_ready(sih) == on_check);
6128*4882a593Smuzhiyun #endif /* NOT_YET */
6129*4882a593Smuzhiyun 	}
6130*4882a593Smuzhiyun 
6131*4882a593Smuzhiyun 	/* Return to original core */
6132*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
6133*4882a593Smuzhiyun } /* si_pmu_otp_power */
6134*4882a593Smuzhiyun 
6135*4882a593Smuzhiyun void
si_pmu_spuravoid(si_t * sih,osl_t * osh,uint8 spuravoid)6136*4882a593Smuzhiyun si_pmu_spuravoid(si_t *sih, osl_t *osh, uint8 spuravoid)
6137*4882a593Smuzhiyun {
6138*4882a593Smuzhiyun 	uint origidx;
6139*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
6140*4882a593Smuzhiyun 
6141*4882a593Smuzhiyun 	/* Block ints and save current core */
6142*4882a593Smuzhiyun 	si_introff(sih, &intr_val);
6143*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
6144*4882a593Smuzhiyun 
6145*4882a593Smuzhiyun 	/* Return to original core */
6146*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
6147*4882a593Smuzhiyun 	si_intrrestore(sih, &intr_val);
6148*4882a593Smuzhiyun } /* si_pmu_spuravoid */
6149*4882a593Smuzhiyun 
6150*4882a593Smuzhiyun /* below function are only for BBPLL parallel purpose */
6151*4882a593Smuzhiyun /* For having the pllcontrol data values for spuravoid */
6152*4882a593Smuzhiyun typedef struct {
6153*4882a593Smuzhiyun 	uint8	spuravoid_mode;
6154*4882a593Smuzhiyun 	uint8	pllctrl_reg;
6155*4882a593Smuzhiyun 	uint32	pllctrl_regval;
6156*4882a593Smuzhiyun } pllctrl_spuravoid_t;
6157*4882a593Smuzhiyun 
6158*4882a593Smuzhiyun uint32
si_pmu_pll28nm_fvco(si_t * sih)6159*4882a593Smuzhiyun si_pmu_pll28nm_fvco(si_t *sih)
6160*4882a593Smuzhiyun {
6161*4882a593Smuzhiyun 	uint32 r_high, r_low, r;
6162*4882a593Smuzhiyun 	uint32 xf = si_alp_clock(sih);
6163*4882a593Smuzhiyun 	/* PLL registers for 4368 */
6164*4882a593Smuzhiyun 	uint32 pllreg5 = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG5, 0, 0);
6165*4882a593Smuzhiyun 	uint32 pllreg4 = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG4, 0, 0);
6166*4882a593Smuzhiyun 	/* p1div has lower 2 bits in pll4 and high 2 bits in pll5  */
6167*4882a593Smuzhiyun 	uint8 p1div_lo = (pllreg4 & PMU4368_PLL1_PC4_P1DIV_MASK) >> PMU4368_PLL1_PC4_P1DIV_SHIFT;
6168*4882a593Smuzhiyun 	uint8 p1div_hi = (pllreg5 & PMU4368_PLL1_PC5_P1DIV_MASK) >> PMU4368_PLL1_PC5_P1DIV_SHIFT;
6169*4882a593Smuzhiyun 	uint8 p1div = (p1div_hi << PMU4368_P1DIV_HI_SHIFT) | (p1div_lo << PMU4368_P1DIV_LO_SHIFT);
6170*4882a593Smuzhiyun 	uint32 ndiv_int = (pllreg5 & PMU4368_PLL1_PC5_NDIV_INT_MASK) >>
6171*4882a593Smuzhiyun 		PMU4368_PLL1_PC5_NDIV_INT_SHIFT;
6172*4882a593Smuzhiyun 	uint32 ndiv_frac = (pllreg5 & PMU4368_PLL1_PC5_NDIV_FRAC_MASK) >>
6173*4882a593Smuzhiyun 		PMU4368_PLL1_PC5_NDIV_FRAC_SHIFT;
6174*4882a593Smuzhiyun 
6175*4882a593Smuzhiyun 	if (ISSIM_ENAB(sih)) {
6176*4882a593Smuzhiyun 		/* PLL CTRL registers are meaningless under QT, return the pre-configured freq */
6177*4882a593Smuzhiyun 		return (FVCO_720 * 1000);
6178*4882a593Smuzhiyun 	} else if (p1div == 0) {
6179*4882a593Smuzhiyun 		/* PLL register read fails, return 0 so caller can retry */
6180*4882a593Smuzhiyun 		PMU_ERROR(("p1div is invalid\n"));
6181*4882a593Smuzhiyun 		return 0;
6182*4882a593Smuzhiyun 	}
6183*4882a593Smuzhiyun 
6184*4882a593Smuzhiyun 	/* Calculate xf * ( ndiv_frac / (1 << 20) + ndiv_int) / p1div)
6185*4882a593Smuzhiyun 	 * To reduce the inaccuracy in division,
6186*4882a593Smuzhiyun 	 * Covert to (xf * ndiv_frac / (1 << 20) + xf * ndiv_int) / p1div
6187*4882a593Smuzhiyun 	 */
6188*4882a593Smuzhiyun 	math_uint64_multiple_add(&r_high, &r_low, xf, ndiv_frac, 0);
6189*4882a593Smuzhiyun 	/* Make sure the caclulated 64 bits number is in the safe rage (with in 52 bits),
6190*4882a593Smuzhiyun 	 * so we have a valid 32 bits result after divided by 1<<20
6191*4882a593Smuzhiyun 	 */
6192*4882a593Smuzhiyun 	ASSERT((r_high & 0xFFE00000) == 0);
6193*4882a593Smuzhiyun 	math_uint64_right_shift(&r, r_high, r_low, 20);
6194*4882a593Smuzhiyun 
6195*4882a593Smuzhiyun 	return (r + ndiv_int * xf) / p1div;
6196*4882a593Smuzhiyun }
6197*4882a593Smuzhiyun 
6198*4882a593Smuzhiyun bool
si_pmu_is_otp_powered(si_t * sih,osl_t * osh)6199*4882a593Smuzhiyun si_pmu_is_otp_powered(si_t *sih, osl_t *osh)
6200*4882a593Smuzhiyun {
6201*4882a593Smuzhiyun 	uint idx;
6202*4882a593Smuzhiyun 	pmuregs_t *pmu;
6203*4882a593Smuzhiyun 	bool st;
6204*4882a593Smuzhiyun 	rsc_per_chip_t *rsc;		/* chip specific resource bit positions */
6205*4882a593Smuzhiyun 
6206*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
6207*4882a593Smuzhiyun 	idx = si_coreidx(sih);
6208*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
6209*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
6210*4882a593Smuzhiyun 	} else {
6211*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
6212*4882a593Smuzhiyun 	}
6213*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
6214*4882a593Smuzhiyun 
6215*4882a593Smuzhiyun 	si_pmu_wait_for_steady_state(sih, osh, pmu);
6216*4882a593Smuzhiyun 
6217*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
6218*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
6219*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
6220*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
6221*4882a593Smuzhiyun 	case BCM4360_CHIP_ID:
6222*4882a593Smuzhiyun 	case BCM43460_CHIP_ID:
6223*4882a593Smuzhiyun 	case BCM43526_CHIP_ID:
6224*4882a593Smuzhiyun 	case BCM4352_CHIP_ID:
6225*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
6226*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
6227*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
6228*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
6229*4882a593Smuzhiyun 		rsc = si_pmu_get_rsc_positions(sih);
6230*4882a593Smuzhiyun 		st = (R_REG(osh, &pmu->res_state) & PMURES_BIT(rsc->otp_pu)) != 0;
6231*4882a593Smuzhiyun 		break;
6232*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
6233*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
6234*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
6235*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
6236*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
6237*4882a593Smuzhiyun 		st = (!(si_gci_direct(sih, GCI_OFFSETOF(sih, otpcontrol), 0u, 0u) &
6238*4882a593Smuzhiyun 			OTPC_FORCE_OTP_PWR_DIS)) && si_pmu_otp_is_ready_and_wait(sih, TRUE);
6239*4882a593Smuzhiyun 		break;
6240*4882a593Smuzhiyun 	default:
6241*4882a593Smuzhiyun 		st = TRUE;
6242*4882a593Smuzhiyun 		break;
6243*4882a593Smuzhiyun 	}
6244*4882a593Smuzhiyun 
6245*4882a593Smuzhiyun 	/* Return to original core */
6246*4882a593Smuzhiyun 	si_setcoreidx(sih, idx);
6247*4882a593Smuzhiyun 	return st;
6248*4882a593Smuzhiyun } /* si_pmu_is_otp_powered */
6249*4882a593Smuzhiyun 
6250*4882a593Smuzhiyun /**
6251*4882a593Smuzhiyun  * Some chip/boards can be optionally fitted with an external 32Khz clock source for increased power
6252*4882a593Smuzhiyun  * savings (due to more accurate sleep intervals).
6253*4882a593Smuzhiyun  */
6254*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_set_lpoclk)6255*4882a593Smuzhiyun BCMATTACHFN(si_pmu_set_lpoclk)(si_t *sih, osl_t *osh)
6256*4882a593Smuzhiyun {
6257*4882a593Smuzhiyun 	uint32 ext_lpo_sel, int_lpo_sel, timeout = 0,
6258*4882a593Smuzhiyun 		ext_lpo_avail = 0, lpo_sel = 0;
6259*4882a593Smuzhiyun 	uint32 ext_lpo_isclock; /* On e.g. 43602a0, either x-tal or clock can be on LPO pins */
6260*4882a593Smuzhiyun 	pmuregs_t *pmu;
6261*4882a593Smuzhiyun 	uint origidx;
6262*4882a593Smuzhiyun 
6263*4882a593Smuzhiyun 	if (!(getintvar(NULL, "boardflags3")))
6264*4882a593Smuzhiyun 		return;
6265*4882a593Smuzhiyun 
6266*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
6267*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
6268*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
6269*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
6270*4882a593Smuzhiyun 	} else {
6271*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
6272*4882a593Smuzhiyun 	}
6273*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
6274*4882a593Smuzhiyun 
6275*4882a593Smuzhiyun 	ext_lpo_sel = getintvar(NULL, "boardflags3") & BFL3_FORCE_EXT_LPO_SEL;
6276*4882a593Smuzhiyun 	int_lpo_sel = getintvar(NULL, "boardflags3") & BFL3_FORCE_INT_LPO_SEL;
6277*4882a593Smuzhiyun 	ext_lpo_isclock = getintvar(NULL, "boardflags3") & BFL3_EXT_LPO_ISCLOCK;
6278*4882a593Smuzhiyun 
6279*4882a593Smuzhiyun 	BCM_REFERENCE(ext_lpo_isclock);
6280*4882a593Smuzhiyun 
6281*4882a593Smuzhiyun 	if (ext_lpo_sel != 0) {
6282*4882a593Smuzhiyun 		switch (CHIPID(sih->chip)) {
6283*4882a593Smuzhiyun 		CASE_BCM43602_CHIP:
6284*4882a593Smuzhiyun 			/* External LPO is POR default enabled */
6285*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL2, PMU43602_CC2_XTAL32_SEL,
6286*4882a593Smuzhiyun 				ext_lpo_isclock ? 0 : PMU43602_CC2_XTAL32_SEL);
6287*4882a593Smuzhiyun 			break;
6288*4882a593Smuzhiyun 		default:
6289*4882a593Smuzhiyun 			/* Force External LPO Power Up */
6290*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL0, CC_EXT_LPO_PU, CC_EXT_LPO_PU);
6291*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CHIPCTRLREG6, GC_EXT_LPO_PU, GC_EXT_LPO_PU);
6292*4882a593Smuzhiyun 			break;
6293*4882a593Smuzhiyun 		}
6294*4882a593Smuzhiyun 
6295*4882a593Smuzhiyun 		ext_lpo_avail = R_REG(osh, &pmu->pmustatus) & EXT_LPO_AVAIL;
6296*4882a593Smuzhiyun 		while (ext_lpo_avail == 0 && timeout < LPO_SEL_TIMEOUT) {
6297*4882a593Smuzhiyun 			OSL_DELAY(1000);
6298*4882a593Smuzhiyun 			ext_lpo_avail = R_REG(osh, &pmu->pmustatus) & EXT_LPO_AVAIL;
6299*4882a593Smuzhiyun 			timeout++;
6300*4882a593Smuzhiyun 		}
6301*4882a593Smuzhiyun 
6302*4882a593Smuzhiyun 		if (timeout >= LPO_SEL_TIMEOUT) {
6303*4882a593Smuzhiyun 			PMU_ERROR(("External LPO is not available\n"));
6304*4882a593Smuzhiyun 		} else {
6305*4882a593Smuzhiyun 			/* External LPO is available, lets use (=select) it */
6306*4882a593Smuzhiyun 			OSL_DELAY(1000);
6307*4882a593Smuzhiyun 			timeout = 0;
6308*4882a593Smuzhiyun 
6309*4882a593Smuzhiyun 			switch (CHIPID(sih->chip)) {
6310*4882a593Smuzhiyun 			CASE_BCM43602_CHIP:
6311*4882a593Smuzhiyun 				si_pmu_chipcontrol(sih, PMU_CHIPCTL2, PMU43602_CC2_FORCE_EXT_LPO,
6312*4882a593Smuzhiyun 					PMU43602_CC2_FORCE_EXT_LPO); /* switches to external LPO */
6313*4882a593Smuzhiyun 				break;
6314*4882a593Smuzhiyun 			default:
6315*4882a593Smuzhiyun 				/* Force External LPO Sel up */
6316*4882a593Smuzhiyun 				si_gci_chipcontrol(sih, CHIPCTRLREG6, EXT_LPO_SEL, EXT_LPO_SEL);
6317*4882a593Smuzhiyun 				/* Clear Force Internal LPO Sel */
6318*4882a593Smuzhiyun 				si_gci_chipcontrol(sih, CHIPCTRLREG6, INT_LPO_SEL, 0x0);
6319*4882a593Smuzhiyun 				OSL_DELAY(1000);
6320*4882a593Smuzhiyun 
6321*4882a593Smuzhiyun 				lpo_sel = R_REG(osh, &pmu->pmucontrol) & LPO_SEL;
6322*4882a593Smuzhiyun 				while (lpo_sel != 0 && timeout < LPO_SEL_TIMEOUT) {
6323*4882a593Smuzhiyun 					OSL_DELAY(1000);
6324*4882a593Smuzhiyun 					lpo_sel = R_REG(osh, &pmu->pmucontrol) & LPO_SEL;
6325*4882a593Smuzhiyun 					timeout++;
6326*4882a593Smuzhiyun 				}
6327*4882a593Smuzhiyun 			}
6328*4882a593Smuzhiyun 
6329*4882a593Smuzhiyun 			if (timeout >= LPO_SEL_TIMEOUT) {
6330*4882a593Smuzhiyun 				PMU_ERROR(("External LPO is not set\n"));
6331*4882a593Smuzhiyun 				/* Clear Force External LPO Sel */
6332*4882a593Smuzhiyun 				switch (CHIPID(sih->chip)) {
6333*4882a593Smuzhiyun 				CASE_BCM43602_CHIP:
6334*4882a593Smuzhiyun 					si_pmu_chipcontrol(sih, PMU_CHIPCTL2,
6335*4882a593Smuzhiyun 						PMU43602_CC2_FORCE_EXT_LPO, 0);
6336*4882a593Smuzhiyun 					break;
6337*4882a593Smuzhiyun 				default:
6338*4882a593Smuzhiyun 					si_gci_chipcontrol(sih, CHIPCTRLREG6, EXT_LPO_SEL, 0x0);
6339*4882a593Smuzhiyun 					break;
6340*4882a593Smuzhiyun 				}
6341*4882a593Smuzhiyun 			} else {
6342*4882a593Smuzhiyun 				/* Clear Force Internal LPO Power Up */
6343*4882a593Smuzhiyun 				switch (CHIPID(sih->chip)) {
6344*4882a593Smuzhiyun 				CASE_BCM43602_CHIP:
6345*4882a593Smuzhiyun 					break;
6346*4882a593Smuzhiyun 				default:
6347*4882a593Smuzhiyun 					si_pmu_chipcontrol(sih, PMU_CHIPCTL0, CC_INT_LPO_PU, 0x0);
6348*4882a593Smuzhiyun 					si_gci_chipcontrol(sih, CHIPCTRLREG6, GC_INT_LPO_PU, 0x0);
6349*4882a593Smuzhiyun 					break;
6350*4882a593Smuzhiyun 				}
6351*4882a593Smuzhiyun 			} /* if (timeout) */
6352*4882a593Smuzhiyun 		} /* if (timeout) */
6353*4882a593Smuzhiyun 	} else if (int_lpo_sel != 0) {
6354*4882a593Smuzhiyun 		switch (CHIPID(sih->chip)) {
6355*4882a593Smuzhiyun 		CASE_BCM43602_CHIP:
6356*4882a593Smuzhiyun 			break; /* do nothing, internal LPO is POR default powered and selected */
6357*4882a593Smuzhiyun 		default:
6358*4882a593Smuzhiyun 			/* Force Internal LPO Power Up */
6359*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL0, CC_INT_LPO_PU, CC_INT_LPO_PU);
6360*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CHIPCTRLREG6, GC_INT_LPO_PU, GC_INT_LPO_PU);
6361*4882a593Smuzhiyun 
6362*4882a593Smuzhiyun 			OSL_DELAY(1000);
6363*4882a593Smuzhiyun 
6364*4882a593Smuzhiyun 			/* Force Internal LPO Sel up */
6365*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CHIPCTRLREG6, INT_LPO_SEL, INT_LPO_SEL);
6366*4882a593Smuzhiyun 			/* Clear Force External LPO Sel */
6367*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CHIPCTRLREG6, EXT_LPO_SEL, 0x0);
6368*4882a593Smuzhiyun 
6369*4882a593Smuzhiyun 			OSL_DELAY(1000);
6370*4882a593Smuzhiyun 
6371*4882a593Smuzhiyun 			lpo_sel = R_REG(osh, &pmu->pmucontrol) & LPO_SEL;
6372*4882a593Smuzhiyun 			timeout = 0;
6373*4882a593Smuzhiyun 			while (lpo_sel == 0 && timeout < LPO_SEL_TIMEOUT) {
6374*4882a593Smuzhiyun 				OSL_DELAY(1000);
6375*4882a593Smuzhiyun 				lpo_sel = R_REG(osh, &pmu->pmucontrol) & LPO_SEL;
6376*4882a593Smuzhiyun 				timeout++;
6377*4882a593Smuzhiyun 			}
6378*4882a593Smuzhiyun 			if (timeout >= LPO_SEL_TIMEOUT) {
6379*4882a593Smuzhiyun 				PMU_ERROR(("Internal LPO is not set\n"));
6380*4882a593Smuzhiyun 				/* Clear Force Internal LPO Sel */
6381*4882a593Smuzhiyun 				si_gci_chipcontrol(sih, CHIPCTRLREG6, INT_LPO_SEL, 0x0);
6382*4882a593Smuzhiyun 			} else {
6383*4882a593Smuzhiyun 				/* Clear Force External LPO Power Up */
6384*4882a593Smuzhiyun 				si_pmu_chipcontrol(sih, PMU_CHIPCTL0, CC_EXT_LPO_PU, 0x0);
6385*4882a593Smuzhiyun 				si_gci_chipcontrol(sih, CHIPCTRLREG6, GC_EXT_LPO_PU, 0x0);
6386*4882a593Smuzhiyun 			}
6387*4882a593Smuzhiyun 			break;
6388*4882a593Smuzhiyun 		}
6389*4882a593Smuzhiyun 		if ((PMUREV(sih->pmurev) >= 33)) {
6390*4882a593Smuzhiyun 			/* Enabling FAST_SEQ */
6391*4882a593Smuzhiyun 			PMU_REG(sih, pmucontrol_ext, PCTL_EXT_FASTSEQ_ENAB, PCTL_EXT_FASTSEQ_ENAB);
6392*4882a593Smuzhiyun 		}
6393*4882a593Smuzhiyun 	}
6394*4882a593Smuzhiyun 
6395*4882a593Smuzhiyun 	/* Return to original core */
6396*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
6397*4882a593Smuzhiyun } /* si_pmu_set_lpoclk */
6398*4882a593Smuzhiyun 
6399*4882a593Smuzhiyun static int
si_pmu_fast_lpo_locked(si_t * sih,osl_t * osh)6400*4882a593Smuzhiyun si_pmu_fast_lpo_locked(si_t *sih, osl_t *osh)
6401*4882a593Smuzhiyun {
6402*4882a593Smuzhiyun 	int lock = 0;
6403*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
6404*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
6405*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
6406*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
6407*4882a593Smuzhiyun 		lock = CHIPC_REG(sih, chipstatus, 0, 0) & CST43012_FLL_LOCK;
6408*4882a593Smuzhiyun 		break;
6409*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
6410*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
6411*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
6412*4882a593Smuzhiyun 		lock = si_gci_chipstatus(sih, GCI_CHIPSTATUS_13) & GCI_CS_4369_FLL1MHZ_LOCK_MASK;
6413*4882a593Smuzhiyun 		break;
6414*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
6415*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
6416*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
6417*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
6418*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
6419*4882a593Smuzhiyun 		lock = si_gci_chipstatus(sih, GCI_CHIPSTATUS_15) & GCI_CS_4387_FLL1MHZ_LOCK_MASK;
6420*4882a593Smuzhiyun 		break;
6421*4882a593Smuzhiyun 	default:
6422*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_fast_lpo_locked: LPO enable: unsupported chip!\n"));
6423*4882a593Smuzhiyun 	}
6424*4882a593Smuzhiyun 	return lock ? 1 : 0;
6425*4882a593Smuzhiyun }
6426*4882a593Smuzhiyun 
6427*4882a593Smuzhiyun /* Turn ON FAST LPO FLL (1MHz) */
6428*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_fast_lpo_enable)6429*4882a593Smuzhiyun BCMATTACHFN(si_pmu_fast_lpo_enable)(si_t *sih, osl_t *osh)
6430*4882a593Smuzhiyun {
6431*4882a593Smuzhiyun 	int i = 0, lock = 0;
6432*4882a593Smuzhiyun 
6433*4882a593Smuzhiyun 	BCM_REFERENCE(i);
6434*4882a593Smuzhiyun 	BCM_REFERENCE(lock);
6435*4882a593Smuzhiyun 
6436*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
6437*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
6438*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
6439*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
6440*4882a593Smuzhiyun 		PMU_REG(sih, pmucontrol_ext, PCTL_EXT_FASTLPO_ENAB, PCTL_EXT_FASTLPO_ENAB);
6441*4882a593Smuzhiyun 		lock = CHIPC_REG(sih, chipstatus, 0, 0) & CST43012_FLL_LOCK;
6442*4882a593Smuzhiyun 
6443*4882a593Smuzhiyun 		for (i = 0; ((i <= 30) && (!lock)); i++)
6444*4882a593Smuzhiyun 		{
6445*4882a593Smuzhiyun 			lock = CHIPC_REG(sih, chipstatus, 0, 0) & CST43012_FLL_LOCK;
6446*4882a593Smuzhiyun 			OSL_DELAY(10);
6447*4882a593Smuzhiyun 		}
6448*4882a593Smuzhiyun 
6449*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_fast_lpo_enable: duration: %d\n", i*10));
6450*4882a593Smuzhiyun 
6451*4882a593Smuzhiyun 		if (!lock) {
6452*4882a593Smuzhiyun 			PMU_MSG(("si_pmu_fast_lpo_enable: FLL lock not present!"));
6453*4882a593Smuzhiyun 			ROMMABLE_ASSERT(0);
6454*4882a593Smuzhiyun 		}
6455*4882a593Smuzhiyun 
6456*4882a593Smuzhiyun 		/* Now switch to using FAST LPO clk */
6457*4882a593Smuzhiyun 		PMU_REG(sih, pmucontrol_ext, PCTL_EXT_FASTLPO_SWENAB, PCTL_EXT_FASTLPO_SWENAB);
6458*4882a593Smuzhiyun 		break;
6459*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
6460*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
6461*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
6462*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
6463*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
6464*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
6465*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
6466*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
6467*4882a593Smuzhiyun 	{
6468*4882a593Smuzhiyun 		uint8	fastlpo_dis = fastlpo_dis_get();
6469*4882a593Smuzhiyun 		uint8	fastlpo_pcie_dis = fastlpo_pcie_dis_get();
6470*4882a593Smuzhiyun 
6471*4882a593Smuzhiyun 		if (!fastlpo_dis || !fastlpo_pcie_dis) {
6472*4882a593Smuzhiyun 			/* LHL rev 6 in 4387 requires this bit to be set first */
6473*4882a593Smuzhiyun 			if ((LHLREV(sih->lhlrev) >= 6) && !PMU_FLL_PU_ENAB()) {
6474*4882a593Smuzhiyun 				LHL_REG(sih, lhl_top_pwrseq_ctl_adr,
6475*4882a593Smuzhiyun 				        LHL_PWRSEQCTL_PMU_LPLDO_PD, LHL_PWRSEQCTL_WL_FLLPU_EN);
6476*4882a593Smuzhiyun 			}
6477*4882a593Smuzhiyun 
6478*4882a593Smuzhiyun 			PMU_REG(sih, pmucontrol_ext, PCTL_EXT_FASTLPO_ENAB, PCTL_EXT_FASTLPO_ENAB);
6479*4882a593Smuzhiyun 
6480*4882a593Smuzhiyun 			lock = si_pmu_fast_lpo_locked(sih, osh);
6481*4882a593Smuzhiyun 			for (i = 0; ((i < 300) && (!lock)); i++) {
6482*4882a593Smuzhiyun 				lock = si_pmu_fast_lpo_locked(sih, osh);
6483*4882a593Smuzhiyun 				OSL_DELAY(10);
6484*4882a593Smuzhiyun 			}
6485*4882a593Smuzhiyun 			ASSERT(lock);
6486*4882a593Smuzhiyun 		}
6487*4882a593Smuzhiyun 
6488*4882a593Smuzhiyun 		if (!fastlpo_dis) {
6489*4882a593Smuzhiyun 			/* Now switch to using FAST LPO clk */
6490*4882a593Smuzhiyun 			PMU_REG(sih, pmucontrol_ext,
6491*4882a593Smuzhiyun 				PCTL_EXT_FASTLPO_SWENAB, PCTL_EXT_FASTLPO_SWENAB);
6492*4882a593Smuzhiyun 
6493*4882a593Smuzhiyun 			OSL_DELAY(1000);
6494*4882a593Smuzhiyun 			PMU_MSG(("pmu fast lpo enabled\n"));
6495*4882a593Smuzhiyun 		}
6496*4882a593Smuzhiyun 		break;
6497*4882a593Smuzhiyun 	}
6498*4882a593Smuzhiyun 	default:
6499*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_fast_lpo_enable: LPO enable: unsupported chip!\n"));
6500*4882a593Smuzhiyun 	}
6501*4882a593Smuzhiyun }
6502*4882a593Smuzhiyun 
6503*4882a593Smuzhiyun /* Turn ON FAST LPO FLL (1MHz) for PCIE */
6504*4882a593Smuzhiyun bool
BCMATTACHFN(si_pmu_fast_lpo_enable_pcie)6505*4882a593Smuzhiyun BCMATTACHFN(si_pmu_fast_lpo_enable_pcie)(si_t *sih)
6506*4882a593Smuzhiyun {
6507*4882a593Smuzhiyun 	if (!FASTLPO_ENAB()) {
6508*4882a593Smuzhiyun 		return FALSE;
6509*4882a593Smuzhiyun 	}
6510*4882a593Smuzhiyun 
6511*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
6512*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
6513*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
6514*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
6515*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
6516*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
6517*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
6518*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
6519*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
6520*4882a593Smuzhiyun 	{
6521*4882a593Smuzhiyun 		uint8	fastlpo_pcie_dis = fastlpo_pcie_dis_get();
6522*4882a593Smuzhiyun 
6523*4882a593Smuzhiyun 		if (!fastlpo_pcie_dis) {
6524*4882a593Smuzhiyun 			PMU_REG(sih, pmucontrol_ext,
6525*4882a593Smuzhiyun 				PCTL_EXT_FASTLPO_PCIE_SWENAB, PCTL_EXT_FASTLPO_PCIE_SWENAB);
6526*4882a593Smuzhiyun 			OSL_DELAY(1000);
6527*4882a593Smuzhiyun 			PMU_MSG(("pcie fast lpo enabled\n"));
6528*4882a593Smuzhiyun 			return TRUE;
6529*4882a593Smuzhiyun 		}
6530*4882a593Smuzhiyun 		break;
6531*4882a593Smuzhiyun 	}
6532*4882a593Smuzhiyun 	default:
6533*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_fast_lpo_enable_pcie: LPO enable: unsupported chip!\n"));
6534*4882a593Smuzhiyun 	}
6535*4882a593Smuzhiyun 
6536*4882a593Smuzhiyun 	return FALSE;
6537*4882a593Smuzhiyun }
6538*4882a593Smuzhiyun 
6539*4882a593Smuzhiyun /* Turn ON FAST LPO FLL (1MHz) for PMU */
6540*4882a593Smuzhiyun bool
BCMATTACHFN(si_pmu_fast_lpo_enable_pmu)6541*4882a593Smuzhiyun BCMATTACHFN(si_pmu_fast_lpo_enable_pmu)(si_t *sih)
6542*4882a593Smuzhiyun {
6543*4882a593Smuzhiyun 	if (!FASTLPO_ENAB()) {
6544*4882a593Smuzhiyun 		return FALSE;
6545*4882a593Smuzhiyun 	}
6546*4882a593Smuzhiyun 
6547*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
6548*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
6549*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
6550*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
6551*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
6552*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
6553*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
6554*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
6555*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
6556*4882a593Smuzhiyun 	{
6557*4882a593Smuzhiyun 		uint8	fastlpo_dis = fastlpo_dis_get();
6558*4882a593Smuzhiyun 
6559*4882a593Smuzhiyun 		if (!fastlpo_dis) {
6560*4882a593Smuzhiyun 			PMU_MSG(("pmu fast lpo enabled\n"));
6561*4882a593Smuzhiyun 			return TRUE;
6562*4882a593Smuzhiyun 		}
6563*4882a593Smuzhiyun 		break;
6564*4882a593Smuzhiyun 	}
6565*4882a593Smuzhiyun 	default:
6566*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_fast_lpo_enable_pmu: LPO enable: unsupported chip!\n"));
6567*4882a593Smuzhiyun 	}
6568*4882a593Smuzhiyun 
6569*4882a593Smuzhiyun 	return FALSE;
6570*4882a593Smuzhiyun }
6571*4882a593Smuzhiyun 
6572*4882a593Smuzhiyun static uint8
BCMATTACHFN(fastlpo_dis_get)6573*4882a593Smuzhiyun BCMATTACHFN(fastlpo_dis_get)(void)
6574*4882a593Smuzhiyun {
6575*4882a593Smuzhiyun 	uint8 fastlpo_dis = 1;
6576*4882a593Smuzhiyun 
6577*4882a593Smuzhiyun #if defined(BCM_FASTLPO_PMU) && !defined(BCM_FASTLPO_PMU_DISABLED)
6578*4882a593Smuzhiyun 	if (FASTLPO_ENAB()) {
6579*4882a593Smuzhiyun 		fastlpo_dis = 0;
6580*4882a593Smuzhiyun 		if (getvar(NULL, rstr_fastlpo_dis) != NULL) {
6581*4882a593Smuzhiyun 			fastlpo_dis = (uint8)getintvar(NULL, rstr_fastlpo_dis);
6582*4882a593Smuzhiyun 		}
6583*4882a593Smuzhiyun 	}
6584*4882a593Smuzhiyun #endif  /* BCM_FASTLPO_PMU */
6585*4882a593Smuzhiyun 	return fastlpo_dis;
6586*4882a593Smuzhiyun }
6587*4882a593Smuzhiyun 
6588*4882a593Smuzhiyun static uint8
BCMATTACHFN(fastlpo_pcie_dis_get)6589*4882a593Smuzhiyun BCMATTACHFN(fastlpo_pcie_dis_get)(void)
6590*4882a593Smuzhiyun {
6591*4882a593Smuzhiyun 	uint8 fastlpo_pcie_dis = 1;
6592*4882a593Smuzhiyun 
6593*4882a593Smuzhiyun 	if (FASTLPO_ENAB()) {
6594*4882a593Smuzhiyun 		fastlpo_pcie_dis = 0;
6595*4882a593Smuzhiyun 		if (getvar(NULL, rstr_fastlpo_pcie_dis) != NULL) {
6596*4882a593Smuzhiyun 			fastlpo_pcie_dis = (uint8)getintvar(NULL, rstr_fastlpo_pcie_dis);
6597*4882a593Smuzhiyun 		}
6598*4882a593Smuzhiyun 	}
6599*4882a593Smuzhiyun 	return fastlpo_pcie_dis;
6600*4882a593Smuzhiyun }
6601*4882a593Smuzhiyun 
6602*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_fll_preload_enable)6603*4882a593Smuzhiyun BCMATTACHFN(si_pmu_fll_preload_enable)(si_t *sih)
6604*4882a593Smuzhiyun {
6605*4882a593Smuzhiyun 	if (!PMU_FLL_PU_ENAB()) {
6606*4882a593Smuzhiyun 		return;
6607*4882a593Smuzhiyun 	}
6608*4882a593Smuzhiyun 
6609*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
6610*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
6611*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
6612*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
6613*4882a593Smuzhiyun 	{
6614*4882a593Smuzhiyun 		uint32 fll_dac_out;
6615*4882a593Smuzhiyun 
6616*4882a593Smuzhiyun 		fll_dac_out = (si_gci_chipstatus(sih, GCI_CHIPSTATUS_15) &
6617*4882a593Smuzhiyun 			GCI_CS_4387_FLL1MHZ_DAC_OUT_MASK)
6618*4882a593Smuzhiyun 			>> GCI_CS_4387_FLL1MHZ_DAC_OUT_SHIFT;
6619*4882a593Smuzhiyun 
6620*4882a593Smuzhiyun 		LHL_REG(sih, lhl_wl_hw_ctl_adr[1],
6621*4882a593Smuzhiyun 			LHL_1MHZ_FLL_DAC_EXT_MASK,
6622*4882a593Smuzhiyun 			(fll_dac_out) << LHL_1MHZ_FLL_DAC_EXT_SHIFT);
6623*4882a593Smuzhiyun 		LHL_REG(sih, lhl_wl_hw_ctl_adr[1],
6624*4882a593Smuzhiyun 			LHL_1MHZ_FLL_PRELOAD_MASK,
6625*4882a593Smuzhiyun 			LHL_1MHZ_FLL_PRELOAD_MASK);
6626*4882a593Smuzhiyun 		break;
6627*4882a593Smuzhiyun 	}
6628*4882a593Smuzhiyun 	default:
6629*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_fll_preload_enable: unsupported chip!\n"));
6630*4882a593Smuzhiyun 		ASSERT(0);
6631*4882a593Smuzhiyun 		break;
6632*4882a593Smuzhiyun 	}
6633*4882a593Smuzhiyun }
6634*4882a593Smuzhiyun 
6635*4882a593Smuzhiyun /* LV sleep mode summary:
6636*4882a593Smuzhiyun  * LV mode is where both ABUCK and CBUCK are programmed to low voltages during
6637*4882a593Smuzhiyun  * sleep, and VMUX selects ABUCK as VDDOUT_AON. LPLDO needs to power off.
6638*4882a593Smuzhiyun  * With ASR ON, LPLDO OFF
6639*4882a593Smuzhiyun  */
6640*4882a593Smuzhiyun #if defined(SAVERESTORE)
6641*4882a593Smuzhiyun static void
BCMATTACHFN(si_set_lv_sleep_mode_pmu)6642*4882a593Smuzhiyun BCMATTACHFN(si_set_lv_sleep_mode_pmu)(si_t *sih, osl_t *osh)
6643*4882a593Smuzhiyun {
6644*4882a593Smuzhiyun 	/* jtag_udr_write USER_REG9W jtag_serdes_pic_enable 1 */
6645*4882a593Smuzhiyun 	if (BCM4369_CHIP(sih->chip) && (CHIPREV(sih->chiprev) == 0)) {
6646*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL4, PMU_CC4_4369_AUX_PD_MEMLPLDO2VDDB_ON, 0);
6647*4882a593Smuzhiyun 
6648*4882a593Smuzhiyun 		//JTAG_SEL override. When this bit is set, jtag_sel 0, Required for JTAG writes
6649*4882a593Smuzhiyun 		/* Temporarily we are disabling this as it is not required..
6650*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_06, 0x10, 0x10);
6651*4882a593Smuzhiyun 		jtag_setbit_128(sih, 9, 103, 1);
6652*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_06, 0x10, 0x0);
6653*4882a593Smuzhiyun 		*/
6654*4882a593Smuzhiyun 
6655*4882a593Smuzhiyun 	}
6656*4882a593Smuzhiyun 
6657*4882a593Smuzhiyun 	/* Program pmu VREG resgiter for Resouce based ABUCK and CBUCK modes
6658*4882a593Smuzhiyun 	 *      cbuck rsrc 0 - PWM and abuck rsrc 0 - Auto, rsrc 1 - PWM
6659*4882a593Smuzhiyun 	 */
6660*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_16, PMU_4369_VREG16_RSRC0_CBUCK_MODE_MASK,
6661*4882a593Smuzhiyun 		0x3u << PMU_4369_VREG16_RSRC0_CBUCK_MODE_SHIFT);
6662*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_16, PMU_4369_VREG16_RSRC0_ABUCK_MODE_MASK,
6663*4882a593Smuzhiyun 		0x3u << PMU_4369_VREG16_RSRC0_ABUCK_MODE_SHIFT);
6664*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_16, PMU_4369_VREG16_RSRC1_ABUCK_MODE_MASK,
6665*4882a593Smuzhiyun 		0x3u << PMU_4369_VREG16_RSRC1_ABUCK_MODE_SHIFT);
6666*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_16, PMU_4369_VREG16_RSRC2_ABUCK_MODE_MASK,
6667*4882a593Smuzhiyun 		0x3u << PMU_4369_VREG16_RSRC2_ABUCK_MODE_SHIFT);
6668*4882a593Smuzhiyun 
6669*4882a593Smuzhiyun 	/* asr voltage adjust PWM - 0.8V */
6670*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_8, PMU_4369_VREG8_ASR_OVADJ_LPPFM_MASK,
6671*4882a593Smuzhiyun 		0x10u << PMU_4369_VREG8_ASR_OVADJ_LPPFM_SHIFT);
6672*4882a593Smuzhiyun 
6673*4882a593Smuzhiyun 	/* Enable rsrc_en_asr_msk[0] and msk[1] */
6674*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_13, PMU_4369_VREG13_RSRC_EN0_ASR_MASK,
6675*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG13_RSRC_EN0_ASR_SHIFT);
6676*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_13, PMU_4369_VREG13_RSRC_EN1_ASR_MASK,
6677*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG13_RSRC_EN1_ASR_SHIFT);
6678*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_13, PMU_4369_VREG13_RSRC_EN2_ASR_MASK,
6679*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG13_RSRC_EN2_ASR_SHIFT);
6680*4882a593Smuzhiyun 
6681*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_14, PMU_4369_VREG14_RSRC_EN_CSR_MASK0_MASK,
6682*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG14_RSRC_EN_CSR_MASK0_SHIFT);
6683*4882a593Smuzhiyun 
6684*4882a593Smuzhiyun 	/* disable force_hp_mode and enable wl_pmu_lv_mod */
6685*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_7,
6686*4882a593Smuzhiyun 		(PMU_4369_VREG_7_WL_PMU_LV_MODE_MASK | PMU_4369_VREG_7_WL_PMU_LP_MODE_MASK |
6687*4882a593Smuzhiyun 		PMU_4369_VREG_7_PMU_FORCE_HP_MODE_MASK), PMU_4369_VREG_7_WL_PMU_LV_MODE_MASK);
6688*4882a593Smuzhiyun 
6689*4882a593Smuzhiyun 	/* Enable MISCLDO only for A0, MEMLPLDO_adj -0.7V, Disable LPLDO power up */
6690*4882a593Smuzhiyun 	/* For 4387, should not disable because this is PU when analog PMU is out of sleep
6691*4882a593Smuzhiyun 	 * and bypass when in sleep mode
6692*4882a593Smuzhiyun 	 */
6693*4882a593Smuzhiyun 	if (!(BCM4389_CHIP(sih->chip) || BCM4388_CHIP(sih->chip) || BCM4397_CHIP(sih->chip) ||
6694*4882a593Smuzhiyun 		BCM4387_CHIP(sih->chip))) {
6695*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_5, PMU_4369_VREG_5_MISCLDO_POWER_UP_MASK,
6696*4882a593Smuzhiyun 			((CHIPREV(sih->chiprev) == 0) ? 1 : 0) <<
6697*4882a593Smuzhiyun 			  PMU_4369_VREG_5_MISCLDO_POWER_UP_SHIFT);
6698*4882a593Smuzhiyun 	}
6699*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_5, PMU_4369_VREG_5_LPLDO_POWER_UP_MASK, 0x0u);
6700*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_5, PMU_4369_VREG_5_MEMLPLDO_OP_VLT_ADJ_CTRL_MASK,
6701*4882a593Smuzhiyun 		0xDu << PMU_4369_VREG_5_MEMLPLDO_OP_VLT_ADJ_CTRL_SHIFT);
6702*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_5, PMU_4369_VREG_5_LPLDO_OP_VLT_ADJ_CTRL_MASK,
6703*4882a593Smuzhiyun 		0xFu << PMU_4369_VREG_5_LPLDO_OP_VLT_ADJ_CTRL_SHIFT);
6704*4882a593Smuzhiyun 
6705*4882a593Smuzhiyun 	/* Enabale MEMLPLDO ( to enable 0x08)and BTLDO is enabled. At sleep RFLDO is disabled */
6706*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_6, PMU_4369_VREG_6_MEMLPLDO_POWER_UP_MASK,
6707*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG_6_MEMLPLDO_POWER_UP_SHIFT);
6708*4882a593Smuzhiyun 
6709*4882a593Smuzhiyun 	/* Program PMU chip cntrl register to control
6710*4882a593Smuzhiyun 	 *     cbuck2vddb_pwrsw_force_on =1 and memlpldo2vddb_pwrsw_force_off = 1
6711*4882a593Smuzhiyun 	 *     cbuck2ret_pwrsw_force_on = 1 and memlpldo2vddb_pwrsw_force_off = 1
6712*4882a593Smuzhiyun 	 *     set d11_2x2_bw80_cbuck2vddb_pwrsw_force_on and
6713*4882a593Smuzhiyun 	 *     d11_2x2_bw20_cbuck2vddb_pwrsw_force_on cbuck2ret_pwrsw on 4 cores
6714*4882a593Smuzhiyun 	 */
6715*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
6716*4882a593Smuzhiyun 		(PMU_CC4_4369_MAIN_PD_CBUCK2VDDB_ON | PMU_CC4_4369_MAIN_PD_CBUCK2VDDRET_ON |
6717*4882a593Smuzhiyun 		PMU_CC4_4369_MAIN_PD_MEMLPLDO2VDDB_ON | PMU_CC4_4369_MAIN_PD_MEMLPDLO2VDDRET_ON),
6718*4882a593Smuzhiyun 		(PMU_CC4_4369_MAIN_PD_CBUCK2VDDB_ON | PMU_CC4_4369_MAIN_PD_CBUCK2VDDRET_ON));
6719*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
6720*4882a593Smuzhiyun 		(PMU_CC4_4369_AUX_PD_CBUCK2VDDB_ON | PMU_CC4_4369_AUX_PD_CBUCK2VDDRET_ON |
6721*4882a593Smuzhiyun 		PMU_CC4_4369_AUX_PD_MEMLPLDO2VDDB_ON | PMU_CC4_4369_AUX_PD_MEMLPLDO2VDDRET_ON),
6722*4882a593Smuzhiyun 		(PMU_CC4_4369_AUX_PD_CBUCK2VDDB_ON | PMU_CC4_4369_AUX_PD_CBUCK2VDDRET_ON));
6723*4882a593Smuzhiyun 
6724*4882a593Smuzhiyun 	/* set subcore_cbuck2vddb_pwrsw_force_on */
6725*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL5,
6726*4882a593Smuzhiyun 		(PMU_CC5_4369_SUBCORE_CBUCK2VDDB_ON | PMU_CC5_4369_SUBCORE_CBUCK2VDDRET_ON |
6727*4882a593Smuzhiyun 		PMU_CC5_4369_SUBCORE_MEMLPLDO2VDDB_ON | PMU_CC5_4369_SUBCORE_MEMLPLDO2VDDRET_ON),
6728*4882a593Smuzhiyun 		(PMU_CC5_4369_SUBCORE_CBUCK2VDDB_ON | PMU_CC5_4369_SUBCORE_CBUCK2VDDRET_ON));
6729*4882a593Smuzhiyun 
6730*4882a593Smuzhiyun 	/* Set subcore_memlpldo2vddb_pwrsw_force_off, d11_2x2_bw80_memlpldo2vddb_pwrsw_force_off
6731*4882a593Smuzhiyun 	 * and d11_2x2_bw20_memlpldo2vddb_pwrsw_force_off
6732*4882a593Smuzhiyun 	 * Set subcore_memlpldo2vddret_pwrsw_force_off,d11_2x2_bw80_memlpldo2vddret_pwrsw_force_off
6733*4882a593Smuzhiyun 	 * and d11_2x2_bw20_memlpldo2vddret_pwrsw_force_off
6734*4882a593Smuzhiyun 	 */
6735*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6736*4882a593Smuzhiyun 		(PMU_CC13_SUBCORE_CBUCK2VDDB_OFF | PMU_CC13_SUBCORE_CBUCK2VDDRET_OFF |
6737*4882a593Smuzhiyun 		PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF | PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF),
6738*4882a593Smuzhiyun 		(PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF | PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF));
6739*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6740*4882a593Smuzhiyun 		(PMU_CC13_MAIN_CBUCK2VDDB_OFF | PMU_CC13_MAIN_CBUCK2VDDRET_OFF |
6741*4882a593Smuzhiyun 		PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF | PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF),
6742*4882a593Smuzhiyun 		(PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF | PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF));
6743*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6744*4882a593Smuzhiyun 		(PMU_CC13_AUX_CBUCK2VDDB_OFF | PMU_CC13_AUX_CBUCK2VDDRET_OFF |
6745*4882a593Smuzhiyun 		PMU_CC13_AUX_MEMLPLDO2VDDB_OFF | PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF),
6746*4882a593Smuzhiyun 		(PMU_CC13_AUX_MEMLPLDO2VDDB_OFF | PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF));
6747*4882a593Smuzhiyun 
6748*4882a593Smuzhiyun 	/* PCIE retention mode enable */
6749*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL6,
6750*4882a593Smuzhiyun 		PMU_CC6_ENABLE_PCIE_RETENTION, PMU_CC6_ENABLE_PCIE_RETENTION);
6751*4882a593Smuzhiyun }
6752*4882a593Smuzhiyun 
6753*4882a593Smuzhiyun static void
BCMATTACHFN(si_set_lv_sleep_mode_4369)6754*4882a593Smuzhiyun BCMATTACHFN(si_set_lv_sleep_mode_4369)(si_t *sih, osl_t *osh)
6755*4882a593Smuzhiyun {
6756*4882a593Smuzhiyun 	si_set_lv_sleep_mode_pmu(sih, osh);
6757*4882a593Smuzhiyun 
6758*4882a593Smuzhiyun 	si_set_lv_sleep_mode_lhl_config_4369(sih);
6759*4882a593Smuzhiyun 
6760*4882a593Smuzhiyun 	/* Enable PMU interrupts */
6761*4882a593Smuzhiyun 	CHIPC_REG(sih, intmask, (1u << 4u), (1u << 4u));
6762*4882a593Smuzhiyun }
6763*4882a593Smuzhiyun 
si_set_abuck_mode_4362(si_t * sih,uint8 mode)6764*4882a593Smuzhiyun void si_set_abuck_mode_4362(si_t *sih, uint8 mode)
6765*4882a593Smuzhiyun {
6766*4882a593Smuzhiyun 
6767*4882a593Smuzhiyun 	if (mode < 2 || mode > 4) {
6768*4882a593Smuzhiyun 		ASSERT(0);
6769*4882a593Smuzhiyun 		return;
6770*4882a593Smuzhiyun 	}
6771*4882a593Smuzhiyun 
6772*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_16, PMU_4362_VREG16_RSRC0_ABUCK_MODE_MASK,
6773*4882a593Smuzhiyun 		mode << PMU_4362_VREG16_RSRC0_ABUCK_MODE_SHIFT);
6774*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_16, PMU_4362_VREG16_RSRC1_ABUCK_MODE_MASK,
6775*4882a593Smuzhiyun 		mode << PMU_4362_VREG16_RSRC1_ABUCK_MODE_SHIFT);
6776*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_16, PMU_4362_VREG16_RSRC2_ABUCK_MODE_MASK,
6777*4882a593Smuzhiyun 		mode << PMU_4362_VREG16_RSRC2_ABUCK_MODE_SHIFT);
6778*4882a593Smuzhiyun }
6779*4882a593Smuzhiyun 
6780*4882a593Smuzhiyun static void
BCMATTACHFN(si_set_lv_sleep_mode_4378)6781*4882a593Smuzhiyun BCMATTACHFN(si_set_lv_sleep_mode_4378)(si_t *sih, osl_t *osh)
6782*4882a593Smuzhiyun {
6783*4882a593Smuzhiyun 	si_set_lv_sleep_mode_pmu(sih, osh);
6784*4882a593Smuzhiyun 
6785*4882a593Smuzhiyun 	si_set_lv_sleep_mode_lhl_config_4378(sih);
6786*4882a593Smuzhiyun }
6787*4882a593Smuzhiyun 
6788*4882a593Smuzhiyun static void
BCMATTACHFN(si_set_lv_sleep_mode_pmu_4387)6789*4882a593Smuzhiyun BCMATTACHFN(si_set_lv_sleep_mode_pmu_4387)(si_t *sih, osl_t *osh)
6790*4882a593Smuzhiyun {
6791*4882a593Smuzhiyun 	/* Program pmu VREG resgiter for Resouce based ABUCK and CBUCK modes
6792*4882a593Smuzhiyun 	 *      cbuck rsrc 0 - PWM and abuck rsrc 0 - Auto, rsrc 1 - PWM
6793*4882a593Smuzhiyun 	 */
6794*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_16, PMU_4369_VREG16_RSRC1_ABUCK_MODE_MASK,
6795*4882a593Smuzhiyun 		0x2u << PMU_4369_VREG16_RSRC1_ABUCK_MODE_SHIFT);
6796*4882a593Smuzhiyun 
6797*4882a593Smuzhiyun 	/* asr voltage adjust PWM - 0.8V */
6798*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_8, PMU_4369_VREG8_ASR_OVADJ_LPPFM_MASK,
6799*4882a593Smuzhiyun 		0x10u << PMU_4369_VREG8_ASR_OVADJ_LPPFM_SHIFT);
6800*4882a593Smuzhiyun 
6801*4882a593Smuzhiyun 	/* Enable rsrc_en_asr_msk[0] and msk[1] */
6802*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_13, PMU_4369_VREG13_RSRC_EN0_ASR_MASK,
6803*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG13_RSRC_EN0_ASR_SHIFT);
6804*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_13, PMU_4369_VREG13_RSRC_EN1_ASR_MASK,
6805*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG13_RSRC_EN1_ASR_SHIFT);
6806*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_13, PMU_4369_VREG13_RSRC_EN2_ASR_MASK,
6807*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG13_RSRC_EN2_ASR_SHIFT);
6808*4882a593Smuzhiyun 
6809*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_14, PMU_4369_VREG14_RSRC_EN_CSR_MASK0_MASK,
6810*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG14_RSRC_EN_CSR_MASK0_SHIFT);
6811*4882a593Smuzhiyun 
6812*4882a593Smuzhiyun 	/* disable force_hp_mode and enable wl_pmu_lv_mod */
6813*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_7,
6814*4882a593Smuzhiyun 		(PMU_4369_VREG_7_WL_PMU_LV_MODE_MASK | PMU_4369_VREG_7_WL_PMU_LP_MODE_MASK |
6815*4882a593Smuzhiyun 		PMU_4369_VREG_7_PMU_FORCE_HP_MODE_MASK), PMU_4369_VREG_7_WL_PMU_LV_MODE_MASK);
6816*4882a593Smuzhiyun 
6817*4882a593Smuzhiyun 	/* Enabale MEMLPLDO ( to enable 0x08)and BTLDO is enabled. At sleep RFLDO is disabled */
6818*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_6, PMU_4369_VREG_6_MEMLPLDO_POWER_UP_MASK,
6819*4882a593Smuzhiyun 		0x1u << PMU_4369_VREG_6_MEMLPLDO_POWER_UP_SHIFT);
6820*4882a593Smuzhiyun 
6821*4882a593Smuzhiyun 	/* For 4387C0, we don't need memlpldo2vddret_on nor cldo2vddb_on.
6822*4882a593Smuzhiyun 	 * We just need to clear the memlpldo2vddb_forceoff to turn on all the memlpldo2vddb pwrsw
6823*4882a593Smuzhiyun 	 */
6824*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) < 39) {
6825*4882a593Smuzhiyun 		/* Program PMU chip cntrl register to control
6826*4882a593Smuzhiyun 		 *     cbuck2vddb_pwrsw_force_on =1 and memlpldo2vddb_pwrsw_force_off = 1
6827*4882a593Smuzhiyun 		 *     cbuck2ret_pwrsw_force_on = 1 and memlpldo2vddb_pwrsw_force_off = 1
6828*4882a593Smuzhiyun 		 *     set d11_2x2_bw80_cbuck2vddb_pwrsw_force_on and
6829*4882a593Smuzhiyun 		 *     d11_2x2_bw20_cbuck2vddb_pwrsw_force_on cbuck2ret_pwrsw on 4 cores
6830*4882a593Smuzhiyun 		 */
6831*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
6832*4882a593Smuzhiyun 			(PMU_CC4_4369_MAIN_PD_CBUCK2VDDB_ON | PMU_CC4_4369_MAIN_PD_CBUCK2VDDRET_ON |
6833*4882a593Smuzhiyun 			PMU_CC4_4369_MAIN_PD_MEMLPLDO2VDDB_ON |
6834*4882a593Smuzhiyun 			PMU_CC4_4369_MAIN_PD_MEMLPDLO2VDDRET_ON),
6835*4882a593Smuzhiyun 			(PMU_CC4_4369_MAIN_PD_CBUCK2VDDB_ON |
6836*4882a593Smuzhiyun 			PMU_CC4_4369_MAIN_PD_CBUCK2VDDRET_ON));
6837*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
6838*4882a593Smuzhiyun 			(PMU_CC4_4369_AUX_PD_CBUCK2VDDB_ON | PMU_CC4_4369_AUX_PD_CBUCK2VDDRET_ON |
6839*4882a593Smuzhiyun 			PMU_CC4_4369_AUX_PD_MEMLPLDO2VDDB_ON |
6840*4882a593Smuzhiyun 			PMU_CC4_4369_AUX_PD_MEMLPLDO2VDDRET_ON),
6841*4882a593Smuzhiyun 			(PMU_CC4_4369_AUX_PD_CBUCK2VDDB_ON | PMU_CC4_4369_AUX_PD_CBUCK2VDDRET_ON));
6842*4882a593Smuzhiyun 
6843*4882a593Smuzhiyun 		/* set subcore_cbuck2vddb_pwrsw_force_on */
6844*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL5,
6845*4882a593Smuzhiyun 			(PMU_CC5_4369_SUBCORE_CBUCK2VDDB_ON | PMU_CC5_4369_SUBCORE_CBUCK2VDDRET_ON |
6846*4882a593Smuzhiyun 			PMU_CC5_4369_SUBCORE_MEMLPLDO2VDDB_ON |
6847*4882a593Smuzhiyun 			PMU_CC5_4369_SUBCORE_MEMLPLDO2VDDRET_ON),
6848*4882a593Smuzhiyun 			(PMU_CC5_4369_SUBCORE_CBUCK2VDDB_ON |
6849*4882a593Smuzhiyun 			PMU_CC5_4369_SUBCORE_CBUCK2VDDRET_ON));
6850*4882a593Smuzhiyun 
6851*4882a593Smuzhiyun 		/* Set subcore_memlpldo2vddb_pwrsw_force_off,
6852*4882a593Smuzhiyun 		 * d11_2x2_bw80_memlpldo2vddb_pwrsw_force_off
6853*4882a593Smuzhiyun 		 * and d11_2x2_bw20_memlpldo2vddb_pwrsw_force_off
6854*4882a593Smuzhiyun 		 * Set subcore_memlpldo2vddret_pwrsw_force_off,
6855*4882a593Smuzhiyun 		 * d11_2x2_bw80_memlpldo2vddret_pwrsw_force_off
6856*4882a593Smuzhiyun 		 * and d11_2x2_bw20_memlpldo2vddret_pwrsw_force_off
6857*4882a593Smuzhiyun 		 */
6858*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6859*4882a593Smuzhiyun 			(PMU_CC13_SUBCORE_CBUCK2VDDB_OFF | PMU_CC13_SUBCORE_CBUCK2VDDRET_OFF |
6860*4882a593Smuzhiyun 			PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF | PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF),
6861*4882a593Smuzhiyun 			(PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF |
6862*4882a593Smuzhiyun 			PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF));
6863*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6864*4882a593Smuzhiyun 			(PMU_CC13_MAIN_CBUCK2VDDB_OFF | PMU_CC13_MAIN_CBUCK2VDDRET_OFF |
6865*4882a593Smuzhiyun 			PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF | PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF),
6866*4882a593Smuzhiyun 			(PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF | PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF));
6867*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6868*4882a593Smuzhiyun 			(PMU_CC13_AUX_CBUCK2VDDB_OFF | PMU_CC13_AUX_CBUCK2VDDRET_OFF |
6869*4882a593Smuzhiyun 			PMU_CC13_AUX_MEMLPLDO2VDDB_OFF | PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF),
6870*4882a593Smuzhiyun 			(PMU_CC13_AUX_MEMLPLDO2VDDB_OFF | PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF));
6871*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
6872*4882a593Smuzhiyun 			PMU_CC4_4369_AUX_PD_MEMLPLDO2VDDRET_ON,
6873*4882a593Smuzhiyun 			PMU_CC4_4369_AUX_PD_MEMLPLDO2VDDRET_ON);
6874*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL5,
6875*4882a593Smuzhiyun 			PMU_CC5_4369_SUBCORE_MEMLPLDO2VDDRET_ON,
6876*4882a593Smuzhiyun 			PMU_CC5_4369_SUBCORE_MEMLPLDO2VDDRET_ON),
6877*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6878*4882a593Smuzhiyun 			PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF |
6879*4882a593Smuzhiyun 			PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF |
6880*4882a593Smuzhiyun 			PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF |
6881*4882a593Smuzhiyun 			PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF |
6882*4882a593Smuzhiyun 			PMU_CC13_AUX_MEMLPLDO2VDDB_OFF |
6883*4882a593Smuzhiyun 			PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF |
6884*4882a593Smuzhiyun 			PMU_CC13_CMN_MEMLPLDO2VDDRET_ON,
6885*4882a593Smuzhiyun 			PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF |
6886*4882a593Smuzhiyun 			PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF |
6887*4882a593Smuzhiyun 			PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF |
6888*4882a593Smuzhiyun 			PMU_CC13_AUX_MEMLPLDO2VDDB_OFF |
6889*4882a593Smuzhiyun 			PMU_CC13_CMN_MEMLPLDO2VDDRET_ON);
6890*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL17,
6891*4882a593Smuzhiyun 			PMU_CC17_SCAN_MEMLPLDO2VDDRET_ON |
6892*4882a593Smuzhiyun 			PMU_CC17_SCAN_CBUCK2VDDB_ON |
6893*4882a593Smuzhiyun 			PMU_CC17_SCAN_MEMLPLDO2VDDRET_OFF,
6894*4882a593Smuzhiyun 			PMU_CC17_SCAN_MEMLPLDO2VDDRET_ON |
6895*4882a593Smuzhiyun 			PMU_CC17_SCAN_CBUCK2VDDB_ON);
6896*4882a593Smuzhiyun 	} else {
6897*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6898*4882a593Smuzhiyun 			PMU_CC13_CMN_MEMLPLDO2VDDRET_ON |
6899*4882a593Smuzhiyun 			PMU_CC13_AUX_MEMLPLDO2VDDB_OFF |
6900*4882a593Smuzhiyun 			PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF |
6901*4882a593Smuzhiyun 			PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF,
6902*4882a593Smuzhiyun 			PMU_CC13_CMN_MEMLPLDO2VDDRET_ON);
6903*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL17,
6904*4882a593Smuzhiyun 			PMU_CC17_SCAN_MEMLPLDO2VDDB_OFF, 0);
6905*4882a593Smuzhiyun 	}
6906*4882a593Smuzhiyun 
6907*4882a593Smuzhiyun 	/* PCIE retention mode enable */
6908*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL6,
6909*4882a593Smuzhiyun 		PMU_CC6_ENABLE_PCIE_RETENTION, PMU_CC6_ENABLE_PCIE_RETENTION);
6910*4882a593Smuzhiyun 
6911*4882a593Smuzhiyun 	/* H/W JIRA http://jira.broadcom.com/browse/HW4387-825
6912*4882a593Smuzhiyun 	 * B0 only, the h/w bug is fixed in C0
6913*4882a593Smuzhiyun 	 */
6914*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) == 38) {
6915*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_14,
6916*4882a593Smuzhiyun 			PMU_VREG14_RSRC_EN_ASR_PWM_PFM_MASK,
6917*4882a593Smuzhiyun 			PMU_VREG14_RSRC_EN_ASR_PWM_PFM_MASK);
6918*4882a593Smuzhiyun 	}
6919*4882a593Smuzhiyun 
6920*4882a593Smuzhiyun 	/* WAR for jira HW4387-922 */
6921*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_1,
6922*4882a593Smuzhiyun 		PMU_4387_VREG1_CSR_OVERI_DIS_MASK,
6923*4882a593Smuzhiyun 		PMU_4387_VREG1_CSR_OVERI_DIS_MASK);
6924*4882a593Smuzhiyun 
6925*4882a593Smuzhiyun 	/* Clear Misc_LDO override */
6926*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_5, VREG5_4387_MISCLDO_PU_MASK, 0);
6927*4882a593Smuzhiyun 
6928*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_8,
6929*4882a593Smuzhiyun 		PMU_4387_VREG8_ASR_OVERI_DIS_MASK,
6930*4882a593Smuzhiyun 		PMU_4387_VREG8_ASR_OVERI_DIS_MASK);
6931*4882a593Smuzhiyun 
6932*4882a593Smuzhiyun 	if (BCMSRTOPOFF_ENAB()) {
6933*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_6,
6934*4882a593Smuzhiyun 			PMU_4387_VREG6_WL_PMU_LV_MODE_MASK, 0);
6935*4882a593Smuzhiyun 
6936*4882a593Smuzhiyun 		/* Clear memldo_pu bit as 4387 doesn't plan to use MEMLDO */
6937*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_6,
6938*4882a593Smuzhiyun 			PMU_4387_VREG6_MEMLDO_PU_MASK, 0);
6939*4882a593Smuzhiyun 	} else {
6940*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_6,
6941*4882a593Smuzhiyun 			PMU_4387_VREG6_WL_PMU_LV_MODE_MASK,
6942*4882a593Smuzhiyun 			PMU_4387_VREG6_WL_PMU_LV_MODE_MASK);
6943*4882a593Smuzhiyun 	}
6944*4882a593Smuzhiyun }
6945*4882a593Smuzhiyun 
6946*4882a593Smuzhiyun static void
BCMATTACHFN(si_set_lv_sleep_mode_4387)6947*4882a593Smuzhiyun BCMATTACHFN(si_set_lv_sleep_mode_4387)(si_t *sih, osl_t *osh)
6948*4882a593Smuzhiyun {
6949*4882a593Smuzhiyun 	si_set_lv_sleep_mode_pmu_4387(sih, osh);
6950*4882a593Smuzhiyun 	si_set_lv_sleep_mode_lhl_config_4387(sih);
6951*4882a593Smuzhiyun }
6952*4882a593Smuzhiyun 
6953*4882a593Smuzhiyun static void
BCMATTACHFN(si_set_lv_sleep_mode_4389)6954*4882a593Smuzhiyun BCMATTACHFN(si_set_lv_sleep_mode_4389)(si_t *sih, osl_t *osh)
6955*4882a593Smuzhiyun {
6956*4882a593Smuzhiyun 	si_set_lv_sleep_mode_pmu(sih, osh);
6957*4882a593Smuzhiyun 
6958*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
6959*4882a593Smuzhiyun 		PMU_CC4_4387_MAIN_PD_CBUCK2VDDRET_ON |
6960*4882a593Smuzhiyun 		PMU_CC4_4387_AUX_PD_CBUCK2VDDRET_ON,
6961*4882a593Smuzhiyun 		0);
6962*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL5,
6963*4882a593Smuzhiyun 		PMU_CC5_4387_SUBCORE_CBUCK2VDDRET_ON,
6964*4882a593Smuzhiyun 		0);
6965*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL6,
6966*4882a593Smuzhiyun 		PMU_CC6_RX4_CLK_SEQ_SELECT_MASK,
6967*4882a593Smuzhiyun 		0);
6968*4882a593Smuzhiyun 	/* Disable lq_clk - HW4387-254 */
6969*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL12,
6970*4882a593Smuzhiyun 		PMU_CC12_DISABLE_LQ_CLK_ON,
6971*4882a593Smuzhiyun 		PMU_CC12_DISABLE_LQ_CLK_ON);
6972*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6973*4882a593Smuzhiyun 		PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF |
6974*4882a593Smuzhiyun 		PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF |
6975*4882a593Smuzhiyun 		PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF,
6976*4882a593Smuzhiyun 		0);
6977*4882a593Smuzhiyun 
6978*4882a593Smuzhiyun #ifdef NOT_YET
6979*4882a593Smuzhiyun 	/* FIXME: this setting is causing the load switch from CSR to ASR */
6980*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
6981*4882a593Smuzhiyun 		PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF |
6982*4882a593Smuzhiyun 		PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF |
6983*4882a593Smuzhiyun 		PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF |
6984*4882a593Smuzhiyun 		PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF |
6985*4882a593Smuzhiyun 		PMU_CC13_AUX_MEMLPLDO2VDDB_OFF |
6986*4882a593Smuzhiyun 		PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF |
6987*4882a593Smuzhiyun 		PMU_CC13_CMN_MEMLPLDO2VDDRET_ON, 0);
6988*4882a593Smuzhiyun #endif /* NOT_YET */
6989*4882a593Smuzhiyun 
6990*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL17,
6991*4882a593Smuzhiyun 		PMU_CC17_SCAN_MEMLPLDO2VDDRET_ON |
6992*4882a593Smuzhiyun 		PMU_CC17_SCAN_CBUCK2VDDB_ON |
6993*4882a593Smuzhiyun 		PMU_CC17_SCAN_MEMLPLDO2VDDRET_OFF,
6994*4882a593Smuzhiyun 		PMU_CC17_SCAN_MEMLPLDO2VDDRET_ON |
6995*4882a593Smuzhiyun 		PMU_CC17_SCAN_CBUCK2VDDB_ON);
6996*4882a593Smuzhiyun 
6997*4882a593Smuzhiyun 	si_set_lv_sleep_mode_lhl_config_4389(sih);
6998*4882a593Smuzhiyun 
6999*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_6,
7000*4882a593Smuzhiyun 		(PMU_4389_VREG6_WL_PMU_LV_MODE_MASK | PMU_4389_VREG6_MEMLDO_PU_MASK),
7001*4882a593Smuzhiyun 		PMU_4389_VREG6_WL_PMU_LV_MODE_MASK);
7002*4882a593Smuzhiyun 
7003*4882a593Smuzhiyun 	/* SW WAR for 4389B0(rev 01) issue - HW4387-922. 4389C0(rev 02) already has HW fix */
7004*4882a593Smuzhiyun 	if (CHIPREV(sih->chiprev) == 1) {
7005*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_1,
7006*4882a593Smuzhiyun 			PMU_4387_VREG1_CSR_OVERI_DIS_MASK,
7007*4882a593Smuzhiyun 			PMU_4387_VREG1_CSR_OVERI_DIS_MASK);
7008*4882a593Smuzhiyun 
7009*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_8,
7010*4882a593Smuzhiyun 			PMU_4387_VREG8_ASR_OVERI_DIS_MASK,
7011*4882a593Smuzhiyun 			PMU_4387_VREG8_ASR_OVERI_DIS_MASK);
7012*4882a593Smuzhiyun 	}
7013*4882a593Smuzhiyun }
7014*4882a593Smuzhiyun 
7015*4882a593Smuzhiyun static void
BCMATTACHFN(si_set_lv_sleep_mode_4362)7016*4882a593Smuzhiyun BCMATTACHFN(si_set_lv_sleep_mode_4362)(si_t *sih, osl_t *osh)
7017*4882a593Smuzhiyun {
7018*4882a593Smuzhiyun 	/* Program pmu VREG resgiter for Resouce based ABUCK and CBUCK modes
7019*4882a593Smuzhiyun 	 *      cbuck rsrc 0 - PWM and abuck rsrc 0 - Auto, rsrc 1 - PWM
7020*4882a593Smuzhiyun 	 */
7021*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_16, PMU_4362_VREG16_RSRC0_CBUCK_MODE_MASK,
7022*4882a593Smuzhiyun 		0x3u << PMU_4362_VREG16_RSRC0_CBUCK_MODE_SHIFT);
7023*4882a593Smuzhiyun 
7024*4882a593Smuzhiyun 	si_set_abuck_mode_4362(sih, 0x3u);
7025*4882a593Smuzhiyun 
7026*4882a593Smuzhiyun 	/* asr voltage adjust PWM - 0.8V */
7027*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_8, PMU_4362_VREG8_ASR_OVADJ_LPPFM_MASK,
7028*4882a593Smuzhiyun 		0x10u << PMU_4362_VREG8_ASR_OVADJ_LPPFM_SHIFT);
7029*4882a593Smuzhiyun 
7030*4882a593Smuzhiyun 	/* Enable rsrc_en_asr_msk[0] and msk[1] */
7031*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_13, PMU_4362_VREG13_RSRC_EN0_ASR_MASK,
7032*4882a593Smuzhiyun 		0x1u << PMU_4362_VREG13_RSRC_EN0_ASR_SHIFT);
7033*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_13, PMU_4362_VREG13_RSRC_EN1_ASR_MASK,
7034*4882a593Smuzhiyun 		0x1u << PMU_4362_VREG13_RSRC_EN1_ASR_SHIFT);
7035*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_13, PMU_4362_VREG13_RSRC_EN2_ASR_MASK,
7036*4882a593Smuzhiyun 		0x1u << PMU_4362_VREG13_RSRC_EN2_ASR_SHIFT);
7037*4882a593Smuzhiyun 
7038*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_14, PMU_4362_VREG14_RSRC_EN_CSR_MASK0_MASK,
7039*4882a593Smuzhiyun 		0x1u << PMU_4362_VREG14_RSRC_EN_CSR_MASK0_SHIFT);
7040*4882a593Smuzhiyun 
7041*4882a593Smuzhiyun 	/* disable force_hp_mode and enable wl_pmu_lv_mod */
7042*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_7,
7043*4882a593Smuzhiyun 		(PMU_4362_VREG_7_WL_PMU_LV_MODE_MASK | PMU_4362_VREG_7_WL_PMU_LP_MODE_MASK |
7044*4882a593Smuzhiyun 		PMU_4362_VREG_7_PMU_FORCE_HP_MODE_MASK), PMU_4362_VREG_7_WL_PMU_LV_MODE_MASK);
7045*4882a593Smuzhiyun 
7046*4882a593Smuzhiyun 	/* Enable MISCLDO, MEMLPLDO_adj -0.7V, Disable LPLDO power up */
7047*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_5, PMU_4362_VREG_5_MISCLDO_POWER_UP_MASK,
7048*4882a593Smuzhiyun 		0x1u << PMU_4362_VREG_5_MISCLDO_POWER_UP_SHIFT);
7049*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_5, PMU_4362_VREG_5_LPLDO_POWER_UP_MASK, 0x0u);
7050*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_5, PMU_4362_VREG_5_MEMLPLDO_OP_VLT_ADJ_CTRL_MASK,
7051*4882a593Smuzhiyun 		0xBu << PMU_4362_VREG_5_MEMLPLDO_OP_VLT_ADJ_CTRL_SHIFT);
7052*4882a593Smuzhiyun 
7053*4882a593Smuzhiyun 	/* Enabale MEMLPLDO ( to enable 0x08)and BTLDO is enabled. At sleep RFLDO is disabled */
7054*4882a593Smuzhiyun 	si_pmu_vreg_control(sih, PMU_VREG_6, PMU_4362_VREG_6_MEMLPLDO_POWER_UP_MASK,
7055*4882a593Smuzhiyun 		0x1u << PMU_4362_VREG_6_MEMLPLDO_POWER_UP_SHIFT);
7056*4882a593Smuzhiyun 
7057*4882a593Smuzhiyun 	/* Program PMU chip cntrl register to control
7058*4882a593Smuzhiyun 	 *     cbuck2vddb_pwrsw_force_on =1 and memlpldo2vddb_pwrsw_force_off = 1
7059*4882a593Smuzhiyun 	 *     cbuck2ret_pwrsw_force_on = 1 and memlpldo2vddb_pwrsw_force_off = 1
7060*4882a593Smuzhiyun 	 *     set d11_2x2_bw80_cbuck2vddb_pwrsw_force_on and
7061*4882a593Smuzhiyun 	 *     d11_2x2_bw20_cbuck2vddb_pwrsw_force_on cbuck2ret_pwrsw on 4 cores
7062*4882a593Smuzhiyun 	 */
7063*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
7064*4882a593Smuzhiyun 		(PMU_CC4_4362_PD_CBUCK2VDDB_ON | PMU_CC4_4362_PD_CBUCK2VDDRET_ON |
7065*4882a593Smuzhiyun 		PMU_CC4_4362_PD_MEMLPLDO2VDDB_ON | PMU_CC4_4362_PD_MEMLPDLO2VDDRET_ON),
7066*4882a593Smuzhiyun 		(PMU_CC4_4362_PD_CBUCK2VDDB_ON | PMU_CC4_4362_PD_CBUCK2VDDRET_ON));
7067*4882a593Smuzhiyun 
7068*4882a593Smuzhiyun 	/* set subcore_cbuck2vddb_pwrsw_force_on */
7069*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL5,
7070*4882a593Smuzhiyun 		(PMU_CC5_4362_SUBCORE_CBUCK2VDDB_ON | PMU_CC5_4362_SUBCORE_CBUCK2VDDRET_ON |
7071*4882a593Smuzhiyun 		PMU_CC5_4362_SUBCORE_MEMLPLDO2VDDB_ON | PMU_CC5_4362_SUBCORE_MEMLPLDO2VDDRET_ON),
7072*4882a593Smuzhiyun 		(PMU_CC5_4362_SUBCORE_CBUCK2VDDB_ON | PMU_CC5_4362_SUBCORE_CBUCK2VDDRET_ON));
7073*4882a593Smuzhiyun 
7074*4882a593Smuzhiyun 	/* Set subcore_memlpldo2vddb_pwrsw_force_off, d11_2x2_bw80_memlpldo2vddb_pwrsw_force_off
7075*4882a593Smuzhiyun 	 * and d11_2x2_bw20_memlpldo2vddb_pwrsw_force_off
7076*4882a593Smuzhiyun 	 * Set subcore_memlpldo2vddret_pwrsw_force_off,d11_2x2_bw80_memlpldo2vddret_pwrsw_force_off
7077*4882a593Smuzhiyun 	 * and d11_2x2_bw20_memlpldo2vddret_pwrsw_force_off
7078*4882a593Smuzhiyun 	 */
7079*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
7080*4882a593Smuzhiyun 		(PMU_CC13_SUBCORE_CBUCK2VDDB_OFF | PMU_CC13_SUBCORE_CBUCK2VDDRET_OFF |
7081*4882a593Smuzhiyun 		PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF | PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF),
7082*4882a593Smuzhiyun 		(PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF | PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF));
7083*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
7084*4882a593Smuzhiyun 		(PMU_CC13_MAIN_CBUCK2VDDB_OFF | PMU_CC13_MAIN_CBUCK2VDDB_OFF |
7085*4882a593Smuzhiyun 		PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF | PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF),
7086*4882a593Smuzhiyun 		(PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF | PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF));
7087*4882a593Smuzhiyun 
7088*4882a593Smuzhiyun 	/* PCIE retention mode enable */
7089*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL6,
7090*4882a593Smuzhiyun 		PMU_CC6_ENABLE_PCIE_RETENTION, PMU_CC6_ENABLE_PCIE_RETENTION);
7091*4882a593Smuzhiyun 
7092*4882a593Smuzhiyun 	si_set_lv_sleep_mode_lhl_config_4362(sih);
7093*4882a593Smuzhiyun 
7094*4882a593Smuzhiyun 	/* Enable PMU interrupts */
7095*4882a593Smuzhiyun 	CHIPC_REG(sih, intmask, (1u << 4u), (1u << 4u));
7096*4882a593Smuzhiyun }
7097*4882a593Smuzhiyun 
7098*4882a593Smuzhiyun void
BCMATTACHFN(si_pmu_fis_setup)7099*4882a593Smuzhiyun BCMATTACHFN(si_pmu_fis_setup)(si_t *sih)
7100*4882a593Smuzhiyun {
7101*4882a593Smuzhiyun 	uint origidx;
7102*4882a593Smuzhiyun 	pmuregs_t *pmu;
7103*4882a593Smuzhiyun 	int val;
7104*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
7105*4882a593Smuzhiyun 
7106*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7107*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
7108*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
7109*4882a593Smuzhiyun 	} else {
7110*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
7111*4882a593Smuzhiyun 	}
7112*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
7113*4882a593Smuzhiyun 
7114*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
7115*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
7116*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
7117*4882a593Smuzhiyun 		val = R_REG(osh, &pmu->max_res_mask);
7118*4882a593Smuzhiyun 		W_REG(osh, &pmu->fis_start_min_res_mask, val);
7119*4882a593Smuzhiyun 
7120*4882a593Smuzhiyun 		val = R_REG(osh, &pmu->min_res_mask);
7121*4882a593Smuzhiyun 		W_REG(osh, &pmu->fis_min_res_mask, val);
7122*4882a593Smuzhiyun 
7123*4882a593Smuzhiyun 		W_REG(osh, &pmu->fis_ctrl_status,
7124*4882a593Smuzhiyun 			(PMU_FIS_DN_TIMER_VAL_4378 << PMU_FIS_DN_TIMER_VAL_SHIFT)
7125*4882a593Smuzhiyun 			& PMU_FIS_DN_TIMER_VAL_MASK);
7126*4882a593Smuzhiyun 		break;
7127*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
7128*4882a593Smuzhiyun 		val = R_REG(osh, &pmu->max_res_mask);
7129*4882a593Smuzhiyun 		W_REG(osh, &pmu->fis_start_min_res_mask, val);
7130*4882a593Smuzhiyun 
7131*4882a593Smuzhiyun 		val = R_REG(osh, &pmu->min_res_mask);
7132*4882a593Smuzhiyun 		W_REG(osh, &pmu->fis_min_res_mask, val);
7133*4882a593Smuzhiyun 
7134*4882a593Smuzhiyun 		W_REG(osh, &pmu->fis_ctrl_status,
7135*4882a593Smuzhiyun 			((PMU_FIS_DN_TIMER_VAL_4388 << PMU_FIS_DN_TIMER_VAL_SHIFT)
7136*4882a593Smuzhiyun 			 & PMU_FIS_DN_TIMER_VAL_MASK) | PMU_FIS_PCIE_SAVE_EN_VALUE);
7137*4882a593Smuzhiyun 		break;
7138*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
7139*4882a593Smuzhiyun 		val = R_REG(osh, &pmu->max_res_mask);
7140*4882a593Smuzhiyun 		W_REG(osh, &pmu->fis_start_min_res_mask, val);
7141*4882a593Smuzhiyun 
7142*4882a593Smuzhiyun 		val = R_REG(osh, &pmu->min_res_mask);
7143*4882a593Smuzhiyun 		W_REG(osh, &pmu->fis_min_res_mask, val);
7144*4882a593Smuzhiyun 
7145*4882a593Smuzhiyun 		W_REG(osh, &pmu->fis_ctrl_status,
7146*4882a593Smuzhiyun 			((PMU_FIS_DN_TIMER_VAL_4389 << PMU_FIS_DN_TIMER_VAL_SHIFT)
7147*4882a593Smuzhiyun 			 & PMU_FIS_DN_TIMER_VAL_MASK) | PMU_FIS_PCIE_SAVE_EN_VALUE);
7148*4882a593Smuzhiyun 		break;
7149*4882a593Smuzhiyun 
7150*4882a593Smuzhiyun 	default:
7151*4882a593Smuzhiyun 		break;
7152*4882a593Smuzhiyun 	}
7153*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
7154*4882a593Smuzhiyun }
7155*4882a593Smuzhiyun #endif /* defined(SAVERESTORE) */
7156*4882a593Smuzhiyun 
7157*4882a593Smuzhiyun /*
7158*4882a593Smuzhiyun  * Enable: Dynamic Clk Switching
7159*4882a593Smuzhiyun  * Disable: Mirrored Mode
7160*4882a593Smuzhiyun  * use nvram to enable
7161*4882a593Smuzhiyun  */
7162*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_dynamic_clk_switch_enab)7163*4882a593Smuzhiyun BCMATTACHFN(si_pmu_dynamic_clk_switch_enab)(si_t *sih)
7164*4882a593Smuzhiyun {
7165*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 36) {
7166*4882a593Smuzhiyun 		if (getintvar(NULL, rstr_dyn_clksw_en)) {
7167*4882a593Smuzhiyun 			PMU_REG(sih, pmucontrol_ext,
7168*4882a593Smuzhiyun 				PCTL_EXT_REQ_MIRROR_ENAB, 0);
7169*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL2,
7170*4882a593Smuzhiyun 				CC2_4378_USE_WLAN_BP_CLK_ON_REQ_MASK |
7171*4882a593Smuzhiyun 				CC2_4378_USE_CMN_BP_CLK_ON_REQ_MASK,
7172*4882a593Smuzhiyun 				0);
7173*4882a593Smuzhiyun 		}
7174*4882a593Smuzhiyun 	}
7175*4882a593Smuzhiyun }
7176*4882a593Smuzhiyun 
7177*4882a593Smuzhiyun /* use pmu rsrc XTAL_PU to count deep sleep of chip */
7178*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_enb_slp_cnt_on_rsrc)7179*4882a593Smuzhiyun BCMATTACHFN(si_pmu_enb_slp_cnt_on_rsrc)(si_t *sih, osl_t *osh)
7180*4882a593Smuzhiyun {
7181*4882a593Smuzhiyun 	uint origidx;
7182*4882a593Smuzhiyun 	pmuregs_t *pmu;
7183*4882a593Smuzhiyun 	uint32 rsrc_slp = 0xffffffff;
7184*4882a593Smuzhiyun 
7185*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7186*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
7187*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
7188*4882a593Smuzhiyun 	} else {
7189*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
7190*4882a593Smuzhiyun 	}
7191*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
7192*4882a593Smuzhiyun 
7193*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
7194*4882a593Smuzhiyun 
7195*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
7196*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
7197*4882a593Smuzhiyun 		rsrc_slp = RES4378_XTAL_PU;
7198*4882a593Smuzhiyun 		break;
7199*4882a593Smuzhiyun 
7200*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
7201*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
7202*4882a593Smuzhiyun 		rsrc_slp = RES4387_XTAL_PU;
7203*4882a593Smuzhiyun 		break;
7204*4882a593Smuzhiyun 
7205*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
7206*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
7207*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
7208*4882a593Smuzhiyun 		rsrc_slp = RES4389_XTAL_PU;
7209*4882a593Smuzhiyun 		break;
7210*4882a593Smuzhiyun 
7211*4882a593Smuzhiyun 	default:
7212*4882a593Smuzhiyun 		break;
7213*4882a593Smuzhiyun 	}
7214*4882a593Smuzhiyun 
7215*4882a593Smuzhiyun 	if (rsrc_slp != 0xffffffff) {
7216*4882a593Smuzhiyun 		W_REG(osh, &pmu->rsrc_event0, PMURES_BIT(rsrc_slp));
7217*4882a593Smuzhiyun 	}
7218*4882a593Smuzhiyun 
7219*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
7220*4882a593Smuzhiyun }
7221*4882a593Smuzhiyun 
7222*4882a593Smuzhiyun #define MISC_LDO_STEPPING_DELAY	(150u)	/* 150 us, includes 50us additional margin */
7223*4882a593Smuzhiyun 
7224*4882a593Smuzhiyun /** initialize PMU chip controls and other chip level stuff */
7225*4882a593Smuzhiyun void
BCMATTACHFN(si_pmu_chip_init)7226*4882a593Smuzhiyun BCMATTACHFN(si_pmu_chip_init)(si_t *sih, osl_t *osh)
7227*4882a593Smuzhiyun {
7228*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
7229*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
7230*4882a593Smuzhiyun 		if (hnd_pmur == NULL) {
7231*4882a593Smuzhiyun 			uint coreidx = si_coreidx(sih);
7232*4882a593Smuzhiyun 			hnd_pmur = si_setcore(sih, PMU_CORE_ID, 0);
7233*4882a593Smuzhiyun 			ASSERT(hnd_pmur != NULL);
7234*4882a593Smuzhiyun 			/* Restore to CC */
7235*4882a593Smuzhiyun 			si_setcoreidx(sih, coreidx);
7236*4882a593Smuzhiyun 		}
7237*4882a593Smuzhiyun 	}
7238*4882a593Smuzhiyun 
7239*4882a593Smuzhiyun 	si_pmu_otp_chipcontrol(sih, osh);
7240*4882a593Smuzhiyun 
7241*4882a593Smuzhiyun #ifdef CHIPC_UART_ALWAYS_ON
7242*4882a593Smuzhiyun 	si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), CCS_FORCEALP, CCS_FORCEALP);
7243*4882a593Smuzhiyun #endif /* CHIPC_UART_ALWAYS_ON */
7244*4882a593Smuzhiyun 
7245*4882a593Smuzhiyun 	si_pmu_enb_slp_cnt_on_rsrc(sih, osh);
7246*4882a593Smuzhiyun 
7247*4882a593Smuzhiyun 	/* Misc. chip control, has nothing to do with PMU */
7248*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
7249*4882a593Smuzhiyun 
7250*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
7251*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
7252*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
7253*4882a593Smuzhiyun 	{
7254*4882a593Smuzhiyun #ifdef USE_LHL_TIMER
7255*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL2, PMUCCTL02_43012_LHL_TIMER_SELECT,
7256*4882a593Smuzhiyun 			PMUCCTL02_43012_LHL_TIMER_SELECT);
7257*4882a593Smuzhiyun #else
7258*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL2, PMUCCTL02_43012_LHL_TIMER_SELECT, 0);
7259*4882a593Smuzhiyun #endif /* USE_LHL_TIMER */
7260*4882a593Smuzhiyun 
7261*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL2, PMUCCTL02_43012_RFLDO3P3_PU_FORCE_ON, 0);
7262*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL4, PMUCCTL14_43012_DISABLE_LQ_AVAIL, 0);
7263*4882a593Smuzhiyun 
7264*4882a593Smuzhiyun 		PMU_REG_NEW(sih, extwakemask0,
7265*4882a593Smuzhiyun 				PMU_EXT_WAKE_MASK_0_SDIO, PMU_EXT_WAKE_MASK_0_SDIO);
7266*4882a593Smuzhiyun 		PMU_REG_NEW(sih, extwakereqmask[0], ~0, si_pmu_rsrc_ht_avail_clk_deps(sih, osh));
7267*4882a593Smuzhiyun 
7268*4882a593Smuzhiyun 		if (sih->lpflags & LPFLAGS_SI_FORCE_PWM_WHEN_RADIO_ON) {
7269*4882a593Smuzhiyun 			/* Force PWM when Radio ON */
7270*4882a593Smuzhiyun 			/* 2G_Listen/2G_RX/2G_TX/5G_Listen/5G_RX/5G_TX = PWM */
7271*4882a593Smuzhiyun 			si_pmu_vreg_control(sih, PMU_VREG_8,
7272*4882a593Smuzhiyun 				PMU_43012_VREG8_DYNAMIC_CBUCK_MODE_MASK,
7273*4882a593Smuzhiyun 				PMU_43012_VREG8_DYNAMIC_CBUCK_MODE0);
7274*4882a593Smuzhiyun 			si_pmu_vreg_control(sih, PMU_VREG_9,
7275*4882a593Smuzhiyun 				PMU_43012_VREG9_DYNAMIC_CBUCK_MODE_MASK,
7276*4882a593Smuzhiyun 				PMU_43012_VREG9_DYNAMIC_CBUCK_MODE0);
7277*4882a593Smuzhiyun 		}
7278*4882a593Smuzhiyun 		else {
7279*4882a593Smuzhiyun 			/* LPPFM opt setting for ePA */
7280*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL16, PMU_CC16_CLK4M_DIS, 1);
7281*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL16, PMU_CC16_FF_ZERO_ADJ, 4);
7282*4882a593Smuzhiyun 			/* 2G_Listen/2G_RX = LPPFM, 2G_TX/5G_Listen/5G_RX/5G_TX = PWM */
7283*4882a593Smuzhiyun 			si_pmu_vreg_control(sih, PMU_VREG_8,
7284*4882a593Smuzhiyun 				PMU_43012_VREG8_DYNAMIC_CBUCK_MODE_MASK,
7285*4882a593Smuzhiyun 				PMU_43012_VREG8_DYNAMIC_CBUCK_MODE1);
7286*4882a593Smuzhiyun 			si_pmu_vreg_control(sih, PMU_VREG_9,
7287*4882a593Smuzhiyun 				PMU_43012_VREG9_DYNAMIC_CBUCK_MODE_MASK,
7288*4882a593Smuzhiyun 				PMU_43012_VREG9_DYNAMIC_CBUCK_MODE1);
7289*4882a593Smuzhiyun 		}
7290*4882a593Smuzhiyun 		/* Set external LPO */
7291*4882a593Smuzhiyun 		si_lhl_set_lpoclk(sih, osh, LHL_LPO_AUTO);
7292*4882a593Smuzhiyun 
7293*4882a593Smuzhiyun 		/* Enabling WL2CDIG sleep */
7294*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL2, PMUCCTL02_43012_WL2CDIG_I_PMU_SLEEP_ENAB,
7295*4882a593Smuzhiyun 			PMUCCTL02_43012_WL2CDIG_I_PMU_SLEEP_ENAB);
7296*4882a593Smuzhiyun 
7297*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL9,
7298*4882a593Smuzhiyun 			PMUCCTL09_43012_XTAL_CORESIZE_BIAS_ADJ_STARTUP_MASK,
7299*4882a593Smuzhiyun 			PMUCCTL09_43012_XTAL_CORESIZE_BIAS_ADJ_STARTUP_VAL <<
7300*4882a593Smuzhiyun 				PMUCCTL09_43012_XTAL_CORESIZE_BIAS_ADJ_STARTUP_SHIFT);
7301*4882a593Smuzhiyun 
7302*4882a593Smuzhiyun 		/* Setting MemLPLDO voltage to 0.74 */
7303*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_6, VREG6_43012_MEMLPLDO_ADJ_MASK,
7304*4882a593Smuzhiyun 			0x8 << VREG6_43012_MEMLPLDO_ADJ_SHIFT);
7305*4882a593Smuzhiyun 
7306*4882a593Smuzhiyun 		/* Setting LPLDO voltage to 0.8 */
7307*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_6, VREG6_43012_LPLDO_ADJ_MASK,
7308*4882a593Smuzhiyun 			0xB << VREG6_43012_LPLDO_ADJ_SHIFT);
7309*4882a593Smuzhiyun 
7310*4882a593Smuzhiyun 		/* Turn off power switch 1P8 in sleep */
7311*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_7, VREG7_43012_PWRSW_1P8_PU_MASK, 0);
7312*4882a593Smuzhiyun 
7313*4882a593Smuzhiyun 		/* Enable PMU sleep mode0 (DS0-PS0) */
7314*4882a593Smuzhiyun 		LHL_REG(sih, lhl_top_pwrseq_ctl_adr, ~0, PMU_SLEEP_MODE_0);
7315*4882a593Smuzhiyun 
7316*4882a593Smuzhiyun 		si_pmu_fast_lpo_enable(sih, osh);
7317*4882a593Smuzhiyun 
7318*4882a593Smuzhiyun 		/* Enable the 'power kill' (power off selected retention memories) */
7319*4882a593Smuzhiyun 		GCI_REG_NEW(sih, bt_smem_control0, GCI_BT_SMEM_CTRL0_SUBCORE_ENABLE_PKILL,
7320*4882a593Smuzhiyun 			GCI_BT_SMEM_CTRL0_SUBCORE_ENABLE_PKILL);
7321*4882a593Smuzhiyun 
7322*4882a593Smuzhiyun 		break;
7323*4882a593Smuzhiyun 	}
7324*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
7325*4882a593Smuzhiyun 	{
7326*4882a593Smuzhiyun 		pmuregs_t *pmu = si_setcore(sih, PMU_CORE_ID, 0);
7327*4882a593Smuzhiyun 		uint32 lpo = LHL_LPO_AUTO;
7328*4882a593Smuzhiyun 		uint32 lhl_tmr_sel = 0;
7329*4882a593Smuzhiyun 
7330*4882a593Smuzhiyun 		/* DMAHANG WAR:SWWLAN:171729
7331*4882a593Smuzhiyun 		 * Stretch the ALP and HT clocks after de-asserting
7332*4882a593Smuzhiyun 		 * the request. During the RX frame transfer from RXFIFO to
7333*4882a593Smuzhiyun 		 * DP FIFO, in certain cases the clock is getting de-asserted
7334*4882a593Smuzhiyun 		 * by ucode as it does not have visibility beyond BM
7335*4882a593Smuzhiyun 		 */
7336*4882a593Smuzhiyun 		W_REG(osh, &pmu->clkstretch, 0x0fff0fff);
7337*4882a593Smuzhiyun 
7338*4882a593Smuzhiyun #ifdef USE_LHL_TIMER
7339*4882a593Smuzhiyun 		lhl_tmr_sel = PMU_CC13_LHL_TIMER_SELECT;
7340*4882a593Smuzhiyun #endif /* USE_LHL_TIMER */
7341*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13, PMU_CC13_LHL_TIMER_SELECT, lhl_tmr_sel);
7342*4882a593Smuzhiyun 
7343*4882a593Smuzhiyun 		if (R_REG(osh, &pmu->pmustatus) & PST_EXTLPOAVAIL) {
7344*4882a593Smuzhiyun 			lpo = LHL_EXT_LPO_ENAB;
7345*4882a593Smuzhiyun 		}
7346*4882a593Smuzhiyun 
7347*4882a593Smuzhiyun 		if (!ISSIM_ENAB(sih)) {
7348*4882a593Smuzhiyun 			si_lhl_set_lpoclk(sih, osh, lpo);
7349*4882a593Smuzhiyun 		}
7350*4882a593Smuzhiyun 
7351*4882a593Smuzhiyun 		if (getintvar(NULL, rstr_btldo3p3pu)) {
7352*4882a593Smuzhiyun 			si_pmu_regcontrol(sih, 4,
7353*4882a593Smuzhiyun 				PMU_28NM_VREG4_WL_LDO_CNTL_EN,
7354*4882a593Smuzhiyun 				PMU_28NM_VREG4_WL_LDO_CNTL_EN);
7355*4882a593Smuzhiyun 			si_pmu_regcontrol(sih, 6,
7356*4882a593Smuzhiyun 				PMU_28NM_VREG6_BTLDO3P3_PU,
7357*4882a593Smuzhiyun 				PMU_28NM_VREG6_BTLDO3P3_PU);
7358*4882a593Smuzhiyun 		}
7359*4882a593Smuzhiyun 
7360*4882a593Smuzhiyun 		/* write the XTAL preferred startup/normal A0/B0 revision */
7361*4882a593Smuzhiyun 		si_pmu_chipcontrol_xtal_settings_4362(sih);
7362*4882a593Smuzhiyun 
7363*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL6,
7364*4882a593Smuzhiyun 			(PMU_CC6_ENABLE_CLKREQ_WAKEUP | PMU_CC6_ENABLE_PCIE_RETENTION),
7365*4882a593Smuzhiyun 			(PMU_CC6_ENABLE_CLKREQ_WAKEUP | PMU_CC6_ENABLE_PCIE_RETENTION));
7366*4882a593Smuzhiyun 
7367*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_8, PMU_4362_VREG8_ASR_OVADJ_LPPFM_MASK,
7368*4882a593Smuzhiyun 			0x02u << PMU_4362_VREG8_ASR_OVADJ_LPPFM_SHIFT);
7369*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_8, PMU_4362_VREG8_ASR_OVADJ_PFM_MASK,
7370*4882a593Smuzhiyun 			0x02u << PMU_4362_VREG8_ASR_OVADJ_PFM_SHIFT);
7371*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_8, PMU_4362_VREG8_ASR_OVADJ_PWM_MASK,
7372*4882a593Smuzhiyun 			0x02u << PMU_4362_VREG8_ASR_OVADJ_PWM_SHIFT);
7373*4882a593Smuzhiyun #if defined(SAVERESTORE)
7374*4882a593Smuzhiyun 		if (SR_ENAB()) {
7375*4882a593Smuzhiyun 			si_set_lv_sleep_mode_4362(sih, osh);
7376*4882a593Smuzhiyun 		}
7377*4882a593Smuzhiyun #endif /* SAVERESTORE */
7378*4882a593Smuzhiyun 
7379*4882a593Smuzhiyun 		si_pmu_fast_lpo_enable(sih, osh);
7380*4882a593Smuzhiyun 		if ((PMUREV(sih->pmurev) >= 33) && FASTLPO_ENAB()) {
7381*4882a593Smuzhiyun 			/* Enabling FAST_SEQ */
7382*4882a593Smuzhiyun 			uint8	fastlpo_dis = fastlpo_dis_get();
7383*4882a593Smuzhiyun 			uint8	fastlpo_pcie_dis = fastlpo_pcie_dis_get();
7384*4882a593Smuzhiyun 			if (!fastlpo_dis || !fastlpo_pcie_dis) {
7385*4882a593Smuzhiyun 				PMU_REG(sih, pmucontrol_ext, PCTL_EXT_FASTSEQ_ENAB,
7386*4882a593Smuzhiyun 					PCTL_EXT_FASTSEQ_ENAB);
7387*4882a593Smuzhiyun 			}
7388*4882a593Smuzhiyun 		}
7389*4882a593Smuzhiyun 
7390*4882a593Smuzhiyun 		break;
7391*4882a593Smuzhiyun 	}
7392*4882a593Smuzhiyun 
7393*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
7394*4882a593Smuzhiyun 	{
7395*4882a593Smuzhiyun 		pmuregs_t *pmu = si_setcore(sih, PMU_CORE_ID, 0);
7396*4882a593Smuzhiyun 		uint32 lpo = LHL_LPO_AUTO;
7397*4882a593Smuzhiyun 		uint32 lhl_tmr_sel = 0;
7398*4882a593Smuzhiyun 
7399*4882a593Smuzhiyun 		/* DMAHANG WAR:SWWLAN:171729
7400*4882a593Smuzhiyun 		 * Stretch the ALP and HT clocks after de-asserting
7401*4882a593Smuzhiyun 		 * the request. During the RX frame transfer from RXFIFO to
7402*4882a593Smuzhiyun 		 * DP FIFO, in certain cases the clock is getting de-asserted
7403*4882a593Smuzhiyun 		 * by ucode as it does not have visibility beyond BM
7404*4882a593Smuzhiyun 		 */
7405*4882a593Smuzhiyun #ifndef ATE_BUILD
7406*4882a593Smuzhiyun 		W_REG(osh, &pmu->clkstretch, 0x0fff0fff);
7407*4882a593Smuzhiyun #endif
7408*4882a593Smuzhiyun 
7409*4882a593Smuzhiyun #ifdef USE_LHL_TIMER
7410*4882a593Smuzhiyun 		lhl_tmr_sel = PMU_CC13_4369_LHL_TIMER_SELECT;
7411*4882a593Smuzhiyun #endif
7412*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13, PMU_CC13_4369_LHL_TIMER_SELECT, lhl_tmr_sel);
7413*4882a593Smuzhiyun 
7414*4882a593Smuzhiyun 		if (R_REG(osh, &pmu->pmustatus) & PST_EXTLPOAVAIL) {
7415*4882a593Smuzhiyun 			lpo = LHL_EXT_LPO_ENAB;
7416*4882a593Smuzhiyun 		}
7417*4882a593Smuzhiyun 
7418*4882a593Smuzhiyun 		if (!ISSIM_ENAB(sih)) {
7419*4882a593Smuzhiyun 			si_lhl_set_lpoclk(sih, osh, lpo);
7420*4882a593Smuzhiyun 		}
7421*4882a593Smuzhiyun 
7422*4882a593Smuzhiyun 		if (getintvar(NULL, rstr_btldo3p3pu)) {
7423*4882a593Smuzhiyun 			si_pmu_regcontrol(sih, 4,
7424*4882a593Smuzhiyun 				PMU_28NM_VREG4_WL_LDO_CNTL_EN,
7425*4882a593Smuzhiyun 				PMU_28NM_VREG4_WL_LDO_CNTL_EN);
7426*4882a593Smuzhiyun 			si_pmu_regcontrol(sih, 6,
7427*4882a593Smuzhiyun 				PMU_28NM_VREG6_BTLDO3P3_PU,
7428*4882a593Smuzhiyun 				PMU_28NM_VREG6_BTLDO3P3_PU);
7429*4882a593Smuzhiyun 		}
7430*4882a593Smuzhiyun 
7431*4882a593Smuzhiyun 		/* write the XTAL preferred startup/normal A0/B0 revision */
7432*4882a593Smuzhiyun 		si_pmu_chipcontrol_xtal_settings_4369(sih);
7433*4882a593Smuzhiyun 
7434*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL6,
7435*4882a593Smuzhiyun 			(PMU_CC6_ENABLE_CLKREQ_WAKEUP | PMU_CC6_ENABLE_PCIE_RETENTION),
7436*4882a593Smuzhiyun 			(PMU_CC6_ENABLE_CLKREQ_WAKEUP | PMU_CC6_ENABLE_PCIE_RETENTION));
7437*4882a593Smuzhiyun 
7438*4882a593Smuzhiyun 		/* write the PWRSW CLK start/stop delay only for A0 revision */
7439*4882a593Smuzhiyun 		if (CHIPREV(sih->chiprev) == 0) {
7440*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL1, PMU_CC1_PWRSW_CLKSTRSTP_DELAY_MASK,
7441*4882a593Smuzhiyun 				PMU_CC1_PWRSW_CLKSTRSTP_DELAY);
7442*4882a593Smuzhiyun 		}
7443*4882a593Smuzhiyun 
7444*4882a593Smuzhiyun #if defined(SAVERESTORE)
7445*4882a593Smuzhiyun 		if (SR_ENAB()) {
7446*4882a593Smuzhiyun 			si_set_lv_sleep_mode_4369(sih, osh);
7447*4882a593Smuzhiyun 		}
7448*4882a593Smuzhiyun #endif /* SAVERESTORE */
7449*4882a593Smuzhiyun 
7450*4882a593Smuzhiyun 		si_pmu_fast_lpo_enable(sih, osh);
7451*4882a593Smuzhiyun #ifdef BCM_LDO3P3_SOFTSTART
7452*4882a593Smuzhiyun 		if (CHIPID(sih->chip) != BCM4377_CHIP_ID) {
7453*4882a593Smuzhiyun 			si_pmu_ldo3p3_soft_start_wl_set(sih, osh, 3);
7454*4882a593Smuzhiyun 		}
7455*4882a593Smuzhiyun #endif
7456*4882a593Smuzhiyun 		if ((PMUREV(sih->pmurev) >= 33) && FASTLPO_ENAB()) {
7457*4882a593Smuzhiyun 			/* Enabling FAST_SEQ */
7458*4882a593Smuzhiyun 			uint8	fastlpo_dis = fastlpo_dis_get();
7459*4882a593Smuzhiyun 			uint8	fastlpo_pcie_dis = fastlpo_pcie_dis_get();
7460*4882a593Smuzhiyun 			if (!fastlpo_dis || !fastlpo_pcie_dis) {
7461*4882a593Smuzhiyun 				PMU_REG(sih, pmucontrol_ext, PCTL_EXT_FASTSEQ_ENAB,
7462*4882a593Smuzhiyun 					PCTL_EXT_FASTSEQ_ENAB);
7463*4882a593Smuzhiyun 			}
7464*4882a593Smuzhiyun 		}
7465*4882a593Smuzhiyun 
7466*4882a593Smuzhiyun 		break;
7467*4882a593Smuzhiyun 	}
7468*4882a593Smuzhiyun 
7469*4882a593Smuzhiyun 	CASE_BCM43602_CHIP: /* fall through */
7470*4882a593Smuzhiyun 		/* Set internal/external LPO */
7471*4882a593Smuzhiyun 		si_pmu_set_lpoclk(sih, osh);
7472*4882a593Smuzhiyun 		break;
7473*4882a593Smuzhiyun 
7474*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
7475*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
7476*4882a593Smuzhiyun 	{
7477*4882a593Smuzhiyun 		pmuregs_t *pmu = si_setcore(sih, PMU_CORE_ID, 0);
7478*4882a593Smuzhiyun 		uint32 lpo = LHL_LPO_AUTO;
7479*4882a593Smuzhiyun 		uint32 lhl_tmr_sel = 0;
7480*4882a593Smuzhiyun 
7481*4882a593Smuzhiyun #ifdef USE_LHL_TIMER
7482*4882a593Smuzhiyun 		lhl_tmr_sel = PMU_CC13_4378_LHL_TIMER_SELECT;
7483*4882a593Smuzhiyun #endif
7484*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13, PMU_CC13_4378_LHL_TIMER_SELECT, lhl_tmr_sel);
7485*4882a593Smuzhiyun 
7486*4882a593Smuzhiyun 		if (R_REG(osh, &pmu->pmustatus) & PST_EXTLPOAVAIL) {
7487*4882a593Smuzhiyun 			lpo = LHL_EXT_LPO_ENAB;
7488*4882a593Smuzhiyun 		}
7489*4882a593Smuzhiyun 
7490*4882a593Smuzhiyun 		if (!ISSIM_ENAB(sih)) {
7491*4882a593Smuzhiyun 			si_lhl_set_lpoclk(sih, osh, lpo);
7492*4882a593Smuzhiyun 		}
7493*4882a593Smuzhiyun 
7494*4882a593Smuzhiyun 		/* JIRA: SWWLAN-228979
7495*4882a593Smuzhiyun 		 * BT LDO is required for Aux 2G Tx only. Keep powerd down until Aux is up
7496*4882a593Smuzhiyun 		 */
7497*4882a593Smuzhiyun 		si_pmu_bt_ldo_pu(sih, FALSE);
7498*4882a593Smuzhiyun 
7499*4882a593Smuzhiyun 		/* Updating xtal pmu registers to combat slow powerup issue */
7500*4882a593Smuzhiyun 		si_pmu_chipcontrol_xtal_settings_4378(sih);
7501*4882a593Smuzhiyun 
7502*4882a593Smuzhiyun 		if (LHL_IS_PSMODE_1(sih)) {
7503*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_07,
7504*4882a593Smuzhiyun 				((1 << GCI_CC7_AAON_BYPASS_PWRSW_SEL) |
7505*4882a593Smuzhiyun 				(1 << GCI_CC7_AAON_BYPASS_PWRSW_SEQ_ON)),
7506*4882a593Smuzhiyun 				0);
7507*4882a593Smuzhiyun 		}
7508*4882a593Smuzhiyun 
7509*4882a593Smuzhiyun 		si_lhl_setup(sih, osh);
7510*4882a593Smuzhiyun 
7511*4882a593Smuzhiyun 		/* Setting MemLPLDO voltage */
7512*4882a593Smuzhiyun 		if (getvar(NULL, rstr_memlpldo_volt) != NULL) {
7513*4882a593Smuzhiyun 			int memlpldo_volt = getintvar(NULL, rstr_memlpldo_volt);
7514*4882a593Smuzhiyun 
7515*4882a593Smuzhiyun 			if (memlpldo_volt >= PMU_VREG5_LPLDO_VOLT_0_90 &&
7516*4882a593Smuzhiyun 				memlpldo_volt <= PMU_VREG5_LPLDO_VOLT_0_88) {
7517*4882a593Smuzhiyun 				si_pmu_regcontrol(sih, PMU_VREG_5, VREG5_4378_MEMLPLDO_ADJ_MASK,
7518*4882a593Smuzhiyun 					memlpldo_volt << VREG5_4378_MEMLPLDO_ADJ_SHIFT);
7519*4882a593Smuzhiyun 			} else {
7520*4882a593Smuzhiyun 				PMU_MSG(("Invalid memlpldo value: %d\n", memlpldo_volt));
7521*4882a593Smuzhiyun 			}
7522*4882a593Smuzhiyun 		}
7523*4882a593Smuzhiyun 
7524*4882a593Smuzhiyun 		/* Setting LPLDO voltage */
7525*4882a593Smuzhiyun 		if (getvar(NULL, rstr_lpldo_volt) != NULL) {
7526*4882a593Smuzhiyun 			int lpldo_volt = getintvar(NULL, rstr_lpldo_volt);
7527*4882a593Smuzhiyun 
7528*4882a593Smuzhiyun 			if (lpldo_volt >= PMU_VREG5_LPLDO_VOLT_0_90 &&
7529*4882a593Smuzhiyun 				lpldo_volt <= PMU_VREG5_LPLDO_VOLT_0_88) {
7530*4882a593Smuzhiyun 				si_pmu_regcontrol(sih, PMU_VREG_5, VREG5_4378_LPLDO_ADJ_MASK,
7531*4882a593Smuzhiyun 					lpldo_volt << VREG5_4378_LPLDO_ADJ_SHIFT);
7532*4882a593Smuzhiyun 			} else {
7533*4882a593Smuzhiyun 				PMU_MSG(("Invalid lpldo value: %d\n", lpldo_volt));
7534*4882a593Smuzhiyun 			}
7535*4882a593Smuzhiyun 		}
7536*4882a593Smuzhiyun 
7537*4882a593Smuzhiyun 		/* Enable fast LPO */
7538*4882a593Smuzhiyun 		si_pmu_fast_lpo_enable(sih, osh);
7539*4882a593Smuzhiyun 
7540*4882a593Smuzhiyun #if defined(SAVERESTORE)
7541*4882a593Smuzhiyun 		if (SR_ENAB()) {
7542*4882a593Smuzhiyun 			si_set_lv_sleep_mode_4378(sih, osh);
7543*4882a593Smuzhiyun 		}
7544*4882a593Smuzhiyun #endif /* SAVERESTORE */
7545*4882a593Smuzhiyun 
7546*4882a593Smuzhiyun 		si_pmu_dynamic_clk_switch_enab(sih);
7547*4882a593Smuzhiyun 
7548*4882a593Smuzhiyun 		if (CHIPID(sih->chip) == BCM4378_CHIP_GRPID) {
7549*4882a593Smuzhiyun 			si_pmu_vreg_control(sih, PMU_VREG_0,
7550*4882a593Smuzhiyun 				VREG0_4378_CSR_VOLT_ADJ_PWM_MASK |
7551*4882a593Smuzhiyun 				VREG0_4378_CSR_VOLT_ADJ_PFM_MASK |
7552*4882a593Smuzhiyun 				VREG0_4378_CSR_VOLT_ADJ_LP_PFM_MASK |
7553*4882a593Smuzhiyun 				VREG0_4378_CSR_OUT_VOLT_TRIM_ADJ_MASK,
7554*4882a593Smuzhiyun 				(CSR_VOLT_ADJ_PWM_4378 << VREG0_4378_CSR_VOLT_ADJ_PWM_SHIFT) |
7555*4882a593Smuzhiyun 				(CSR_VOLT_ADJ_PFM_4378 << VREG0_4378_CSR_VOLT_ADJ_PFM_SHIFT) |
7556*4882a593Smuzhiyun 				(CSR_VOLT_ADJ_LP_PFM_4378 << VREG0_4378_CSR_VOLT_ADJ_LP_PFM_SHIFT) |
7557*4882a593Smuzhiyun 				(CSR_OUT_VOLT_TRIM_ADJ_4378 <<
7558*4882a593Smuzhiyun 					VREG0_4378_CSR_OUT_VOLT_TRIM_ADJ_SHIFT));
7559*4882a593Smuzhiyun #ifdef BCM_LDO3P3_SOFTSTART
7560*4882a593Smuzhiyun 			si_pmu_ldo3p3_soft_start_wl_set(sih, osh, 0x03u);
7561*4882a593Smuzhiyun 			si_pmu_ldo3p3_soft_start_bt_set(sih, osh, 0x03u);
7562*4882a593Smuzhiyun #endif
7563*4882a593Smuzhiyun 		} else {
7564*4882a593Smuzhiyun 			/* 4368 */
7565*4882a593Smuzhiyun 			int nvcsr;
7566*4882a593Smuzhiyun 			if ((nvcsr = getintvar(NULL, rstr_csrtune))) {
7567*4882a593Smuzhiyun 				si_pmu_vreg_control(sih, PMU_VREG_0,
7568*4882a593Smuzhiyun 					VREG0_4378_CSR_VOLT_ADJ_PWM_MASK |
7569*4882a593Smuzhiyun 					VREG0_4378_CSR_VOLT_ADJ_PFM_MASK |
7570*4882a593Smuzhiyun 					VREG0_4378_CSR_VOLT_ADJ_LP_PFM_MASK,
7571*4882a593Smuzhiyun 					(nvcsr << VREG0_4378_CSR_VOLT_ADJ_PWM_SHIFT) |
7572*4882a593Smuzhiyun 					(nvcsr << VREG0_4378_CSR_VOLT_ADJ_PFM_SHIFT) |
7573*4882a593Smuzhiyun 					(nvcsr << VREG0_4378_CSR_VOLT_ADJ_LP_PFM_SHIFT));
7574*4882a593Smuzhiyun 			}
7575*4882a593Smuzhiyun 		}
7576*4882a593Smuzhiyun 	}
7577*4882a593Smuzhiyun 		break;
7578*4882a593Smuzhiyun 
7579*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
7580*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
7581*4882a593Smuzhiyun 	{
7582*4882a593Smuzhiyun 		pmuregs_t *pmu = si_setcore(sih, PMU_CORE_ID, 0);
7583*4882a593Smuzhiyun 		uint32 lpo = LHL_LPO_AUTO;
7584*4882a593Smuzhiyun 		uint32 lhl_tmr_sel = 0;
7585*4882a593Smuzhiyun 		uint32 abuck_volt, cbuck_volt;
7586*4882a593Smuzhiyun 		uint32 min_mask;
7587*4882a593Smuzhiyun 		uint32 misc_ldo_volt, curr_misc_ldo_volt, i;
7588*4882a593Smuzhiyun 
7589*4882a593Smuzhiyun #ifdef DONGLEBUILD
7590*4882a593Smuzhiyun 		si_set_arm_clkfreq_high(sih);
7591*4882a593Smuzhiyun #endif
7592*4882a593Smuzhiyun 
7593*4882a593Smuzhiyun 		if (PMU_FLL_PU_ENAB()) {
7594*4882a593Smuzhiyun 			min_mask = R_REG(osh, &pmu->min_res_mask) |
7595*4882a593Smuzhiyun 				PMURES_BIT(RES4387_FAST_LPO_AVAIL) |
7596*4882a593Smuzhiyun 				PMURES_BIT(RES4387_PMU_LP);
7597*4882a593Smuzhiyun 			W_REG(osh, &pmu->min_res_mask, min_mask);
7598*4882a593Smuzhiyun 		}
7599*4882a593Smuzhiyun 
7600*4882a593Smuzhiyun #ifdef USE_LHL_TIMER
7601*4882a593Smuzhiyun 		lhl_tmr_sel = PMU_CC13_4387_LHL_TIMER_SELECT;
7602*4882a593Smuzhiyun #endif
7603*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13, PMU_CC13_4387_LHL_TIMER_SELECT, lhl_tmr_sel);
7604*4882a593Smuzhiyun 
7605*4882a593Smuzhiyun #if defined(SAVERESTORE)
7606*4882a593Smuzhiyun 		if (SR_ENAB()) {
7607*4882a593Smuzhiyun 			si_set_lv_sleep_mode_4387(sih, osh);
7608*4882a593Smuzhiyun 		}
7609*4882a593Smuzhiyun #endif /* SAVERESTORE */
7610*4882a593Smuzhiyun 
7611*4882a593Smuzhiyun 		if (R_REG(osh, &pmu->pmustatus) & PST_EXTLPOAVAIL) {
7612*4882a593Smuzhiyun 			lpo = LHL_EXT_LPO_ENAB;
7613*4882a593Smuzhiyun 		}
7614*4882a593Smuzhiyun 
7615*4882a593Smuzhiyun 		if (!ISSIM_ENAB(sih)) {
7616*4882a593Smuzhiyun 			si_lhl_set_lpoclk(sih, osh, lpo);
7617*4882a593Smuzhiyun 		}
7618*4882a593Smuzhiyun 
7619*4882a593Smuzhiyun 		if (getintvar(NULL, rstr_btldo3p3pu)) {
7620*4882a593Smuzhiyun 			si_pmu_regcontrol(sih, 4,
7621*4882a593Smuzhiyun 				PMU_28NM_VREG4_WL_LDO_CNTL_EN,
7622*4882a593Smuzhiyun 				PMU_28NM_VREG4_WL_LDO_CNTL_EN);
7623*4882a593Smuzhiyun 			si_pmu_regcontrol(sih, 6,
7624*4882a593Smuzhiyun 				PMU_4387_VREG6_BTLDO3P3_PU,
7625*4882a593Smuzhiyun 				PMU_4387_VREG6_BTLDO3P3_PU);
7626*4882a593Smuzhiyun 		}
7627*4882a593Smuzhiyun 
7628*4882a593Smuzhiyun 		if (LHL_IS_PSMODE_1(sih)) {
7629*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_07,
7630*4882a593Smuzhiyun 				((1 << GCI_CC7_AAON_BYPASS_PWRSW_SEL) |
7631*4882a593Smuzhiyun 				(1 << GCI_CC7_AAON_BYPASS_PWRSW_SEQ_ON)),
7632*4882a593Smuzhiyun 				0);
7633*4882a593Smuzhiyun 		}
7634*4882a593Smuzhiyun 
7635*4882a593Smuzhiyun 		si_lhl_setup(sih, osh);
7636*4882a593Smuzhiyun 
7637*4882a593Smuzhiyun 		/* Setting MemLPLDO voltage */
7638*4882a593Smuzhiyun 		if (getvar(NULL, rstr_memlpldo_volt) != NULL) {
7639*4882a593Smuzhiyun 			int memlpldo_volt = getintvar(NULL, rstr_memlpldo_volt);
7640*4882a593Smuzhiyun 
7641*4882a593Smuzhiyun 			if (memlpldo_volt >= PMU_VREG5_LPLDO_VOLT_0_90 &&
7642*4882a593Smuzhiyun 				memlpldo_volt <= PMU_VREG5_LPLDO_VOLT_0_88) {
7643*4882a593Smuzhiyun 				si_pmu_regcontrol(sih, PMU_VREG_5, VREG5_4387_MEMLPLDO_ADJ_MASK,
7644*4882a593Smuzhiyun 					memlpldo_volt << VREG5_4387_MEMLPLDO_ADJ_SHIFT);
7645*4882a593Smuzhiyun 			} else {
7646*4882a593Smuzhiyun 				PMU_MSG(("Invalid memlpldo value: %d\n", memlpldo_volt));
7647*4882a593Smuzhiyun 			}
7648*4882a593Smuzhiyun 		}
7649*4882a593Smuzhiyun 
7650*4882a593Smuzhiyun 		/* Setting LPLDO voltage */
7651*4882a593Smuzhiyun 		if (getvar(NULL, rstr_lpldo_volt) != NULL) {
7652*4882a593Smuzhiyun 			int lpldo_volt = getintvar(NULL, rstr_lpldo_volt);
7653*4882a593Smuzhiyun 
7654*4882a593Smuzhiyun 			if (lpldo_volt >= PMU_VREG5_LPLDO_VOLT_0_90 &&
7655*4882a593Smuzhiyun 				lpldo_volt <= PMU_VREG5_LPLDO_VOLT_0_88) {
7656*4882a593Smuzhiyun 				si_pmu_regcontrol(sih, PMU_VREG_5, VREG5_4387_LPLDO_ADJ_MASK,
7657*4882a593Smuzhiyun 					lpldo_volt << VREG5_4387_LPLDO_ADJ_SHIFT);
7658*4882a593Smuzhiyun 			} else {
7659*4882a593Smuzhiyun 				PMU_MSG(("Invalid lpldo value: %d\n", lpldo_volt));
7660*4882a593Smuzhiyun 			}
7661*4882a593Smuzhiyun 		}
7662*4882a593Smuzhiyun 
7663*4882a593Smuzhiyun 		/* Setting misc ldo voltage to 0.85625V but need stepping up */
7664*4882a593Smuzhiyun 		curr_misc_ldo_volt = (si_pmu_regcontrol(sih, PMU_VREG_5, 0, 0) &
7665*4882a593Smuzhiyun 			VREG5_4387_MISC_LDO_ADJ_MASK) >> VREG5_4387_MISC_LDO_ADJ_SHIFT;
7666*4882a593Smuzhiyun 
7667*4882a593Smuzhiyun 		/* Only after POR, chip default is 0.8V */
7668*4882a593Smuzhiyun 		if (curr_misc_ldo_volt == PMU_VREG5_MISC_LDO_VOLT_0p800) {
7669*4882a593Smuzhiyun 			misc_ldo_volt = PMU_VREG5_MISC_LDO_VOLT_0p856;  /* 0.85625V */
7670*4882a593Smuzhiyun 
7671*4882a593Smuzhiyun 			for (i = PMU_VREG5_MISC_LDO_VOLT_0p818; i <= misc_ldo_volt; i ++) {
7672*4882a593Smuzhiyun 				si_pmu_regcontrol(sih, PMU_VREG_5, VREG5_4387_MISC_LDO_ADJ_MASK,
7673*4882a593Smuzhiyun 					i << VREG5_4387_MISC_LDO_ADJ_SHIFT);
7674*4882a593Smuzhiyun 				OSL_DELAY(MISC_LDO_STEPPING_DELAY);
7675*4882a593Smuzhiyun 			}
7676*4882a593Smuzhiyun 		}
7677*4882a593Smuzhiyun 
7678*4882a593Smuzhiyun 		/* Enable fast LPO */
7679*4882a593Smuzhiyun 		si_pmu_fast_lpo_enable(sih, osh);
7680*4882a593Smuzhiyun 
7681*4882a593Smuzhiyun 		if (PMU_FLL_PU_ENAB()) {
7682*4882a593Smuzhiyun 			/* Wait until fast LPO is stable */
7683*4882a593Smuzhiyun 			OSL_DELAY(500u);
7684*4882a593Smuzhiyun 			si_pmu_fll_preload_enable(sih);
7685*4882a593Smuzhiyun 		}
7686*4882a593Smuzhiyun 
7687*4882a593Smuzhiyun 		si_pmu_dynamic_clk_switch_enab(sih);
7688*4882a593Smuzhiyun 
7689*4882a593Smuzhiyun 		/* HQ settings */
7690*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_25,
7691*4882a593Smuzhiyun 			0xFFFFFFFF, XTAL_HQ_SETTING_4387);
7692*4882a593Smuzhiyun 
7693*4882a593Smuzhiyun 		/* LQ settings */
7694*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_26,
7695*4882a593Smuzhiyun 			0xFFFFFFFF, XTAL_LQ_SETTING_4387);
7696*4882a593Smuzhiyun 
7697*4882a593Smuzhiyun 		/* Enable Radiodig Clk Gating */
7698*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13, PMU_CC13_4387_ENAB_RADIO_REG_CLK, 0);
7699*4882a593Smuzhiyun 
7700*4882a593Smuzhiyun 		/* Set up HW based switch-off of select BBPLL channels when SCAN-only mode
7701*4882a593Smuzhiyun 		 *
7702*4882a593Smuzhiyun 		 * Assign bbpll_ch_control_grp_pd_trigger_mask = {gci_chip_cntrl[559:554],
7703*4882a593Smuzhiyun 		 * gci_chip_cntrl[543:522], 1'b0, gci_chip_cntrl[521], 1'b0};
7704*4882a593Smuzhiyun 		 */
7705*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_16,
7706*4882a593Smuzhiyun 			CC_GCI_16_BBPLL_CH_CTRL_GRP_PD_TRIG_1_MASK |
7707*4882a593Smuzhiyun 			CC_GCI_16_BBPLL_CH_CTRL_GRP_PD_TRIG_24_3_MASK,
7708*4882a593Smuzhiyun 			(((GRP_PD_TRIGGER_MASK_4387 >> 1) & 0x1) <<	/* bit 1 */
7709*4882a593Smuzhiyun 			CC_GCI_16_BBPLL_CH_CTRL_GRP_PD_TRIG_1_SHIFT) |
7710*4882a593Smuzhiyun 			(((GRP_PD_TRIGGER_MASK_4387 >> 3) & 0x3FFFFF) << /* bit 24:3 */
7711*4882a593Smuzhiyun 			CC_GCI_16_BBPLL_CH_CTRL_GRP_PD_TRIG_24_3_SHIFT));
7712*4882a593Smuzhiyun 
7713*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_17,
7714*4882a593Smuzhiyun 			CC_GCI_17_BBPLL_CH_CTRL_GRP_PD_TRIG_30_25_MASK |
7715*4882a593Smuzhiyun 			CC_GCI_17_BBPLL_CH_CTRL_EN_MASK,
7716*4882a593Smuzhiyun 			(((GRP_PD_TRIGGER_MASK_4387 >> 25) & 0x3F) <<	/* bits 30:25 */
7717*4882a593Smuzhiyun 			CC_GCI_17_BBPLL_CH_CTRL_GRP_PD_TRIG_30_25_SHIFT) |
7718*4882a593Smuzhiyun 			CC_GCI_17_BBPLL_CH_CTRL_EN_MASK);
7719*4882a593Smuzhiyun 
7720*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_20,
7721*4882a593Smuzhiyun 			CC_GCI_20_BBPLL_CH_CTRL_GRP_MASK,
7722*4882a593Smuzhiyun 			(GRP_PD_MASK_4387 << CC_GCI_20_BBPLL_CH_CTRL_GRP_SHIFT));
7723*4882a593Smuzhiyun 
7724*4882a593Smuzhiyun 		if (CHIPID(sih->chip) == BCM4397_CHIP_GRPID) {
7725*4882a593Smuzhiyun 			/* For Phy Reg Access configure IHRP access */
7726*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_28,
7727*4882a593Smuzhiyun 				GCI_CC28_IHRP_SEL_MASK,
7728*4882a593Smuzhiyun 				0u << GCI_CC28_IHRP_SEL_SHIFT);
7729*4882a593Smuzhiyun 		}
7730*4882a593Smuzhiyun 
7731*4882a593Smuzhiyun 		if (getvar(NULL, rstr_abuck_volt) != NULL) {
7732*4882a593Smuzhiyun 			abuck_volt = getintvar(NULL, rstr_abuck_volt);
7733*4882a593Smuzhiyun 		} else {
7734*4882a593Smuzhiyun 			abuck_volt = ABUCK_VOLT_SW_DEFAULT_4387;
7735*4882a593Smuzhiyun 		}
7736*4882a593Smuzhiyun 
7737*4882a593Smuzhiyun 		if (CHIPID(sih->chip) == BCM4397_CHIP_GRPID) {
7738*4882a593Smuzhiyun 			/* For Phy Reg Access configure IHRP access */
7739*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_28,
7740*4882a593Smuzhiyun 				GCI_CC28_IHRP_SEL_MASK,
7741*4882a593Smuzhiyun 				0u << GCI_CC28_IHRP_SEL_SHIFT);
7742*4882a593Smuzhiyun 		}
7743*4882a593Smuzhiyun 
7744*4882a593Smuzhiyun 		/* For 4397, PMU has only 11 Regulator Registers */
7745*4882a593Smuzhiyun 		if (sih->chip != BCM4397_CHIP_ID) {
7746*4882a593Smuzhiyun 			si_pmu_vreg_control(sih, PMU_VREG_13,
7747*4882a593Smuzhiyun 				PMU_VREG13_ASR_OVADJ_PWM_MASK,
7748*4882a593Smuzhiyun 				abuck_volt << PMU_VREG13_ASR_OVADJ_PWM_SHIFT);
7749*4882a593Smuzhiyun 		}
7750*4882a593Smuzhiyun 		if (BCM_PWR_OPT_ENAB()) {
7751*4882a593Smuzhiyun 			if (getvar(NULL, rstr_cbuck_volt) != NULL) {
7752*4882a593Smuzhiyun 				cbuck_volt = getintvar(NULL, rstr_cbuck_volt);
7753*4882a593Smuzhiyun 			} else {
7754*4882a593Smuzhiyun 				cbuck_volt = CBUCK_VOLT_SW_DEFAULT_4387;
7755*4882a593Smuzhiyun 			}
7756*4882a593Smuzhiyun 
7757*4882a593Smuzhiyun 			si_pmu_vreg_control(sih, PMU_VREG_0,
7758*4882a593Smuzhiyun 				VREG0_4378_CSR_VOLT_ADJ_PWM_MASK,
7759*4882a593Smuzhiyun 				cbuck_volt << VREG0_4378_CSR_VOLT_ADJ_PWM_SHIFT);
7760*4882a593Smuzhiyun 		}
7761*4882a593Smuzhiyun 
7762*4882a593Smuzhiyun 		PMU_REG(sih, pmucontrol_ext, PCTL_EXT_FAST_TRANS_ENAB, PCTL_EXT_FAST_TRANS_ENAB);
7763*4882a593Smuzhiyun 
7764*4882a593Smuzhiyun 		if (si_hib_ext_wakeup_isenab(sih)) {
7765*4882a593Smuzhiyun 			/* pull up common BP */
7766*4882a593Smuzhiyun 			int rsrc_num = RES4387_CORE_RDY_CB;
7767*4882a593Smuzhiyun 			uint32 deps = PMURES_BIT(rsrc_num) |
7768*4882a593Smuzhiyun 				si_pmu_res_deps(sih, osh, pmu, PMURES_BIT(rsrc_num), TRUE);
7769*4882a593Smuzhiyun 			W_REG(osh, &pmu->extwakereqmask[0], deps);
7770*4882a593Smuzhiyun 		}
7771*4882a593Smuzhiyun 
7772*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL17,
7773*4882a593Smuzhiyun 			PMU_CC17_SCAN_DIG_SR_CLK_MASK,
7774*4882a593Smuzhiyun 			SCAN_DIG_SR_CLK_40_MHZ << PMU_CC17_SCAN_DIG_SR_CLK_SHIFT);
7775*4882a593Smuzhiyun 	}
7776*4882a593Smuzhiyun 		break;
7777*4882a593Smuzhiyun 
7778*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
7779*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
7780*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
7781*4882a593Smuzhiyun 	{
7782*4882a593Smuzhiyun 		pmuregs_t *pmu = si_setcore(sih, PMU_CORE_ID, 0);
7783*4882a593Smuzhiyun 		uint32 lpo = LHL_LPO_AUTO;
7784*4882a593Smuzhiyun 		uint32 lhl_tmr_sel = 0;
7785*4882a593Smuzhiyun 		uint32 abuck_volt, cbuck_volt;
7786*4882a593Smuzhiyun 		uint32 min_mask;
7787*4882a593Smuzhiyun 
7788*4882a593Smuzhiyun 		if (PMU_FLL_PU_ENAB()) {
7789*4882a593Smuzhiyun 			min_mask = R_REG(osh, &pmu->min_res_mask) |
7790*4882a593Smuzhiyun 				PMURES_BIT(RES4389_FAST_LPO_AVAIL) |
7791*4882a593Smuzhiyun 				PMURES_BIT(RES4389_PMU_LP);
7792*4882a593Smuzhiyun 			W_REG(osh, &pmu->min_res_mask, min_mask);
7793*4882a593Smuzhiyun 		}
7794*4882a593Smuzhiyun 
7795*4882a593Smuzhiyun #ifdef USE_LHL_TIMER
7796*4882a593Smuzhiyun 		lhl_tmr_sel = PMU_CC13_4387_LHL_TIMER_SELECT;
7797*4882a593Smuzhiyun #endif
7798*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13, PMU_CC13_4387_LHL_TIMER_SELECT, lhl_tmr_sel);
7799*4882a593Smuzhiyun 
7800*4882a593Smuzhiyun #if defined(SAVERESTORE)
7801*4882a593Smuzhiyun 		if (SR_ENAB()) {
7802*4882a593Smuzhiyun 			si_set_lv_sleep_mode_4389(sih, osh);
7803*4882a593Smuzhiyun 		}
7804*4882a593Smuzhiyun #endif /* SAVERESTORE */
7805*4882a593Smuzhiyun 		/* SET CB2WL Intr PWR Request irrespective of Default value */
7806*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL2, PMU_CC2_CB2WL_INTR_PWRREQ_EN,
7807*4882a593Smuzhiyun 				PMU_CC2_CB2WL_INTR_PWRREQ_EN);
7808*4882a593Smuzhiyun 
7809*4882a593Smuzhiyun 		if (R_REG(osh, &pmu->pmustatus) & PST_EXTLPOAVAIL) {
7810*4882a593Smuzhiyun 			lpo = LHL_EXT_LPO_ENAB;
7811*4882a593Smuzhiyun 		}
7812*4882a593Smuzhiyun 
7813*4882a593Smuzhiyun 		if (!ISSIM_ENAB(sih)) {
7814*4882a593Smuzhiyun 			si_lhl_set_lpoclk(sih, osh, lpo);
7815*4882a593Smuzhiyun 		}
7816*4882a593Smuzhiyun 
7817*4882a593Smuzhiyun 		if (getintvar(NULL, rstr_btldo3p3pu)) {
7818*4882a593Smuzhiyun 			si_pmu_regcontrol(sih, 4,
7819*4882a593Smuzhiyun 				PMU_28NM_VREG4_WL_LDO_CNTL_EN,
7820*4882a593Smuzhiyun 				PMU_28NM_VREG4_WL_LDO_CNTL_EN);
7821*4882a593Smuzhiyun 			si_pmu_regcontrol(sih, 6,
7822*4882a593Smuzhiyun 				PMU_4387_VREG6_BTLDO3P3_PU,
7823*4882a593Smuzhiyun 				PMU_4387_VREG6_BTLDO3P3_PU);
7824*4882a593Smuzhiyun 		}
7825*4882a593Smuzhiyun 
7826*4882a593Smuzhiyun 		if (LHL_IS_PSMODE_1(sih)) {
7827*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_07,
7828*4882a593Smuzhiyun 				((1 << GCI_CC7_AAON_BYPASS_PWRSW_SEL) |
7829*4882a593Smuzhiyun 				(1 << GCI_CC7_AAON_BYPASS_PWRSW_SEQ_ON)),
7830*4882a593Smuzhiyun 				0);
7831*4882a593Smuzhiyun 		}
7832*4882a593Smuzhiyun 
7833*4882a593Smuzhiyun 		si_lhl_setup(sih, osh);
7834*4882a593Smuzhiyun 
7835*4882a593Smuzhiyun 		/* Setting MemLPLDO voltage */
7836*4882a593Smuzhiyun 		if (getvar(NULL, rstr_memlpldo_volt) != NULL) {
7837*4882a593Smuzhiyun 			int memlpldo_volt = getintvar(NULL, rstr_memlpldo_volt);
7838*4882a593Smuzhiyun 
7839*4882a593Smuzhiyun 			if (memlpldo_volt >= PMU_VREG5_LPLDO_VOLT_0_90 &&
7840*4882a593Smuzhiyun 				memlpldo_volt <= PMU_VREG5_LPLDO_VOLT_0_88) {
7841*4882a593Smuzhiyun 				si_pmu_regcontrol(sih, PMU_VREG_5, VREG5_4387_MEMLPLDO_ADJ_MASK,
7842*4882a593Smuzhiyun 					memlpldo_volt << VREG5_4387_MEMLPLDO_ADJ_SHIFT);
7843*4882a593Smuzhiyun 			} else {
7844*4882a593Smuzhiyun 				PMU_MSG(("Invalid memlpldo value: %d\n", memlpldo_volt));
7845*4882a593Smuzhiyun 			}
7846*4882a593Smuzhiyun 		}
7847*4882a593Smuzhiyun 
7848*4882a593Smuzhiyun 		/* Setting LPLDO voltage */
7849*4882a593Smuzhiyun 		if (getvar(NULL, rstr_lpldo_volt) != NULL) {
7850*4882a593Smuzhiyun 			int lpldo_volt = getintvar(NULL, rstr_lpldo_volt);
7851*4882a593Smuzhiyun 
7852*4882a593Smuzhiyun 			if (lpldo_volt >= PMU_VREG5_LPLDO_VOLT_0_90 &&
7853*4882a593Smuzhiyun 				lpldo_volt <= PMU_VREG5_LPLDO_VOLT_0_88) {
7854*4882a593Smuzhiyun 				si_pmu_regcontrol(sih, PMU_VREG_5, VREG5_4387_LPLDO_ADJ_MASK,
7855*4882a593Smuzhiyun 					lpldo_volt << VREG5_4387_LPLDO_ADJ_SHIFT);
7856*4882a593Smuzhiyun 			} else {
7857*4882a593Smuzhiyun 				PMU_MSG(("Invalid lpldo value: %d\n", lpldo_volt));
7858*4882a593Smuzhiyun 			}
7859*4882a593Smuzhiyun 		}
7860*4882a593Smuzhiyun 
7861*4882a593Smuzhiyun 		/* Enable fast LPO */
7862*4882a593Smuzhiyun 		si_pmu_fast_lpo_enable(sih, osh);
7863*4882a593Smuzhiyun 
7864*4882a593Smuzhiyun 		if (PMU_FLL_PU_ENAB()) {
7865*4882a593Smuzhiyun 			/* Wait until fast LPO is stable */
7866*4882a593Smuzhiyun 			OSL_DELAY(500u);
7867*4882a593Smuzhiyun 			si_pmu_fll_preload_enable(sih);
7868*4882a593Smuzhiyun 		}
7869*4882a593Smuzhiyun 
7870*4882a593Smuzhiyun 		si_pmu_dynamic_clk_switch_enab(sih);
7871*4882a593Smuzhiyun 
7872*4882a593Smuzhiyun 		/* HQ settings */
7873*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_25,
7874*4882a593Smuzhiyun 			0xFFFFFFFF, XTAL_HQ_SETTING_4387);
7875*4882a593Smuzhiyun 
7876*4882a593Smuzhiyun 		/* LQ settings */
7877*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_26,
7878*4882a593Smuzhiyun 			0xFFFFFFFF, XTAL_LQ_SETTING_4387);
7879*4882a593Smuzhiyun 
7880*4882a593Smuzhiyun 		/* Enable Radiodig Clk Gating */
7881*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13, PMU_CC13_4387_ENAB_RADIO_REG_CLK, 0);
7882*4882a593Smuzhiyun 
7883*4882a593Smuzhiyun 		/* Set up HW based switch-off of select BBPLL channels when SCAN-only mode
7884*4882a593Smuzhiyun 		 *
7885*4882a593Smuzhiyun 		 * Assign bbpll_ch_control_grp_pd_trigger_mask = {gci_chip_cntrl[559:554],
7886*4882a593Smuzhiyun 		 * gci_chip_cntrl[543:522], 1'b0, gci_chip_cntrl[521], 1'b0};
7887*4882a593Smuzhiyun 		 */
7888*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_16,
7889*4882a593Smuzhiyun 			CC_GCI_16_BBPLL_CH_CTRL_GRP_PD_TRIG_1_MASK |
7890*4882a593Smuzhiyun 			CC_GCI_16_BBPLL_CH_CTRL_GRP_PD_TRIG_24_3_MASK,
7891*4882a593Smuzhiyun 			(((GRP_PD_TRIGGER_MASK_4387 >> 1) & 0x1) <<	/* bit 1 */
7892*4882a593Smuzhiyun 			CC_GCI_16_BBPLL_CH_CTRL_GRP_PD_TRIG_1_SHIFT) |
7893*4882a593Smuzhiyun 			(((GRP_PD_TRIGGER_MASK_4387 >> 3) & 0x3FFFFF) << /* bit 24:3 */
7894*4882a593Smuzhiyun 			CC_GCI_16_BBPLL_CH_CTRL_GRP_PD_TRIG_24_3_SHIFT));
7895*4882a593Smuzhiyun 
7896*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_17,
7897*4882a593Smuzhiyun 			CC_GCI_17_BBPLL_CH_CTRL_GRP_PD_TRIG_30_25_MASK |
7898*4882a593Smuzhiyun 			CC_GCI_17_BBPLL_CH_CTRL_EN_MASK,
7899*4882a593Smuzhiyun 			(((GRP_PD_TRIGGER_MASK_4387 >> 25) & 0x3F) <<	/* bits 30:25 */
7900*4882a593Smuzhiyun 			CC_GCI_17_BBPLL_CH_CTRL_GRP_PD_TRIG_30_25_SHIFT) |
7901*4882a593Smuzhiyun 			CC_GCI_17_BBPLL_CH_CTRL_EN_MASK);
7902*4882a593Smuzhiyun 
7903*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_20,
7904*4882a593Smuzhiyun 			CC_GCI_20_BBPLL_CH_CTRL_GRP_MASK,
7905*4882a593Smuzhiyun 			(GRP_PD_MASK_4387 << CC_GCI_20_BBPLL_CH_CTRL_GRP_SHIFT));
7906*4882a593Smuzhiyun 
7907*4882a593Smuzhiyun 		if (getvar(NULL, rstr_abuck_volt) != NULL) {
7908*4882a593Smuzhiyun 			abuck_volt = getintvar(NULL, rstr_abuck_volt);
7909*4882a593Smuzhiyun 		} else {
7910*4882a593Smuzhiyun 			abuck_volt = ABUCK_VOLT_SW_DEFAULT_4387;
7911*4882a593Smuzhiyun 		}
7912*4882a593Smuzhiyun 
7913*4882a593Smuzhiyun 		if (CHIPID(sih->chip) == BCM4397_CHIP_GRPID) {
7914*4882a593Smuzhiyun 			/* For Phy Reg Access configure IHRP access */
7915*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_28,
7916*4882a593Smuzhiyun 				GCI_CC28_IHRP_SEL_MASK,
7917*4882a593Smuzhiyun 				0u << GCI_CC28_IHRP_SEL_SHIFT);
7918*4882a593Smuzhiyun 		}
7919*4882a593Smuzhiyun 
7920*4882a593Smuzhiyun 		/* For 4397, PMU has only 11 Regulator Registers */
7921*4882a593Smuzhiyun 		if (sih->chip != BCM4397_CHIP_ID) {
7922*4882a593Smuzhiyun 			si_pmu_vreg_control(sih, PMU_VREG_13,
7923*4882a593Smuzhiyun 				PMU_VREG13_ASR_OVADJ_PWM_MASK,
7924*4882a593Smuzhiyun 				abuck_volt << PMU_VREG13_ASR_OVADJ_PWM_SHIFT);
7925*4882a593Smuzhiyun 		}
7926*4882a593Smuzhiyun 
7927*4882a593Smuzhiyun 		if (BCM_PWR_OPT_ENAB()) {
7928*4882a593Smuzhiyun 			if (getvar(NULL, rstr_cbuck_volt) != NULL) {
7929*4882a593Smuzhiyun 				cbuck_volt = getintvar(NULL, rstr_cbuck_volt);
7930*4882a593Smuzhiyun 			} else {
7931*4882a593Smuzhiyun 				cbuck_volt = CBUCK_VOLT_SW_DEFAULT_4387;
7932*4882a593Smuzhiyun 			}
7933*4882a593Smuzhiyun 
7934*4882a593Smuzhiyun 			si_pmu_vreg_control(sih, PMU_VREG_0,
7935*4882a593Smuzhiyun 				VREG0_4378_CSR_VOLT_ADJ_PWM_MASK,
7936*4882a593Smuzhiyun 				cbuck_volt << VREG0_4378_CSR_VOLT_ADJ_PWM_SHIFT);
7937*4882a593Smuzhiyun 		}
7938*4882a593Smuzhiyun 
7939*4882a593Smuzhiyun 		PMU_REG(sih, pmucontrol_ext, PCTL_EXT_FAST_TRANS_ENAB, PCTL_EXT_FAST_TRANS_ENAB);
7940*4882a593Smuzhiyun 
7941*4882a593Smuzhiyun 		if (PMUREV(sih->pmurev) == 39) {
7942*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_04,
7943*4882a593Smuzhiyun 				CC_GCI_04_4387C0_XTAL_PM_CLK,
7944*4882a593Smuzhiyun 				CC_GCI_04_4387C0_XTAL_PM_CLK);
7945*4882a593Smuzhiyun 		}
7946*4882a593Smuzhiyun 	}
7947*4882a593Smuzhiyun 		break;
7948*4882a593Smuzhiyun 
7949*4882a593Smuzhiyun 	default:
7950*4882a593Smuzhiyun 		break;
7951*4882a593Smuzhiyun 	}
7952*4882a593Smuzhiyun } /* si_pmu_chip_init */
7953*4882a593Smuzhiyun 
7954*4882a593Smuzhiyun /** Reference: http://confluence.broadcom.com/display/WLAN/Open+loop+Calibration+Sequence */
7955*4882a593Smuzhiyun int
si_pmu_openloop_cal(si_t * sih,uint16 currtemp)7956*4882a593Smuzhiyun si_pmu_openloop_cal(si_t *sih, uint16 currtemp)
7957*4882a593Smuzhiyun {
7958*4882a593Smuzhiyun 	int err = BCME_OK;
7959*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
7960*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
7961*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
7962*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
7963*4882a593Smuzhiyun 		err = si_pmu_openloop_cal_43012(sih, currtemp);
7964*4882a593Smuzhiyun 		break;
7965*4882a593Smuzhiyun 
7966*4882a593Smuzhiyun 	default:
7967*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_openloop_cal: chip not supported!\n"));
7968*4882a593Smuzhiyun 		break;
7969*4882a593Smuzhiyun 	}
7970*4882a593Smuzhiyun 	return err;
7971*4882a593Smuzhiyun }
7972*4882a593Smuzhiyun 
7973*4882a593Smuzhiyun static int
si_pmu_openloop_cal_43012(si_t * sih,uint16 currtemp)7974*4882a593Smuzhiyun si_pmu_openloop_cal_43012(si_t *sih, uint16 currtemp)
7975*4882a593Smuzhiyun {
7976*4882a593Smuzhiyun 	int32 a1 = -27, a2 = -15, b1 = 18704, b2 = 7531, a3, y1, y2, b3, y3;
7977*4882a593Smuzhiyun 	int32 xtal, array_size = 0, dco_code = 0, origidx = 0, pll_reg = 0, err;
7978*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
7979*4882a593Smuzhiyun 	pmuregs_t *pmu = NULL;
7980*4882a593Smuzhiyun 	const pllctrl_data_t *pllctrlreg_update;
7981*4882a593Smuzhiyun 	const uint32 *pllctrlreg_val;
7982*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
7983*4882a593Smuzhiyun 	uint32 final_dco_code = si_get_openloop_dco_code(sih);
7984*4882a593Smuzhiyun 
7985*4882a593Smuzhiyun 	xtal = si_xtalfreq(sih);
7986*4882a593Smuzhiyun 	err = BCME_OK;
7987*4882a593Smuzhiyun 
7988*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
7989*4882a593Smuzhiyun 	pmu = si_setcore(sih, PMU_CORE_ID, 0);
7990*4882a593Smuzhiyun 	if (!pmu) {
7991*4882a593Smuzhiyun 		PMU_MSG(("si_pmu_openloop_cal_43012: NULL pmu pointer \n"));
7992*4882a593Smuzhiyun 		err = BCME_ERROR;
7993*4882a593Smuzhiyun 		goto done;
7994*4882a593Smuzhiyun 	}
7995*4882a593Smuzhiyun 
7996*4882a593Smuzhiyun 	if (final_dco_code == 0) {
7997*4882a593Smuzhiyun 		currtemp = (currtemp == 0)?-1: currtemp;
7998*4882a593Smuzhiyun 
7999*4882a593Smuzhiyun 		SPINWAIT(((si_corereg(sih, SI_CC_IDX,
8000*4882a593Smuzhiyun 			OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
8001*4882a593Smuzhiyun 			& CCS_HTAVAIL) != CCS_HTAVAIL), PMU_MAX_TRANSITION_DLY);
8002*4882a593Smuzhiyun 		ASSERT((si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), 0, 0)
8003*4882a593Smuzhiyun 			& CCS_HTAVAIL));
8004*4882a593Smuzhiyun 
8005*4882a593Smuzhiyun 		/* Stop using PLL clks, by programming the disable_ht_avail */
8006*4882a593Smuzhiyun 		/* and disable_lq_avail in the pmu chip control bit */
8007*4882a593Smuzhiyun 		/* Turn Off PLL */
8008*4882a593Smuzhiyun 		si_pmu_pll_off_43012(sih, osh, pmu);
8009*4882a593Smuzhiyun 
8010*4882a593Smuzhiyun 		/* Program PLL for 320MHz VCO */
8011*4882a593Smuzhiyun 		pllctrlreg_update = pmu1_xtaltab0_43012;
8012*4882a593Smuzhiyun 		array_size = ARRAYSIZE(pmu1_xtaltab0_43012);
8013*4882a593Smuzhiyun 		pllctrlreg_val = pmu1_pllctrl_tab_43012_1600mhz;
8014*4882a593Smuzhiyun 		si_pmu_pllctrlreg_update(sih, osh, pmu, xtal, 100,
8015*4882a593Smuzhiyun 			pllctrlreg_update, array_size, pllctrlreg_val);
8016*4882a593Smuzhiyun 
8017*4882a593Smuzhiyun 		/* Update PLL control register */
8018*4882a593Smuzhiyun 		/* Set the Update bit (bit 10) in PMU for PLL registers */
8019*4882a593Smuzhiyun 		OR_REG(osh, &pmu->pmucontrol, PCTL_PLL_PLLCTL_UPD);
8020*4882a593Smuzhiyun 
8021*4882a593Smuzhiyun 		/* Turn PLL ON but ensure that force_bbpll_dreset */
8022*4882a593Smuzhiyun 		/* bit is set , so that PLL 320Mhz clocks cannot be consumed */
8023*4882a593Smuzhiyun 		si_pmu_pll_on_43012(sih, osh, pmu, 1);
8024*4882a593Smuzhiyun 
8025*4882a593Smuzhiyun 		/* Settings to get dco_code on PLL test outputs and then read */
8026*4882a593Smuzhiyun 		/* from gci chip status */
8027*4882a593Smuzhiyun 		pll_reg = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG1, 0, 0);
8028*4882a593Smuzhiyun 		pll_reg = (pll_reg & (~0x3C000)) | (0x4<<14);
8029*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG1, ~0, pll_reg);
8030*4882a593Smuzhiyun 		OR_REG(osh, &pmu->pmucontrol, PCTL_PLL_PLLCTL_UPD);
8031*4882a593Smuzhiyun 
8032*4882a593Smuzhiyun 		pll_reg = pll_reg | (1<<17);
8033*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG1, ~0, pll_reg);
8034*4882a593Smuzhiyun 		OR_REG(osh, &pmu->pmucontrol, PCTL_PLL_PLLCTL_UPD);
8035*4882a593Smuzhiyun 
8036*4882a593Smuzhiyun 		/* Get the DCO code from GCI CHIP STATUS Register 7 , bits 27 downto 16 */
8037*4882a593Smuzhiyun 		dco_code = (si_gci_chipstatus(sih, GCI_CHIPSTATUS_07));
8038*4882a593Smuzhiyun 		dco_code = ((dco_code & 0x0FFF0000) >> 16);
8039*4882a593Smuzhiyun 		dco_code = (dco_code  >> 4);
8040*4882a593Smuzhiyun 
8041*4882a593Smuzhiyun 		/* The DCO code obtained above and the temperature */
8042*4882a593Smuzhiyun 		/* sensed at this time will give us the DCO code */
8043*4882a593Smuzhiyun 		/* that needs to be programmed to ensure VCO does not crosses 160 MHz at 125C */
8044*4882a593Smuzhiyun 		y1 = ((a1 * currtemp) + b1);
8045*4882a593Smuzhiyun 		y2 = ((a2 * currtemp) + b2);
8046*4882a593Smuzhiyun 		dco_code = (dco_code * 100);
8047*4882a593Smuzhiyun 		b3 = b1 + (((b2-b1)/(y2 - y1)) * (dco_code - y1));
8048*4882a593Smuzhiyun 		if (b3 > dco_code) {
8049*4882a593Smuzhiyun 			a3 = (b3 - dco_code) / currtemp;
8050*4882a593Smuzhiyun 			y3 = b3 - (a3 * 125);
8051*4882a593Smuzhiyun 		}
8052*4882a593Smuzhiyun 		else {
8053*4882a593Smuzhiyun 			 a3 = (dco_code - b3) / currtemp;
8054*4882a593Smuzhiyun 			 y3 = b3 + (a3 * 125);
8055*4882a593Smuzhiyun 		}
8056*4882a593Smuzhiyun 		y3 = (y3/100);
8057*4882a593Smuzhiyun 		PMU_MSG(("DCO_CODE = %d\n", y3));
8058*4882a593Smuzhiyun 
8059*4882a593Smuzhiyun 		/* Turning ON PLL at 160.1 MHz for Normal Operation */
8060*4882a593Smuzhiyun 		si_pmu_pll_off_43012(sih, osh, pmu);
8061*4882a593Smuzhiyun 		pllctrlreg_update = pmu1_xtaltab0_43012;
8062*4882a593Smuzhiyun 		array_size = ARRAYSIZE(pmu1_xtaltab0_43012);
8063*4882a593Smuzhiyun 		pllctrlreg_val = pmu1_pllctrl_tab_43012_1600mhz;
8064*4882a593Smuzhiyun 		si_pmu_pllctrlreg_update(sih, osh, pmu, xtal, 0,
8065*4882a593Smuzhiyun 			pllctrlreg_update, array_size, pllctrlreg_val);
8066*4882a593Smuzhiyun 
8067*4882a593Smuzhiyun 		/* Update PLL control register */
8068*4882a593Smuzhiyun 		/* Set the Update bit (bit 10) in PMU for PLL registers */
8069*4882a593Smuzhiyun 		OR_REG(osh, &pmu->pmucontrol, PCTL_PLL_PLLCTL_UPD);
8070*4882a593Smuzhiyun 
8071*4882a593Smuzhiyun 		si_pmu_pll_on_43012(sih, osh, pmu, 0);
8072*4882a593Smuzhiyun 		y3 = (y3 << 4);
8073*4882a593Smuzhiyun 		final_dco_code = y3;
8074*4882a593Smuzhiyun 		PMU_MSG(("openloop_dco_code = %x\n", final_dco_code));
8075*4882a593Smuzhiyun 	}
8076*4882a593Smuzhiyun 
8077*4882a593Smuzhiyun 	pll_reg = si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG3, 0, 0);
8078*4882a593Smuzhiyun 	y3 = (pll_reg >> 16) & 0xFFF;
8079*4882a593Smuzhiyun 
8080*4882a593Smuzhiyun 	if (final_dco_code != (uint32)y3) {
8081*4882a593Smuzhiyun 
8082*4882a593Smuzhiyun 		/* Program the DCO code to bits 27 */
8083*4882a593Smuzhiyun 		/* downto 16 of the PLL control 3 register */
8084*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG3,
8085*4882a593Smuzhiyun 			0x0FFF0000, (final_dco_code << 16));
8086*4882a593Smuzhiyun 
8087*4882a593Smuzhiyun 		/* Enable Extra post divison for Open Loop */
8088*4882a593Smuzhiyun 		/* by writing 1 to bit 14 of above register */
8089*4882a593Smuzhiyun 		si_pmu_pllcontrol(sih, PMU_PLL_CTRL_REG3, 0x00004000, (1<<14));
8090*4882a593Smuzhiyun 
8091*4882a593Smuzhiyun 		/* Update PLL control register */
8092*4882a593Smuzhiyun 		/* Set the Update bit (bit 10) in PMU for PLL registers */
8093*4882a593Smuzhiyun 		OR_REG(osh, &pmu->pmucontrol, PCTL_PLL_PLLCTL_UPD);
8094*4882a593Smuzhiyun 		/* After cal openloop VCO Max=320MHz, Min=240Mhz (with extra margin */
8095*4882a593Smuzhiyun 		/* 230-220MHz). Update SAVE_RESTORE up/down times accordingly */
8096*4882a593Smuzhiyun 		W_REG(osh, &pmu->res_table_sel,	RES43012_SR_SAVE_RESTORE);
8097*4882a593Smuzhiyun 		W_REG(osh, &pmu->res_updn_timer, 0x01800180);
8098*4882a593Smuzhiyun 	}
8099*4882a593Smuzhiyun 
8100*4882a593Smuzhiyun 	si_restore_core(sih, origidx, &intr_val);
8101*4882a593Smuzhiyun 	si_set_openloop_dco_code(sih, final_dco_code);
8102*4882a593Smuzhiyun done:
8103*4882a593Smuzhiyun 	return err;
8104*4882a593Smuzhiyun }
8105*4882a593Smuzhiyun 
8106*4882a593Smuzhiyun void
si_pmu_slow_clk_reinit(si_t * sih,osl_t * osh)8107*4882a593Smuzhiyun si_pmu_slow_clk_reinit(si_t *sih, osl_t *osh)
8108*4882a593Smuzhiyun {
8109*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8110*4882a593Smuzhiyun 	chipcregs_t *cc;
8111*4882a593Smuzhiyun 	uint origidx;
8112*4882a593Smuzhiyun 	uint32 xtalfreq;
8113*4882a593Smuzhiyun 
8114*4882a593Smuzhiyun 	/* PMU specific initializations */
8115*4882a593Smuzhiyun 	if (!PMUCTL_ENAB(sih))
8116*4882a593Smuzhiyun 		return;
8117*4882a593Smuzhiyun 	/* Remember original core before switch to chipc */
8118*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8119*4882a593Smuzhiyun 	cc = si_setcoreidx(sih, SI_CC_IDX);
8120*4882a593Smuzhiyun 	ASSERT(cc != NULL);
8121*4882a593Smuzhiyun 	if (cc == NULL)
8122*4882a593Smuzhiyun 		return;
8123*4882a593Smuzhiyun 
8124*4882a593Smuzhiyun 	xtalfreq = getintvar(NULL, rstr_xtalfreq);
8125*4882a593Smuzhiyun 	/*
8126*4882a593Smuzhiyun 	 * workaround for chips that don't support external LPO, thus ALP clock
8127*4882a593Smuzhiyun 	 * can not be measured accurately:
8128*4882a593Smuzhiyun 	 */
8129*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8130*4882a593Smuzhiyun 		CASE_BCM43602_CHIP:
8131*4882a593Smuzhiyun 			xtalfreq = XTAL_FREQ_54MHZ;
8132*4882a593Smuzhiyun 			break;
8133*4882a593Smuzhiyun 		default:
8134*4882a593Smuzhiyun 			break;
8135*4882a593Smuzhiyun 	}
8136*4882a593Smuzhiyun 	/* If xtalfreq var not available, try to measure it */
8137*4882a593Smuzhiyun 	if (xtalfreq == 0)
8138*4882a593Smuzhiyun 		xtalfreq = si_pmu_measure_alpclk(sih, osh);
8139*4882a593Smuzhiyun 	si_pmu_enb_slow_clk(sih, osh, xtalfreq);
8140*4882a593Smuzhiyun 	/* Return to original core */
8141*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8142*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
8143*4882a593Smuzhiyun }
8144*4882a593Smuzhiyun 
8145*4882a593Smuzhiyun /** initialize PMU registers in case default values proved to be suboptimal */
8146*4882a593Smuzhiyun void
BCMATTACHFN(si_pmu_swreg_init)8147*4882a593Smuzhiyun BCMATTACHFN(si_pmu_swreg_init)(si_t *sih, osl_t *osh)
8148*4882a593Smuzhiyun {
8149*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
8150*4882a593Smuzhiyun 
8151*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8152*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
8153*4882a593Smuzhiyun 		/* adjust PA Vref to 2.80V */
8154*4882a593Smuzhiyun 		si_pmu_set_ldo_voltage(sih, osh, SET_LDO_VOLTAGE_PAREF, 0x0c);
8155*4882a593Smuzhiyun 		break;
8156*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
8157*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_04, GPIO_DRIVE_4378_MASK,
8158*4882a593Smuzhiyun 			GPIO_DRIVE_4378_VAL);
8159*4882a593Smuzhiyun 		/* fall through */
8160*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
8161*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
8162*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
8163*4882a593Smuzhiyun #ifdef BCM_AVS
8164*4882a593Smuzhiyun 		if (BCM_AVS_ENAB()) {
8165*4882a593Smuzhiyun 			si_pmu_set_avs(sih);
8166*4882a593Smuzhiyun 		}
8167*4882a593Smuzhiyun #endif
8168*4882a593Smuzhiyun 		break;
8169*4882a593Smuzhiyun 	default:
8170*4882a593Smuzhiyun 		break;
8171*4882a593Smuzhiyun 	}
8172*4882a593Smuzhiyun 	si_pmu_otp_vreg_control(sih, osh);
8173*4882a593Smuzhiyun } /* si_pmu_swreg_init */
8174*4882a593Smuzhiyun 
8175*4882a593Smuzhiyun /** Wait for a particular clock level to be on the backplane */
8176*4882a593Smuzhiyun uint32
si_pmu_waitforclk_on_backplane(si_t * sih,osl_t * osh,uint32 clk,uint32 delay_val)8177*4882a593Smuzhiyun si_pmu_waitforclk_on_backplane(si_t *sih, osl_t *osh, uint32 clk, uint32 delay_val)
8178*4882a593Smuzhiyun {
8179*4882a593Smuzhiyun 	pmuregs_t *pmu;
8180*4882a593Smuzhiyun 	uint origidx;
8181*4882a593Smuzhiyun 	uint32 val;
8182*4882a593Smuzhiyun 
8183*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
8184*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
8185*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8186*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
8187*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
8188*4882a593Smuzhiyun 	} else {
8189*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
8190*4882a593Smuzhiyun 	}
8191*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
8192*4882a593Smuzhiyun 
8193*4882a593Smuzhiyun 	if (delay_val)
8194*4882a593Smuzhiyun 		SPINWAIT(((R_REG(osh, &pmu->pmustatus) & clk) != clk), delay_val);
8195*4882a593Smuzhiyun 	val = R_REG(osh, &pmu->pmustatus) & clk;
8196*4882a593Smuzhiyun 
8197*4882a593Smuzhiyun 	/* Return to original core */
8198*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8199*4882a593Smuzhiyun 	return (val);
8200*4882a593Smuzhiyun }
8201*4882a593Smuzhiyun 
8202*4882a593Smuzhiyun #define EXT_ILP_HZ 32768
8203*4882a593Smuzhiyun 
8204*4882a593Smuzhiyun /**
8205*4882a593Smuzhiyun  * Measures the ALP clock frequency in KHz.  Returns 0 if not possible.
8206*4882a593Smuzhiyun  * Possible only if PMU rev >= 10 and there is an external LPO 32768Hz crystal.
8207*4882a593Smuzhiyun  */
8208*4882a593Smuzhiyun uint32
BCMATTACHFN(si_pmu_measure_alpclk)8209*4882a593Smuzhiyun BCMATTACHFN(si_pmu_measure_alpclk)(si_t *sih, osl_t *osh)
8210*4882a593Smuzhiyun {
8211*4882a593Smuzhiyun 	uint32 alp_khz;
8212*4882a593Smuzhiyun 	uint32 pmustat_lpo = 0;
8213*4882a593Smuzhiyun 	pmuregs_t *pmu;
8214*4882a593Smuzhiyun 	uint origidx;
8215*4882a593Smuzhiyun 
8216*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) < 10)
8217*4882a593Smuzhiyun 		return 0;
8218*4882a593Smuzhiyun 
8219*4882a593Smuzhiyun 	ASSERT(sih->cccaps & CC_CAP_PMU);
8220*4882a593Smuzhiyun 
8221*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
8222*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8223*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
8224*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
8225*4882a593Smuzhiyun 	} else {
8226*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
8227*4882a593Smuzhiyun 	}
8228*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
8229*4882a593Smuzhiyun 
8230*4882a593Smuzhiyun 	if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) ||
8231*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43013_CHIP_ID) ||
8232*4882a593Smuzhiyun 		(CHIPID(sih->chip) == BCM43014_CHIP_ID) ||
8233*4882a593Smuzhiyun 		(PMUREV(sih->pmurev) >= 22))
8234*4882a593Smuzhiyun 		pmustat_lpo = !(R_REG(osh, &pmu->pmucontrol) & PCTL_LPO_SEL);
8235*4882a593Smuzhiyun 	else
8236*4882a593Smuzhiyun 		pmustat_lpo = R_REG(osh, &pmu->pmustatus) & PST_EXTLPOAVAIL;
8237*4882a593Smuzhiyun 
8238*4882a593Smuzhiyun 	if (pmustat_lpo) {
8239*4882a593Smuzhiyun 		uint32 ilp_ctr, alp_hz;
8240*4882a593Smuzhiyun 
8241*4882a593Smuzhiyun 		/* Enable the reg to measure the freq, in case disabled before */
8242*4882a593Smuzhiyun 		W_REG(osh, &pmu->pmu_xtalfreq, 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT);
8243*4882a593Smuzhiyun 
8244*4882a593Smuzhiyun 		/* Delay for well over 4 ILP clocks */
8245*4882a593Smuzhiyun 		OSL_DELAY(1000);
8246*4882a593Smuzhiyun 
8247*4882a593Smuzhiyun 		/* Read the latched number of ALP ticks per 4 ILP ticks */
8248*4882a593Smuzhiyun 		ilp_ctr = R_REG(osh, &pmu->pmu_xtalfreq) & PMU_XTALFREQ_REG_ILPCTR_MASK;
8249*4882a593Smuzhiyun 
8250*4882a593Smuzhiyun 		/* Turn off the PMU_XTALFREQ_REG_MEASURE_SHIFT bit to save power */
8251*4882a593Smuzhiyun 		W_REG(osh, &pmu->pmu_xtalfreq, 0);
8252*4882a593Smuzhiyun 
8253*4882a593Smuzhiyun 		/* Calculate ALP frequency */
8254*4882a593Smuzhiyun 		alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4;
8255*4882a593Smuzhiyun 
8256*4882a593Smuzhiyun 		/* Round to nearest 100KHz, and at the same time convert to KHz */
8257*4882a593Smuzhiyun 		alp_khz = (alp_hz + 50000) / 100000 * 100;
8258*4882a593Smuzhiyun 	} else
8259*4882a593Smuzhiyun 		alp_khz = 0;
8260*4882a593Smuzhiyun 
8261*4882a593Smuzhiyun 	/* Return to original core */
8262*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8263*4882a593Smuzhiyun 
8264*4882a593Smuzhiyun 	return alp_khz;
8265*4882a593Smuzhiyun } /* si_pmu_measure_alpclk */
8266*4882a593Smuzhiyun 
8267*4882a593Smuzhiyun /** Update min/max resources after SR-ASM download to d11 txfifo */
8268*4882a593Smuzhiyun void
si_pmu_res_minmax_update(si_t * sih,osl_t * osh)8269*4882a593Smuzhiyun si_pmu_res_minmax_update(si_t *sih, osl_t *osh)
8270*4882a593Smuzhiyun {
8271*4882a593Smuzhiyun 	uint32 min_mask = 0, max_mask = 0;
8272*4882a593Smuzhiyun 	pmuregs_t *pmu;
8273*4882a593Smuzhiyun 	uint origidx;
8274*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
8275*4882a593Smuzhiyun 
8276*4882a593Smuzhiyun 	/* Block ints and save current core */
8277*4882a593Smuzhiyun 	si_introff(sih, &intr_val);
8278*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
8279*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8280*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
8281*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
8282*4882a593Smuzhiyun 	} else {
8283*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
8284*4882a593Smuzhiyun 	}
8285*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
8286*4882a593Smuzhiyun 
8287*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8288*4882a593Smuzhiyun 	CASE_BCM43602_CHIP:
8289*4882a593Smuzhiyun 		max_mask = 0; /* Only care about min_mask for now */
8290*4882a593Smuzhiyun 		break;
8291*4882a593Smuzhiyun 	case BCM43012_CHIP_ID:
8292*4882a593Smuzhiyun 	case BCM43013_CHIP_ID:
8293*4882a593Smuzhiyun 	case BCM43014_CHIP_ID:
8294*4882a593Smuzhiyun 		min_mask = RES43012_PMU_SLEEP;
8295*4882a593Smuzhiyun 		break;
8296*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
8297*4882a593Smuzhiyun 	case BCM4362_CHIP_GRPID:
8298*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
8299*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
8300*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
8301*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
8302*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
8303*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
8304*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
8305*4882a593Smuzhiyun 		si_pmu_res_masks(sih, &min_mask, &max_mask);
8306*4882a593Smuzhiyun 		max_mask = 0; /* Don't need to update max */
8307*4882a593Smuzhiyun 		break;
8308*4882a593Smuzhiyun 	default:
8309*4882a593Smuzhiyun 		break;
8310*4882a593Smuzhiyun 	}
8311*4882a593Smuzhiyun 	if (min_mask) {
8312*4882a593Smuzhiyun 		/* Add min mask dependencies */
8313*4882a593Smuzhiyun 		min_mask |= si_pmu_res_deps(sih, osh, pmu, min_mask, FALSE);
8314*4882a593Smuzhiyun 		W_REG(osh, &pmu->min_res_mask, min_mask);
8315*4882a593Smuzhiyun 	}
8316*4882a593Smuzhiyun 	if (max_mask) {
8317*4882a593Smuzhiyun 		max_mask |= si_pmu_res_deps(sih, osh, pmu, max_mask, FALSE);
8318*4882a593Smuzhiyun 		W_REG(osh, &pmu->max_res_mask, max_mask);
8319*4882a593Smuzhiyun 	}
8320*4882a593Smuzhiyun 
8321*4882a593Smuzhiyun 	si_pmu_wait_for_steady_state(sih, osh, pmu);
8322*4882a593Smuzhiyun 
8323*4882a593Smuzhiyun 	/* Return to original core */
8324*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8325*4882a593Smuzhiyun 	si_intrrestore(sih, &intr_val);
8326*4882a593Smuzhiyun } /* si_pmu_res_minmax_update */
8327*4882a593Smuzhiyun 
8328*4882a593Smuzhiyun #ifdef DONGLEBUILD
8329*4882a593Smuzhiyun 
8330*4882a593Smuzhiyun #define PMUCAP_DUMP_TAG_SIZE_BYTES	4
8331*4882a593Smuzhiyun 
8332*4882a593Smuzhiyun /* Move the below definitions to .ro_ontrap section so they
8333*4882a593Smuzhiyun  * won't be reused when reusing rodata section after trap.
8334*4882a593Smuzhiyun  */
8335*4882a593Smuzhiyun static const uint32 BCMPOST_TRAP_RODATA(chipc_regs_to_dump)[] = {
8336*4882a593Smuzhiyun 	OFFSETOF(chipcregs_t, clk_ctl_st),
8337*4882a593Smuzhiyun 	OFFSETOF(chipcregs_t, powerctl)
8338*4882a593Smuzhiyun };
8339*4882a593Smuzhiyun 
8340*4882a593Smuzhiyun static const uint BCMPOST_TRAP_RODATA(pmuregsdump)[] = {
8341*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, pmucontrol),
8342*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, pmucapabilities),
8343*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, pmustatus),
8344*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, res_state),
8345*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, res_pending),
8346*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, pmutimer),
8347*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, min_res_mask),
8348*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, max_res_mask),
8349*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, clkstretch),
8350*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, res_req_timer),
8351*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, res_req_mask),
8352*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, mac_res_req_timer),
8353*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, mac_res_req_mask),
8354*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, pmuintmask0),
8355*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, pmuintstatus),
8356*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, pmuintctrl0),
8357*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, extwakeupstatus),
8358*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, extwakemask0)
8359*4882a593Smuzhiyun };
8360*4882a593Smuzhiyun 
8361*4882a593Smuzhiyun static const uint BCMPOST_TRAP_RODATA(pmuregsdump_mac_res1)[] = {
8362*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, mac_res_req_timer1),
8363*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, mac_res_req_mask1)
8364*4882a593Smuzhiyun };
8365*4882a593Smuzhiyun 
8366*4882a593Smuzhiyun static const uint BCMPOST_TRAP_RODATA(pmuregsdump_mac_res2)[] = {
8367*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, mac_res_req_timer2),
8368*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, mac_res_req_mask2)
8369*4882a593Smuzhiyun };
8370*4882a593Smuzhiyun 
8371*4882a593Smuzhiyun static const uint BCMPOST_TRAP_RODATA(pmuregsdump_pmu_int1)[] = {
8372*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, pmuintmask1),
8373*4882a593Smuzhiyun 		OFFSETOF(pmuregs_t, pmuintctrl1)
8374*4882a593Smuzhiyun };
8375*4882a593Smuzhiyun 
8376*4882a593Smuzhiyun /* Pointer to location in ROdata where PMU registers are stored.
8377*4882a593Smuzhiyun  * It is good to avoid re-reading PMU registers as: 1. reading regs is slow
8378*4882a593Smuzhiyun  * 2. As part of trap, these registers are dumped to RO data section anyway.
8379*4882a593Smuzhiyun  * so why not read directly from ROdata section and send to host?
8380*4882a593Smuzhiyun  * these registers will be dumped n RODATA first and then hnd_minidump_pmuegs_dump()
8381*4882a593Smuzhiyun  * will pick these up. For it to pick these up, it
8382*4882a593Smuzhiyun  * needs to know where they are stored.
8383*4882a593Smuzhiyun  */
8384*4882a593Smuzhiyun /* Length of the reg dump containing address, value pair */
8385*4882a593Smuzhiyun #define SI_PMU_REG_DUMP_BASE_SIZE      (ARRAYSIZE(pmuregsdump) * 2u * sizeof(uint32))
8386*4882a593Smuzhiyun #define SI_PMU_REG_DUMP_MACRSRC1_SIZE  (ARRAYSIZE(pmuregsdump_mac_res1) * 2u * sizeof(uint32))
8387*4882a593Smuzhiyun #define SI_PMU_REG_DUMP_MACRSRC2_SIZE  (ARRAYSIZE(pmuregsdump_mac_res2) * 2u * sizeof(uint32))
8388*4882a593Smuzhiyun #define SI_PMU_REG_DUMP_INTRCV1_SIZE   (ARRAYSIZE(pmuregsdump_pmu_int1) * 2u * sizeof(uint32))
8389*4882a593Smuzhiyun 
8390*4882a593Smuzhiyun static uint32 *rodata_pmuregdump_ptr = NULL;
8391*4882a593Smuzhiyun 
8392*4882a593Smuzhiyun /** size of the buffer needed to store the PMU register dump specifically PMU indirect registers */
8393*4882a593Smuzhiyun uint32
BCMATTACHFN(si_pmu_dump_buf_size_pmucap)8394*4882a593Smuzhiyun BCMATTACHFN(si_pmu_dump_buf_size_pmucap)(si_t *sih)
8395*4882a593Smuzhiyun {
8396*4882a593Smuzhiyun 	uint32 buf_size = 0;
8397*4882a593Smuzhiyun 	uint32 pmu_size = 0;
8398*4882a593Smuzhiyun 	uint32 cnt;
8399*4882a593Smuzhiyun 
8400*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) < 5)
8401*4882a593Smuzhiyun 		return 0;
8402*4882a593Smuzhiyun 
8403*4882a593Smuzhiyun 	/* pmu resources resource mask and resource updown */
8404*4882a593Smuzhiyun 	cnt = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT;
8405*4882a593Smuzhiyun 	if (cnt) {
8406*4882a593Smuzhiyun 		buf_size += (cnt * 2 * sizeof(uint32)) + PMUCAP_DUMP_TAG_SIZE_BYTES;
8407*4882a593Smuzhiyun 	}
8408*4882a593Smuzhiyun 	/* pll controls */
8409*4882a593Smuzhiyun 	cnt = (sih->pmucaps & PCAP5_PC_MASK) >> PCAP5_PC_SHIFT;
8410*4882a593Smuzhiyun 	if (cnt) {
8411*4882a593Smuzhiyun 		buf_size += (cnt * sizeof(uint32)) + PMUCAP_DUMP_TAG_SIZE_BYTES;
8412*4882a593Smuzhiyun 	}
8413*4882a593Smuzhiyun 
8414*4882a593Smuzhiyun 	/* voltage controls */
8415*4882a593Smuzhiyun 	cnt = (sih->pmucaps & PCAP5_VC_MASK) >> PCAP5_VC_SHIFT;
8416*4882a593Smuzhiyun 	if (cnt) {
8417*4882a593Smuzhiyun 		buf_size += (cnt * sizeof(uint32)) + PMUCAP_DUMP_TAG_SIZE_BYTES;
8418*4882a593Smuzhiyun 	}
8419*4882a593Smuzhiyun 
8420*4882a593Smuzhiyun 	/* chip controls */
8421*4882a593Smuzhiyun 	cnt = (sih->pmucaps & PCAP5_CC_MASK) >> PCAP5_CC_SHIFT;
8422*4882a593Smuzhiyun 	if (cnt) {
8423*4882a593Smuzhiyun 		buf_size += (cnt * sizeof(uint32)) + PMUCAP_DUMP_TAG_SIZE_BYTES;
8424*4882a593Smuzhiyun 	}
8425*4882a593Smuzhiyun 
8426*4882a593Smuzhiyun 	/* include chip common regsiters from the list */
8427*4882a593Smuzhiyun 	/* cnt indicates how many registers, tag_id 0 will say these are address/value */
8428*4882a593Smuzhiyun 	if (ARRAYSIZE(chipc_regs_to_dump)) {
8429*4882a593Smuzhiyun 		buf_size += PMUCAP_DUMP_TAG_SIZE_BYTES;
8430*4882a593Smuzhiyun 		/* address/value pairs */
8431*4882a593Smuzhiyun 		buf_size += sizeof(chipc_regs_to_dump);
8432*4882a593Smuzhiyun 		buf_size += sizeof(chipc_regs_to_dump);
8433*4882a593Smuzhiyun 	}
8434*4882a593Smuzhiyun 
8435*4882a593Smuzhiyun 	/* include PMU regsiters from the list 'pmuregsdumpXX' */
8436*4882a593Smuzhiyun 	if ((PMUREV(sih->pmurev) > 27) && ARRAYSIZE(pmuregsdump) != 0) {
8437*4882a593Smuzhiyun 		uint8 rsrc_cnt = si_pmu_get_mac_rsrc_req_tmr_cnt(sih);
8438*4882a593Smuzhiyun 		buf_size += PMUCAP_DUMP_TAG_SIZE_BYTES;
8439*4882a593Smuzhiyun 		pmu_size += sizeof(pmuregsdump);
8440*4882a593Smuzhiyun 		if (ARRAYSIZE(pmuregsdump_mac_res1) != 0 && rsrc_cnt > 1) {
8441*4882a593Smuzhiyun 			buf_size += PMUCAP_DUMP_TAG_SIZE_BYTES;
8442*4882a593Smuzhiyun 			pmu_size += sizeof(pmuregsdump_mac_res1);
8443*4882a593Smuzhiyun 		}
8444*4882a593Smuzhiyun 		if (ARRAYSIZE(pmuregsdump_mac_res2) != 0 && rsrc_cnt > 2) {
8445*4882a593Smuzhiyun 			buf_size += PMUCAP_DUMP_TAG_SIZE_BYTES;
8446*4882a593Smuzhiyun 			pmu_size += sizeof(pmuregsdump_mac_res2);
8447*4882a593Smuzhiyun 		}
8448*4882a593Smuzhiyun 		if (ARRAYSIZE(pmuregsdump_pmu_int1) != 0 &&
8449*4882a593Smuzhiyun 			si_pmu_get_pmu_interrupt_rcv_cnt(sih) > 1) {
8450*4882a593Smuzhiyun 			buf_size += PMUCAP_DUMP_TAG_SIZE_BYTES;
8451*4882a593Smuzhiyun 			pmu_size += sizeof(pmuregsdump_pmu_int1);
8452*4882a593Smuzhiyun 		}
8453*4882a593Smuzhiyun 		/* address/value pairs */
8454*4882a593Smuzhiyun 		buf_size += (pmu_size << 1);
8455*4882a593Smuzhiyun 	}
8456*4882a593Smuzhiyun 
8457*4882a593Smuzhiyun 	return buf_size;
8458*4882a593Smuzhiyun }
8459*4882a593Smuzhiyun 
8460*4882a593Smuzhiyun /**
8461*4882a593Smuzhiyun  * routine to dump the registers into the user specified buffer
8462*4882a593Smuzhiyun  * needed to store the PMU register dump specifically PMU indirect registers
8463*4882a593Smuzhiyun  * format is sets of count, base regiser, register values
8464*4882a593Smuzhiyun */
8465*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_dump_pmucap_binary)8466*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_dump_pmucap_binary)(si_t *sih, uchar *p)
8467*4882a593Smuzhiyun {
8468*4882a593Smuzhiyun 	uint32 cnt, i;
8469*4882a593Smuzhiyun 	osl_t *osh;
8470*4882a593Smuzhiyun 	pmuregs_t *pmu;
8471*4882a593Smuzhiyun 	uint origidx;
8472*4882a593Smuzhiyun 	uint mac_res_cnt;
8473*4882a593Smuzhiyun 	uint pmu_int_rcv_cnt;
8474*4882a593Smuzhiyun 	uint32 pmu_totalsize = 0;
8475*4882a593Smuzhiyun 
8476*4882a593Smuzhiyun 	uint32 *p32 = (uint32 *)p;
8477*4882a593Smuzhiyun 
8478*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) < 5)
8479*4882a593Smuzhiyun 		return 0;
8480*4882a593Smuzhiyun 
8481*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8482*4882a593Smuzhiyun 
8483*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
8484*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
8485*4882a593Smuzhiyun 	}
8486*4882a593Smuzhiyun 	else {
8487*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
8488*4882a593Smuzhiyun 	}
8489*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
8490*4882a593Smuzhiyun 
8491*4882a593Smuzhiyun 	osh = si_osh(sih);
8492*4882a593Smuzhiyun 
8493*4882a593Smuzhiyun 	cnt = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT;
8494*4882a593Smuzhiyun 	if (cnt) {
8495*4882a593Smuzhiyun 		*p32++ = (cnt << 16 | RSRCTABLEADDR);
8496*4882a593Smuzhiyun 		for (i = 0; i < cnt; i++) {
8497*4882a593Smuzhiyun 			W_REG(osh, &pmu->res_table_sel, i);
8498*4882a593Smuzhiyun 			*p32++ = R_REG(osh, &pmu->res_dep_mask);
8499*4882a593Smuzhiyun 			*p32++ = R_REG(osh, &pmu->res_updn_timer);
8500*4882a593Smuzhiyun 		}
8501*4882a593Smuzhiyun 	}
8502*4882a593Smuzhiyun 
8503*4882a593Smuzhiyun 	cnt = (sih->pmucaps & PCAP5_PC_MASK) >> PCAP5_PC_SHIFT;
8504*4882a593Smuzhiyun 	if (cnt) {
8505*4882a593Smuzhiyun 		*p32++ = (cnt << 16 | PMU_PLL_CONTROL_ADDR);
8506*4882a593Smuzhiyun 		for (i = 0; i < cnt; i++) {
8507*4882a593Smuzhiyun 			*p32++ = si_pmu_pllcontrol(sih, i, 0, 0);
8508*4882a593Smuzhiyun 		}
8509*4882a593Smuzhiyun 	}
8510*4882a593Smuzhiyun 
8511*4882a593Smuzhiyun 	cnt = (sih->pmucaps & PCAP5_VC_MASK) >> PCAP5_VC_SHIFT;
8512*4882a593Smuzhiyun 	if (cnt) {
8513*4882a593Smuzhiyun 		*p32++ = (cnt << 16 | PMU_REG_CONTROL_ADDR);
8514*4882a593Smuzhiyun 		for (i = 0; i < cnt; i++) {
8515*4882a593Smuzhiyun 			*p32++ = si_pmu_vreg_control(sih, i, 0, 0);
8516*4882a593Smuzhiyun 		}
8517*4882a593Smuzhiyun 	}
8518*4882a593Smuzhiyun 	cnt = (sih->pmucaps & PCAP5_CC_MASK) >> PCAP5_CC_SHIFT;
8519*4882a593Smuzhiyun 	if (cnt) {
8520*4882a593Smuzhiyun 		*p32++ = (cnt << 16 | CC_CHIPCTL_ADDR);
8521*4882a593Smuzhiyun 		for (i = 0; i < cnt; i++) {
8522*4882a593Smuzhiyun 			*p32++ = si_pmu_chipcontrol(sih, i, 0, 0);
8523*4882a593Smuzhiyun 		}
8524*4882a593Smuzhiyun 	}
8525*4882a593Smuzhiyun 	if (ARRAYSIZE(chipc_regs_to_dump)) {
8526*4882a593Smuzhiyun 		uint32 *addr;
8527*4882a593Smuzhiyun 		*p32++ = (ARRAYSIZE(chipc_regs_to_dump) << 16 | 0);
8528*4882a593Smuzhiyun 		for (i = 0; i < ARRAYSIZE(chipc_regs_to_dump); i++) {
8529*4882a593Smuzhiyun 			addr = (uint32 *)(SI_ENUM_BASE(sih) + chipc_regs_to_dump[i]);
8530*4882a593Smuzhiyun 			*p32++ = (uint32)addr;
8531*4882a593Smuzhiyun 			*p32++ = R_REG(osh, addr);
8532*4882a593Smuzhiyun 		}
8533*4882a593Smuzhiyun 	}
8534*4882a593Smuzhiyun 
8535*4882a593Smuzhiyun 	if ((PMUREV(sih->pmurev) > 27)) {
8536*4882a593Smuzhiyun 		volatile uint32 *addr;
8537*4882a593Smuzhiyun 		*p32++ = (ARRAYSIZE(pmuregsdump) << 16 | 1);
8538*4882a593Smuzhiyun 		for (i = 0; i < ARRAYSIZE(pmuregsdump); i++) {
8539*4882a593Smuzhiyun 			addr = (volatile uint32*)((volatile char*)pmu + pmuregsdump[i]);
8540*4882a593Smuzhiyun 			*p32++ = (uint32)addr;
8541*4882a593Smuzhiyun 			*p32++ = R_REG(osh, addr);
8542*4882a593Smuzhiyun 		}
8543*4882a593Smuzhiyun 		pmu_totalsize += (ARRAYSIZE(pmuregsdump));
8544*4882a593Smuzhiyun 		mac_res_cnt = si_pmu_get_mac_rsrc_req_tmr_cnt(sih);
8545*4882a593Smuzhiyun 		if (mac_res_cnt > 1) {
8546*4882a593Smuzhiyun 			*p32++ = (ARRAYSIZE(pmuregsdump_mac_res1) << 16 | 1);
8547*4882a593Smuzhiyun 			for (i = 0; i < ARRAYSIZE(pmuregsdump_mac_res1); i++) {
8548*4882a593Smuzhiyun 				addr = (volatile uint32*)((volatile char*)pmu +
8549*4882a593Smuzhiyun 						pmuregsdump_mac_res1[i]);
8550*4882a593Smuzhiyun 				*p32++ = (uint32)addr;
8551*4882a593Smuzhiyun 				*p32++ = R_REG(osh, addr);
8552*4882a593Smuzhiyun 			}
8553*4882a593Smuzhiyun 			pmu_totalsize += (ARRAYSIZE(pmuregsdump_mac_res1));
8554*4882a593Smuzhiyun 		}
8555*4882a593Smuzhiyun 		if (mac_res_cnt > 2) {
8556*4882a593Smuzhiyun 			*p32++ = (ARRAYSIZE(pmuregsdump_mac_res2) << 16 | 1);
8557*4882a593Smuzhiyun 			for (i = 0; i < ARRAYSIZE(pmuregsdump_mac_res2); i++) {
8558*4882a593Smuzhiyun 				addr = (volatile uint32*)((volatile char*)pmu +
8559*4882a593Smuzhiyun 						pmuregsdump_mac_res2[i]);
8560*4882a593Smuzhiyun 				*p32++ = (uint32)addr;
8561*4882a593Smuzhiyun 				*p32++ = R_REG(osh, addr);
8562*4882a593Smuzhiyun 			}
8563*4882a593Smuzhiyun 			pmu_totalsize += (ARRAYSIZE(pmuregsdump_mac_res2));
8564*4882a593Smuzhiyun 		}
8565*4882a593Smuzhiyun 		pmu_int_rcv_cnt = si_pmu_get_pmu_interrupt_rcv_cnt(sih);
8566*4882a593Smuzhiyun 		if (pmu_int_rcv_cnt > 1) {
8567*4882a593Smuzhiyun 			*p32++ = (ARRAYSIZE(pmuregsdump_pmu_int1) << 16 | 1);
8568*4882a593Smuzhiyun 			for (i = 0; i < ARRAYSIZE(pmuregsdump_pmu_int1); i++) {
8569*4882a593Smuzhiyun 				addr = (volatile uint32*)((volatile char*)pmu +
8570*4882a593Smuzhiyun 						pmuregsdump_pmu_int1[i]);
8571*4882a593Smuzhiyun 				*p32++ = (uint32)addr;
8572*4882a593Smuzhiyun 				*p32++ = R_REG(osh, addr);
8573*4882a593Smuzhiyun 			}
8574*4882a593Smuzhiyun 			pmu_totalsize += (ARRAYSIZE(pmuregsdump_pmu_int1));
8575*4882a593Smuzhiyun 		}
8576*4882a593Smuzhiyun 		/* Mark the location where these registers are dumped  to avoid a re-read in
8577*4882a593Smuzhiyun 		 * trap context.
8578*4882a593Smuzhiyun 		 */
8579*4882a593Smuzhiyun 		rodata_pmuregdump_ptr = (p32 - (2 * pmu_totalsize));
8580*4882a593Smuzhiyun 	}
8581*4882a593Smuzhiyun 
8582*4882a593Smuzhiyun 	/* Return to original core */
8583*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8584*4882a593Smuzhiyun 	return 1;
8585*4882a593Smuzhiyun } /* si_pmu_dump_pmucap_binary */
8586*4882a593Smuzhiyun 
8587*4882a593Smuzhiyun #endif /* DONGLEBUILD */
8588*4882a593Smuzhiyun /**
8589*4882a593Smuzhiyun  * Function to enable the min_mask with specified resources along with its dependencies.
8590*4882a593Smuzhiyun  * Also it can be used for bringing back to the default value of the device.
8591*4882a593Smuzhiyun  */
8592*4882a593Smuzhiyun int
si_pmu_min_res_set(si_t * sih,osl_t * osh,uint min_mask,bool set)8593*4882a593Smuzhiyun si_pmu_min_res_set(si_t *sih, osl_t *osh, uint min_mask, bool set)
8594*4882a593Smuzhiyun {
8595*4882a593Smuzhiyun 	uint32 min_res, max_res;
8596*4882a593Smuzhiyun 	uint origidx;
8597*4882a593Smuzhiyun 	bcm_int_bitmask_t intr_val;
8598*4882a593Smuzhiyun 	pmuregs_t *pmu;
8599*4882a593Smuzhiyun 
8600*4882a593Smuzhiyun 	/* Block ints and save current core */
8601*4882a593Smuzhiyun 	si_introff(sih, &intr_val);
8602*4882a593Smuzhiyun 
8603*4882a593Smuzhiyun 	/* Remember original core before switch to chipc */
8604*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8605*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
8606*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
8607*4882a593Smuzhiyun 	} else {
8608*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
8609*4882a593Smuzhiyun 	}
8610*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
8611*4882a593Smuzhiyun 
8612*4882a593Smuzhiyun 	si_pmu_res_masks(sih, &min_res, &max_res);
8613*4882a593Smuzhiyun 	min_mask |= si_pmu_res_deps(sih, osh, pmu, min_mask, TRUE);
8614*4882a593Smuzhiyun 
8615*4882a593Smuzhiyun 	/*
8616*4882a593Smuzhiyun 	 * If set is enabled, the resources specified in the min_mask is brought up. If not set,
8617*4882a593Smuzhiyun 	 * go to the default min_resource of the device.
8618*4882a593Smuzhiyun 	 */
8619*4882a593Smuzhiyun 	if (set) {
8620*4882a593Smuzhiyun 		OR_REG(osh, &pmu->min_res_mask, min_mask);
8621*4882a593Smuzhiyun 	} else {
8622*4882a593Smuzhiyun 		min_mask &= ~min_res;
8623*4882a593Smuzhiyun 		AND_REG(osh, &pmu->min_res_mask, ~min_mask);
8624*4882a593Smuzhiyun 	}
8625*4882a593Smuzhiyun 
8626*4882a593Smuzhiyun 	si_pmu_wait_for_steady_state(sih, osh, pmu);
8627*4882a593Smuzhiyun 
8628*4882a593Smuzhiyun 	/* Return to original core */
8629*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8630*4882a593Smuzhiyun 	si_intrrestore(sih, &intr_val);
8631*4882a593Smuzhiyun 
8632*4882a593Smuzhiyun 	return min_mask;
8633*4882a593Smuzhiyun }
8634*4882a593Smuzhiyun 
8635*4882a593Smuzhiyun void
si_pmu_bt_ldo_pu(si_t * sih,bool up)8636*4882a593Smuzhiyun si_pmu_bt_ldo_pu(si_t *sih, bool up)
8637*4882a593Smuzhiyun {
8638*4882a593Smuzhiyun 	si_pmu_regcontrol(sih, PMU_VREG_6, PMU_28NM_VREG6_BTLDO3P3_PU,
8639*4882a593Smuzhiyun 		(up == TRUE) ? PMU_28NM_VREG6_BTLDO3P3_PU : 0x00);
8640*4882a593Smuzhiyun }
8641*4882a593Smuzhiyun 
8642*4882a593Smuzhiyun #ifdef BCM_LDO3P3_SOFTSTART
si_pmu_ldo3p3_soft_start_wl_get(si_t * sih,osl_t * osh,int * res)8643*4882a593Smuzhiyun int si_pmu_ldo3p3_soft_start_wl_get(si_t *sih, osl_t *osh, int *res)
8644*4882a593Smuzhiyun {
8645*4882a593Smuzhiyun 	uint32 bt_or_wl = 0u;
8646*4882a593Smuzhiyun 	return si_pmu_ldo3p3_soft_start_get(sih, osh, bt_or_wl, res);
8647*4882a593Smuzhiyun }
8648*4882a593Smuzhiyun 
si_pmu_ldo3p3_soft_start_bt_get(si_t * sih,osl_t * osh,int * res)8649*4882a593Smuzhiyun int si_pmu_ldo3p3_soft_start_bt_get(si_t *sih, osl_t *osh, int *res)
8650*4882a593Smuzhiyun {
8651*4882a593Smuzhiyun 	uint32 bt_or_wl = 1u;
8652*4882a593Smuzhiyun 	return si_pmu_ldo3p3_soft_start_get(sih, osh, bt_or_wl, res);
8653*4882a593Smuzhiyun }
8654*4882a593Smuzhiyun 
8655*4882a593Smuzhiyun static int
si_pmu_soft_start_params(si_t * sih,uint32 bt_or_wl,uint * en_reg,uint32 * en_shift,uint32 * en_mask,uint32 * en_val,uint * val_reg,uint32 * val_shift,uint32 * val_mask)8656*4882a593Smuzhiyun si_pmu_soft_start_params(si_t *sih, uint32 bt_or_wl, uint *en_reg, uint32 *en_shift,
8657*4882a593Smuzhiyun 	uint32 *en_mask, uint32 *en_val, uint *val_reg, uint32 *val_shift, uint32 *val_mask)
8658*4882a593Smuzhiyun {
8659*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8660*4882a593Smuzhiyun 		case BCM4369_CHIP_GRPID:
8661*4882a593Smuzhiyun 			*en_reg = SOFT_START_EN_REG_4369;
8662*4882a593Smuzhiyun 			*en_shift = SOFT_START_EN_SHIFT_4369(bt_or_wl);
8663*4882a593Smuzhiyun 			*en_mask = SOFT_START_EN_MASK_4369;
8664*4882a593Smuzhiyun 			*en_val = SOFT_START_EN_VALUE_4369;
8665*4882a593Smuzhiyun 			*val_reg = SLEW_RATE_VALUE_REG_4369;
8666*4882a593Smuzhiyun 			*val_shift = SLEW_RATE_SHIFT_4369(bt_or_wl);
8667*4882a593Smuzhiyun 			*val_mask = SLEW_RATE_MASK_4369;
8668*4882a593Smuzhiyun 			break;
8669*4882a593Smuzhiyun 		case BCM4376_CHIP_GRPID:
8670*4882a593Smuzhiyun 		case BCM4378_CHIP_GRPID:
8671*4882a593Smuzhiyun 			*en_reg = SOFT_START_EN_REG_4378;
8672*4882a593Smuzhiyun 			*en_shift = SOFT_START_EN_SHIFT_4378(bt_or_wl);
8673*4882a593Smuzhiyun 			*en_mask = SOFT_START_EN_MASK_4378;
8674*4882a593Smuzhiyun 			*en_val = SOFT_START_EN_VALUE_4378;
8675*4882a593Smuzhiyun 			*val_reg = SLEW_RATE_VALUE_REG_4378;
8676*4882a593Smuzhiyun 			*val_shift = SLEW_RATE_SHIFT_4378(bt_or_wl);
8677*4882a593Smuzhiyun 			*val_mask = SLEW_RATE_MASK_4378;
8678*4882a593Smuzhiyun 			if (BCM4378_CHIP(sih->chip) && PMUREV(sih->pmurev) == 37) {
8679*4882a593Smuzhiyun 				*en_val = SOFT_START_EN_VALUE_4378_REV37;
8680*4882a593Smuzhiyun 			}
8681*4882a593Smuzhiyun 			break;
8682*4882a593Smuzhiyun 		case BCM4387_CHIP_GRPID:
8683*4882a593Smuzhiyun 			if (bt_or_wl == 0) {
8684*4882a593Smuzhiyun 				return BCME_UNSUPPORTED;
8685*4882a593Smuzhiyun 			}
8686*4882a593Smuzhiyun 			*en_reg = SOFT_START_EN_REG_4387;
8687*4882a593Smuzhiyun 			*en_shift = SOFT_START_EN_SHIFT_4387(bt_or_wl);
8688*4882a593Smuzhiyun 			*en_mask = SOFT_START_EN_MASK_4387;
8689*4882a593Smuzhiyun 			*en_val = SOFT_START_EN_VALUE_4387;
8690*4882a593Smuzhiyun 			*val_reg = SLEW_RATE_VALUE_REG_4387;
8691*4882a593Smuzhiyun 			*val_shift = SLEW_RATE_SHIFT_4387(bt_or_wl);
8692*4882a593Smuzhiyun 			*val_mask = SLEW_RATE_MASK_4387;
8693*4882a593Smuzhiyun 			break;
8694*4882a593Smuzhiyun 		default:
8695*4882a593Smuzhiyun 			/* Add support */
8696*4882a593Smuzhiyun 			ASSERT(0);
8697*4882a593Smuzhiyun 			break;
8698*4882a593Smuzhiyun 	}
8699*4882a593Smuzhiyun 	return BCME_OK;
8700*4882a593Smuzhiyun }
8701*4882a593Smuzhiyun 
si_pmu_ldo3p3_soft_start_get(si_t * sih,osl_t * osh,uint32 bt_or_wl,int * res)8702*4882a593Smuzhiyun static int si_pmu_ldo3p3_soft_start_get(si_t *sih, osl_t *osh, uint32 bt_or_wl, int *res)
8703*4882a593Smuzhiyun {
8704*4882a593Smuzhiyun 	uint en_reg = 0, val_reg = 0;
8705*4882a593Smuzhiyun 	uint32 en_shift = 0, en_mask = 0, en_val = 0, val_shift = 0, val_mask = 0;
8706*4882a593Smuzhiyun 	uint32 soft_start_en, slew_rate;
8707*4882a593Smuzhiyun 	int ret = si_pmu_soft_start_params(sih, bt_or_wl, &en_reg, &en_shift, &en_mask, &en_val,
8708*4882a593Smuzhiyun 		&val_reg, &val_shift, &val_mask);
8709*4882a593Smuzhiyun 
8710*4882a593Smuzhiyun 	if (BCME_OK != ret) {
8711*4882a593Smuzhiyun 		return ret;
8712*4882a593Smuzhiyun 	}
8713*4882a593Smuzhiyun 	soft_start_en = (si_pmu_vreg_control(sih, en_reg, 0, 0) >> en_shift);
8714*4882a593Smuzhiyun 	soft_start_en &= en_mask;
8715*4882a593Smuzhiyun 	if (en_val == 0u) {
8716*4882a593Smuzhiyun 		soft_start_en = !soft_start_en;
8717*4882a593Smuzhiyun 	}
8718*4882a593Smuzhiyun 	if (soft_start_en) {
8719*4882a593Smuzhiyun 		slew_rate = (si_pmu_vreg_control(sih, val_reg, 0, 0) >> val_shift);
8720*4882a593Smuzhiyun 		slew_rate &= val_mask;
8721*4882a593Smuzhiyun 		*res = slew_rate;
8722*4882a593Smuzhiyun 	} else {
8723*4882a593Smuzhiyun 		*res =  -1;
8724*4882a593Smuzhiyun 	}
8725*4882a593Smuzhiyun 	return BCME_OK;
8726*4882a593Smuzhiyun }
8727*4882a593Smuzhiyun 
si_pmu_ldo3p3_soft_start_wl_set(si_t * sih,osl_t * osh,uint32 slew_rate)8728*4882a593Smuzhiyun int si_pmu_ldo3p3_soft_start_wl_set(si_t *sih, osl_t *osh, uint32 slew_rate)
8729*4882a593Smuzhiyun {
8730*4882a593Smuzhiyun 	uint32 bt_or_wl = 0u;
8731*4882a593Smuzhiyun 	return si_pmu_ldo3p3_soft_start_set(sih, osh, bt_or_wl, slew_rate);
8732*4882a593Smuzhiyun }
8733*4882a593Smuzhiyun 
si_pmu_ldo3p3_soft_start_bt_set(si_t * sih,osl_t * osh,uint32 slew_rate)8734*4882a593Smuzhiyun int si_pmu_ldo3p3_soft_start_bt_set(si_t *sih, osl_t *osh, uint32 slew_rate)
8735*4882a593Smuzhiyun {
8736*4882a593Smuzhiyun 	uint32 bt_or_wl = 1u;
8737*4882a593Smuzhiyun 	return si_pmu_ldo3p3_soft_start_set(sih, osh, bt_or_wl, slew_rate);
8738*4882a593Smuzhiyun }
8739*4882a593Smuzhiyun 
si_pmu_ldo3p3_soft_start_set(si_t * sih,osl_t * osh,uint32 bt_or_wl,uint32 slew_rate)8740*4882a593Smuzhiyun static int si_pmu_ldo3p3_soft_start_set(si_t *sih, osl_t *osh, uint32 bt_or_wl, uint32 slew_rate)
8741*4882a593Smuzhiyun {
8742*4882a593Smuzhiyun 	uint en_reg = 0, val_reg = 0;
8743*4882a593Smuzhiyun 	uint32 en_shift = 0, en_mask = 0, en_val = 0, val_shift = 0, val_mask = 0;
8744*4882a593Smuzhiyun 	int ret = si_pmu_soft_start_params(sih, bt_or_wl, &en_reg, &en_shift, &en_mask, &en_val,
8745*4882a593Smuzhiyun 		&val_reg, &val_shift, &val_mask);
8746*4882a593Smuzhiyun 	uint32 dis_val = en_val ? 0u : 1u;
8747*4882a593Smuzhiyun 
8748*4882a593Smuzhiyun 	if (BCME_OK != ret) {
8749*4882a593Smuzhiyun 		return ret;
8750*4882a593Smuzhiyun 	}
8751*4882a593Smuzhiyun 
8752*4882a593Smuzhiyun 	if (slew_rate != (uint32)(~0u)) {
8753*4882a593Smuzhiyun 
8754*4882a593Smuzhiyun 		/* Without disabling soft start bit
8755*4882a593Smuzhiyun 		 * programming a new slew rate value
8756*4882a593Smuzhiyun 		 * doesn't take effect
8757*4882a593Smuzhiyun 		 */
8758*4882a593Smuzhiyun 
8759*4882a593Smuzhiyun 		/* Disable soft start */
8760*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, en_reg, (en_mask << en_shift), (dis_val << en_shift));
8761*4882a593Smuzhiyun 
8762*4882a593Smuzhiyun 		/* Program Slew rate */
8763*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, val_reg, (val_mask << val_shift),
8764*4882a593Smuzhiyun 			((slew_rate & val_mask) << val_shift));
8765*4882a593Smuzhiyun 
8766*4882a593Smuzhiyun 		/* Enable Soft start */
8767*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, en_reg, (en_mask << en_shift), (en_val << en_shift));
8768*4882a593Smuzhiyun 	} else {
8769*4882a593Smuzhiyun 		/* Slew rate value of 0xFFFF is used as a special value
8770*4882a593Smuzhiyun 		 * to disable/reset soft start feature
8771*4882a593Smuzhiyun 		 */
8772*4882a593Smuzhiyun 
8773*4882a593Smuzhiyun 		/* Disable soft start */
8774*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, en_reg, (en_mask << en_shift), (dis_val << en_shift));
8775*4882a593Smuzhiyun 
8776*4882a593Smuzhiyun 		/* Set slew rate value to zero */
8777*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, val_reg, (val_mask << val_shift), 0u);
8778*4882a593Smuzhiyun 	}
8779*4882a593Smuzhiyun 	return BCME_OK;
8780*4882a593Smuzhiyun }
8781*4882a593Smuzhiyun #endif /* BCM_LDO3P3_SOFTSTART */
8782*4882a593Smuzhiyun 
8783*4882a593Smuzhiyun #ifdef LDO3P3_MIN_RES_MASK
8784*4882a593Smuzhiyun static bool ldo3p3_min_res_enabled = FALSE;
8785*4882a593Smuzhiyun /** Set ldo 3.3V mask in the min resources mask register */
8786*4882a593Smuzhiyun int
si_pmu_min_res_ldo3p3_set(si_t * sih,osl_t * osh,bool on)8787*4882a593Smuzhiyun si_pmu_min_res_ldo3p3_set(si_t *sih, osl_t *osh, bool on)
8788*4882a593Smuzhiyun {
8789*4882a593Smuzhiyun 	uint32 min_mask = 0;
8790*4882a593Smuzhiyun 	uint coreidx = si_findcoreidx(sih, GCI_CORE_ID, 0);
8791*4882a593Smuzhiyun 
8792*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8793*4882a593Smuzhiyun 		case BCM4369_CHIP_GRPID:
8794*4882a593Smuzhiyun 		case BCM4362_CHIP_GRPID:
8795*4882a593Smuzhiyun 			min_mask = PMURES_BIT(RES4369_LDO3P3_PU);
8796*4882a593Smuzhiyun 			if (on) {
8797*4882a593Smuzhiyun 				si_corereg(sih, coreidx, LHL_REG_OFF(lhl_lp_main_ctl1_adr),
8798*4882a593Smuzhiyun 						BCM_MASK32(23, 0), 0x9E9F9F);
8799*4882a593Smuzhiyun 			} else {
8800*4882a593Smuzhiyun 				si_corereg(sih, coreidx, LHL_REG_OFF(lhl_lp_main_ctl1_adr),
8801*4882a593Smuzhiyun 						BCM_MASK32(23, 0), 0x9E9F97);
8802*4882a593Smuzhiyun 			}
8803*4882a593Smuzhiyun 			break;
8804*4882a593Smuzhiyun 		case BCM4376_CHIP_GRPID:
8805*4882a593Smuzhiyun 		case BCM4378_CHIP_GRPID:
8806*4882a593Smuzhiyun 			min_mask = PMURES_BIT(RES4378_LDO3P3_PU);
8807*4882a593Smuzhiyun 			break;
8808*4882a593Smuzhiyun 		default:
8809*4882a593Smuzhiyun 			return BCME_UNSUPPORTED;
8810*4882a593Smuzhiyun 	}
8811*4882a593Smuzhiyun 
8812*4882a593Smuzhiyun 	si_pmu_min_res_set(sih, osh, min_mask, on);
8813*4882a593Smuzhiyun 	ldo3p3_min_res_enabled = on;
8814*4882a593Smuzhiyun 
8815*4882a593Smuzhiyun 	return BCME_OK;
8816*4882a593Smuzhiyun }
8817*4882a593Smuzhiyun 
8818*4882a593Smuzhiyun int
si_pmu_min_res_ldo3p3_get(si_t * sih,osl_t * osh,int * res)8819*4882a593Smuzhiyun si_pmu_min_res_ldo3p3_get(si_t *sih, osl_t *osh, int *res)
8820*4882a593Smuzhiyun {
8821*4882a593Smuzhiyun 	*res = (int)ldo3p3_min_res_enabled;
8822*4882a593Smuzhiyun 	return BCME_OK;
8823*4882a593Smuzhiyun }
8824*4882a593Smuzhiyun #endif /* LDO3P3_MIN_RES_MASK */
8825*4882a593Smuzhiyun int
si_pmu_min_res_otp_pu_set(si_t * sih,osl_t * osh,bool on)8826*4882a593Smuzhiyun si_pmu_min_res_otp_pu_set(si_t *sih, osl_t *osh, bool on)
8827*4882a593Smuzhiyun {
8828*4882a593Smuzhiyun 	uint32 min_mask = 0;
8829*4882a593Smuzhiyun 	rsc_per_chip_t *rsc;
8830*4882a593Smuzhiyun 
8831*4882a593Smuzhiyun 	rsc = si_pmu_get_rsc_positions(sih);
8832*4882a593Smuzhiyun 	if (rsc) {
8833*4882a593Smuzhiyun 		min_mask = PMURES_BIT(rsc->otp_pu);
8834*4882a593Smuzhiyun 	} else {
8835*4882a593Smuzhiyun 		return BCME_UNSUPPORTED;
8836*4882a593Smuzhiyun 	}
8837*4882a593Smuzhiyun 	si_pmu_min_res_set(sih, osh, min_mask, on);
8838*4882a593Smuzhiyun 	return BCME_OK;
8839*4882a593Smuzhiyun }
8840*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
8841*4882a593Smuzhiyun 
8842*4882a593Smuzhiyun uint32
BCMPOSTTRAPFN(si_pmu_wake_bit_offset)8843*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_wake_bit_offset)(si_t *sih)
8844*4882a593Smuzhiyun {
8845*4882a593Smuzhiyun 	uint32 wakebit;
8846*4882a593Smuzhiyun 
8847*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
8848*4882a593Smuzhiyun 	case BCM4369_CHIP_GRPID:
8849*4882a593Smuzhiyun 		wakebit = PMU_CC2_GCI2_WAKE;
8850*4882a593Smuzhiyun 		break;
8851*4882a593Smuzhiyun 	case BCM4376_CHIP_GRPID:
8852*4882a593Smuzhiyun 	case BCM4378_CHIP_GRPID:
8853*4882a593Smuzhiyun 		wakebit = CC2_4378_GCI2WAKE_MASK;
8854*4882a593Smuzhiyun 		break;
8855*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
8856*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
8857*4882a593Smuzhiyun 		wakebit = CC2_4387_GCI2WAKE_MASK;
8858*4882a593Smuzhiyun 		break;
8859*4882a593Smuzhiyun 	case BCM4388_CHIP_GRPID:
8860*4882a593Smuzhiyun 	case BCM4389_CHIP_GRPID:
8861*4882a593Smuzhiyun 	case BCM4397_CHIP_GRPID:
8862*4882a593Smuzhiyun 		wakebit = CC2_4389_GCI2WAKE_MASK;
8863*4882a593Smuzhiyun 		break;
8864*4882a593Smuzhiyun 	default:
8865*4882a593Smuzhiyun 		wakebit = 0;
8866*4882a593Smuzhiyun 		ASSERT(0);
8867*4882a593Smuzhiyun 		break;
8868*4882a593Smuzhiyun 	}
8869*4882a593Smuzhiyun 
8870*4882a593Smuzhiyun 	return wakebit;
8871*4882a593Smuzhiyun }
8872*4882a593Smuzhiyun 
8873*4882a593Smuzhiyun #ifdef ATE_BUILD
hnd_pmu_clr_int_sts_req_active(osl_t * hnd_osh,si_t * sih)8874*4882a593Smuzhiyun void hnd_pmu_clr_int_sts_req_active(osl_t *hnd_osh, si_t *sih)
8875*4882a593Smuzhiyun {
8876*4882a593Smuzhiyun 	uint32 res_req_timer;
8877*4882a593Smuzhiyun 	pmuregs_t *pmu;
8878*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
8879*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
8880*4882a593Smuzhiyun 	} else {
8881*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
8882*4882a593Smuzhiyun 	}
8883*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
8884*4882a593Smuzhiyun 	W_REG(hnd_osh, &pmu->pmuintstatus,
8885*4882a593Smuzhiyun 		RSRC_INTR_MASK_TIMER_INT_0);
8886*4882a593Smuzhiyun 	(void)R_REG(hnd_osh, &pmu->pmuintstatus);
8887*4882a593Smuzhiyun 	res_req_timer = R_REG(hnd_osh, &pmu->res_req_timer);
8888*4882a593Smuzhiyun 	W_REG(hnd_osh, &pmu->res_req_timer,
8889*4882a593Smuzhiyun 			res_req_timer & ~(PRRT_REQ_ACTIVE << flags_shift));
8890*4882a593Smuzhiyun 	(void)R_REG(hnd_osh, &pmu->res_req_timer);
8891*4882a593Smuzhiyun }
8892*4882a593Smuzhiyun #endif /* ATE_BUILD */
8893*4882a593Smuzhiyun 
si_pmu_set_min_res_mask(si_t * sih,osl_t * osh,uint min_res_mask)8894*4882a593Smuzhiyun void si_pmu_set_min_res_mask(si_t *sih, osl_t *osh, uint min_res_mask)
8895*4882a593Smuzhiyun {
8896*4882a593Smuzhiyun 	pmuregs_t *pmu;
8897*4882a593Smuzhiyun 	uint origidx;
8898*4882a593Smuzhiyun 
8899*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
8900*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
8901*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
8902*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
8903*4882a593Smuzhiyun 	}
8904*4882a593Smuzhiyun 	else {
8905*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
8906*4882a593Smuzhiyun 	}
8907*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
8908*4882a593Smuzhiyun 
8909*4882a593Smuzhiyun 	W_REG(osh, &pmu->min_res_mask, min_res_mask);
8910*4882a593Smuzhiyun 	OSL_DELAY(100);
8911*4882a593Smuzhiyun 
8912*4882a593Smuzhiyun 	/* Return to original core */
8913*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
8914*4882a593Smuzhiyun }
8915*4882a593Smuzhiyun 
8916*4882a593Smuzhiyun bool
si_pmu_cap_fast_lpo(si_t * sih)8917*4882a593Smuzhiyun si_pmu_cap_fast_lpo(si_t *sih)
8918*4882a593Smuzhiyun {
8919*4882a593Smuzhiyun 	return (PMU_REG(sih, core_cap_ext, 0, 0) & PCAP_EXT_USE_MUXED_ILP_CLK_MASK) ? TRUE : FALSE;
8920*4882a593Smuzhiyun }
8921*4882a593Smuzhiyun 
8922*4882a593Smuzhiyun int
si_pmu_fast_lpo_disable(si_t * sih)8923*4882a593Smuzhiyun si_pmu_fast_lpo_disable(si_t *sih)
8924*4882a593Smuzhiyun {
8925*4882a593Smuzhiyun 	if (!si_pmu_cap_fast_lpo(sih)) {
8926*4882a593Smuzhiyun 		PMU_ERROR(("si_pmu_fast_lpo_disable: No Fast LPO capability\n"));
8927*4882a593Smuzhiyun 		return BCME_ERROR;
8928*4882a593Smuzhiyun 	}
8929*4882a593Smuzhiyun 
8930*4882a593Smuzhiyun 	PMU_REG(sih, pmucontrol_ext,
8931*4882a593Smuzhiyun 		PCTL_EXT_FASTLPO_ENAB |
8932*4882a593Smuzhiyun 		PCTL_EXT_FASTLPO_SWENAB |
8933*4882a593Smuzhiyun 		PCTL_EXT_FASTLPO_PCIE_SWENAB,
8934*4882a593Smuzhiyun 		0);
8935*4882a593Smuzhiyun 	OSL_DELAY(1000);
8936*4882a593Smuzhiyun 	return BCME_OK;
8937*4882a593Smuzhiyun }
8938*4882a593Smuzhiyun 
8939*4882a593Smuzhiyun /*
8940*4882a593Smuzhiyun * 4389B0/C0 - WL and BT turn on WAR,
8941*4882a593Smuzhiyun * set below bits in PMU chip control 6
8942*4882a593Smuzhiyun * - global bit[195] / bit[3] - enable legacy pmu_wakeup to make
8943*4882a593Smuzhiyun * domain 1 (WL) power request
8944*4882a593Smuzhiyun * - global bit[206] / bit[14] - perst_wake_en
8945*4882a593Smuzhiyun */
8946*4882a593Smuzhiyun void
si_pmu_dmn1_perst_wakeup(si_t * sih,bool set)8947*4882a593Smuzhiyun si_pmu_dmn1_perst_wakeup(si_t *sih, bool set)
8948*4882a593Smuzhiyun {
8949*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) == 40) {
8950*4882a593Smuzhiyun 		if (set) {
8951*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL6,
8952*4882a593Smuzhiyun 				(PMU_CC6_ENABLE_DMN1_WAKEUP |
8953*4882a593Smuzhiyun 				PMU_CC6_ENABLE_PMU_WAKEUP_PERST),
8954*4882a593Smuzhiyun 				(PMU_CC6_ENABLE_DMN1_WAKEUP |
8955*4882a593Smuzhiyun 				PMU_CC6_ENABLE_PMU_WAKEUP_PERST));
8956*4882a593Smuzhiyun 		} else {
8957*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL6,
8958*4882a593Smuzhiyun 				(PMU_CC6_ENABLE_DMN1_WAKEUP |
8959*4882a593Smuzhiyun 				PMU_CC6_ENABLE_PMU_WAKEUP_PERST),
8960*4882a593Smuzhiyun 				0);
8961*4882a593Smuzhiyun 		}
8962*4882a593Smuzhiyun 	}
8963*4882a593Smuzhiyun }
8964*4882a593Smuzhiyun 
8965*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
8966*4882a593Smuzhiyun 
8967*4882a593Smuzhiyun /* write :
8968*4882a593Smuzhiyun  *   TRUE - Programs the PLLCTRL6 with xtal and returns value written in pllctrl6 register.
8969*4882a593Smuzhiyun  *   FALSE - returns 0 if xtal programming is same as pllctrl6 register else retruns value of
8970*4882a593Smuzhiyun  *   pllctrl6 val. This will not program any register.
8971*4882a593Smuzhiyun  */
8972*4882a593Smuzhiyun static uint32
si_pmu_pll6val_armclk_calc(osl_t * osh,pmuregs_t * pmu,uint32 armclk,uint32 xtal,bool write)8973*4882a593Smuzhiyun si_pmu_pll6val_armclk_calc(osl_t *osh, pmuregs_t *pmu, uint32 armclk, uint32 xtal, bool write)
8974*4882a593Smuzhiyun {
8975*4882a593Smuzhiyun 	uint32 q, r;
8976*4882a593Smuzhiyun 	uint32 xtal_scale;
8977*4882a593Smuzhiyun 	uint32 pll6val;
8978*4882a593Smuzhiyun 	if (armclk == 0 || xtal == 0) {
8979*4882a593Smuzhiyun 		PMU_ERROR((" si_pmu_pll6val_armclk_calc: invalid armclk = %d or xtal = %d\n",
8980*4882a593Smuzhiyun 			armclk, xtal));
8981*4882a593Smuzhiyun 		return 0;
8982*4882a593Smuzhiyun 	}
8983*4882a593Smuzhiyun 	q = (armclk * 1000 * PMU4369_PLL6VAL_P1DIV) / xtal;
8984*4882a593Smuzhiyun 	xtal_scale = xtal / 100;
8985*4882a593Smuzhiyun 	r = ((armclk * 10 * PMU4369_PLL6VAL_P1DIV * PMU4369_PLL6VAL_PRE_SCALE) / xtal_scale) -
8986*4882a593Smuzhiyun 		(q * PMU4369_PLL6VAL_PRE_SCALE);
8987*4882a593Smuzhiyun 	r *= PMU4369_PLL6VAL_POST_SCALE;
8988*4882a593Smuzhiyun 
8989*4882a593Smuzhiyun 	pll6val = (r << PMU4369_PLL1_PC6_NDIV_FRAC_SHIFT) |
8990*4882a593Smuzhiyun 		(q << PMU4369_PLL1_PC6_NDIV_INT_SHIFT) | PMU4369_PLL6VAL_P1DIV_BIT3_2;
8991*4882a593Smuzhiyun 
8992*4882a593Smuzhiyun 	PMU_MSG(("si_pmu_pll6val_armclk_calc, armclk %d, xtal %d, q %d, r 0x%8x, pll6val 0x%8x\n",
8993*4882a593Smuzhiyun 		armclk, xtal, q, r, pll6val));
8994*4882a593Smuzhiyun 
8995*4882a593Smuzhiyun 	if (write) {
8996*4882a593Smuzhiyun 		W_REG(osh, &pmu->pllcontrol_addr, PMU1_PLL0_PLLCTL6);
8997*4882a593Smuzhiyun 		W_REG(osh, &pmu->pllcontrol_data, pll6val);
8998*4882a593Smuzhiyun 	} else {
8999*4882a593Smuzhiyun 		W_REG(osh, &pmu->pllcontrol_addr, PMU1_PLL0_PLLCTL6);
9000*4882a593Smuzhiyun 		if (pll6val == R_REG(osh, &pmu->pllcontrol_data))
9001*4882a593Smuzhiyun 			return 0;
9002*4882a593Smuzhiyun 	}
9003*4882a593Smuzhiyun 
9004*4882a593Smuzhiyun 	return pll6val;
9005*4882a593Smuzhiyun }
9006*4882a593Smuzhiyun 
9007*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4369)9008*4882a593Smuzhiyun BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4369)(si_t *sih)
9009*4882a593Smuzhiyun {
9010*4882a593Smuzhiyun 
9011*4882a593Smuzhiyun /* 4369 XTAL Bias settings */
9012*4882a593Smuzhiyun /*
9013*4882a593Smuzhiyun 	Reg name		startup		Normal
9014*4882a593Smuzhiyun 	xtal_bias_adj		0xFF		0x1A
9015*4882a593Smuzhiyun 	xtal_coresize_nmos	0x3f		0x3f
9016*4882a593Smuzhiyun 	xtal_coresize_pmos	0x3f		0x3f
9017*4882a593Smuzhiyun 	xtal_sel_bias_res	0x2		0x6
9018*4882a593Smuzhiyun 	xt_res_bypass		0x0		0x1
9019*4882a593Smuzhiyun */
9020*4882a593Smuzhiyun 	uint32 u32Val;
9021*4882a593Smuzhiyun 	uint32 u32Mask;
9022*4882a593Smuzhiyun 	u32Val = (PMU_CC0_4369B0_XTALCORESIZE_BIAS_ADJ_NORMAL_VAL |
9023*4882a593Smuzhiyun 		PMU_CC0_4369_XTAL_RES_BYPASS_NORMAL_VAL);
9024*4882a593Smuzhiyun 
9025*4882a593Smuzhiyun 	u32Mask = (PMU_CC0_4369_XTALCORESIZE_BIAS_ADJ_NORMAL_MASK |
9026*4882a593Smuzhiyun 		PMU_CC0_4369_XTAL_RES_BYPASS_NORMAL_MASK);
9027*4882a593Smuzhiyun 
9028*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL0, u32Mask, u32Val);
9029*4882a593Smuzhiyun 
9030*4882a593Smuzhiyun 	u32Val = (PMU_CC2_4369_XTALCORESIZE_BIAS_ADJ_NORMAL_VAL);
9031*4882a593Smuzhiyun 	u32Mask = (PMU_CC2_4369_XTALCORESIZE_BIAS_ADJ_NORMAL_MASK);
9032*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL2, u32Mask, u32Val);
9033*4882a593Smuzhiyun 
9034*4882a593Smuzhiyun 	u32Val = (PMU_CC3_4369_XTALCORESIZE_PMOS_NORMAL_VAL |
9035*4882a593Smuzhiyun 		PMU_CC3_4369_XTALCORESIZE_NMOS_NORMAL_VAL |
9036*4882a593Smuzhiyun 		PMU_CC3_4369_XTALSEL_BIAS_RES_NORMAL_VAL);
9037*4882a593Smuzhiyun 
9038*4882a593Smuzhiyun 	u32Mask = (PMU_CC3_4369_XTALCORESIZE_PMOS_NORMAL_MASK |
9039*4882a593Smuzhiyun 		PMU_CC3_4369_XTALCORESIZE_NMOS_NORMAL_MASK |
9040*4882a593Smuzhiyun 		PMU_CC3_4369_XTALSEL_BIAS_RES_NORMAL_MASK);
9041*4882a593Smuzhiyun 
9042*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL3, u32Mask, u32Val);
9043*4882a593Smuzhiyun 
9044*4882a593Smuzhiyun }
9045*4882a593Smuzhiyun 
9046*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4362)9047*4882a593Smuzhiyun BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4362)(si_t *sih)
9048*4882a593Smuzhiyun {
9049*4882a593Smuzhiyun 	/* 4369 XTAL Bias settings */
9050*4882a593Smuzhiyun 	/*
9051*4882a593Smuzhiyun 		Reg name		startup		Normal
9052*4882a593Smuzhiyun 		xtal_bias_adj		0xFF		0x1A
9053*4882a593Smuzhiyun 		xtal_coresize_nmos	0x3f		0x3f
9054*4882a593Smuzhiyun 		xtal_coresize_pmos	0x3f		0x3f
9055*4882a593Smuzhiyun 		xtal_sel_bias_res	0x2		0x6
9056*4882a593Smuzhiyun 		xt_res_bypass		0x0		0x1
9057*4882a593Smuzhiyun 	*/
9058*4882a593Smuzhiyun 	uint32 u32Val;
9059*4882a593Smuzhiyun 	uint32 u32Mask;
9060*4882a593Smuzhiyun 	u32Val = (PMU_CC0_4362_XTALCORESIZE_BIAS_ADJ_NORMAL_VAL |
9061*4882a593Smuzhiyun 		PMU_CC0_4362_XTAL_RES_BYPASS_NORMAL_VAL);
9062*4882a593Smuzhiyun 
9063*4882a593Smuzhiyun 	u32Mask = (PMU_CC0_4362_XTALCORESIZE_BIAS_ADJ_NORMAL_MASK |
9064*4882a593Smuzhiyun 		PMU_CC0_4362_XTAL_RES_BYPASS_NORMAL_MASK);
9065*4882a593Smuzhiyun 
9066*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL0, u32Mask, u32Val);
9067*4882a593Smuzhiyun 
9068*4882a593Smuzhiyun 	u32Val = (PMU_CC2_4362_XTALCORESIZE_BIAS_ADJ_NORMAL_VAL);
9069*4882a593Smuzhiyun 	u32Mask = (PMU_CC2_4362_XTALCORESIZE_BIAS_ADJ_NORMAL_MASK);
9070*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL2, u32Mask, u32Val);
9071*4882a593Smuzhiyun 
9072*4882a593Smuzhiyun 	u32Val = (PMU_CC3_4362_XTALCORESIZE_PMOS_NORMAL_VAL |
9073*4882a593Smuzhiyun 		PMU_CC3_4362_XTALCORESIZE_NMOS_NORMAL_VAL |
9074*4882a593Smuzhiyun 		PMU_CC3_4362_XTALSEL_BIAS_RES_NORMAL_VAL);
9075*4882a593Smuzhiyun 
9076*4882a593Smuzhiyun 	u32Mask = (PMU_CC3_4362_XTALCORESIZE_PMOS_NORMAL_MASK |
9077*4882a593Smuzhiyun 		PMU_CC3_4362_XTALCORESIZE_NMOS_NORMAL_MASK |
9078*4882a593Smuzhiyun 		PMU_CC3_4362_XTALSEL_BIAS_RES_NORMAL_MASK);
9079*4882a593Smuzhiyun 
9080*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL3, u32Mask, u32Val);
9081*4882a593Smuzhiyun 
9082*4882a593Smuzhiyun }
9083*4882a593Smuzhiyun 
9084*4882a593Smuzhiyun /* 4378 based on 4369 XTAL Bias settings
9085*4882a593Smuzhiyun  *	Reg name		startup		Normal
9086*4882a593Smuzhiyun  *	xtal_bias_adj		0xFF		0x1A
9087*4882a593Smuzhiyun  *	xtal_coresize_nmos	0x3f		0x3f
9088*4882a593Smuzhiyun  *	xtal_coresize_pmos	0x3f		0x3f
9089*4882a593Smuzhiyun  *	xtal_sel_bias_res	0x2		0x2
9090*4882a593Smuzhiyun  *	xt_res_bypass		0x0		0x2
9091*4882a593Smuzhiyun  */
9092*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4378)9093*4882a593Smuzhiyun BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4378)(si_t *sih)
9094*4882a593Smuzhiyun {
9095*4882a593Smuzhiyun 	uint32 u32Val;
9096*4882a593Smuzhiyun 	uint32 u32Mask;
9097*4882a593Smuzhiyun 	uint16 xtal_bias_adj;
9098*4882a593Smuzhiyun 	uint8 xtal_bias_adj_otp = 0, xtal_bias_cal_otp_done = 0;
9099*4882a593Smuzhiyun 
9100*4882a593Smuzhiyun #ifdef XTAL_BIAS_FROM_OTP
9101*4882a593Smuzhiyun 	/* Read xtal bias cal done bit and xtal biase from OTP */
9102*4882a593Smuzhiyun 	si_pmu_chipcontrol_xtal_bias_from_otp(sih, &xtal_bias_cal_otp_done, &xtal_bias_adj_otp);
9103*4882a593Smuzhiyun #endif /* XTAL_BIAS_FROM_OTP */
9104*4882a593Smuzhiyun 
9105*4882a593Smuzhiyun 	/*
9106*4882a593Smuzhiyun 	 * If xtal_bias_cal_done flag is read as non zero, write the xtal biase in PMU control
9107*4882a593Smuzhiyun 	 * register from OTP otherwise write the default value of 0x1a.
9108*4882a593Smuzhiyun 	 */
9109*4882a593Smuzhiyun 	xtal_bias_adj = (uint16)xtal_bias_adj_otp;
9110*4882a593Smuzhiyun 	xtal_bias_adj = xtal_bias_cal_otp_done != 0 ? (xtal_bias_adj << 6) :
9111*4882a593Smuzhiyun 		PMU_CC0_4378_XTALCORESIZE_BIAS_ADJ_NORMAL_VAL;
9112*4882a593Smuzhiyun 
9113*4882a593Smuzhiyun 	u32Val = (xtal_bias_adj | PMU_CC0_4378_XTAL_RES_BYPASS_NORMAL_VAL);
9114*4882a593Smuzhiyun 
9115*4882a593Smuzhiyun 	u32Mask = (PMU_CC0_4378_XTALCORESIZE_BIAS_ADJ_NORMAL_MASK |
9116*4882a593Smuzhiyun 		PMU_CC0_4378_XTAL_RES_BYPASS_NORMAL_MASK);
9117*4882a593Smuzhiyun 
9118*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL0, u32Mask, u32Val);
9119*4882a593Smuzhiyun 
9120*4882a593Smuzhiyun 	u32Val = (PMU_CC2_4378_XTALCORESIZE_BIAS_ADJ_NORMAL_VAL);
9121*4882a593Smuzhiyun 	u32Mask = (PMU_CC2_4378_XTALCORESIZE_BIAS_ADJ_NORMAL_MASK);
9122*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL2, u32Mask, u32Val);
9123*4882a593Smuzhiyun 
9124*4882a593Smuzhiyun 	u32Val = (PMU_CC3_4378_XTALCORESIZE_PMOS_NORMAL_VAL |
9125*4882a593Smuzhiyun 		PMU_CC3_4378_XTALCORESIZE_NMOS_NORMAL_VAL |
9126*4882a593Smuzhiyun 		PMU_CC3_4378_XTALSEL_BIAS_RES_NORMAL_VAL);
9127*4882a593Smuzhiyun 
9128*4882a593Smuzhiyun 	u32Mask = (PMU_CC3_4378_XTALCORESIZE_PMOS_NORMAL_MASK |
9129*4882a593Smuzhiyun 		PMU_CC3_4378_XTALCORESIZE_NMOS_NORMAL_MASK |
9130*4882a593Smuzhiyun 		PMU_CC3_4378_XTALSEL_BIAS_RES_NORMAL_MASK);
9131*4882a593Smuzhiyun 
9132*4882a593Smuzhiyun 	si_pmu_chipcontrol(sih, PMU_CHIPCTL3, u32Mask, u32Val);
9133*4882a593Smuzhiyun 
9134*4882a593Smuzhiyun }
9135*4882a593Smuzhiyun 
9136*4882a593Smuzhiyun #ifdef XTAL_BIAS_FROM_OTP
9137*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_from_otp)9138*4882a593Smuzhiyun BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_from_otp)(si_t *sih, uint8* flag, uint8* val)
9139*4882a593Smuzhiyun {
9140*4882a593Smuzhiyun 	uint8 xtal_bias_adj = 0, xtal_bias_cal_otp_done = 0;
9141*4882a593Smuzhiyun #ifndef BCM_OTP_API
9142*4882a593Smuzhiyun 	uint16 datum, offset;
9143*4882a593Smuzhiyun 	uint8 shift, mask;
9144*4882a593Smuzhiyun #endif /* !BCM_OTP_API */
9145*4882a593Smuzhiyun 
9146*4882a593Smuzhiyun 	/* Read the XTAL BIAS CAL value from OTP.
9147*4882a593Smuzhiyun 	 * 1) Read the xtal cal done bit and the xtal biase value from OTP.
9148*4882a593Smuzhiyun 	 * 2) OTP memory is zero by default, so the chips which aren't OTP programmed will read a
9149*4882a593Smuzhiyun 	 *   '0' for xtal_bias_cal_otp_done.
9150*4882a593Smuzhiyun 	*/
9151*4882a593Smuzhiyun #ifdef BCM_OTP_API
9152*4882a593Smuzhiyun 	otp_read_8b_field(sih, BCM_OTP_FLD_XTAL_BIAS_FLAG, &xtal_bias_cal_otp_done);
9153*4882a593Smuzhiyun 	if (xtal_bias_cal_otp_done) {
9154*4882a593Smuzhiyun 		otp_read_8b_field(sih, BCM_OTP_FLD_XTAL_BIAS_ADJ, &xtal_bias_adj);
9155*4882a593Smuzhiyun 	}
9156*4882a593Smuzhiyun #else
9157*4882a593Smuzhiyun 	si_pmu_chipcontrol_xtal_bias_cal_done_offsets(sih, &offset, &shift, &mask);
9158*4882a593Smuzhiyun 	if (!otp_read_word(sih, offset, &datum)) {
9159*4882a593Smuzhiyun 		xtal_bias_cal_otp_done = ((datum >> shift) & mask);
9160*4882a593Smuzhiyun 	}
9161*4882a593Smuzhiyun 
9162*4882a593Smuzhiyun 	si_pmu_chipcontrol_xtal_bias_val_offsets(sih, &offset, &shift, &mask);
9163*4882a593Smuzhiyun 	if (xtal_bias_cal_otp_done && (!otp_read_word(sih, offset, &datum)))
9164*4882a593Smuzhiyun 	{
9165*4882a593Smuzhiyun 		xtal_bias_adj = ((datum >> shift) & mask);
9166*4882a593Smuzhiyun 	}
9167*4882a593Smuzhiyun #endif /* BCM_OTP_API */
9168*4882a593Smuzhiyun 	*flag = xtal_bias_cal_otp_done;
9169*4882a593Smuzhiyun 	*val = xtal_bias_adj;
9170*4882a593Smuzhiyun }
9171*4882a593Smuzhiyun 
9172*4882a593Smuzhiyun #ifndef BCM_OTP_API
9173*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_cal_done_offsets)9174*4882a593Smuzhiyun BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_cal_done_offsets)(si_t *sih, uint16* wrd_offset,
9175*4882a593Smuzhiyun 		uint8* wrd_shift, uint8* wrd_mask)
9176*4882a593Smuzhiyun {
9177*4882a593Smuzhiyun 	/* Offset is 16 bit aligned address, shift is the starting bit position of the value
9178*4882a593Smuzhiyun 	 * mask defines the bitwidth of the value. Each value in the array is for one of the
9179*4882a593Smuzhiyun 	 * cores.
9180*4882a593Smuzhiyun 	 */
9181*4882a593Smuzhiyun 	/* XTAL BIAS CAL done                 11896 */
9182*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
9183*4882a593Smuzhiyun 		case BCM4376_CHIP_GRPID:
9184*4882a593Smuzhiyun 		case BCM4378_CHIP_GRPID:
9185*4882a593Smuzhiyun 			*wrd_offset = OTP_XTAL_BIAS_CAL_DONE_4378_WRD_OFFSET;
9186*4882a593Smuzhiyun 			*wrd_shift  = OTP_XTAL_BIAS_CAL_DONE_4378_WRD_SHIFT;
9187*4882a593Smuzhiyun 			*wrd_mask   = OTP_XTAL_BIAS_CAL_DONE_4378_WRD_MASK;
9188*4882a593Smuzhiyun 			break;
9189*4882a593Smuzhiyun 		default:
9190*4882a593Smuzhiyun 			ASSERT(0);
9191*4882a593Smuzhiyun 			break;
9192*4882a593Smuzhiyun 	}
9193*4882a593Smuzhiyun }
9194*4882a593Smuzhiyun 
9195*4882a593Smuzhiyun static void
BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_val_offsets)9196*4882a593Smuzhiyun BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_val_offsets)(si_t *sih, uint16* wrd_offset,
9197*4882a593Smuzhiyun 		uint8* wrd_shift, uint8* wrd_mask)
9198*4882a593Smuzhiyun {
9199*4882a593Smuzhiyun 	/* Offset is 16 bit aligned address, shift is the starting bit position of the value
9200*4882a593Smuzhiyun 	 * mask defines the bitwidth of the value. Each value in the array is for one of the
9201*4882a593Smuzhiyun 	 * cores.
9202*4882a593Smuzhiyun 	 */
9203*4882a593Smuzhiyun 	/* XTAL BIAS value                    11888 */
9204*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
9205*4882a593Smuzhiyun 		case BCM4376_CHIP_GRPID:
9206*4882a593Smuzhiyun 		case BCM4378_CHIP_GRPID:
9207*4882a593Smuzhiyun 			*wrd_offset = OTP_XTAL_BIAS_VAL_4378_WRD_OFFSET;
9208*4882a593Smuzhiyun 			*wrd_shift  = OTP_XTAL_BIAS_VAL_4378_WRD_SHIFT;
9209*4882a593Smuzhiyun 			*wrd_mask   = OTP_XTAL_BIAS_VAL_4378_WRD_MASK;
9210*4882a593Smuzhiyun 			break;
9211*4882a593Smuzhiyun 		default:
9212*4882a593Smuzhiyun 			ASSERT(0);
9213*4882a593Smuzhiyun 			break;
9214*4882a593Smuzhiyun 	}
9215*4882a593Smuzhiyun }
9216*4882a593Smuzhiyun #endif /* !BCM_OTP_API */
9217*4882a593Smuzhiyun #endif /* XTAL_BIAS_FROM_OTP */
9218*4882a593Smuzhiyun 
9219*4882a593Smuzhiyun #endif /* !BCMDONGLEHOST */
9220*4882a593Smuzhiyun 
9221*4882a593Smuzhiyun #ifdef BCMPMU_STATS
9222*4882a593Smuzhiyun /*
9223*4882a593Smuzhiyun  * 8 pmu statistics timer default map
9224*4882a593Smuzhiyun  *
9225*4882a593Smuzhiyun  * for CORE_RDY_AUX measure, set as below for timer 6 and 7 instead of CORE_RDY_MAIN.
9226*4882a593Smuzhiyun  *	//core-n active duration : pmu_rsrc_state(CORE_RDY_AUX)
9227*4882a593Smuzhiyun  *	{ SRC_CORE_RDY_AUX, FALSE, TRUE, LEVEL_HIGH},
9228*4882a593Smuzhiyun  *	//core-n active duration : pmu_rsrc_state(CORE_RDY_AUX)
9229*4882a593Smuzhiyun  *	{ SRC_CORE_RDY_AUX, FALSE, TRUE, EDGE_RISE}
9230*4882a593Smuzhiyun  */
9231*4882a593Smuzhiyun static pmu_stats_timer_t pmustatstimer[] = {
9232*4882a593Smuzhiyun 	{ SRC_LINK_IN_L12, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},	//link_in_l12
9233*4882a593Smuzhiyun 	{ SRC_LINK_IN_L23, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},	//link_in_l23
9234*4882a593Smuzhiyun 	{ SRC_PM_ST_IN_D0, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},	//pm_st_in_d0
9235*4882a593Smuzhiyun 	{ SRC_PM_ST_IN_D3, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},	//pm_st_in_d3
9236*4882a593Smuzhiyun 	//deep-sleep duration : pmu_rsrc_state(XTAL_PU)
9237*4882a593Smuzhiyun 	{ SRC_XTAL_PU, FALSE, TRUE, PMU_STATS_LEVEL_LOW},
9238*4882a593Smuzhiyun 	//deep-sleep entry count : pmu_rsrc_state(XTAL_PU)
9239*4882a593Smuzhiyun 	{ SRC_XTAL_PU, FALSE, TRUE, PMU_STATS_EDGE_FALL},
9240*4882a593Smuzhiyun 	//core-n active duration : pmu_rsrc_state(CORE_RDY_MAIN)
9241*4882a593Smuzhiyun 	{ SRC_CORE_RDY_MAIN, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},
9242*4882a593Smuzhiyun 	//core-n active duration : pmu_rsrc_state(CORE_RDY_MAIN)
9243*4882a593Smuzhiyun 	{ SRC_CORE_RDY_MAIN, FALSE, TRUE, PMU_STATS_EDGE_RISE}
9244*4882a593Smuzhiyun };
9245*4882a593Smuzhiyun 
9246*4882a593Smuzhiyun static void
si_pmustatstimer_update(osl_t * osh,pmuregs_t * pmu,uint8 timerid)9247*4882a593Smuzhiyun si_pmustatstimer_update(osl_t *osh, pmuregs_t *pmu, uint8 timerid)
9248*4882a593Smuzhiyun {
9249*4882a593Smuzhiyun 	uint32 stats_timer_ctrl;
9250*4882a593Smuzhiyun 
9251*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
9252*4882a593Smuzhiyun 	stats_timer_ctrl =
9253*4882a593Smuzhiyun 		((pmustatstimer[timerid].src_num << PMU_ST_SRC_SHIFT) &
9254*4882a593Smuzhiyun 			PMU_ST_SRC_MASK) |
9255*4882a593Smuzhiyun 		((pmustatstimer[timerid].cnt_mode << PMU_ST_CNT_MODE_SHIFT) &
9256*4882a593Smuzhiyun 			PMU_ST_CNT_MODE_MASK) |
9257*4882a593Smuzhiyun 		((pmustatstimer[timerid].enable << PMU_ST_EN_SHIFT) & PMU_ST_EN_MASK) |
9258*4882a593Smuzhiyun 		((pmustatstimer[timerid].int_enable << PMU_ST_INT_EN_SHIFT) & PMU_ST_INT_EN_MASK);
9259*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_ctrl, stats_timer_ctrl);
9260*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_N, 0);
9261*4882a593Smuzhiyun }
9262*4882a593Smuzhiyun 
9263*4882a593Smuzhiyun void
si_pmustatstimer_int_enable(si_t * sih)9264*4882a593Smuzhiyun si_pmustatstimer_int_enable(si_t *sih)
9265*4882a593Smuzhiyun {
9266*4882a593Smuzhiyun 	pmuregs_t *pmu;
9267*4882a593Smuzhiyun 	uint origidx;
9268*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9269*4882a593Smuzhiyun 
9270*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9271*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9272*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9273*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9274*4882a593Smuzhiyun 	} else {
9275*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9276*4882a593Smuzhiyun 	}
9277*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9278*4882a593Smuzhiyun 
9279*4882a593Smuzhiyun 	OR_REG(osh, &pmu->pmuintmask0, PMU_INT_STAT_TIMER_INT_MASK);
9280*4882a593Smuzhiyun 
9281*4882a593Smuzhiyun 	/* Return to original core */
9282*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9283*4882a593Smuzhiyun }
9284*4882a593Smuzhiyun 
9285*4882a593Smuzhiyun void
si_pmustatstimer_int_disable(si_t * sih)9286*4882a593Smuzhiyun si_pmustatstimer_int_disable(si_t *sih)
9287*4882a593Smuzhiyun {
9288*4882a593Smuzhiyun 	pmuregs_t *pmu;
9289*4882a593Smuzhiyun 	uint origidx;
9290*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9291*4882a593Smuzhiyun 
9292*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9293*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9294*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9295*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9296*4882a593Smuzhiyun 	} else {
9297*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9298*4882a593Smuzhiyun 	}
9299*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9300*4882a593Smuzhiyun 
9301*4882a593Smuzhiyun 	AND_REG(osh, &pmu->pmuintmask0, ~PMU_INT_STAT_TIMER_INT_MASK);
9302*4882a593Smuzhiyun 
9303*4882a593Smuzhiyun 	/* Return to original core */
9304*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9305*4882a593Smuzhiyun }
9306*4882a593Smuzhiyun 
9307*4882a593Smuzhiyun void
si_pmustatstimer_init(si_t * sih)9308*4882a593Smuzhiyun si_pmustatstimer_init(si_t *sih)
9309*4882a593Smuzhiyun {
9310*4882a593Smuzhiyun 	pmuregs_t *pmu;
9311*4882a593Smuzhiyun 	uint origidx;
9312*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9313*4882a593Smuzhiyun 	uint32 core_cap_ext;
9314*4882a593Smuzhiyun 	uint8 max_stats_timer_num;
9315*4882a593Smuzhiyun 	int8 i;
9316*4882a593Smuzhiyun 
9317*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9318*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9319*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9320*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9321*4882a593Smuzhiyun 	} else {
9322*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9323*4882a593Smuzhiyun 	}
9324*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9325*4882a593Smuzhiyun 
9326*4882a593Smuzhiyun 	core_cap_ext = R_REG(osh, &pmu->core_cap_ext);
9327*4882a593Smuzhiyun 
9328*4882a593Smuzhiyun 	max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >> PCAP_EXT_ST_NUM_SHIFT) + 1;
9329*4882a593Smuzhiyun 
9330*4882a593Smuzhiyun 	for (i = 0; i < max_stats_timer_num; i++) {
9331*4882a593Smuzhiyun 		si_pmustatstimer_update(osh, pmu, i);
9332*4882a593Smuzhiyun 	}
9333*4882a593Smuzhiyun 
9334*4882a593Smuzhiyun 	OR_REG(osh, &pmu->pmuintmask0, PMU_INT_STAT_TIMER_INT_MASK);
9335*4882a593Smuzhiyun 
9336*4882a593Smuzhiyun 	/* Return to original core */
9337*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9338*4882a593Smuzhiyun }
9339*4882a593Smuzhiyun 
9340*4882a593Smuzhiyun void
si_pmustatstimer_dump(si_t * sih)9341*4882a593Smuzhiyun si_pmustatstimer_dump(si_t *sih)
9342*4882a593Smuzhiyun {
9343*4882a593Smuzhiyun 	pmuregs_t *pmu;
9344*4882a593Smuzhiyun 	uint origidx;
9345*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9346*4882a593Smuzhiyun 	uint32 core_cap_ext, pmucapabilities, AlpPeriod, ILPPeriod, pmuintmask0, pmuintstatus;
9347*4882a593Smuzhiyun 	uint8 max_stats_timer_num, max_stats_timer_src_num;
9348*4882a593Smuzhiyun 	uint32 stat_timer_ctrl, stat_timer_N;
9349*4882a593Smuzhiyun 	uint8 i;
9350*4882a593Smuzhiyun 	uint32 current_time_ms = OSL_SYSUPTIME();
9351*4882a593Smuzhiyun 
9352*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9353*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9354*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9355*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9356*4882a593Smuzhiyun 	} else {
9357*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9358*4882a593Smuzhiyun 	}
9359*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9360*4882a593Smuzhiyun 
9361*4882a593Smuzhiyun 	pmucapabilities = R_REG(osh, &pmu->pmucapabilities);
9362*4882a593Smuzhiyun 	core_cap_ext = R_REG(osh, &pmu->core_cap_ext);
9363*4882a593Smuzhiyun 	AlpPeriod = R_REG(osh, &pmu->slowclkperiod);
9364*4882a593Smuzhiyun 	ILPPeriod = R_REG(osh, &pmu->ILPPeriod);
9365*4882a593Smuzhiyun 
9366*4882a593Smuzhiyun 	max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >>
9367*4882a593Smuzhiyun 		PCAP_EXT_ST_NUM_SHIFT) + 1;
9368*4882a593Smuzhiyun 	max_stats_timer_src_num = ((core_cap_ext & PCAP_EXT_ST_SRC_NUM_MASK) >>
9369*4882a593Smuzhiyun 		PCAP_EXT_ST_SRC_NUM_SHIFT) + 1;
9370*4882a593Smuzhiyun 
9371*4882a593Smuzhiyun 	pmuintstatus = R_REG(osh, &pmu->pmuintstatus);
9372*4882a593Smuzhiyun 	pmuintmask0 = R_REG(osh, &pmu->pmuintmask0);
9373*4882a593Smuzhiyun 
9374*4882a593Smuzhiyun 	PMU_ERROR(("si_pmustatstimer_dump : TIME %d\n", current_time_ms));
9375*4882a593Smuzhiyun 
9376*4882a593Smuzhiyun 	PMU_ERROR(("\tMAX Timer Num %d, MAX Source Num %d\n",
9377*4882a593Smuzhiyun 		max_stats_timer_num, max_stats_timer_src_num));
9378*4882a593Smuzhiyun 	PMU_ERROR(("\tpmucapabilities 0x%8x, core_cap_ext 0x%8x, AlpPeriod 0x%8x, ILPPeriod 0x%8x, "
9379*4882a593Smuzhiyun 		"pmuintmask0 0x%8x, pmuintstatus 0x%8x, pmurev %d\n",
9380*4882a593Smuzhiyun 		pmucapabilities, core_cap_ext, AlpPeriod, ILPPeriod,
9381*4882a593Smuzhiyun 		pmuintmask0, pmuintstatus, PMUREV(sih->pmurev)));
9382*4882a593Smuzhiyun 
9383*4882a593Smuzhiyun 	for (i = 0; i < max_stats_timer_num; i++) {
9384*4882a593Smuzhiyun 		W_REG(osh, &pmu->pmu_statstimer_addr, i);
9385*4882a593Smuzhiyun 		stat_timer_ctrl = R_REG(osh, &pmu->pmu_statstimer_ctrl);
9386*4882a593Smuzhiyun 		stat_timer_N = R_REG(osh, &pmu->pmu_statstimer_N);
9387*4882a593Smuzhiyun 		PMU_ERROR(("\t Timer %d : control 0x%8x, %d\n",
9388*4882a593Smuzhiyun 			i, stat_timer_ctrl, stat_timer_N));
9389*4882a593Smuzhiyun 	}
9390*4882a593Smuzhiyun 
9391*4882a593Smuzhiyun 	/* Return to original core */
9392*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9393*4882a593Smuzhiyun }
9394*4882a593Smuzhiyun 
9395*4882a593Smuzhiyun void
si_pmustatstimer_start(si_t * sih,uint8 timerid)9396*4882a593Smuzhiyun si_pmustatstimer_start(si_t *sih, uint8 timerid)
9397*4882a593Smuzhiyun {
9398*4882a593Smuzhiyun 	pmuregs_t *pmu;
9399*4882a593Smuzhiyun 	uint origidx;
9400*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9401*4882a593Smuzhiyun 
9402*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9403*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9404*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9405*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9406*4882a593Smuzhiyun 	} else {
9407*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9408*4882a593Smuzhiyun 	}
9409*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9410*4882a593Smuzhiyun 
9411*4882a593Smuzhiyun 	pmustatstimer[timerid].enable = TRUE;
9412*4882a593Smuzhiyun 
9413*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
9414*4882a593Smuzhiyun 	OR_REG(osh, &pmu->pmu_statstimer_ctrl, PMU_ST_ENAB << PMU_ST_EN_SHIFT);
9415*4882a593Smuzhiyun 
9416*4882a593Smuzhiyun 	/* Return to original core */
9417*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9418*4882a593Smuzhiyun }
9419*4882a593Smuzhiyun 
9420*4882a593Smuzhiyun void
si_pmustatstimer_stop(si_t * sih,uint8 timerid)9421*4882a593Smuzhiyun si_pmustatstimer_stop(si_t *sih, uint8 timerid)
9422*4882a593Smuzhiyun {
9423*4882a593Smuzhiyun 	pmuregs_t *pmu;
9424*4882a593Smuzhiyun 	uint origidx;
9425*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9426*4882a593Smuzhiyun 
9427*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9428*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9429*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9430*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9431*4882a593Smuzhiyun 	} else {
9432*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9433*4882a593Smuzhiyun 	}
9434*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9435*4882a593Smuzhiyun 
9436*4882a593Smuzhiyun 	pmustatstimer[timerid].enable = FALSE;
9437*4882a593Smuzhiyun 
9438*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
9439*4882a593Smuzhiyun 	AND_REG(osh, &pmu->pmu_statstimer_ctrl, ~(PMU_ST_ENAB << PMU_ST_EN_SHIFT));
9440*4882a593Smuzhiyun 
9441*4882a593Smuzhiyun 	/* Return to original core */
9442*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9443*4882a593Smuzhiyun }
9444*4882a593Smuzhiyun 
9445*4882a593Smuzhiyun void
si_pmustatstimer_clear(si_t * sih,uint8 timerid)9446*4882a593Smuzhiyun si_pmustatstimer_clear(si_t *sih, uint8 timerid)
9447*4882a593Smuzhiyun {
9448*4882a593Smuzhiyun 	pmuregs_t *pmu;
9449*4882a593Smuzhiyun 	uint origidx;
9450*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9451*4882a593Smuzhiyun 
9452*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9453*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9454*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9455*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9456*4882a593Smuzhiyun 	} else {
9457*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9458*4882a593Smuzhiyun 	}
9459*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9460*4882a593Smuzhiyun 
9461*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
9462*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_N, 0);
9463*4882a593Smuzhiyun 
9464*4882a593Smuzhiyun 	/* Return to original core */
9465*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9466*4882a593Smuzhiyun }
9467*4882a593Smuzhiyun 
9468*4882a593Smuzhiyun void
si_pmustatstimer_clear_overflow(si_t * sih)9469*4882a593Smuzhiyun si_pmustatstimer_clear_overflow(si_t *sih)
9470*4882a593Smuzhiyun {
9471*4882a593Smuzhiyun 	uint8 i;
9472*4882a593Smuzhiyun 	uint32 core_cap_ext;
9473*4882a593Smuzhiyun 	uint8 max_stats_timer_num;
9474*4882a593Smuzhiyun 	uint32 timerN;
9475*4882a593Smuzhiyun 	pmuregs_t *pmu;
9476*4882a593Smuzhiyun 	uint origidx;
9477*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9478*4882a593Smuzhiyun 
9479*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9480*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9481*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9482*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9483*4882a593Smuzhiyun 	} else {
9484*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9485*4882a593Smuzhiyun 	}
9486*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9487*4882a593Smuzhiyun 
9488*4882a593Smuzhiyun 	core_cap_ext = R_REG(osh, &pmu->core_cap_ext);
9489*4882a593Smuzhiyun 	max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >> PCAP_EXT_ST_NUM_SHIFT) + 1;
9490*4882a593Smuzhiyun 
9491*4882a593Smuzhiyun 	for (i = 0; i < max_stats_timer_num; i++) {
9492*4882a593Smuzhiyun 		W_REG(osh, &pmu->pmu_statstimer_addr, i);
9493*4882a593Smuzhiyun 		timerN = R_REG(osh, &pmu->pmu_statstimer_N);
9494*4882a593Smuzhiyun 		if (timerN == 0xFFFFFFFF) {
9495*4882a593Smuzhiyun 			PMU_ERROR(("pmustatstimer overflow clear - timerid : %d\n", i));
9496*4882a593Smuzhiyun 			si_pmustatstimer_clear(sih, i);
9497*4882a593Smuzhiyun 		}
9498*4882a593Smuzhiyun 	}
9499*4882a593Smuzhiyun 
9500*4882a593Smuzhiyun 	/* Return to original core */
9501*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9502*4882a593Smuzhiyun }
9503*4882a593Smuzhiyun 
9504*4882a593Smuzhiyun uint32
si_pmustatstimer_read(si_t * sih,uint8 timerid)9505*4882a593Smuzhiyun si_pmustatstimer_read(si_t *sih, uint8 timerid)
9506*4882a593Smuzhiyun {
9507*4882a593Smuzhiyun 	pmuregs_t *pmu;
9508*4882a593Smuzhiyun 	uint origidx;
9509*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9510*4882a593Smuzhiyun 	uint32 stats_timer_N;
9511*4882a593Smuzhiyun 
9512*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9513*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9514*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9515*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9516*4882a593Smuzhiyun 	} else {
9517*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9518*4882a593Smuzhiyun 	}
9519*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9520*4882a593Smuzhiyun 
9521*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
9522*4882a593Smuzhiyun 	stats_timer_N = R_REG(osh, &pmu->pmu_statstimer_N);
9523*4882a593Smuzhiyun 
9524*4882a593Smuzhiyun 	/* Return to original core */
9525*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9526*4882a593Smuzhiyun 
9527*4882a593Smuzhiyun 	return stats_timer_N;
9528*4882a593Smuzhiyun }
9529*4882a593Smuzhiyun 
9530*4882a593Smuzhiyun void
si_pmustatstimer_cfg_src_num(si_t * sih,uint8 src_num,uint8 timerid)9531*4882a593Smuzhiyun si_pmustatstimer_cfg_src_num(si_t *sih, uint8 src_num, uint8 timerid)
9532*4882a593Smuzhiyun {
9533*4882a593Smuzhiyun 	pmuregs_t *pmu;
9534*4882a593Smuzhiyun 	uint origidx;
9535*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9536*4882a593Smuzhiyun 
9537*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9538*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9539*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9540*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9541*4882a593Smuzhiyun 	} else {
9542*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9543*4882a593Smuzhiyun 	}
9544*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9545*4882a593Smuzhiyun 
9546*4882a593Smuzhiyun 	pmustatstimer[timerid].src_num = src_num;
9547*4882a593Smuzhiyun 	si_pmustatstimer_update(osh, pmu, timerid);
9548*4882a593Smuzhiyun 
9549*4882a593Smuzhiyun 	/* Return to original core */
9550*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9551*4882a593Smuzhiyun }
9552*4882a593Smuzhiyun 
9553*4882a593Smuzhiyun void
si_pmustatstimer_cfg_cnt_mode(si_t * sih,uint8 cnt_mode,uint8 timerid)9554*4882a593Smuzhiyun si_pmustatstimer_cfg_cnt_mode(si_t *sih, uint8 cnt_mode, uint8 timerid)
9555*4882a593Smuzhiyun {
9556*4882a593Smuzhiyun 	pmuregs_t *pmu;
9557*4882a593Smuzhiyun 	uint origidx;
9558*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9559*4882a593Smuzhiyun 
9560*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9561*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9562*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9563*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9564*4882a593Smuzhiyun 	} else {
9565*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9566*4882a593Smuzhiyun 	}
9567*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9568*4882a593Smuzhiyun 
9569*4882a593Smuzhiyun 	pmustatstimer[timerid].cnt_mode = cnt_mode;
9570*4882a593Smuzhiyun 	si_pmustatstimer_update(osh, pmu, timerid);
9571*4882a593Smuzhiyun 
9572*4882a593Smuzhiyun 	/* Return to original core */
9573*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9574*4882a593Smuzhiyun }
9575*4882a593Smuzhiyun #endif /* BCMPMU_STATS */
9576*4882a593Smuzhiyun 
9577*4882a593Smuzhiyun #ifdef DONGLEBUILD
9578*4882a593Smuzhiyun /* Note this could be called from trap context !!
9579*4882a593Smuzhiyun  * So observe caution. Do NOT ASSERT() in this function
9580*4882a593Smuzhiyun  * len parameter is dual purpose - On input it is length of the
9581*4882a593Smuzhiyun  * buffer provided. On output it is the amount of data written in
9582*4882a593Smuzhiyun  * bytes.
9583*4882a593Smuzhiyun  */
9584*4882a593Smuzhiyun /* This includes address data pair
9585*4882a593Smuzhiyun  * Note presence of arg2. arg2 could further define what subset of information
9586*4882a593Smuzhiyun  * needs to be dumped. Some external entities such as SMD could optionally pass
9587*4882a593Smuzhiyun  * arg2 to define subset of information needed
9588*4882a593Smuzhiyun  */
9589*4882a593Smuzhiyun int
BCMPOSTTRAPFN(si_pmu_regs_in_rodata_dump)9590*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_regs_in_rodata_dump)(void *sih, void *arg2,
9591*4882a593Smuzhiyun 	uint32 *bufptr, uint16 *len)
9592*4882a593Smuzhiyun {
9593*4882a593Smuzhiyun 	int rc = BCME_OK;
9594*4882a593Smuzhiyun 	uint16 totalsize = SI_PMU_REG_DUMP_BASE_SIZE;
9595*4882a593Smuzhiyun 
9596*4882a593Smuzhiyun 	if ((bufptr == NULL) || (len == NULL)) {
9597*4882a593Smuzhiyun 		rc = BCME_NOMEM;
9598*4882a593Smuzhiyun 		goto fail;
9599*4882a593Smuzhiyun 	}
9600*4882a593Smuzhiyun 
9601*4882a593Smuzhiyun 	/* Are PMU registers available in rodata? If not, bail out
9602*4882a593Smuzhiyun 	 * Avoid re-read. If data is not there, then there could have been
9603*4882a593Smuzhiyun 	 * an error in reading these regs.
9604*4882a593Smuzhiyun 	 */
9605*4882a593Smuzhiyun 	if (rodata_pmuregdump_ptr == NULL) {
9606*4882a593Smuzhiyun 		rc = BCME_ERROR;
9607*4882a593Smuzhiyun 		goto fail;
9608*4882a593Smuzhiyun 	}
9609*4882a593Smuzhiyun 
9610*4882a593Smuzhiyun 	if (si_pmu_get_mac_rsrc_req_tmr_cnt(sih) > 1) {
9611*4882a593Smuzhiyun 		totalsize += SI_PMU_REG_DUMP_MACRSRC1_SIZE;
9612*4882a593Smuzhiyun 	}
9613*4882a593Smuzhiyun 	if (si_pmu_get_mac_rsrc_req_tmr_cnt(sih) > 2) {
9614*4882a593Smuzhiyun 		totalsize += SI_PMU_REG_DUMP_MACRSRC2_SIZE;
9615*4882a593Smuzhiyun 	}
9616*4882a593Smuzhiyun 	if (si_pmu_get_pmu_interrupt_rcv_cnt(sih) > 1) {
9617*4882a593Smuzhiyun 		totalsize += SI_PMU_REG_DUMP_INTRCV1_SIZE;
9618*4882a593Smuzhiyun 	}
9619*4882a593Smuzhiyun 
9620*4882a593Smuzhiyun 	/* Make sure there is enough space for address value pair */
9621*4882a593Smuzhiyun 	if (len && *len < totalsize) {
9622*4882a593Smuzhiyun 		rc = BCME_BUFTOOSHORT;
9623*4882a593Smuzhiyun 		goto fail;
9624*4882a593Smuzhiyun 	}
9625*4882a593Smuzhiyun 
9626*4882a593Smuzhiyun 	/* Write registers to supplied buffer */
9627*4882a593Smuzhiyun 	/* Note that rodata_pmuregdump_size needs to be
9628*4882a593Smuzhiyun 	 * a multiple of a word size
9629*4882a593Smuzhiyun 	 */
9630*4882a593Smuzhiyun 	memcpy((uint8*)bufptr, rodata_pmuregdump_ptr, totalsize);
9631*4882a593Smuzhiyun 
9632*4882a593Smuzhiyun 	*len = totalsize;
9633*4882a593Smuzhiyun fail:
9634*4882a593Smuzhiyun 	return rc;
9635*4882a593Smuzhiyun 
9636*4882a593Smuzhiyun }
9637*4882a593Smuzhiyun #endif /* DONGLEBUILD */
9638*4882a593Smuzhiyun 
9639*4882a593Smuzhiyun /* query the # of mac resource request timers */
9640*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_pmu_get_mac_rsrc_req_tmr_cnt)9641*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_get_mac_rsrc_req_tmr_cnt)(si_t *sih)
9642*4882a593Smuzhiyun {
9643*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 26) {
9644*4882a593Smuzhiyun 		uint32 core_cap_ext = PMU_REG(sih, core_cap_ext, 0, 0);
9645*4882a593Smuzhiyun 		uint mac_rsrc_cnt =
9646*4882a593Smuzhiyun 		        ((core_cap_ext & PCAP_EXT_MAC_RSRC_REQ_TMR_CNT_MASK) >>
9647*4882a593Smuzhiyun 		         PCAP_EXT_MAC_RSRC_REQ_TMR_CNT_SHIFT) + 1;
9648*4882a593Smuzhiyun 		return mac_rsrc_cnt;
9649*4882a593Smuzhiyun 	}
9650*4882a593Smuzhiyun 
9651*4882a593Smuzhiyun 	return si_numd11coreunits(sih);
9652*4882a593Smuzhiyun }
9653*4882a593Smuzhiyun 
9654*4882a593Smuzhiyun /* query the # of pmu interrupt recevier */
9655*4882a593Smuzhiyun uint
BCMPOSTTRAPFN(si_pmu_get_pmu_interrupt_rcv_cnt)9656*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_get_pmu_interrupt_rcv_cnt)(si_t *sih)
9657*4882a593Smuzhiyun {
9658*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) >= 26) {
9659*4882a593Smuzhiyun 		uint32 core_cap_ext = PMU_REG(sih, core_cap_ext, 0, 0);
9660*4882a593Smuzhiyun 		uint pmu_intr_rcvr_cnt =
9661*4882a593Smuzhiyun 		        ((core_cap_ext & PCAP_EXT_PMU_INTR_RCVR_CNT_MASK) >>
9662*4882a593Smuzhiyun 		         PCAP_EXT_PMU_INTR_RCVR_CNT_SHIFT) + 1;
9663*4882a593Smuzhiyun 		return pmu_intr_rcvr_cnt;
9664*4882a593Smuzhiyun 	}
9665*4882a593Smuzhiyun 
9666*4882a593Smuzhiyun 	return si_numd11coreunits(sih);
9667*4882a593Smuzhiyun }
9668*4882a593Smuzhiyun 
9669*4882a593Smuzhiyun #ifdef DONGLEBUILD
9670*4882a593Smuzhiyun int
si_pmu_mem_pwr_off(si_t * sih,int core_idx)9671*4882a593Smuzhiyun si_pmu_mem_pwr_off(si_t *sih, int core_idx)
9672*4882a593Smuzhiyun {
9673*4882a593Smuzhiyun 	int ret = BCME_OK;
9674*4882a593Smuzhiyun 
9675*4882a593Smuzhiyun 	if (si_setcore(sih, D11_CORE_ID, core_idx) == NULL) {
9676*4882a593Smuzhiyun 		/* core_idx doesn't exsist */
9677*4882a593Smuzhiyun 		return BCME_BADOPTION;
9678*4882a593Smuzhiyun 	}
9679*4882a593Smuzhiyun 
9680*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
9681*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
9682*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
9683*4882a593Smuzhiyun 		if (core_idx == 0) {
9684*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
9685*4882a593Smuzhiyun 				(PMU_CC4_4387_MAIN_PD_CBUCK2VDDB_ON |
9686*4882a593Smuzhiyun 				PMU_CC4_4387_MAIN_PD_CBUCK2VDDRET_ON |
9687*4882a593Smuzhiyun 				PMU_CC4_4387_MAIN_PD_MEMLPLDO2VDDB_ON |
9688*4882a593Smuzhiyun 				PMU_CC4_4387_MAIN_PD_MEMLPDLO2VDDRET_ON),
9689*4882a593Smuzhiyun 				0);
9690*4882a593Smuzhiyun 
9691*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
9692*4882a593Smuzhiyun 				(PMU_CC13_MAIN_CBUCK2VDDB_OFF |
9693*4882a593Smuzhiyun 				PMU_CC13_MAIN_CBUCK2VDDRET_OFF |
9694*4882a593Smuzhiyun 				PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF |
9695*4882a593Smuzhiyun 				PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF),
9696*4882a593Smuzhiyun 				(PMU_CC13_MAIN_CBUCK2VDDB_OFF |
9697*4882a593Smuzhiyun 				PMU_CC13_MAIN_CBUCK2VDDRET_OFF |
9698*4882a593Smuzhiyun 				PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF |
9699*4882a593Smuzhiyun 				PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF));
9700*4882a593Smuzhiyun 
9701*4882a593Smuzhiyun 			/* LQ settings */
9702*4882a593Smuzhiyun 			si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_25,
9703*4882a593Smuzhiyun 				0xFFFFFFFF, XTAL_LQ_SETTING_4387);
9704*4882a593Smuzhiyun 		} else if (core_idx == 1) {
9705*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL4,
9706*4882a593Smuzhiyun 				(PMU_CC4_4387_AUX_PD_CBUCK2VDDB_ON |
9707*4882a593Smuzhiyun 				PMU_CC4_4387_AUX_PD_CBUCK2VDDRET_ON |
9708*4882a593Smuzhiyun 				PMU_CC4_4387_AUX_PD_MEMLPLDO2VDDB_ON |
9709*4882a593Smuzhiyun 				PMU_CC4_4387_AUX_PD_MEMLPLDO2VDDRET_ON),
9710*4882a593Smuzhiyun 				0);
9711*4882a593Smuzhiyun 
9712*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
9713*4882a593Smuzhiyun 				(PMU_CC13_AUX_CBUCK2VDDB_OFF |
9714*4882a593Smuzhiyun 				PMU_CC13_AUX_CBUCK2VDDRET_OFF |
9715*4882a593Smuzhiyun 				PMU_CC13_AUX_MEMLPLDO2VDDB_OFF |
9716*4882a593Smuzhiyun 				PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF),
9717*4882a593Smuzhiyun 				(PMU_CC13_AUX_CBUCK2VDDB_OFF |
9718*4882a593Smuzhiyun 				PMU_CC13_AUX_CBUCK2VDDRET_OFF |
9719*4882a593Smuzhiyun 				PMU_CC13_AUX_MEMLPLDO2VDDB_OFF |
9720*4882a593Smuzhiyun 				PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF));
9721*4882a593Smuzhiyun 		} else if (core_idx == 2) {
9722*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL17,
9723*4882a593Smuzhiyun 				(PMU_CC17_SCAN_CBUCK2VDDB_ON |
9724*4882a593Smuzhiyun 				PMU_CC17_SCAN_MEMLPLDO2VDDB_ON |
9725*4882a593Smuzhiyun 				PMU_CC17_SCAN_MEMLPLDO2VDDRET_ON),
9726*4882a593Smuzhiyun 				0);
9727*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL17,
9728*4882a593Smuzhiyun 				(PMU_CC17_SCAN_CBUCK2VDDB_OFF |
9729*4882a593Smuzhiyun 				PMU_CC17_SCAN_MEMLPLDO2VDDB_OFF |
9730*4882a593Smuzhiyun 				PMU_CC17_SCAN_MEMLPLDO2VDDRET_OFF),
9731*4882a593Smuzhiyun 				(PMU_CC17_SCAN_CBUCK2VDDB_OFF |
9732*4882a593Smuzhiyun 				PMU_CC17_SCAN_MEMLPLDO2VDDB_OFF |
9733*4882a593Smuzhiyun 				PMU_CC17_SCAN_MEMLPLDO2VDDRET_OFF));
9734*4882a593Smuzhiyun 		}
9735*4882a593Smuzhiyun 		break;
9736*4882a593Smuzhiyun 
9737*4882a593Smuzhiyun 	default:
9738*4882a593Smuzhiyun 		ret = BCME_UNSUPPORTED;
9739*4882a593Smuzhiyun 		break;
9740*4882a593Smuzhiyun 	}
9741*4882a593Smuzhiyun 
9742*4882a593Smuzhiyun 	return ret;
9743*4882a593Smuzhiyun }
9744*4882a593Smuzhiyun 
9745*4882a593Smuzhiyun int
BCMPOSTTRAPFN(si_pmu_mem_pwr_on)9746*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_mem_pwr_on)(si_t *sih)
9747*4882a593Smuzhiyun {
9748*4882a593Smuzhiyun 	int ret = BCME_OK;
9749*4882a593Smuzhiyun 
9750*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
9751*4882a593Smuzhiyun 	case BCM4385_CHIP_GRPID:
9752*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
9753*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
9754*4882a593Smuzhiyun 			(PMU_CC13_MAIN_CBUCK2VDDB_OFF |
9755*4882a593Smuzhiyun 			PMU_CC13_MAIN_CBUCK2VDDRET_OFF |
9756*4882a593Smuzhiyun 			PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF |
9757*4882a593Smuzhiyun 			PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF),
9758*4882a593Smuzhiyun 			PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF);
9759*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL13,
9760*4882a593Smuzhiyun 			(PMU_CC13_AUX_CBUCK2VDDB_OFF |
9761*4882a593Smuzhiyun 			PMU_CC13_AUX_CBUCK2VDDRET_OFF |
9762*4882a593Smuzhiyun 			PMU_CC13_AUX_MEMLPLDO2VDDB_OFF |
9763*4882a593Smuzhiyun 			PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF),
9764*4882a593Smuzhiyun 			PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF);
9765*4882a593Smuzhiyun 		si_pmu_chipcontrol(sih, PMU_CHIPCTL17,
9766*4882a593Smuzhiyun 			(PMU_CC17_SCAN_CBUCK2VDDB_OFF |
9767*4882a593Smuzhiyun 			PMU_CC17_SCAN_MEMLPLDO2VDDB_OFF |
9768*4882a593Smuzhiyun 			PMU_CC17_SCAN_MEMLPLDO2VDDRET_OFF),
9769*4882a593Smuzhiyun 			PMU_CC17_SCAN_MEMLPLDO2VDDRET_OFF);
9770*4882a593Smuzhiyun 
9771*4882a593Smuzhiyun 		/* HQ settings */
9772*4882a593Smuzhiyun 		si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_25,
9773*4882a593Smuzhiyun 			0xFFFFFFFF, XTAL_HQ_SETTING_4387);
9774*4882a593Smuzhiyun 	break;
9775*4882a593Smuzhiyun 
9776*4882a593Smuzhiyun 	default:
9777*4882a593Smuzhiyun 		ret = BCME_UNSUPPORTED;
9778*4882a593Smuzhiyun 		break;
9779*4882a593Smuzhiyun 	}
9780*4882a593Smuzhiyun 
9781*4882a593Smuzhiyun 	return ret;
9782*4882a593Smuzhiyun }
9783*4882a593Smuzhiyun 
9784*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_pmu_disable_intr_pwrreq)9785*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_disable_intr_pwrreq)(si_t *sih)
9786*4882a593Smuzhiyun {
9787*4882a593Smuzhiyun 	if (MULTIBP_CAP(sih)) {
9788*4882a593Smuzhiyun 		switch (CHIPID(sih->chip)) {
9789*4882a593Smuzhiyun 		case BCM4376_CHIP_GRPID:
9790*4882a593Smuzhiyun 		case BCM4378_CHIP_GRPID:
9791*4882a593Smuzhiyun 		case BCM4385_CHIP_GRPID:
9792*4882a593Smuzhiyun 		case BCM4387_CHIP_GRPID:
9793*4882a593Smuzhiyun 		case BCM4388_CHIP_GRPID:
9794*4882a593Smuzhiyun 		case BCM4389_CHIP_GRPID:
9795*4882a593Smuzhiyun 		case BCM4397_CHIP_GRPID:
9796*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL2, PMU_CC2_CB2WL_INTR_PWRREQ_EN, 0);
9797*4882a593Smuzhiyun 			si_pmu_chipcontrol(sih, PMU_CHIPCTL6, PMU_CC6_ENABLE_DMN1_WAKEUP, 0);
9798*4882a593Smuzhiyun 			break;
9799*4882a593Smuzhiyun 		default:
9800*4882a593Smuzhiyun 			PMU_ERROR(("si_pmu_disable_intr_pwrreq: add support for this chip!\n"));
9801*4882a593Smuzhiyun 			OSL_SYS_HALT();
9802*4882a593Smuzhiyun 			break;
9803*4882a593Smuzhiyun 		}
9804*4882a593Smuzhiyun 	}
9805*4882a593Smuzhiyun }
9806*4882a593Smuzhiyun 
9807*4882a593Smuzhiyun void
BCMPOSTTRAPFN(si_pmu_clear_intmask)9808*4882a593Smuzhiyun BCMPOSTTRAPFN(si_pmu_clear_intmask)(si_t *sih)
9809*4882a593Smuzhiyun {
9810*4882a593Smuzhiyun 	pmuregs_t *pmu;
9811*4882a593Smuzhiyun 	uint origidx;
9812*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9813*4882a593Smuzhiyun 	uint pmu_intr_recvr_cnt;
9814*4882a593Smuzhiyun 
9815*4882a593Smuzhiyun 	/* Remember original core before switch to chipc/pmu */
9816*4882a593Smuzhiyun 	origidx = si_coreidx(sih);
9817*4882a593Smuzhiyun 	if (AOB_ENAB(sih)) {
9818*4882a593Smuzhiyun 		pmu = si_setcore(sih, PMU_CORE_ID, 0);
9819*4882a593Smuzhiyun 	} else {
9820*4882a593Smuzhiyun 		pmu = si_setcoreidx(sih, SI_CC_IDX);
9821*4882a593Smuzhiyun 	}
9822*4882a593Smuzhiyun 
9823*4882a593Smuzhiyun 	ASSERT(pmu != NULL);
9824*4882a593Smuzhiyun 	W_REG(osh, &pmu->pmuintmask0, 0);
9825*4882a593Smuzhiyun 
9826*4882a593Smuzhiyun 	pmu_intr_recvr_cnt = ((R_REG(osh, &pmu->core_cap_ext) & PCAP_EXT_PMU_INTR_RCVR_CNT_MASK)
9827*4882a593Smuzhiyun 			>> PCAP_EXT_PMU_INTR_RCVR_CNT_SHIFT) + 1;
9828*4882a593Smuzhiyun 
9829*4882a593Smuzhiyun 	if (pmu_intr_recvr_cnt > 1) {
9830*4882a593Smuzhiyun 		W_REG(osh, &pmu->pmuintmask1, 0);
9831*4882a593Smuzhiyun 	}
9832*4882a593Smuzhiyun 
9833*4882a593Smuzhiyun 	/* Return to original core */
9834*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9835*4882a593Smuzhiyun }
9836*4882a593Smuzhiyun #endif /* DONGLEBUILD */
9837*4882a593Smuzhiyun 
9838*4882a593Smuzhiyun int
si_pmu_res_state_pwrsw_main_wait(si_t * sih)9839*4882a593Smuzhiyun si_pmu_res_state_pwrsw_main_wait(si_t *sih)
9840*4882a593Smuzhiyun {
9841*4882a593Smuzhiyun 	int ret = BCME_OK;
9842*4882a593Smuzhiyun 
9843*4882a593Smuzhiyun 	switch (CHIPID(sih->chip)) {
9844*4882a593Smuzhiyun 	case BCM4387_CHIP_GRPID:
9845*4882a593Smuzhiyun 		if (PMU_REG(sih, res_state, 0, 0) & PMURES_BIT(RES4387_PWRSW_MAIN)) {
9846*4882a593Smuzhiyun 			SPINWAIT((PMU_REG(sih, res_state, 0, 0) &
9847*4882a593Smuzhiyun 				PMURES_BIT(RES4387_PWRSW_MAIN)), 10000);
9848*4882a593Smuzhiyun 			OSL_DELAY(1000);
9849*4882a593Smuzhiyun 		}
9850*4882a593Smuzhiyun 		ret = (PMU_REG(sih, res_state, 0, 0) & PMURES_BIT(RES4387_PWRSW_MAIN)) ?
9851*4882a593Smuzhiyun 			BCME_ERROR : BCME_OK;
9852*4882a593Smuzhiyun 		break;
9853*4882a593Smuzhiyun 	default:
9854*4882a593Smuzhiyun 		PMU_ERROR(("si_pmu_res_state_pwrsw_main_wait: add support for this chip!\n"));
9855*4882a593Smuzhiyun 		OSL_SYS_HALT();
9856*4882a593Smuzhiyun 		break;
9857*4882a593Smuzhiyun 	}
9858*4882a593Smuzhiyun 
9859*4882a593Smuzhiyun 	return ret;
9860*4882a593Smuzhiyun }
9861*4882a593Smuzhiyun 
9862*4882a593Smuzhiyun int
si_pmu_lvm_csr_update(si_t * sih,bool lvm)9863*4882a593Smuzhiyun si_pmu_lvm_csr_update(si_t *sih, bool lvm)
9864*4882a593Smuzhiyun {
9865*4882a593Smuzhiyun 
9866*4882a593Smuzhiyun #ifdef BCMDVFS
9867*4882a593Smuzhiyun 	if (BCMDVFS_ENAB() && si_dvfs_enable_status(sih)) {
9868*4882a593Smuzhiyun 		uint32 ndv_volt = lvm ? DVFS_VOLTAGE_NDV : DVFS_VOLTAGE_NDV_NON_LVM;
9869*4882a593Smuzhiyun 		si_dvfs_set_ndv_voltage(sih, ndv_volt);
9870*4882a593Smuzhiyun 	} else
9871*4882a593Smuzhiyun #endif /* BCMDVFS */
9872*4882a593Smuzhiyun 	{
9873*4882a593Smuzhiyun 		uint32 cbuck_volt = lvm ? CBUCK_VOLT_SW_DEFAULT_4387 : CBUCK_VOLT_NON_LVM;
9874*4882a593Smuzhiyun 		si_pmu_vreg_control(sih, PMU_VREG_0,
9875*4882a593Smuzhiyun 			VREG0_4378_CSR_VOLT_ADJ_PWM_MASK,
9876*4882a593Smuzhiyun 			cbuck_volt << VREG0_4378_CSR_VOLT_ADJ_PWM_SHIFT);
9877*4882a593Smuzhiyun 	}
9878*4882a593Smuzhiyun 	return BCME_OK;
9879*4882a593Smuzhiyun }
9880*4882a593Smuzhiyun 
9881*4882a593Smuzhiyun #if defined(BT_WLAN_REG_ON_WAR)
9882*4882a593Smuzhiyun void
si_pmu_reg_on_war_ext_wake_perst_set(si_t * sih)9883*4882a593Smuzhiyun si_pmu_reg_on_war_ext_wake_perst_set(si_t *sih)
9884*4882a593Smuzhiyun {
9885*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
9886*4882a593Smuzhiyun 	pmuregs_t *pmu = si_setcore(sih, PMU_CORE_ID, 0);
9887*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9888*4882a593Smuzhiyun 
9889*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) == 40) {
9890*4882a593Smuzhiyun 		/*
9891*4882a593Smuzhiyun 		 * set PCIEPerstReq (bit-5) as a wake-up source in
9892*4882a593Smuzhiyun 		 * ExtWakeMask0 (0x760) register
9893*4882a593Smuzhiyun 		 */
9894*4882a593Smuzhiyun 		W_REG(osh, &pmu->extwakemask0, PMU_EXT_WAKE_MASK_0_PCIE_PERST);
9895*4882a593Smuzhiyun 
9896*4882a593Smuzhiyun 		/*
9897*4882a593Smuzhiyun 		 * configure the wakemask as "common backplane" resources to
9898*4882a593Smuzhiyun 		 * be up during wake-up in ExtWakeReqMask0 (0x770) register
9899*4882a593Smuzhiyun 		 */
9900*4882a593Smuzhiyun 		W_REG(osh, &pmu->extwakereqmask[0], REG_ON_WAR_PMU_EXT_WAKE_REQ_MASK0_VAL);
9901*4882a593Smuzhiyun 	}
9902*4882a593Smuzhiyun 
9903*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9904*4882a593Smuzhiyun }
9905*4882a593Smuzhiyun 
9906*4882a593Smuzhiyun void
si_pmu_reg_on_war_ext_wake_perst_clear(si_t * sih)9907*4882a593Smuzhiyun si_pmu_reg_on_war_ext_wake_perst_clear(si_t *sih)
9908*4882a593Smuzhiyun {
9909*4882a593Smuzhiyun 	uint32 val = 0;
9910*4882a593Smuzhiyun 	uint origidx = si_coreidx(sih);
9911*4882a593Smuzhiyun 	pmuregs_t *pmu = si_setcore(sih, PMU_CORE_ID, 0);
9912*4882a593Smuzhiyun 	osl_t *osh = si_osh(sih);
9913*4882a593Smuzhiyun 
9914*4882a593Smuzhiyun 	if (PMUREV(sih->pmurev) == 40) {
9915*4882a593Smuzhiyun 		/* clear all set bits in ExtWakeupStatus (0x744) register */
9916*4882a593Smuzhiyun 		val = R_REG(osh, &pmu->extwakeupstatus);
9917*4882a593Smuzhiyun 		W_REG(osh, &pmu->extwakeupstatus, val);
9918*4882a593Smuzhiyun 	}
9919*4882a593Smuzhiyun 
9920*4882a593Smuzhiyun 	si_setcoreidx(sih, origidx);
9921*4882a593Smuzhiyun }
9922*4882a593Smuzhiyun #endif /* BT_WLAN_REG_ON_WAR */
9923*4882a593Smuzhiyun 
9924*4882a593Smuzhiyun void
si_pmu_res_state_wait(si_t * sih,uint rsrc)9925*4882a593Smuzhiyun si_pmu_res_state_wait(si_t *sih, uint rsrc)
9926*4882a593Smuzhiyun {
9927*4882a593Smuzhiyun 	SPINWAIT(!(PMU_REG(sih, res_state, 0, 0) & PMURES_BIT(rsrc)), PMU_MAX_TRANSITION_DLY);
9928*4882a593Smuzhiyun 	ASSERT(PMU_REG(sih, res_state, 0, 0) & PMURES_BIT(rsrc));
9929*4882a593Smuzhiyun }
9930