2 * Sonics Silicon Backplane
3 * Broadcom ChipCommon Power Management Unit driver
5 * Copyright 2009, Michael Buesch <mb@bu3sch.de>
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>
16 #include "ssb_private.h"
18 static u32
ssb_chipco_pll_read(struct ssb_chipcommon
*cc
, u32 offset
)
20 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_ADDR
, offset
);
21 return chipco_read32(cc
, SSB_CHIPCO_PLLCTL_DATA
);
24 static void ssb_chipco_pll_write(struct ssb_chipcommon
*cc
,
25 u32 offset
, u32 value
)
27 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_ADDR
, offset
);
28 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_DATA
, value
);
31 struct pmu0_plltab_entry
{
32 u16 freq
; /* Crystal frequency in kHz.*/
33 u8 xf
; /* Crystal frequency value for PMU control */
38 static const struct pmu0_plltab_entry pmu0_plltab
[] = {
39 { .freq
= 12000, .xf
= 1, .wb_int
= 73, .wb_frac
= 349525, },
40 { .freq
= 13000, .xf
= 2, .wb_int
= 67, .wb_frac
= 725937, },
41 { .freq
= 14400, .xf
= 3, .wb_int
= 61, .wb_frac
= 116508, },
42 { .freq
= 15360, .xf
= 4, .wb_int
= 57, .wb_frac
= 305834, },
43 { .freq
= 16200, .xf
= 5, .wb_int
= 54, .wb_frac
= 336579, },
44 { .freq
= 16800, .xf
= 6, .wb_int
= 52, .wb_frac
= 399457, },
45 { .freq
= 19200, .xf
= 7, .wb_int
= 45, .wb_frac
= 873813, },
46 { .freq
= 19800, .xf
= 8, .wb_int
= 44, .wb_frac
= 466033, },
47 { .freq
= 20000, .xf
= 9, .wb_int
= 44, .wb_frac
= 0, },
48 { .freq
= 25000, .xf
= 10, .wb_int
= 70, .wb_frac
= 419430, },
49 { .freq
= 26000, .xf
= 11, .wb_int
= 67, .wb_frac
= 725937, },
50 { .freq
= 30000, .xf
= 12, .wb_int
= 58, .wb_frac
= 699050, },
51 { .freq
= 38400, .xf
= 13, .wb_int
= 45, .wb_frac
= 873813, },
52 { .freq
= 40000, .xf
= 14, .wb_int
= 45, .wb_frac
= 0, },
54 #define SSB_PMU0_DEFAULT_XTALFREQ 20000
56 static const struct pmu0_plltab_entry
* pmu0_plltab_find_entry(u32 crystalfreq
)
58 const struct pmu0_plltab_entry
*e
;
61 for (i
= 0; i
< ARRAY_SIZE(pmu0_plltab
); i
++) {
63 if (e
->freq
== crystalfreq
)
70 /* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
71 static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon
*cc
,
74 struct ssb_bus
*bus
= cc
->dev
->bus
;
75 const struct pmu0_plltab_entry
*e
= NULL
;
76 u32 pmuctl
, tmp
, pllctl
;
79 if ((bus
->chip_id
== 0x5354) && !crystalfreq
) {
80 /* The 5354 crystal freq is 25MHz */
84 e
= pmu0_plltab_find_entry(crystalfreq
);
86 e
= pmu0_plltab_find_entry(SSB_PMU0_DEFAULT_XTALFREQ
);
88 crystalfreq
= e
->freq
;
89 cc
->pmu
.crystalfreq
= e
->freq
;
91 /* Check if the PLL already is programmed to this frequency. */
92 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
93 if (((pmuctl
& SSB_CHIPCO_PMU_CTL_XTALFREQ
) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) == e
->xf
) {
94 /* We're already there... */
98 ssb_printk(KERN_INFO PFX
"Programming PLL to %u.%03u MHz\n",
99 (crystalfreq
/ 1000), (crystalfreq
% 1000));
101 /* First turn the PLL off. */
102 switch (bus
->chip_id
) {
104 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
,
105 ~(1 << SSB_PMURES_4328_BB_PLL_PU
));
106 chipco_mask32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
,
107 ~(1 << SSB_PMURES_4328_BB_PLL_PU
));
110 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
,
111 ~(1 << SSB_PMURES_5354_BB_PLL_PU
));
112 chipco_mask32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
,
113 ~(1 << SSB_PMURES_5354_BB_PLL_PU
));
118 for (i
= 1500; i
; i
--) {
119 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
120 if (!(tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
))
124 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
125 if (tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
)
126 ssb_printk(KERN_EMERG PFX
"Failed to turn the PLL off!\n");
128 /* Set PDIV in PLL control 0. */
129 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU0_PLLCTL0
);
130 if (crystalfreq
>= SSB_PMU0_PLLCTL0_PDIV_FREQ
)
131 pllctl
|= SSB_PMU0_PLLCTL0_PDIV_MSK
;
133 pllctl
&= ~SSB_PMU0_PLLCTL0_PDIV_MSK
;
134 ssb_chipco_pll_write(cc
, SSB_PMU0_PLLCTL0
, pllctl
);
136 /* Set WILD in PLL control 1. */
137 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU0_PLLCTL1
);
138 pllctl
&= ~SSB_PMU0_PLLCTL1_STOPMOD
;
139 pllctl
&= ~(SSB_PMU0_PLLCTL1_WILD_IMSK
| SSB_PMU0_PLLCTL1_WILD_FMSK
);
140 pllctl
|= ((u32
)e
->wb_int
<< SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT
) & SSB_PMU0_PLLCTL1_WILD_IMSK
;
141 pllctl
|= ((u32
)e
->wb_frac
<< SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT
) & SSB_PMU0_PLLCTL1_WILD_FMSK
;
143 pllctl
|= SSB_PMU0_PLLCTL1_STOPMOD
;
144 ssb_chipco_pll_write(cc
, SSB_PMU0_PLLCTL1
, pllctl
);
146 /* Set WILD in PLL control 2. */
147 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU0_PLLCTL2
);
148 pllctl
&= ~SSB_PMU0_PLLCTL2_WILD_IMSKHI
;
149 pllctl
|= (((u32
)e
->wb_int
>> 4) << SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT
) & SSB_PMU0_PLLCTL2_WILD_IMSKHI
;
150 ssb_chipco_pll_write(cc
, SSB_PMU0_PLLCTL2
, pllctl
);
152 /* Set the crystalfrequency and the divisor. */
153 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
154 pmuctl
&= ~SSB_CHIPCO_PMU_CTL_ILP_DIV
;
155 pmuctl
|= (((crystalfreq
+ 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT
)
156 & SSB_CHIPCO_PMU_CTL_ILP_DIV
;
157 pmuctl
&= ~SSB_CHIPCO_PMU_CTL_XTALFREQ
;
158 pmuctl
|= ((u32
)e
->xf
<< SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) & SSB_CHIPCO_PMU_CTL_XTALFREQ
;
159 chipco_write32(cc
, SSB_CHIPCO_PMU_CTL
, pmuctl
);
162 struct pmu1_plltab_entry
{
163 u16 freq
; /* Crystal frequency in kHz.*/
164 u8 xf
; /* Crystal frequency value for PMU control */
171 static const struct pmu1_plltab_entry pmu1_plltab
[] = {
172 { .freq
= 12000, .xf
= 1, .p1div
= 3, .p2div
= 22, .ndiv_int
= 0x9, .ndiv_frac
= 0xFFFFEF, },
173 { .freq
= 13000, .xf
= 2, .p1div
= 1, .p2div
= 6, .ndiv_int
= 0xb, .ndiv_frac
= 0x483483, },
174 { .freq
= 14400, .xf
= 3, .p1div
= 1, .p2div
= 10, .ndiv_int
= 0xa, .ndiv_frac
= 0x1C71C7, },
175 { .freq
= 15360, .xf
= 4, .p1div
= 1, .p2div
= 5, .ndiv_int
= 0xb, .ndiv_frac
= 0x755555, },
176 { .freq
= 16200, .xf
= 5, .p1div
= 1, .p2div
= 10, .ndiv_int
= 0x5, .ndiv_frac
= 0x6E9E06, },
177 { .freq
= 16800, .xf
= 6, .p1div
= 1, .p2div
= 10, .ndiv_int
= 0x5, .ndiv_frac
= 0x3CF3CF, },
178 { .freq
= 19200, .xf
= 7, .p1div
= 1, .p2div
= 9, .ndiv_int
= 0x5, .ndiv_frac
= 0x17B425, },
179 { .freq
= 19800, .xf
= 8, .p1div
= 1, .p2div
= 11, .ndiv_int
= 0x4, .ndiv_frac
= 0xA57EB, },
180 { .freq
= 20000, .xf
= 9, .p1div
= 1, .p2div
= 11, .ndiv_int
= 0x4, .ndiv_frac
= 0, },
181 { .freq
= 24000, .xf
= 10, .p1div
= 3, .p2div
= 11, .ndiv_int
= 0xa, .ndiv_frac
= 0, },
182 { .freq
= 25000, .xf
= 11, .p1div
= 5, .p2div
= 16, .ndiv_int
= 0xb, .ndiv_frac
= 0, },
183 { .freq
= 26000, .xf
= 12, .p1div
= 1, .p2div
= 2, .ndiv_int
= 0x10, .ndiv_frac
= 0xEC4EC4, },
184 { .freq
= 30000, .xf
= 13, .p1div
= 3, .p2div
= 8, .ndiv_int
= 0xb, .ndiv_frac
= 0, },
185 { .freq
= 38400, .xf
= 14, .p1div
= 1, .p2div
= 5, .ndiv_int
= 0x4, .ndiv_frac
= 0x955555, },
186 { .freq
= 40000, .xf
= 15, .p1div
= 1, .p2div
= 2, .ndiv_int
= 0xb, .ndiv_frac
= 0, },
189 #define SSB_PMU1_DEFAULT_XTALFREQ 15360
191 static const struct pmu1_plltab_entry
* pmu1_plltab_find_entry(u32 crystalfreq
)
193 const struct pmu1_plltab_entry
*e
;
196 for (i
= 0; i
< ARRAY_SIZE(pmu1_plltab
); i
++) {
198 if (e
->freq
== crystalfreq
)
205 /* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
206 static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon
*cc
,
209 struct ssb_bus
*bus
= cc
->dev
->bus
;
210 const struct pmu1_plltab_entry
*e
= NULL
;
211 u32 buffer_strength
= 0;
212 u32 tmp
, pllctl
, pmuctl
;
215 if (bus
->chip_id
== 0x4312) {
216 /* We do not touch the BCM4312 PLL and assume
217 * the default crystal settings work out-of-the-box. */
218 cc
->pmu
.crystalfreq
= 20000;
223 e
= pmu1_plltab_find_entry(crystalfreq
);
225 e
= pmu1_plltab_find_entry(SSB_PMU1_DEFAULT_XTALFREQ
);
227 crystalfreq
= e
->freq
;
228 cc
->pmu
.crystalfreq
= e
->freq
;
230 /* Check if the PLL already is programmed to this frequency. */
231 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
232 if (((pmuctl
& SSB_CHIPCO_PMU_CTL_XTALFREQ
) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) == e
->xf
) {
233 /* We're already there... */
237 ssb_printk(KERN_INFO PFX
"Programming PLL to %u.%03u MHz\n",
238 (crystalfreq
/ 1000), (crystalfreq
% 1000));
240 /* First turn the PLL off. */
241 switch (bus
->chip_id
) {
243 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
,
244 ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU
) |
245 (1 << SSB_PMURES_4325_HT_AVAIL
)));
246 chipco_mask32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
,
247 ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU
) |
248 (1 << SSB_PMURES_4325_HT_AVAIL
)));
249 /* Adjust the BBPLL to 2 on all channels later. */
250 buffer_strength
= 0x222222;
255 for (i
= 1500; i
; i
--) {
256 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
257 if (!(tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
))
261 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
262 if (tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
)
263 ssb_printk(KERN_EMERG PFX
"Failed to turn the PLL off!\n");
265 /* Set p1div and p2div. */
266 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL0
);
267 pllctl
&= ~(SSB_PMU1_PLLCTL0_P1DIV
| SSB_PMU1_PLLCTL0_P2DIV
);
268 pllctl
|= ((u32
)e
->p1div
<< SSB_PMU1_PLLCTL0_P1DIV_SHIFT
) & SSB_PMU1_PLLCTL0_P1DIV
;
269 pllctl
|= ((u32
)e
->p2div
<< SSB_PMU1_PLLCTL0_P2DIV_SHIFT
) & SSB_PMU1_PLLCTL0_P2DIV
;
270 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL0
, pllctl
);
272 /* Set ndiv int and ndiv mode */
273 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL2
);
274 pllctl
&= ~(SSB_PMU1_PLLCTL2_NDIVINT
| SSB_PMU1_PLLCTL2_NDIVMODE
);
275 pllctl
|= ((u32
)e
->ndiv_int
<< SSB_PMU1_PLLCTL2_NDIVINT_SHIFT
) & SSB_PMU1_PLLCTL2_NDIVINT
;
276 pllctl
|= (1 << SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT
) & SSB_PMU1_PLLCTL2_NDIVMODE
;
277 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL2
, pllctl
);
280 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL3
);
281 pllctl
&= ~SSB_PMU1_PLLCTL3_NDIVFRAC
;
282 pllctl
|= ((u32
)e
->ndiv_frac
<< SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT
) & SSB_PMU1_PLLCTL3_NDIVFRAC
;
283 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL3
, pllctl
);
285 /* Change the drive strength, if required. */
286 if (buffer_strength
) {
287 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL5
);
288 pllctl
&= ~SSB_PMU1_PLLCTL5_CLKDRV
;
289 pllctl
|= (buffer_strength
<< SSB_PMU1_PLLCTL5_CLKDRV_SHIFT
) & SSB_PMU1_PLLCTL5_CLKDRV
;
290 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL5
, pllctl
);
293 /* Tune the crystalfreq and the divisor. */
294 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
295 pmuctl
&= ~(SSB_CHIPCO_PMU_CTL_ILP_DIV
| SSB_CHIPCO_PMU_CTL_XTALFREQ
);
296 pmuctl
|= ((((u32
)e
->freq
+ 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT
)
297 & SSB_CHIPCO_PMU_CTL_ILP_DIV
;
298 pmuctl
|= ((u32
)e
->xf
<< SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) & SSB_CHIPCO_PMU_CTL_XTALFREQ
;
299 chipco_write32(cc
, SSB_CHIPCO_PMU_CTL
, pmuctl
);
302 static void ssb_pmu_pll_init(struct ssb_chipcommon
*cc
)
304 struct ssb_bus
*bus
= cc
->dev
->bus
;
305 u32 crystalfreq
= 0; /* in kHz. 0 = keep default freq. */
307 if (bus
->bustype
== SSB_BUSTYPE_SSB
) {
308 /* TODO: The user may override the crystal frequency. */
311 switch (bus
->chip_id
) {
314 ssb_pmu1_pllinit_r0(cc
, crystalfreq
);
318 ssb_pmu0_pllinit_r0(cc
, crystalfreq
);
321 ssb_printk(KERN_ERR PFX
322 "ERROR: PLL init unknown for device %04X\n",
327 struct pmu_res_updown_tab_entry
{
328 u8 resource
; /* The resource number */
329 u16 updown
; /* The updown value */
332 enum pmu_res_depend_tab_task
{
338 struct pmu_res_depend_tab_entry
{
339 u8 resource
; /* The resource number */
340 u8 task
; /* SET | ADD | REMOVE */
341 u32 depend
; /* The depend mask */
344 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4328a0
[] = {
345 { .resource
= SSB_PMURES_4328_EXT_SWITCHER_PWM
, .updown
= 0x0101, },
346 { .resource
= SSB_PMURES_4328_BB_SWITCHER_PWM
, .updown
= 0x1F01, },
347 { .resource
= SSB_PMURES_4328_BB_SWITCHER_BURST
, .updown
= 0x010F, },
348 { .resource
= SSB_PMURES_4328_BB_EXT_SWITCHER_BURST
, .updown
= 0x0101, },
349 { .resource
= SSB_PMURES_4328_ILP_REQUEST
, .updown
= 0x0202, },
350 { .resource
= SSB_PMURES_4328_RADIO_SWITCHER_PWM
, .updown
= 0x0F01, },
351 { .resource
= SSB_PMURES_4328_RADIO_SWITCHER_BURST
, .updown
= 0x0F01, },
352 { .resource
= SSB_PMURES_4328_ROM_SWITCH
, .updown
= 0x0101, },
353 { .resource
= SSB_PMURES_4328_PA_REF_LDO
, .updown
= 0x0F01, },
354 { .resource
= SSB_PMURES_4328_RADIO_LDO
, .updown
= 0x0F01, },
355 { .resource
= SSB_PMURES_4328_AFE_LDO
, .updown
= 0x0F01, },
356 { .resource
= SSB_PMURES_4328_PLL_LDO
, .updown
= 0x0F01, },
357 { .resource
= SSB_PMURES_4328_BG_FILTBYP
, .updown
= 0x0101, },
358 { .resource
= SSB_PMURES_4328_TX_FILTBYP
, .updown
= 0x0101, },
359 { .resource
= SSB_PMURES_4328_RX_FILTBYP
, .updown
= 0x0101, },
360 { .resource
= SSB_PMURES_4328_XTAL_PU
, .updown
= 0x0101, },
361 { .resource
= SSB_PMURES_4328_XTAL_EN
, .updown
= 0xA001, },
362 { .resource
= SSB_PMURES_4328_BB_PLL_FILTBYP
, .updown
= 0x0101, },
363 { .resource
= SSB_PMURES_4328_RF_PLL_FILTBYP
, .updown
= 0x0101, },
364 { .resource
= SSB_PMURES_4328_BB_PLL_PU
, .updown
= 0x0701, },
367 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4328a0
[] = {
369 /* Adjust ILP Request to avoid forcing EXT/BB into burst mode. */
370 .resource
= SSB_PMURES_4328_ILP_REQUEST
,
371 .task
= PMU_RES_DEP_SET
,
372 .depend
= ((1 << SSB_PMURES_4328_EXT_SWITCHER_PWM
) |
373 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM
)),
377 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4325a0
[] = {
378 { .resource
= SSB_PMURES_4325_XTAL_PU
, .updown
= 0x1501, },
381 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4325a0
[] = {
383 /* Adjust HT-Available dependencies. */
384 .resource
= SSB_PMURES_4325_HT_AVAIL
,
385 .task
= PMU_RES_DEP_ADD
,
386 .depend
= ((1 << SSB_PMURES_4325_RX_PWRSW_PU
) |
387 (1 << SSB_PMURES_4325_TX_PWRSW_PU
) |
388 (1 << SSB_PMURES_4325_LOGEN_PWRSW_PU
) |
389 (1 << SSB_PMURES_4325_AFE_PWRSW_PU
)),
393 static void ssb_pmu_resources_init(struct ssb_chipcommon
*cc
)
395 struct ssb_bus
*bus
= cc
->dev
->bus
;
396 u32 min_msk
= 0, max_msk
= 0;
398 const struct pmu_res_updown_tab_entry
*updown_tab
= NULL
;
399 unsigned int updown_tab_size
;
400 const struct pmu_res_depend_tab_entry
*depend_tab
= NULL
;
401 unsigned int depend_tab_size
;
403 switch (bus
->chip_id
) {
405 /* We keep the default settings:
411 /* Power OTP down later. */
412 min_msk
= (1 << SSB_PMURES_4325_CBUCK_BURST
) |
413 (1 << SSB_PMURES_4325_LNLDO2_PU
);
414 if (chipco_read32(cc
, SSB_CHIPCO_CHIPSTAT
) &
415 SSB_CHIPCO_CHST_4325_PMUTOP_2B
)
416 min_msk
|= (1 << SSB_PMURES_4325_CLDO_CBUCK_BURST
);
417 /* The PLL may turn on, if it decides so. */
419 updown_tab
= pmu_res_updown_tab_4325a0
;
420 updown_tab_size
= ARRAY_SIZE(pmu_res_updown_tab_4325a0
);
421 depend_tab
= pmu_res_depend_tab_4325a0
;
422 depend_tab_size
= ARRAY_SIZE(pmu_res_depend_tab_4325a0
);
425 min_msk
= (1 << SSB_PMURES_4328_EXT_SWITCHER_PWM
) |
426 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM
) |
427 (1 << SSB_PMURES_4328_XTAL_EN
);
428 /* The PLL may turn on, if it decides so. */
430 updown_tab
= pmu_res_updown_tab_4328a0
;
431 updown_tab_size
= ARRAY_SIZE(pmu_res_updown_tab_4328a0
);
432 depend_tab
= pmu_res_depend_tab_4328a0
;
433 depend_tab_size
= ARRAY_SIZE(pmu_res_depend_tab_4328a0
);
436 /* The PLL may turn on, if it decides so. */
440 ssb_printk(KERN_ERR PFX
441 "ERROR: PMU resource config unknown for device %04X\n",
446 for (i
= 0; i
< updown_tab_size
; i
++) {
447 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_TABSEL
,
448 updown_tab
[i
].resource
);
449 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_UPDNTM
,
450 updown_tab
[i
].updown
);
454 for (i
= 0; i
< depend_tab_size
; i
++) {
455 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_TABSEL
,
456 depend_tab
[i
].resource
);
457 switch (depend_tab
[i
].task
) {
458 case PMU_RES_DEP_SET
:
459 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
460 depend_tab
[i
].depend
);
462 case PMU_RES_DEP_ADD
:
463 chipco_set32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
464 depend_tab
[i
].depend
);
466 case PMU_RES_DEP_REMOVE
:
467 chipco_mask32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
468 ~(depend_tab
[i
].depend
));
476 /* Set the resource masks. */
478 chipco_write32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, min_msk
);
480 chipco_write32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
, max_msk
);
483 void ssb_pmu_init(struct ssb_chipcommon
*cc
)
485 struct ssb_bus
*bus
= cc
->dev
->bus
;
488 if (!(cc
->capabilities
& SSB_CHIPCO_CAP_PMU
))
491 pmucap
= chipco_read32(cc
, SSB_CHIPCO_PMU_CAP
);
492 cc
->pmu
.rev
= (pmucap
& SSB_CHIPCO_PMU_CAP_REVISION
);
494 ssb_dprintk(KERN_DEBUG PFX
"Found rev %u PMU (capabilities 0x%08X)\n",
495 cc
->pmu
.rev
, pmucap
);
497 if (cc
->pmu
.rev
>= 1) {
498 if ((bus
->chip_id
== 0x4325) && (bus
->chip_rev
< 2)) {
499 chipco_mask32(cc
, SSB_CHIPCO_PMU_CTL
,
500 ~SSB_CHIPCO_PMU_CTL_NOILPONW
);
502 chipco_set32(cc
, SSB_CHIPCO_PMU_CTL
,
503 SSB_CHIPCO_PMU_CTL_NOILPONW
);
506 ssb_pmu_pll_init(cc
);
507 ssb_pmu_resources_init(cc
);