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 <asm/mach-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_printk(KERN_INFO PFX
"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_printk(KERN_EMERG PFX
"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_printk(KERN_INFO PFX
"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_printk(KERN_EMERG PFX
"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 (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);
350 ssb_printk(KERN_ERR PFX
351 "ERROR: PLL init unknown for device %04X\n",
356 struct pmu_res_updown_tab_entry
{
357 u8 resource
; /* The resource number */
358 u16 updown
; /* The updown value */
361 enum pmu_res_depend_tab_task
{
367 struct pmu_res_depend_tab_entry
{
368 u8 resource
; /* The resource number */
369 u8 task
; /* SET | ADD | REMOVE */
370 u32 depend
; /* The depend mask */
373 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4328a0
[] = {
374 { .resource
= SSB_PMURES_4328_EXT_SWITCHER_PWM
, .updown
= 0x0101, },
375 { .resource
= SSB_PMURES_4328_BB_SWITCHER_PWM
, .updown
= 0x1F01, },
376 { .resource
= SSB_PMURES_4328_BB_SWITCHER_BURST
, .updown
= 0x010F, },
377 { .resource
= SSB_PMURES_4328_BB_EXT_SWITCHER_BURST
, .updown
= 0x0101, },
378 { .resource
= SSB_PMURES_4328_ILP_REQUEST
, .updown
= 0x0202, },
379 { .resource
= SSB_PMURES_4328_RADIO_SWITCHER_PWM
, .updown
= 0x0F01, },
380 { .resource
= SSB_PMURES_4328_RADIO_SWITCHER_BURST
, .updown
= 0x0F01, },
381 { .resource
= SSB_PMURES_4328_ROM_SWITCH
, .updown
= 0x0101, },
382 { .resource
= SSB_PMURES_4328_PA_REF_LDO
, .updown
= 0x0F01, },
383 { .resource
= SSB_PMURES_4328_RADIO_LDO
, .updown
= 0x0F01, },
384 { .resource
= SSB_PMURES_4328_AFE_LDO
, .updown
= 0x0F01, },
385 { .resource
= SSB_PMURES_4328_PLL_LDO
, .updown
= 0x0F01, },
386 { .resource
= SSB_PMURES_4328_BG_FILTBYP
, .updown
= 0x0101, },
387 { .resource
= SSB_PMURES_4328_TX_FILTBYP
, .updown
= 0x0101, },
388 { .resource
= SSB_PMURES_4328_RX_FILTBYP
, .updown
= 0x0101, },
389 { .resource
= SSB_PMURES_4328_XTAL_PU
, .updown
= 0x0101, },
390 { .resource
= SSB_PMURES_4328_XTAL_EN
, .updown
= 0xA001, },
391 { .resource
= SSB_PMURES_4328_BB_PLL_FILTBYP
, .updown
= 0x0101, },
392 { .resource
= SSB_PMURES_4328_RF_PLL_FILTBYP
, .updown
= 0x0101, },
393 { .resource
= SSB_PMURES_4328_BB_PLL_PU
, .updown
= 0x0701, },
396 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4328a0
[] = {
398 /* Adjust ILP Request to avoid forcing EXT/BB into burst mode. */
399 .resource
= SSB_PMURES_4328_ILP_REQUEST
,
400 .task
= PMU_RES_DEP_SET
,
401 .depend
= ((1 << SSB_PMURES_4328_EXT_SWITCHER_PWM
) |
402 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM
)),
406 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4325a0
[] = {
407 { .resource
= SSB_PMURES_4325_XTAL_PU
, .updown
= 0x1501, },
410 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4325a0
[] = {
412 /* Adjust HT-Available dependencies. */
413 .resource
= SSB_PMURES_4325_HT_AVAIL
,
414 .task
= PMU_RES_DEP_ADD
,
415 .depend
= ((1 << SSB_PMURES_4325_RX_PWRSW_PU
) |
416 (1 << SSB_PMURES_4325_TX_PWRSW_PU
) |
417 (1 << SSB_PMURES_4325_LOGEN_PWRSW_PU
) |
418 (1 << SSB_PMURES_4325_AFE_PWRSW_PU
)),
422 static void ssb_pmu_resources_init(struct ssb_chipcommon
*cc
)
424 struct ssb_bus
*bus
= cc
->dev
->bus
;
425 u32 min_msk
= 0, max_msk
= 0;
427 const struct pmu_res_updown_tab_entry
*updown_tab
= NULL
;
428 unsigned int updown_tab_size
= 0;
429 const struct pmu_res_depend_tab_entry
*depend_tab
= NULL
;
430 unsigned int depend_tab_size
= 0;
432 switch (bus
->chip_id
) {
437 /* We keep the default settings:
443 /* Power OTP down later. */
444 min_msk
= (1 << SSB_PMURES_4325_CBUCK_BURST
) |
445 (1 << SSB_PMURES_4325_LNLDO2_PU
);
446 if (chipco_read32(cc
, SSB_CHIPCO_CHIPSTAT
) &
447 SSB_CHIPCO_CHST_4325_PMUTOP_2B
)
448 min_msk
|= (1 << SSB_PMURES_4325_CLDO_CBUCK_BURST
);
449 /* The PLL may turn on, if it decides so. */
451 updown_tab
= pmu_res_updown_tab_4325a0
;
452 updown_tab_size
= ARRAY_SIZE(pmu_res_updown_tab_4325a0
);
453 depend_tab
= pmu_res_depend_tab_4325a0
;
454 depend_tab_size
= ARRAY_SIZE(pmu_res_depend_tab_4325a0
);
457 min_msk
= (1 << SSB_PMURES_4328_EXT_SWITCHER_PWM
) |
458 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM
) |
459 (1 << SSB_PMURES_4328_XTAL_EN
);
460 /* The PLL may turn on, if it decides so. */
462 updown_tab
= pmu_res_updown_tab_4328a0
;
463 updown_tab_size
= ARRAY_SIZE(pmu_res_updown_tab_4328a0
);
464 depend_tab
= pmu_res_depend_tab_4328a0
;
465 depend_tab_size
= ARRAY_SIZE(pmu_res_depend_tab_4328a0
);
468 /* The PLL may turn on, if it decides so. */
472 ssb_printk(KERN_ERR PFX
473 "ERROR: PMU resource config unknown for device %04X\n",
478 for (i
= 0; i
< updown_tab_size
; i
++) {
479 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_TABSEL
,
480 updown_tab
[i
].resource
);
481 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_UPDNTM
,
482 updown_tab
[i
].updown
);
486 for (i
= 0; i
< depend_tab_size
; i
++) {
487 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_TABSEL
,
488 depend_tab
[i
].resource
);
489 switch (depend_tab
[i
].task
) {
490 case PMU_RES_DEP_SET
:
491 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
492 depend_tab
[i
].depend
);
494 case PMU_RES_DEP_ADD
:
495 chipco_set32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
496 depend_tab
[i
].depend
);
498 case PMU_RES_DEP_REMOVE
:
499 chipco_mask32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
500 ~(depend_tab
[i
].depend
));
508 /* Set the resource masks. */
510 chipco_write32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, min_msk
);
512 chipco_write32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
, max_msk
);
515 /* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
516 void ssb_pmu_init(struct ssb_chipcommon
*cc
)
520 if (!(cc
->capabilities
& SSB_CHIPCO_CAP_PMU
))
523 pmucap
= chipco_read32(cc
, SSB_CHIPCO_PMU_CAP
);
524 cc
->pmu
.rev
= (pmucap
& SSB_CHIPCO_PMU_CAP_REVISION
);
526 ssb_dprintk(KERN_DEBUG PFX
"Found rev %u PMU (capabilities 0x%08X)\n",
527 cc
->pmu
.rev
, pmucap
);
529 if (cc
->pmu
.rev
== 1)
530 chipco_mask32(cc
, SSB_CHIPCO_PMU_CTL
,
531 ~SSB_CHIPCO_PMU_CTL_NOILPONW
);
533 chipco_set32(cc
, SSB_CHIPCO_PMU_CTL
,
534 SSB_CHIPCO_PMU_CTL_NOILPONW
);
535 ssb_pmu_pll_init(cc
);
536 ssb_pmu_resources_init(cc
);
539 void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon
*cc
,
540 enum ssb_pmu_ldo_volt_id id
, u32 voltage
)
542 struct ssb_bus
*bus
= cc
->dev
->bus
;
543 u32 addr
, shift
, mask
;
545 switch (bus
->chip_id
) {
575 if (SSB_WARN_ON(id
!= LDO_PAREF
))
585 ssb_chipco_regctl_maskset(cc
, addr
, ~(mask
<< shift
),
586 (voltage
& mask
) << shift
);
589 void ssb_pmu_set_ldo_paref(struct ssb_chipcommon
*cc
, bool on
)
591 struct ssb_bus
*bus
= cc
->dev
->bus
;
594 switch (bus
->chip_id
) {
596 ldo
= SSB_PMURES_4312_PA_REF_LDO
;
599 ldo
= SSB_PMURES_4328_PA_REF_LDO
;
602 ldo
= SSB_PMURES_5354_PA_REF_LDO
;
609 chipco_set32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, 1 << ldo
);
611 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, ~(1 << ldo
));
612 chipco_read32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
); //SPEC FIXME found via mmiotrace - dummy read?
615 EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage
);
616 EXPORT_SYMBOL(ssb_pmu_set_ldo_paref
);
618 u32
ssb_pmu_get_cpu_clock(struct ssb_chipcommon
*cc
)
620 struct ssb_bus
*bus
= cc
->dev
->bus
;
622 switch (bus
->chip_id
) {
624 /* 5354 chip uses a non programmable PLL of frequency 240MHz */
627 ssb_printk(KERN_ERR PFX
628 "ERROR: PMU cpu clock unknown for device %04X\n",
634 u32
ssb_pmu_get_controlclock(struct ssb_chipcommon
*cc
)
636 struct ssb_bus
*bus
= cc
->dev
->bus
;
638 switch (bus
->chip_id
) {
642 ssb_printk(KERN_ERR PFX
643 "ERROR: PMU controlclock unknown for device %04X\n",