blob: 3b36e3acfd74cb77672af14596dcb8c4c2edc7fa [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2011 Broadcom Corporation
3 *
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.
7 *
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.
15 */
16
17#include <linux/delay.h>
18#include <linux/io.h>
19
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"
26
27/*
28 * external LPO crystal frequency
29 */
30#define EXT_ILP_HZ 32768
31
32/*
33 * Duration for ILP clock frequency measurment in milliseconds
34 *
35 * remark: 1000 must be an integer multiple of this duration
36 */
37#define ILP_CALC_DUR 10
38
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
50
51/* ILP clock */
52#define ILP_CLOCK 32000
53
54/* ALP clock on pre-PMU chips */
55#define ALP_CLOCK 20000000
56
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
68
69/* PMU resource bit position */
70#define PMURES_BIT(bit) (1 << (bit))
71
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.
75 */
76/* pllcontrol registers:
77 * ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>,
78 * p1div, p2div, _bypass_sdmod
79 */
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
86
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
91
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
109
110/* Determine min/max rsrc masks. Value 0 leaves hardware at default. */
111static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax)
112{
113 u32 min_mask = 0, max_mask = 0;
114 uint rsrcs;
115
116 /* # resources */
117 rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT;
118
119 /* determine min/max rsrc masks */
120 switch (sih->chip) {
121 case BCM43224_CHIP_ID:
122 case BCM43225_CHIP_ID:
123 /* ??? */
124 break;
125
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;
135 }
136
137 *pmin = min_mask;
138 *pmax = max_mask;
139}
140
141static void
142si_pmu_spuravoid_pllupdate(struct si_pub *sih, struct chipcregs __iomem *cc,
143 u8 spuravoid)
144{
145 u32 tmp = 0;
146
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);
176 }
177 tmp = 1 << 10;
178 break;
179
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);
192
193 tmp = 1 << 10;
194 break;
195
196 default:
197 /* bail out */
198 return;
199 }
200
201 tmp |= R_REG(&cc->pmucontrol);
202 W_REG(&cc->pmucontrol, tmp);
203}
204
205u16 si_pmu_fast_pwrup_delay(struct si_pub *sih)
206{
207 uint delay = PMU_MAX_TRANSITION_DLY;
208
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;
217 }
218
219 return (u16) delay;
220}
221
222void si_pmu_sprom_enable(struct si_pub *sih, bool enable)
223{
224 struct chipcregs __iomem *cc;
225 uint origidx;
226
227 /* Remember original core before switch to chipc */
228 origidx = ai_coreidx(sih);
229 cc = ai_setcoreidx(sih, SI_CC_IDX);
230
231 /* Return to original core */
232 ai_setcoreidx(sih, origidx);
233}
234
235/* Read/write a chipcontrol reg */
236u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
237{
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);
243}
244
245/* Read/write a regcontrol reg */
246u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
247{
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);
253}
254
255/* Read/write a pllcontrol reg */
256u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
257{
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);
263}
264
265/* PMU PLL update */
266void si_pmu_pllupd(struct si_pub *sih)
267{
268 ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pmucontrol),
269 PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD);
270}
271
272/* query alp/xtal clock frequency */
273u32 si_pmu_alp_clock(struct si_pub *sih)
274{
275 u32 clock = ALP_CLOCK;
276
277 /* bail out with default */
278 if (!(sih->cccaps & CC_CAP_PMU))
279 return clock;
280
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;
290 }
291
292 return clock;
293}
294
295void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid)
296{
297 struct chipcregs __iomem *cc;
298 uint origidx, intr_val;
299
300 /* Remember original core before switch to chipc */
301 cc = (struct chipcregs __iomem *)
302 ai_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
303
304 /* update the pll changes */
305 si_pmu_spuravoid_pllupdate(sih, cc, spuravoid);
306
307 /* Return to original core */
308 ai_restore_core(sih, origidx, intr_val);
309}
310
311/* initialize PMU */
312void si_pmu_init(struct si_pub *sih)
313{
314 struct chipcregs __iomem *cc;
315 uint origidx;
316
317 /* Remember original core before switch to chipc */
318 origidx = ai_coreidx(sih);
319 cc = ai_setcoreidx(sih, SI_CC_IDX);
320
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);
325
326 /* Return to original core */
327 ai_setcoreidx(sih, origidx);
328}
329
330/* initialize PMU chip controls and other chip level stuff */
331void si_pmu_chip_init(struct si_pub *sih)
332{
333 uint origidx;
334
335 /* Gate off SPROM clock and chip select signals */
336 si_pmu_sprom_enable(sih, false);
337
338 /* Remember original core */
339 origidx = ai_coreidx(sih);
340
341 /* Return to original core */
342 ai_setcoreidx(sih, origidx);
343}
344
345/* initialize PMU switch/regulators */
346void si_pmu_swreg_init(struct si_pub *sih)
347{
348}
349
350/* initialize PLL */
351void si_pmu_pll_init(struct si_pub *sih, uint xtalfreq)
352{
353 struct chipcregs __iomem *cc;
354 uint origidx;
355
356 /* Remember original core before switch to chipc */
357 origidx = ai_coreidx(sih);
358 cc = ai_setcoreidx(sih, SI_CC_IDX);
359
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;
368 }
369
370 /* Return to original core */
371 ai_setcoreidx(sih, origidx);
372}
373
374/* initialize PMU resources */
375void si_pmu_res_init(struct si_pub *sih)
376{
377 struct chipcregs __iomem *cc;
378 uint origidx;
379 u32 min_mask = 0, max_mask = 0;
380
381 /* Remember original core before switch to chipc */
382 origidx = ai_coreidx(sih);
383 cc = ai_setcoreidx(sih, SI_CC_IDX);
384
385 /* Determine min/max rsrc masks */
386 si_pmu_res_masks(sih, &min_mask, &max_mask);
387
388 /* It is required to program max_mask first and then min_mask */
389
390 /* Program max resource mask */
391
392 if (max_mask)
393 W_REG(&cc->max_res_mask, max_mask);
394
395 /* Program min resource mask */
396
397 if (min_mask)
398 W_REG(&cc->min_res_mask, min_mask);
399
400 /* Add some delay; allow resources to come up and settle. */
401 mdelay(2);
402
403 /* Return to original core */
404 ai_setcoreidx(sih, origidx);
405}
406
407u32 si_pmu_measure_alpclk(struct si_pub *sih)
408{
409 struct chipcregs __iomem *cc;
410 uint origidx;
411 u32 alp_khz;
412
413 if (sih->pmurev < 10)
414 return 0;
415
416 /* Remember original core before switch to chipc */
417 origidx = ai_coreidx(sih);
418 cc = ai_setcoreidx(sih, SI_CC_IDX);
419
420 if (R_REG(&cc->pmustatus) & PST_EXTLPOAVAIL) {
421 u32 ilp_ctr, alp_hz;
422
423 /*
424 * Enable the reg to measure the freq,
425 * in case it was disabled before
426 */
427 W_REG(&cc->pmu_xtalfreq,
428 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT);
429
430 /* Delay for well over 4 ILP clocks */
431 udelay(1000);
432
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;
436
437 /*
438 * Turn off the PMU_XTALFREQ_REG_MEASURE_SHIFT
439 * bit to save power
440 */
441 W_REG(&cc->pmu_xtalfreq, 0);
442
443 /* Calculate ALP frequency */
444 alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4;
445
446 /*
447 * Round to nearest 100KHz, and at
448 * the same time convert to KHz
449 */
450 alp_khz = (alp_hz + 50000) / 100000 * 100;
451 } else
452 alp_khz = 0;
453
454 /* Return to original core */
455 ai_setcoreidx(sih, origidx);
456
457 return alp_khz;
458}