staging: brcm80211: removed unneeded call to brcms_b_tx_fifo_suspended
[zen-stable.git] / drivers / staging / brcm80211 / brcmsmac / pmu.c
blob3b36e3acfd74cb77672af14596dcb8c4c2edc7fa
1 /*
2 * Copyright (c) 2011 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/delay.h>
18 #include <linux/io.h>
20 #include <brcm_hw_ids.h>
21 #include <chipcommon.h>
22 #include <brcmu_utils.h>
23 #include "pub.h"
24 #include "aiutils.h"
25 #include "pmu.h"
28 * external LPO crystal frequency
30 #define EXT_ILP_HZ 32768
33 * Duration for ILP clock frequency measurment in milliseconds
35 * remark: 1000 must be an integer multiple of this duration
37 #define ILP_CALC_DUR 10
39 /* Fields in pmucontrol */
40 #define PCTL_ILP_DIV_MASK 0xffff0000
41 #define PCTL_ILP_DIV_SHIFT 16
42 #define PCTL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */
43 #define PCTL_NOILP_ON_WAIT 0x00000200 /* rev 1 */
44 #define PCTL_HT_REQ_EN 0x00000100
45 #define PCTL_ALP_REQ_EN 0x00000080
46 #define PCTL_XTALFREQ_MASK 0x0000007c
47 #define PCTL_XTALFREQ_SHIFT 2
48 #define PCTL_ILP_DIV_EN 0x00000002
49 #define PCTL_LPO_SEL 0x00000001
51 /* ILP clock */
52 #define ILP_CLOCK 32000
54 /* ALP clock on pre-PMU chips */
55 #define ALP_CLOCK 20000000
57 /* pmustatus */
58 #define PST_EXTLPOAVAIL 0x0100
59 #define PST_WDRESET 0x0080
60 #define PST_INTPEND 0x0040
61 #define PST_SBCLKST 0x0030
62 #define PST_SBCLKST_ILP 0x0010
63 #define PST_SBCLKST_ALP 0x0020
64 #define PST_SBCLKST_HT 0x0030
65 #define PST_ALPAVAIL 0x0008
66 #define PST_HTAVAIL 0x0004
67 #define PST_RESINIT 0x0003
69 /* PMU resource bit position */
70 #define PMURES_BIT(bit) (1 << (bit))
72 /* PMU corerev and chip specific PLL controls.
73 * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary
74 * number to differentiate different PLLs controlled by the same PMU rev.
76 /* pllcontrol registers:
77 * ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>,
78 * p1div, p2div, _bypass_sdmod
80 #define PMU1_PLL0_PLLCTL0 0
81 #define PMU1_PLL0_PLLCTL1 1
82 #define PMU1_PLL0_PLLCTL2 2
83 #define PMU1_PLL0_PLLCTL3 3
84 #define PMU1_PLL0_PLLCTL4 4
85 #define PMU1_PLL0_PLLCTL5 5
87 /* pmu XtalFreqRatio */
88 #define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF
89 #define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000
90 #define PMU_XTALFREQ_REG_MEASURE_SHIFT 31
92 /* 4313 resources */
93 #define RES4313_BB_PU_RSRC 0
94 #define RES4313_ILP_REQ_RSRC 1
95 #define RES4313_XTAL_PU_RSRC 2
96 #define RES4313_ALP_AVAIL_RSRC 3
97 #define RES4313_RADIO_PU_RSRC 4
98 #define RES4313_BG_PU_RSRC 5
99 #define RES4313_VREG1P4_PU_RSRC 6
100 #define RES4313_AFE_PWRSW_RSRC 7
101 #define RES4313_RX_PWRSW_RSRC 8
102 #define RES4313_TX_PWRSW_RSRC 9
103 #define RES4313_BB_PWRSW_RSRC 10
104 #define RES4313_SYNTH_PWRSW_RSRC 11
105 #define RES4313_MISC_PWRSW_RSRC 12
106 #define RES4313_BB_PLL_PWRSW_RSRC 13
107 #define RES4313_HT_AVAIL_RSRC 14
108 #define RES4313_MACPHY_CLK_AVAIL_RSRC 15
110 /* Determine min/max rsrc masks. Value 0 leaves hardware at default. */
111 static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax)
113 u32 min_mask = 0, max_mask = 0;
114 uint rsrcs;
116 /* # resources */
117 rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT;
119 /* determine min/max rsrc masks */
120 switch (sih->chip) {
121 case BCM43224_CHIP_ID:
122 case BCM43225_CHIP_ID:
123 /* ??? */
124 break;
126 case BCM4313_CHIP_ID:
127 min_mask = PMURES_BIT(RES4313_BB_PU_RSRC) |
128 PMURES_BIT(RES4313_XTAL_PU_RSRC) |
129 PMURES_BIT(RES4313_ALP_AVAIL_RSRC) |
130 PMURES_BIT(RES4313_BB_PLL_PWRSW_RSRC);
131 max_mask = 0xffff;
132 break;
133 default:
134 break;
137 *pmin = min_mask;
138 *pmax = max_mask;
141 static void
142 si_pmu_spuravoid_pllupdate(struct si_pub *sih, struct chipcregs __iomem *cc,
143 u8 spuravoid)
145 u32 tmp = 0;
147 switch (sih->chip) {
148 case BCM43224_CHIP_ID:
149 case BCM43225_CHIP_ID:
150 if (spuravoid == 1) {
151 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0);
152 W_REG(&cc->pllcontrol_data, 0x11500010);
153 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1);
154 W_REG(&cc->pllcontrol_data, 0x000C0C06);
155 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2);
156 W_REG(&cc->pllcontrol_data, 0x0F600a08);
157 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3);
158 W_REG(&cc->pllcontrol_data, 0x00000000);
159 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4);
160 W_REG(&cc->pllcontrol_data, 0x2001E920);
161 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5);
162 W_REG(&cc->pllcontrol_data, 0x88888815);
163 } else {
164 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0);
165 W_REG(&cc->pllcontrol_data, 0x11100010);
166 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1);
167 W_REG(&cc->pllcontrol_data, 0x000c0c06);
168 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2);
169 W_REG(&cc->pllcontrol_data, 0x03000a08);
170 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3);
171 W_REG(&cc->pllcontrol_data, 0x00000000);
172 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4);
173 W_REG(&cc->pllcontrol_data, 0x200005c0);
174 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5);
175 W_REG(&cc->pllcontrol_data, 0x88888815);
177 tmp = 1 << 10;
178 break;
180 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0);
181 W_REG(&cc->pllcontrol_data, 0x11100008);
182 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1);
183 W_REG(&cc->pllcontrol_data, 0x0c000c06);
184 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2);
185 W_REG(&cc->pllcontrol_data, 0x03000a08);
186 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3);
187 W_REG(&cc->pllcontrol_data, 0x00000000);
188 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4);
189 W_REG(&cc->pllcontrol_data, 0x200005c0);
190 W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5);
191 W_REG(&cc->pllcontrol_data, 0x88888855);
193 tmp = 1 << 10;
194 break;
196 default:
197 /* bail out */
198 return;
201 tmp |= R_REG(&cc->pmucontrol);
202 W_REG(&cc->pmucontrol, tmp);
205 u16 si_pmu_fast_pwrup_delay(struct si_pub *sih)
207 uint delay = PMU_MAX_TRANSITION_DLY;
209 switch (sih->chip) {
210 case BCM43224_CHIP_ID:
211 case BCM43225_CHIP_ID:
212 case BCM4313_CHIP_ID:
213 delay = 3700;
214 break;
215 default:
216 break;
219 return (u16) delay;
222 void si_pmu_sprom_enable(struct si_pub *sih, bool enable)
224 struct chipcregs __iomem *cc;
225 uint origidx;
227 /* Remember original core before switch to chipc */
228 origidx = ai_coreidx(sih);
229 cc = ai_setcoreidx(sih, SI_CC_IDX);
231 /* Return to original core */
232 ai_setcoreidx(sih, origidx);
235 /* Read/write a chipcontrol reg */
236 u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
238 ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol_addr),
239 ~0, reg);
240 return ai_corereg(sih, SI_CC_IDX,
241 offsetof(struct chipcregs, chipcontrol_data), mask,
242 val);
245 /* Read/write a regcontrol reg */
246 u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
248 ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, regcontrol_addr),
249 ~0, reg);
250 return ai_corereg(sih, SI_CC_IDX,
251 offsetof(struct chipcregs, regcontrol_data), mask,
252 val);
255 /* Read/write a pllcontrol reg */
256 u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
258 ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pllcontrol_addr),
259 ~0, reg);
260 return ai_corereg(sih, SI_CC_IDX,
261 offsetof(struct chipcregs, pllcontrol_data), mask,
262 val);
265 /* PMU PLL update */
266 void si_pmu_pllupd(struct si_pub *sih)
268 ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pmucontrol),
269 PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD);
272 /* query alp/xtal clock frequency */
273 u32 si_pmu_alp_clock(struct si_pub *sih)
275 u32 clock = ALP_CLOCK;
277 /* bail out with default */
278 if (!(sih->cccaps & CC_CAP_PMU))
279 return clock;
281 switch (sih->chip) {
282 case BCM43224_CHIP_ID:
283 case BCM43225_CHIP_ID:
284 case BCM4313_CHIP_ID:
285 /* always 20Mhz */
286 clock = 20000 * 1000;
287 break;
288 default:
289 break;
292 return clock;
295 void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid)
297 struct chipcregs __iomem *cc;
298 uint origidx, intr_val;
300 /* Remember original core before switch to chipc */
301 cc = (struct chipcregs __iomem *)
302 ai_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
304 /* update the pll changes */
305 si_pmu_spuravoid_pllupdate(sih, cc, spuravoid);
307 /* Return to original core */
308 ai_restore_core(sih, origidx, intr_val);
311 /* initialize PMU */
312 void si_pmu_init(struct si_pub *sih)
314 struct chipcregs __iomem *cc;
315 uint origidx;
317 /* Remember original core before switch to chipc */
318 origidx = ai_coreidx(sih);
319 cc = ai_setcoreidx(sih, SI_CC_IDX);
321 if (sih->pmurev == 1)
322 AND_REG(&cc->pmucontrol, ~PCTL_NOILP_ON_WAIT);
323 else if (sih->pmurev >= 2)
324 OR_REG(&cc->pmucontrol, PCTL_NOILP_ON_WAIT);
326 /* Return to original core */
327 ai_setcoreidx(sih, origidx);
330 /* initialize PMU chip controls and other chip level stuff */
331 void si_pmu_chip_init(struct si_pub *sih)
333 uint origidx;
335 /* Gate off SPROM clock and chip select signals */
336 si_pmu_sprom_enable(sih, false);
338 /* Remember original core */
339 origidx = ai_coreidx(sih);
341 /* Return to original core */
342 ai_setcoreidx(sih, origidx);
345 /* initialize PMU switch/regulators */
346 void si_pmu_swreg_init(struct si_pub *sih)
350 /* initialize PLL */
351 void si_pmu_pll_init(struct si_pub *sih, uint xtalfreq)
353 struct chipcregs __iomem *cc;
354 uint origidx;
356 /* Remember original core before switch to chipc */
357 origidx = ai_coreidx(sih);
358 cc = ai_setcoreidx(sih, SI_CC_IDX);
360 switch (sih->chip) {
361 case BCM4313_CHIP_ID:
362 case BCM43224_CHIP_ID:
363 case BCM43225_CHIP_ID:
364 /* ??? */
365 break;
366 default:
367 break;
370 /* Return to original core */
371 ai_setcoreidx(sih, origidx);
374 /* initialize PMU resources */
375 void si_pmu_res_init(struct si_pub *sih)
377 struct chipcregs __iomem *cc;
378 uint origidx;
379 u32 min_mask = 0, max_mask = 0;
381 /* Remember original core before switch to chipc */
382 origidx = ai_coreidx(sih);
383 cc = ai_setcoreidx(sih, SI_CC_IDX);
385 /* Determine min/max rsrc masks */
386 si_pmu_res_masks(sih, &min_mask, &max_mask);
388 /* It is required to program max_mask first and then min_mask */
390 /* Program max resource mask */
392 if (max_mask)
393 W_REG(&cc->max_res_mask, max_mask);
395 /* Program min resource mask */
397 if (min_mask)
398 W_REG(&cc->min_res_mask, min_mask);
400 /* Add some delay; allow resources to come up and settle. */
401 mdelay(2);
403 /* Return to original core */
404 ai_setcoreidx(sih, origidx);
407 u32 si_pmu_measure_alpclk(struct si_pub *sih)
409 struct chipcregs __iomem *cc;
410 uint origidx;
411 u32 alp_khz;
413 if (sih->pmurev < 10)
414 return 0;
416 /* Remember original core before switch to chipc */
417 origidx = ai_coreidx(sih);
418 cc = ai_setcoreidx(sih, SI_CC_IDX);
420 if (R_REG(&cc->pmustatus) & PST_EXTLPOAVAIL) {
421 u32 ilp_ctr, alp_hz;
424 * Enable the reg to measure the freq,
425 * in case it was disabled before
427 W_REG(&cc->pmu_xtalfreq,
428 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT);
430 /* Delay for well over 4 ILP clocks */
431 udelay(1000);
433 /* Read the latched number of ALP ticks per 4 ILP ticks */
434 ilp_ctr =
435 R_REG(&cc->pmu_xtalfreq) & PMU_XTALFREQ_REG_ILPCTR_MASK;
438 * Turn off the PMU_XTALFREQ_REG_MEASURE_SHIFT
439 * bit to save power
441 W_REG(&cc->pmu_xtalfreq, 0);
443 /* Calculate ALP frequency */
444 alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4;
447 * Round to nearest 100KHz, and at
448 * the same time convert to KHz
450 alp_khz = (alp_hz + 50000) / 100000 * 100;
451 } else
452 alp_khz = 0;
454 /* Return to original core */
455 ai_setcoreidx(sih, origidx);
457 return alp_khz;