2 * Sonics Silicon Backplane
3 * Broadcom ChipCommon Power Management Unit driver
5 * Copyright 2009, Michael Buesch <m@bues.ch>
6 * Copyright 2007, Broadcom Corporation
8 * Licensed under the GNU/GPL. See COPYING for details.
11 #include <linux/ssb/ssb.h>
12 #include <linux/ssb/ssb_regs.h>
13 #include <linux/ssb/ssb_driver_chipcommon.h>
14 #include <linux/delay.h>
15 #include <linux/export.h>
17 #include <bcm47xx_nvram.h>
20 #include "ssb_private.h"
22 static u32
ssb_chipco_pll_read(struct ssb_chipcommon
*cc
, u32 offset
)
24 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_ADDR
, offset
);
25 return chipco_read32(cc
, SSB_CHIPCO_PLLCTL_DATA
);
28 static void ssb_chipco_pll_write(struct ssb_chipcommon
*cc
,
29 u32 offset
, u32 value
)
31 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_ADDR
, offset
);
32 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_DATA
, value
);
35 static void ssb_chipco_regctl_maskset(struct ssb_chipcommon
*cc
,
36 u32 offset
, u32 mask
, u32 set
)
40 chipco_read32(cc
, SSB_CHIPCO_REGCTL_ADDR
);
41 chipco_write32(cc
, SSB_CHIPCO_REGCTL_ADDR
, offset
);
42 chipco_read32(cc
, SSB_CHIPCO_REGCTL_ADDR
);
43 value
= chipco_read32(cc
, SSB_CHIPCO_REGCTL_DATA
);
46 chipco_write32(cc
, SSB_CHIPCO_REGCTL_DATA
, value
);
47 chipco_read32(cc
, SSB_CHIPCO_REGCTL_DATA
);
50 struct pmu0_plltab_entry
{
51 u16 freq
; /* Crystal frequency in kHz.*/
52 u8 xf
; /* Crystal frequency value for PMU control */
57 static const struct pmu0_plltab_entry pmu0_plltab
[] = {
58 { .freq
= 12000, .xf
= 1, .wb_int
= 73, .wb_frac
= 349525, },
59 { .freq
= 13000, .xf
= 2, .wb_int
= 67, .wb_frac
= 725937, },
60 { .freq
= 14400, .xf
= 3, .wb_int
= 61, .wb_frac
= 116508, },
61 { .freq
= 15360, .xf
= 4, .wb_int
= 57, .wb_frac
= 305834, },
62 { .freq
= 16200, .xf
= 5, .wb_int
= 54, .wb_frac
= 336579, },
63 { .freq
= 16800, .xf
= 6, .wb_int
= 52, .wb_frac
= 399457, },
64 { .freq
= 19200, .xf
= 7, .wb_int
= 45, .wb_frac
= 873813, },
65 { .freq
= 19800, .xf
= 8, .wb_int
= 44, .wb_frac
= 466033, },
66 { .freq
= 20000, .xf
= 9, .wb_int
= 44, .wb_frac
= 0, },
67 { .freq
= 25000, .xf
= 10, .wb_int
= 70, .wb_frac
= 419430, },
68 { .freq
= 26000, .xf
= 11, .wb_int
= 67, .wb_frac
= 725937, },
69 { .freq
= 30000, .xf
= 12, .wb_int
= 58, .wb_frac
= 699050, },
70 { .freq
= 38400, .xf
= 13, .wb_int
= 45, .wb_frac
= 873813, },
71 { .freq
= 40000, .xf
= 14, .wb_int
= 45, .wb_frac
= 0, },
73 #define SSB_PMU0_DEFAULT_XTALFREQ 20000
75 static const struct pmu0_plltab_entry
* pmu0_plltab_find_entry(u32 crystalfreq
)
77 const struct pmu0_plltab_entry
*e
;
80 for (i
= 0; i
< ARRAY_SIZE(pmu0_plltab
); i
++) {
82 if (e
->freq
== crystalfreq
)
89 /* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
90 static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon
*cc
,
93 struct ssb_bus
*bus
= cc
->dev
->bus
;
94 const struct pmu0_plltab_entry
*e
= NULL
;
95 u32 pmuctl
, tmp
, pllctl
;
99 e
= pmu0_plltab_find_entry(crystalfreq
);
101 e
= pmu0_plltab_find_entry(SSB_PMU0_DEFAULT_XTALFREQ
);
103 crystalfreq
= e
->freq
;
104 cc
->pmu
.crystalfreq
= e
->freq
;
106 /* Check if the PLL already is programmed to this frequency. */
107 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
108 if (((pmuctl
& SSB_CHIPCO_PMU_CTL_XTALFREQ
) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) == e
->xf
) {
109 /* We're already there... */
113 ssb_info("Programming PLL to %u.%03u MHz\n",
114 crystalfreq
/ 1000, crystalfreq
% 1000);
116 /* First turn the PLL off. */
117 switch (bus
->chip_id
) {
119 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
,
120 ~(1 << SSB_PMURES_4328_BB_PLL_PU
));
121 chipco_mask32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
,
122 ~(1 << SSB_PMURES_4328_BB_PLL_PU
));
125 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
,
126 ~(1 << SSB_PMURES_5354_BB_PLL_PU
));
127 chipco_mask32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
,
128 ~(1 << SSB_PMURES_5354_BB_PLL_PU
));
133 for (i
= 1500; i
; i
--) {
134 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
135 if (!(tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
))
139 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
140 if (tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
)
141 ssb_emerg("Failed to turn the PLL off!\n");
143 /* Set PDIV in PLL control 0. */
144 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU0_PLLCTL0
);
145 if (crystalfreq
>= SSB_PMU0_PLLCTL0_PDIV_FREQ
)
146 pllctl
|= SSB_PMU0_PLLCTL0_PDIV_MSK
;
148 pllctl
&= ~SSB_PMU0_PLLCTL0_PDIV_MSK
;
149 ssb_chipco_pll_write(cc
, SSB_PMU0_PLLCTL0
, pllctl
);
151 /* Set WILD in PLL control 1. */
152 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU0_PLLCTL1
);
153 pllctl
&= ~SSB_PMU0_PLLCTL1_STOPMOD
;
154 pllctl
&= ~(SSB_PMU0_PLLCTL1_WILD_IMSK
| SSB_PMU0_PLLCTL1_WILD_FMSK
);
155 pllctl
|= ((u32
)e
->wb_int
<< SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT
) & SSB_PMU0_PLLCTL1_WILD_IMSK
;
156 pllctl
|= ((u32
)e
->wb_frac
<< SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT
) & SSB_PMU0_PLLCTL1_WILD_FMSK
;
158 pllctl
|= SSB_PMU0_PLLCTL1_STOPMOD
;
159 ssb_chipco_pll_write(cc
, SSB_PMU0_PLLCTL1
, pllctl
);
161 /* Set WILD in PLL control 2. */
162 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU0_PLLCTL2
);
163 pllctl
&= ~SSB_PMU0_PLLCTL2_WILD_IMSKHI
;
164 pllctl
|= (((u32
)e
->wb_int
>> 4) << SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT
) & SSB_PMU0_PLLCTL2_WILD_IMSKHI
;
165 ssb_chipco_pll_write(cc
, SSB_PMU0_PLLCTL2
, pllctl
);
167 /* Set the crystalfrequency and the divisor. */
168 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
169 pmuctl
&= ~SSB_CHIPCO_PMU_CTL_ILP_DIV
;
170 pmuctl
|= (((crystalfreq
+ 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT
)
171 & SSB_CHIPCO_PMU_CTL_ILP_DIV
;
172 pmuctl
&= ~SSB_CHIPCO_PMU_CTL_XTALFREQ
;
173 pmuctl
|= ((u32
)e
->xf
<< SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) & SSB_CHIPCO_PMU_CTL_XTALFREQ
;
174 chipco_write32(cc
, SSB_CHIPCO_PMU_CTL
, pmuctl
);
177 struct pmu1_plltab_entry
{
178 u16 freq
; /* Crystal frequency in kHz.*/
179 u8 xf
; /* Crystal frequency value for PMU control */
186 static const struct pmu1_plltab_entry pmu1_plltab
[] = {
187 { .freq
= 12000, .xf
= 1, .p1div
= 3, .p2div
= 22, .ndiv_int
= 0x9, .ndiv_frac
= 0xFFFFEF, },
188 { .freq
= 13000, .xf
= 2, .p1div
= 1, .p2div
= 6, .ndiv_int
= 0xb, .ndiv_frac
= 0x483483, },
189 { .freq
= 14400, .xf
= 3, .p1div
= 1, .p2div
= 10, .ndiv_int
= 0xa, .ndiv_frac
= 0x1C71C7, },
190 { .freq
= 15360, .xf
= 4, .p1div
= 1, .p2div
= 5, .ndiv_int
= 0xb, .ndiv_frac
= 0x755555, },
191 { .freq
= 16200, .xf
= 5, .p1div
= 1, .p2div
= 10, .ndiv_int
= 0x5, .ndiv_frac
= 0x6E9E06, },
192 { .freq
= 16800, .xf
= 6, .p1div
= 1, .p2div
= 10, .ndiv_int
= 0x5, .ndiv_frac
= 0x3CF3CF, },
193 { .freq
= 19200, .xf
= 7, .p1div
= 1, .p2div
= 9, .ndiv_int
= 0x5, .ndiv_frac
= 0x17B425, },
194 { .freq
= 19800, .xf
= 8, .p1div
= 1, .p2div
= 11, .ndiv_int
= 0x4, .ndiv_frac
= 0xA57EB, },
195 { .freq
= 20000, .xf
= 9, .p1div
= 1, .p2div
= 11, .ndiv_int
= 0x4, .ndiv_frac
= 0, },
196 { .freq
= 24000, .xf
= 10, .p1div
= 3, .p2div
= 11, .ndiv_int
= 0xa, .ndiv_frac
= 0, },
197 { .freq
= 25000, .xf
= 11, .p1div
= 5, .p2div
= 16, .ndiv_int
= 0xb, .ndiv_frac
= 0, },
198 { .freq
= 26000, .xf
= 12, .p1div
= 1, .p2div
= 2, .ndiv_int
= 0x10, .ndiv_frac
= 0xEC4EC4, },
199 { .freq
= 30000, .xf
= 13, .p1div
= 3, .p2div
= 8, .ndiv_int
= 0xb, .ndiv_frac
= 0, },
200 { .freq
= 38400, .xf
= 14, .p1div
= 1, .p2div
= 5, .ndiv_int
= 0x4, .ndiv_frac
= 0x955555, },
201 { .freq
= 40000, .xf
= 15, .p1div
= 1, .p2div
= 2, .ndiv_int
= 0xb, .ndiv_frac
= 0, },
204 #define SSB_PMU1_DEFAULT_XTALFREQ 15360
206 static const struct pmu1_plltab_entry
* pmu1_plltab_find_entry(u32 crystalfreq
)
208 const struct pmu1_plltab_entry
*e
;
211 for (i
= 0; i
< ARRAY_SIZE(pmu1_plltab
); i
++) {
213 if (e
->freq
== crystalfreq
)
220 /* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
221 static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon
*cc
,
224 struct ssb_bus
*bus
= cc
->dev
->bus
;
225 const struct pmu1_plltab_entry
*e
= NULL
;
226 u32 buffer_strength
= 0;
227 u32 tmp
, pllctl
, pmuctl
;
230 if (bus
->chip_id
== 0x4312) {
231 /* We do not touch the BCM4312 PLL and assume
232 * the default crystal settings work out-of-the-box. */
233 cc
->pmu
.crystalfreq
= 20000;
238 e
= pmu1_plltab_find_entry(crystalfreq
);
240 e
= pmu1_plltab_find_entry(SSB_PMU1_DEFAULT_XTALFREQ
);
242 crystalfreq
= e
->freq
;
243 cc
->pmu
.crystalfreq
= e
->freq
;
245 /* Check if the PLL already is programmed to this frequency. */
246 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
247 if (((pmuctl
& SSB_CHIPCO_PMU_CTL_XTALFREQ
) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) == e
->xf
) {
248 /* We're already there... */
252 ssb_info("Programming PLL to %u.%03u MHz\n",
253 crystalfreq
/ 1000, crystalfreq
% 1000);
255 /* First turn the PLL off. */
256 switch (bus
->chip_id
) {
258 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
,
259 ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU
) |
260 (1 << SSB_PMURES_4325_HT_AVAIL
)));
261 chipco_mask32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
,
262 ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU
) |
263 (1 << SSB_PMURES_4325_HT_AVAIL
)));
264 /* Adjust the BBPLL to 2 on all channels later. */
265 buffer_strength
= 0x222222;
270 for (i
= 1500; i
; i
--) {
271 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
272 if (!(tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
))
276 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
277 if (tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
)
278 ssb_emerg("Failed to turn the PLL off!\n");
280 /* Set p1div and p2div. */
281 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL0
);
282 pllctl
&= ~(SSB_PMU1_PLLCTL0_P1DIV
| SSB_PMU1_PLLCTL0_P2DIV
);
283 pllctl
|= ((u32
)e
->p1div
<< SSB_PMU1_PLLCTL0_P1DIV_SHIFT
) & SSB_PMU1_PLLCTL0_P1DIV
;
284 pllctl
|= ((u32
)e
->p2div
<< SSB_PMU1_PLLCTL0_P2DIV_SHIFT
) & SSB_PMU1_PLLCTL0_P2DIV
;
285 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL0
, pllctl
);
287 /* Set ndiv int and ndiv mode */
288 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL2
);
289 pllctl
&= ~(SSB_PMU1_PLLCTL2_NDIVINT
| SSB_PMU1_PLLCTL2_NDIVMODE
);
290 pllctl
|= ((u32
)e
->ndiv_int
<< SSB_PMU1_PLLCTL2_NDIVINT_SHIFT
) & SSB_PMU1_PLLCTL2_NDIVINT
;
291 pllctl
|= (1 << SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT
) & SSB_PMU1_PLLCTL2_NDIVMODE
;
292 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL2
, pllctl
);
295 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL3
);
296 pllctl
&= ~SSB_PMU1_PLLCTL3_NDIVFRAC
;
297 pllctl
|= ((u32
)e
->ndiv_frac
<< SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT
) & SSB_PMU1_PLLCTL3_NDIVFRAC
;
298 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL3
, pllctl
);
300 /* Change the drive strength, if required. */
301 if (buffer_strength
) {
302 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL5
);
303 pllctl
&= ~SSB_PMU1_PLLCTL5_CLKDRV
;
304 pllctl
|= (buffer_strength
<< SSB_PMU1_PLLCTL5_CLKDRV_SHIFT
) & SSB_PMU1_PLLCTL5_CLKDRV
;
305 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL5
, pllctl
);
308 /* Tune the crystalfreq and the divisor. */
309 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
310 pmuctl
&= ~(SSB_CHIPCO_PMU_CTL_ILP_DIV
| SSB_CHIPCO_PMU_CTL_XTALFREQ
);
311 pmuctl
|= ((((u32
)e
->freq
+ 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT
)
312 & SSB_CHIPCO_PMU_CTL_ILP_DIV
;
313 pmuctl
|= ((u32
)e
->xf
<< SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) & SSB_CHIPCO_PMU_CTL_XTALFREQ
;
314 chipco_write32(cc
, SSB_CHIPCO_PMU_CTL
, pmuctl
);
317 static void ssb_pmu_pll_init(struct ssb_chipcommon
*cc
)
319 struct ssb_bus
*bus
= cc
->dev
->bus
;
320 u32 crystalfreq
= 0; /* in kHz. 0 = keep default freq. */
322 if (bus
->bustype
== SSB_BUSTYPE_SSB
) {
323 #ifdef CONFIG_BCM47XX
325 if (bcm47xx_nvram_getenv("xtalfreq", buf
, sizeof(buf
)) >= 0)
326 crystalfreq
= simple_strtoul(buf
, NULL
, 0);
330 switch (bus
->chip_id
) {
333 ssb_pmu1_pllinit_r0(cc
, crystalfreq
);
336 ssb_pmu0_pllinit_r0(cc
, crystalfreq
);
339 if (crystalfreq
== 0)
341 ssb_pmu0_pllinit_r0(cc
, crystalfreq
);
344 if (cc
->pmu
.rev
== 2) {
345 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_ADDR
, 0x0000000A);
346 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_DATA
, 0x380005C0);
352 ssb_err("ERROR: PLL init unknown for device %04X\n",
357 struct pmu_res_updown_tab_entry
{
358 u8 resource
; /* The resource number */
359 u16 updown
; /* The updown value */
362 enum pmu_res_depend_tab_task
{
368 struct pmu_res_depend_tab_entry
{
369 u8 resource
; /* The resource number */
370 u8 task
; /* SET | ADD | REMOVE */
371 u32 depend
; /* The depend mask */
374 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4328a0
[] = {
375 { .resource
= SSB_PMURES_4328_EXT_SWITCHER_PWM
, .updown
= 0x0101, },
376 { .resource
= SSB_PMURES_4328_BB_SWITCHER_PWM
, .updown
= 0x1F01, },
377 { .resource
= SSB_PMURES_4328_BB_SWITCHER_BURST
, .updown
= 0x010F, },
378 { .resource
= SSB_PMURES_4328_BB_EXT_SWITCHER_BURST
, .updown
= 0x0101, },
379 { .resource
= SSB_PMURES_4328_ILP_REQUEST
, .updown
= 0x0202, },
380 { .resource
= SSB_PMURES_4328_RADIO_SWITCHER_PWM
, .updown
= 0x0F01, },
381 { .resource
= SSB_PMURES_4328_RADIO_SWITCHER_BURST
, .updown
= 0x0F01, },
382 { .resource
= SSB_PMURES_4328_ROM_SWITCH
, .updown
= 0x0101, },
383 { .resource
= SSB_PMURES_4328_PA_REF_LDO
, .updown
= 0x0F01, },
384 { .resource
= SSB_PMURES_4328_RADIO_LDO
, .updown
= 0x0F01, },
385 { .resource
= SSB_PMURES_4328_AFE_LDO
, .updown
= 0x0F01, },
386 { .resource
= SSB_PMURES_4328_PLL_LDO
, .updown
= 0x0F01, },
387 { .resource
= SSB_PMURES_4328_BG_FILTBYP
, .updown
= 0x0101, },
388 { .resource
= SSB_PMURES_4328_TX_FILTBYP
, .updown
= 0x0101, },
389 { .resource
= SSB_PMURES_4328_RX_FILTBYP
, .updown
= 0x0101, },
390 { .resource
= SSB_PMURES_4328_XTAL_PU
, .updown
= 0x0101, },
391 { .resource
= SSB_PMURES_4328_XTAL_EN
, .updown
= 0xA001, },
392 { .resource
= SSB_PMURES_4328_BB_PLL_FILTBYP
, .updown
= 0x0101, },
393 { .resource
= SSB_PMURES_4328_RF_PLL_FILTBYP
, .updown
= 0x0101, },
394 { .resource
= SSB_PMURES_4328_BB_PLL_PU
, .updown
= 0x0701, },
397 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4328a0
[] = {
399 /* Adjust ILP Request to avoid forcing EXT/BB into burst mode. */
400 .resource
= SSB_PMURES_4328_ILP_REQUEST
,
401 .task
= PMU_RES_DEP_SET
,
402 .depend
= ((1 << SSB_PMURES_4328_EXT_SWITCHER_PWM
) |
403 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM
)),
407 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4325a0
[] = {
408 { .resource
= SSB_PMURES_4325_XTAL_PU
, .updown
= 0x1501, },
411 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4325a0
[] = {
413 /* Adjust HT-Available dependencies. */
414 .resource
= SSB_PMURES_4325_HT_AVAIL
,
415 .task
= PMU_RES_DEP_ADD
,
416 .depend
= ((1 << SSB_PMURES_4325_RX_PWRSW_PU
) |
417 (1 << SSB_PMURES_4325_TX_PWRSW_PU
) |
418 (1 << SSB_PMURES_4325_LOGEN_PWRSW_PU
) |
419 (1 << SSB_PMURES_4325_AFE_PWRSW_PU
)),
423 static void ssb_pmu_resources_init(struct ssb_chipcommon
*cc
)
425 struct ssb_bus
*bus
= cc
->dev
->bus
;
426 u32 min_msk
= 0, max_msk
= 0;
428 const struct pmu_res_updown_tab_entry
*updown_tab
= NULL
;
429 unsigned int updown_tab_size
= 0;
430 const struct pmu_res_depend_tab_entry
*depend_tab
= NULL
;
431 unsigned int depend_tab_size
= 0;
433 switch (bus
->chip_id
) {
439 /* We keep the default settings:
445 /* Power OTP down later. */
446 min_msk
= (1 << SSB_PMURES_4325_CBUCK_BURST
) |
447 (1 << SSB_PMURES_4325_LNLDO2_PU
);
448 if (chipco_read32(cc
, SSB_CHIPCO_CHIPSTAT
) &
449 SSB_CHIPCO_CHST_4325_PMUTOP_2B
)
450 min_msk
|= (1 << SSB_PMURES_4325_CLDO_CBUCK_BURST
);
451 /* The PLL may turn on, if it decides so. */
453 updown_tab
= pmu_res_updown_tab_4325a0
;
454 updown_tab_size
= ARRAY_SIZE(pmu_res_updown_tab_4325a0
);
455 depend_tab
= pmu_res_depend_tab_4325a0
;
456 depend_tab_size
= ARRAY_SIZE(pmu_res_depend_tab_4325a0
);
459 min_msk
= (1 << SSB_PMURES_4328_EXT_SWITCHER_PWM
) |
460 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM
) |
461 (1 << SSB_PMURES_4328_XTAL_EN
);
462 /* The PLL may turn on, if it decides so. */
464 updown_tab
= pmu_res_updown_tab_4328a0
;
465 updown_tab_size
= ARRAY_SIZE(pmu_res_updown_tab_4328a0
);
466 depend_tab
= pmu_res_depend_tab_4328a0
;
467 depend_tab_size
= ARRAY_SIZE(pmu_res_depend_tab_4328a0
);
470 /* The PLL may turn on, if it decides so. */
474 ssb_err("ERROR: PMU resource config unknown for device %04X\n",
479 for (i
= 0; i
< updown_tab_size
; i
++) {
480 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_TABSEL
,
481 updown_tab
[i
].resource
);
482 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_UPDNTM
,
483 updown_tab
[i
].updown
);
487 for (i
= 0; i
< depend_tab_size
; i
++) {
488 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_TABSEL
,
489 depend_tab
[i
].resource
);
490 switch (depend_tab
[i
].task
) {
491 case PMU_RES_DEP_SET
:
492 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
493 depend_tab
[i
].depend
);
495 case PMU_RES_DEP_ADD
:
496 chipco_set32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
497 depend_tab
[i
].depend
);
499 case PMU_RES_DEP_REMOVE
:
500 chipco_mask32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
501 ~(depend_tab
[i
].depend
));
509 /* Set the resource masks. */
511 chipco_write32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, min_msk
);
513 chipco_write32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
, max_msk
);
516 /* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
517 void ssb_pmu_init(struct ssb_chipcommon
*cc
)
521 if (!(cc
->capabilities
& SSB_CHIPCO_CAP_PMU
))
524 pmucap
= chipco_read32(cc
, SSB_CHIPCO_PMU_CAP
);
525 cc
->pmu
.rev
= (pmucap
& SSB_CHIPCO_PMU_CAP_REVISION
);
527 ssb_dbg("Found rev %u PMU (capabilities 0x%08X)\n",
528 cc
->pmu
.rev
, pmucap
);
530 if (cc
->pmu
.rev
== 1)
531 chipco_mask32(cc
, SSB_CHIPCO_PMU_CTL
,
532 ~SSB_CHIPCO_PMU_CTL_NOILPONW
);
534 chipco_set32(cc
, SSB_CHIPCO_PMU_CTL
,
535 SSB_CHIPCO_PMU_CTL_NOILPONW
);
536 ssb_pmu_pll_init(cc
);
537 ssb_pmu_resources_init(cc
);
540 void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon
*cc
,
541 enum ssb_pmu_ldo_volt_id id
, u32 voltage
)
543 struct ssb_bus
*bus
= cc
->dev
->bus
;
544 u32 addr
, shift
, mask
;
546 switch (bus
->chip_id
) {
576 if (SSB_WARN_ON(id
!= LDO_PAREF
))
586 ssb_chipco_regctl_maskset(cc
, addr
, ~(mask
<< shift
),
587 (voltage
& mask
) << shift
);
590 void ssb_pmu_set_ldo_paref(struct ssb_chipcommon
*cc
, bool on
)
592 struct ssb_bus
*bus
= cc
->dev
->bus
;
595 switch (bus
->chip_id
) {
597 ldo
= SSB_PMURES_4312_PA_REF_LDO
;
600 ldo
= SSB_PMURES_4328_PA_REF_LDO
;
603 ldo
= SSB_PMURES_5354_PA_REF_LDO
;
610 chipco_set32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, 1 << ldo
);
612 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, ~(1 << ldo
));
613 chipco_read32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
); //SPEC FIXME found via mmiotrace - dummy read?
616 EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage
);
617 EXPORT_SYMBOL(ssb_pmu_set_ldo_paref
);
619 static u32
ssb_pmu_get_alp_clock_clk0(struct ssb_chipcommon
*cc
)
622 const struct pmu0_plltab_entry
*e
= NULL
;
624 crystalfreq
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
) &
625 SSB_CHIPCO_PMU_CTL_XTALFREQ
>> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
;
626 e
= pmu0_plltab_find_entry(crystalfreq
);
628 return e
->freq
* 1000;
631 u32
ssb_pmu_get_alp_clock(struct ssb_chipcommon
*cc
)
633 struct ssb_bus
*bus
= cc
->dev
->bus
;
635 switch (bus
->chip_id
) {
637 ssb_pmu_get_alp_clock_clk0(cc
);
639 ssb_err("ERROR: PMU alp clock unknown for device %04X\n",
645 u32
ssb_pmu_get_cpu_clock(struct ssb_chipcommon
*cc
)
647 struct ssb_bus
*bus
= cc
->dev
->bus
;
649 switch (bus
->chip_id
) {
651 /* 5354 chip uses a non programmable PLL of frequency 240MHz */
654 ssb_err("ERROR: PMU cpu clock unknown for device %04X\n",
660 u32
ssb_pmu_get_controlclock(struct ssb_chipcommon
*cc
)
662 struct ssb_bus
*bus
= cc
->dev
->bus
;
664 switch (bus
->chip_id
) {
668 ssb_err("ERROR: PMU controlclock unknown for device %04X\n",
674 void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon
*cc
, int spuravoid
)
678 switch (cc
->dev
->bus
->chip_id
) {
680 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL0
, 0x11100070);
681 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL1
, 0x1014140a);
682 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL5
, 0x88888854);
684 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL2
, 0x05201828);
686 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL2
, 0x05001828);
687 pmu_ctl
= SSB_CHIPCO_PMU_CTL_PLL_UPD
;
690 if (spuravoid
== 1) {
691 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL0
, 0x11500008);
692 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL1
, 0x0C000C06);
693 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL2
, 0x0F600a08);
694 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL3
, 0x00000000);
695 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL4
, 0x2001E920);
696 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL5
, 0x88888815);
698 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL0
, 0x11100008);
699 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL1
, 0x0c000c06);
700 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL2
, 0x03000a08);
701 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL3
, 0x00000000);
702 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL4
, 0x200005c0);
703 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL5
, 0x88888855);
705 pmu_ctl
= SSB_CHIPCO_PMU_CTL_PLL_UPD
;
708 ssb_printk(KERN_ERR PFX
709 "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
710 cc
->dev
->bus
->chip_id
);
714 chipco_set32(cc
, SSB_CHIPCO_PMU_CTL
, pmu_ctl
);
716 EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate
);