2 * Misc utility routines for accessing PMU corerev specific features
3 * of the SiliconBackplane-based Broadcom chips.
5 * Copyright 2007, Broadcom Corporation
8 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
9 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
10 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
11 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
25 #define PMU_ERROR(args)
28 #define PMU_MSG(args) printf args
34 /* PMU rev 0 pll control for BCM4328 and BCM5354 */
35 static void sb_pmu0_pllinit0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
,
37 static uint32
sb_pmu0_alpclk0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
);
38 static uint32
sb_pmu0_cpuclk0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
);
39 /* PMU rev 0 pll control for BCM4325 BCM4329 */
40 static void sb_pmu1_pllinit0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
,
42 static uint32
sb_pmu1_cpuclk0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
);
43 static uint32
sb_pmu1_alpclk0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
);
45 /* Setup switcher voltage */
47 BCMINITFN (sb_pmu_set_switcher_voltage
) (sb_t
* sbh
, osl_t
* osh
,
48 uint8 bb_voltage
, uint8 rf_voltage
)
53 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
55 /* Remember original core before switch to chipc */
56 origidx
= sb_coreidx (sbh
);
57 cc
= sb_setcore (sbh
, SB_CC
, 0);
60 W_REG (osh
, &cc
->regcontrol_addr
, 0x01);
61 W_REG (osh
, &cc
->regcontrol_data
, (uint32
) (bb_voltage
& 0x1f) << 22);
63 W_REG (osh
, &cc
->regcontrol_addr
, 0x00);
64 W_REG (osh
, &cc
->regcontrol_data
, (uint32
) (rf_voltage
& 0x1f) << 14);
66 /* Return to original core */
67 sb_setcoreidx (sbh
, origidx
);
71 sb_pmu_set_ldo_voltage (sb_t
* sbh
, osl_t
* osh
, uint8 ldo
, uint8 voltage
)
73 uint8 sr_cntl_shift
, rc_shift
, shift
, mask
;
76 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
84 case SET_LDO_VOLTAGE_LDO1
:
90 case SET_LDO_VOLTAGE_LDO2
:
96 case SET_LDO_VOLTAGE_LDO3
:
102 case SET_LDO_VOLTAGE_PAREF
:
113 case BCM4312_CHIP_ID
:
116 case SET_LDO_VOLTAGE_PAREF
:
132 shift
= sr_cntl_shift
+ rc_shift
;
134 sb_corereg (sbh
, SB_CC_IDX
, OFFSETOF (chipcregs_t
, regcontrol_addr
),
136 sb_corereg (sbh
, SB_CC_IDX
, OFFSETOF (chipcregs_t
, regcontrol_data
),
137 mask
<< shift
, (voltage
& mask
) << shift
);
141 sb_pmu_paref_ldo_enable (sb_t
* sbh
, osl_t
* osh
, bool enable
)
145 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
149 case BCM4328_CHIP_ID
:
150 ldo
= RES4328_PA_REF_LDO
;
152 case BCM5354_CHIP_ID
:
153 ldo
= RES5354_PA_REF_LDO
;
155 case BCM4312_CHIP_ID
:
156 ldo
= RES4312_PA_REF_LDO
;
162 sb_corereg (sbh
, SB_CC_IDX
, OFFSETOF (chipcregs_t
, min_res_mask
),
163 PMURES_BIT (ldo
), enable
? PMURES_BIT (ldo
) : 0);
166 uint16
BCMINITFN (sb_pmu_fast_pwrup_delay
) (sb_t
* sbh
, osl_t
* osh
)
168 uint16 delay
= PMU_MAX_TRANSITION_DLY
;
170 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
174 case BCM4328_CHIP_ID
:
178 case BCM4325_CHIP_ID
:
179 case BCM4312_CHIP_ID
:
188 PMU_MSG (("No PMU fast power up delay specified "
189 "for chip %x rev %d, using default %d us\n",
190 sbh
->chip
, sbh
->chiprev
, delay
));
197 uint32
BCMINITFN (sb_pmu_force_ilp
) (sb_t
* sbh
, osl_t
* osh
, bool force
)
201 uint32 oldpmucontrol
;
203 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
205 /* Remember original core before switch to chipc */
206 origidx
= sb_coreidx (sbh
);
207 cc
= sb_setcore (sbh
, SB_CC
, 0);
210 oldpmucontrol
= R_REG (osh
, &cc
->pmucontrol
);
212 W_REG (osh
, &cc
->pmucontrol
, oldpmucontrol
&
213 ~(PCTL_HT_REQ_EN
| PCTL_ALP_REQ_EN
));
215 W_REG (osh
, &cc
->pmucontrol
, oldpmucontrol
|
216 (PCTL_HT_REQ_EN
| PCTL_ALP_REQ_EN
));
218 /* Return to original core */
219 sb_setcoreidx (sbh
, origidx
);
221 return oldpmucontrol
;
224 /* Setup min/max resources and up/down timers */
234 int8 action
; /* 0 - set, 1 - add, -1 - remove */
238 static const pmu_res_updown_t
239 BCMINITDATA (bcm4328a0_res_updown
)[] =
242 RES4328_EXT_SWITCHER_PWM
, 0x0101},
244 RES4328_BB_SWITCHER_PWM
, 0x1f01},
246 RES4328_BB_SWITCHER_BURST
, 0x010f},
248 RES4328_BB_EXT_SWITCHER_BURST
, 0x0101},
250 RES4328_ILP_REQUEST
, 0x0202},
252 RES4328_RADIO_SWITCHER_PWM
, 0x0f01},
254 RES4328_RADIO_SWITCHER_BURST
, 0x0f01},
256 RES4328_ROM_SWITCH
, 0x0101},
258 RES4328_PA_REF_LDO
, 0x0f01},
260 RES4328_RADIO_LDO
, 0x0f01},
262 RES4328_AFE_LDO
, 0x0f01},
264 RES4328_PLL_LDO
, 0x0f01},
266 RES4328_BG_FILTBYP
, 0x0101},
268 RES4328_TX_FILTBYP
, 0x0101},
270 RES4328_RX_FILTBYP
, 0x0101},
272 RES4328_XTAL_PU
, 0x0101},
274 RES4328_XTAL_EN
, 0xa001},
276 RES4328_BB_PLL_FILTBYP
, 0x0101},
278 RES4328_RF_PLL_FILTBYP
, 0x0101},
280 RES4328_BB_PLL_PU
, 0x0701}
283 static const pmu_res_depend_t
284 BCMINITDATA (bcm4328a0_res_depend
)[] =
286 /* Adjust ILP request resource not to force ext/BB switchers into burst mode */
288 RES4328_ILP_REQUEST
, 0,
289 PMURES_BIT (RES4328_EXT_SWITCHER_PWM
) |
290 PMURES_BIT (RES4328_BB_SWITCHER_PWM
)}
293 #ifdef BCMQT /* for power save on slow QT/small beacon interval */
294 static const pmu_res_updown_t
295 BCMINITDATA (bcm4325a0_res_updown_qt
)[] =
298 RES4325_HT_AVAIL
, 0x0300},
300 RES4325_BBPLL_PWRSW_PU
, 0x0101},
302 RES4325_RFPLL_PWRSW_PU
, 0x0101},
304 RES4325_ALP_AVAIL
, 0x0100},
306 RES4325_XTAL_PU
, 0x1000},
308 RES4325_LNLDO1_PU
, 0x0800},
310 RES4325_CLDO_CBUCK_PWM
, 0x0101},
312 RES4325_CBUCK_PWM
, 0x0803}
315 static const pmu_res_updown_t
316 BCMINITDATA (bcm4325a0_res_updown
)[] =
319 RES4325_XTAL_PU
, 0x1501}
323 static const pmu_res_depend_t
324 BCMINITDATA (bcm4325a0_res_depend
)[] =
326 /* Adjust HT Avail resource dependencies */
329 PMURES_BIT (RES4325_RX_PWRSW_PU
) | PMURES_BIT (RES4325_TX_PWRSW_PU
) |
330 PMURES_BIT (RES4325_LOGEN_PWRSW_PU
) | PMURES_BIT (RES4325_AFE_PWRSW_PU
)}
333 void BCMINITFN (sb_pmu_res_init
) (sb_t
* sbh
, osl_t
* osh
)
337 const pmu_res_updown_t
*pmu_res_updown_table
= NULL
;
338 int pmu_res_updown_table_sz
= 0;
339 const pmu_res_depend_t
*pmu_res_depend_table
= NULL
;
340 int pmu_res_depend_table_sz
= 0;
341 uint32 min_mask
= 0, max_mask
= 0;
343 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
345 /* Remember original core before switch to chipc */
346 origidx
= sb_coreidx (sbh
);
347 cc
= sb_setcore (sbh
, SB_CC
, 0);
352 case BCM4328_CHIP_ID
:
353 /* Down to ILP request excluding ROM */
354 min_mask
= PMURES_BIT (RES4328_EXT_SWITCHER_PWM
) |
355 PMURES_BIT (RES4328_BB_SWITCHER_PWM
) | PMURES_BIT (RES4328_XTAL_EN
);
358 min_mask
|= PMURES_BIT (RES4328_ROM_SWITCH
);
360 /* Allow (but don't require) PLL to turn on */
362 pmu_res_updown_table
= bcm4328a0_res_updown
;
363 pmu_res_updown_table_sz
= ARRAYSIZE (bcm4328a0_res_updown
);
364 pmu_res_depend_table
= bcm4328a0_res_depend
;
365 pmu_res_depend_table_sz
= ARRAYSIZE (bcm4328a0_res_depend
);
367 case BCM4312_CHIP_ID
:
369 * min_mask = 0xcbb; max_mask = 0x7ffff;
370 * pmu_res_updown_table_sz = 0;
371 * pmu_res_depend_table_sz = 0;
374 case BCM5354_CHIP_ID
:
375 /* Allow (but don't require) PLL to turn on */
379 case BCM4325_CHIP_ID
:
380 /* Leave OTP powered up and power it down later. */
382 PMURES_BIT (RES4325_CBUCK_BURST
) | PMURES_BIT (RES4325_LNLDO2_PU
);
383 if (((sbh
->chipst
& CST4325_PMUTOP_2B_MASK
) >>
384 CST4325_PMUTOP_2B_SHIFT
) == 1)
385 min_mask
|= PMURES_BIT (RES4325_CLDO_CBUCK_BURST
);
386 /* Allow (but don't require) PLL to turn on */
389 pmu_res_updown_table
= bcm4325a0_res_updown_qt
;
390 pmu_res_updown_table_sz
= ARRAYSIZE (bcm4325a0_res_updown_qt
);
392 pmu_res_updown_table
= bcm4325a0_res_updown
;
393 pmu_res_updown_table_sz
= ARRAYSIZE (bcm4325a0_res_updown
);
394 pmu_res_depend_table
= bcm4325a0_res_depend
;
395 pmu_res_depend_table_sz
= ARRAYSIZE (bcm4325a0_res_depend
);
403 /* Program up/down timers */
404 while (pmu_res_updown_table_sz
--)
406 ASSERT (pmu_res_updown_table
);
407 W_REG (osh
, &cc
->res_table_sel
,
408 pmu_res_updown_table
[pmu_res_updown_table_sz
].resnum
);
409 W_REG (osh
, &cc
->res_updn_timer
,
410 pmu_res_updown_table
[pmu_res_updown_table_sz
].updown
);
413 /* Program resource dependencies table */
414 while (pmu_res_depend_table_sz
--)
416 ASSERT (pmu_res_depend_table
);
417 W_REG (osh
, &cc
->res_table_sel
,
418 pmu_res_depend_table
[pmu_res_depend_table_sz
].resnum
);
419 switch (pmu_res_depend_table
[pmu_res_depend_table_sz
].action
)
422 W_REG (osh
, &cc
->res_dep_mask
,
423 pmu_res_depend_table
[pmu_res_depend_table_sz
].depend_mask
);
426 OR_REG (osh
, &cc
->res_dep_mask
,
427 pmu_res_depend_table
[pmu_res_depend_table_sz
].depend_mask
);
430 AND_REG (osh
, &cc
->res_dep_mask
,
431 ~pmu_res_depend_table
[pmu_res_depend_table_sz
].
440 /* program min resource mask */
443 PMU_MSG (("Changing min_res_mask to 0x%x\n", min_mask
));
444 W_REG (osh
, &cc
->min_res_mask
, min_mask
);
446 /* program max resource mask */
449 PMU_MSG (("Changing max_res_mask to 0x%x\n", max_mask
));
450 W_REG (osh
, &cc
->max_res_mask
, max_mask
);
453 /* Return to original core */
454 sb_setcoreidx (sbh
, origidx
);
457 /* setup pll and query clock speed */
466 /* the following table is based on 880Mhz Fvco */
467 #define PMU0_PLL0_FVCO 880000 /* Fvco 880Mhz */
468 static const pmu0_xtaltab0_t
469 BCMINITDATA (pmu0_xtaltab0
)[] =
472 12000, 1, 73, 349525},
474 13000, 2, 67, 725937},
476 14400, 3, 61, 116508},
478 15360, 4, 57, 305834},
480 16200, 5, 54, 336579},
482 16800, 6, 52, 399457},
484 19200, 7, 45, 873813},
486 19800, 8, 44, 466033},
490 25000, 10, 70, 419430},
492 26000, 11, 67, 725937},
494 30000, 12, 58, 699050},
496 38400, 13, 45, 873813},
504 #define PMU0_XTAL0_DEFAULT 11
506 #define PMU0_XTAL0_DEFAULT 8
511 * Set new backplane PLL clock frequency
513 static void BCMINITFN (sb_pmu0_sbclk4328
) (sb_t
* sbh
, int freq
)
515 uint32 tmp
, oldmax
, oldmin
, origidx
;
518 /* Remember original core before switch to chipc */
519 origidx
= sb_coreidx (sbh
);
520 cc
= sb_setcore (sbh
, SB_CC
, 0);
523 /* Set new backplane PLL clock */
524 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL0
);
525 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
526 tmp
&= ~(PMU0_PLL0_PC0_DIV_ARM_MASK
);
527 tmp
|= freq
<< PMU0_PLL0_PC0_DIV_ARM_SHIFT
;
528 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
530 /* Power cycle BB_PLL_PU by disabling/enabling it to take on new freq */
532 oldmin
= R_REG (osh
, &cc
->min_res_mask
);
533 oldmax
= R_REG (osh
, &cc
->max_res_mask
);
534 W_REG (osh
, &cc
->min_res_mask
, oldmin
& ~PMURES_BIT (RES4328_BB_PLL_PU
));
535 W_REG (osh
, &cc
->max_res_mask
, oldmax
& ~PMURES_BIT (RES4328_BB_PLL_PU
));
537 /* It takes over several hundred usec to re-enable the PLL since the
538 * sequencer state machines run on ILP clock. Set delay at 450us to be safe.
540 * Be sure PLL is powered down first before re-enabling it.
543 OSL_DELAY (PLL_DELAY
);
544 SPINWAIT ((R_REG (osh
, &cc
->res_state
) & PMURES_BIT (RES4328_BB_PLL_PU
)),
547 if (R_REG (osh
, &cc
->res_state
) & PMURES_BIT (RES4328_BB_PLL_PU
))
549 /* If BB_PLL not powered down yet, new backplane PLL clock
550 * may not take effect.
552 * Still early during bootup so no serial output here.
554 PMU_ERROR (("Fatal: BB_PLL not power down yet!\n"));
556 (R_REG (osh
, &cc
->res_state
) & PMURES_BIT (RES4328_BB_PLL_PU
)));
560 W_REG (osh
, &cc
->max_res_mask
, oldmax
);
562 /* Return to original core */
563 sb_setcoreidx (sbh
, origidx
);
565 #endif /* BCMUSBDEV */
567 /* Set up PLL registers in the PMU as per the crystal speed.
568 * Uses xtalfreq variable, or passed-in default.
571 BCMINITFN (sb_pmu0_pllinit0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
,
575 const pmu0_xtaltab0_t
*xt
;
577 if ((sb_chip (sbh
) == BCM5354_CHIP_ID
) && (xtal
== 0))
579 /* 5354 has xtal freq of 25MHz */
583 /* Find the frequency in the table */
584 for (xt
= pmu0_xtaltab0
; xt
->freq
; xt
++)
585 if (xt
->freq
== xtal
)
588 xt
= &pmu0_xtaltab0
[PMU0_XTAL0_DEFAULT
];
590 PMU_MSG (("XTAL %d (%d)\n", xtal
, xt
->xf
));
592 /* Check current PLL state */
593 tmp
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
597 PMU_MSG (("PLL already programmed for %d.%d MHz\n",
598 (xt
->freq
/ 1000), (xt
->freq
% 1000)));
601 if (sbh
->chip
== BCM4328_CHIP_ID
)
602 sb_pmu0_sbclk4328 (sbh
, PMU0_PLL0_PC0_DIV_ARM_88MHZ
);
609 PMU_MSG (("Reprogramming PLL for %d.%d MHz (was %d.%dMHz)\n",
610 (xt
->freq
/ 1000), (xt
->freq
% 1000),
611 (pmu0_xtaltab0
[tmp
- 1].freq
/ 1000),
612 (pmu0_xtaltab0
[tmp
- 1].freq
% 1000)));
616 PMU_MSG (("Programming PLL for %d.%d MHz\n", (xt
->freq
/ 1000),
620 /* Make sure the PLL is off */
623 case BCM4328_CHIP_ID
:
624 AND_REG (osh
, &cc
->min_res_mask
, ~PMURES_BIT (RES4328_BB_PLL_PU
));
625 AND_REG (osh
, &cc
->max_res_mask
, ~PMURES_BIT (RES4328_BB_PLL_PU
));
627 case BCM5354_CHIP_ID
:
628 AND_REG (osh
, &cc
->min_res_mask
, ~PMURES_BIT (RES5354_BB_PLL_PU
));
629 AND_REG (osh
, &cc
->max_res_mask
, ~PMURES_BIT (RES5354_BB_PLL_PU
));
634 SPINWAIT (R_REG (osh
, &cc
->clk_ctl_st
) & CCS0_HTAVAIL
,
635 PMU_MAX_TRANSITION_DLY
);
636 ASSERT (!(R_REG (osh
, &cc
->clk_ctl_st
) & CCS0_HTAVAIL
));
638 PMU_MSG (("Done masking\n"));
640 /* Write PDIV in pllcontrol[0] */
641 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL0
);
642 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
643 if (xt
->freq
>= PMU0_PLL0_PC0_PDIV_FREQ
)
644 tmp
|= PMU0_PLL0_PC0_PDIV_MASK
;
646 tmp
&= ~PMU0_PLL0_PC0_PDIV_MASK
;
647 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
649 /* Write WILD in pllcontrol[1] */
650 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL1
);
651 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
653 ((tmp
& ~(PMU0_PLL0_PC1_WILD_INT_MASK
| PMU0_PLL0_PC1_WILD_FRAC_MASK
)) |
655 wbint
<< PMU0_PLL0_PC1_WILD_INT_SHIFT
) & PMU0_PLL0_PC1_WILD_INT_MASK
)
656 | ((xt
->wbfrac
<< PMU0_PLL0_PC1_WILD_FRAC_SHIFT
) &
657 PMU0_PLL0_PC1_WILD_FRAC_MASK
)));
659 tmp
|= PMU0_PLL0_PC1_STOP_MOD
;
661 tmp
&= ~PMU0_PLL0_PC1_STOP_MOD
;
662 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
664 /* Write WILD in pllcontrol[2] */
665 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL2
);
666 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
667 tmp
= ((tmp
& ~PMU0_PLL0_PC2_WILD_INT_MASK
) |
668 ((xt
->wbint
>> PMU0_PLL0_PC2_WILD_INT_SHIFT
) &
669 PMU0_PLL0_PC2_WILD_INT_MASK
));
670 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
672 PMU_MSG (("Done pll\n"));
674 /* Write XtalFreq. Set the divisor also. */
675 tmp
= R_REG (osh
, &cc
->pmucontrol
);
676 tmp
= ((tmp
& ~PCTL_ILP_DIV_MASK
) |
677 (((((xt
->freq
+ 127) / 128) - 1) << PCTL_ILP_DIV_SHIFT
) &
679 tmp
= ((tmp
& ~PCTL_XTALFREQ_MASK
) |
680 ((xt
->xf
<< PCTL_XTALFREQ_SHIFT
) & PCTL_XTALFREQ_MASK
));
681 W_REG (osh
, &cc
->pmucontrol
, tmp
);
685 BCMINITFN (sb_pmu0_alpclk0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
)
687 const pmu0_xtaltab0_t
*xt
;
690 /* Find the frequency in the table */
691 xf
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
693 for (xt
= pmu0_xtaltab0
; xt
->freq
; xt
++)
697 xt
= &pmu0_xtaltab0
[PMU0_XTAL0_DEFAULT
];
699 return xt
->freq
* 1000;
703 BCMINITFN (sb_pmu0_cpuclk0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
)
705 const pmu0_xtaltab0_t
*xt
;
706 uint32 xf
, tmp
, divarm
;
708 uint32 pdiv
, wbint
, wbfrac
, fvco
;
711 if (sb_chip (sbh
) == BCM5354_CHIP_ID
)
713 /* 5354 gets sb clock of 120MHz from main pll */
717 /* Find the xtal frequency in the table */
718 xf
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
720 for (xt
= pmu0_xtaltab0
; xt
->freq
; xt
++)
724 xt
= &pmu0_xtaltab0
[PMU0_XTAL0_DEFAULT
];
726 /* Read divarm from pllcontrol[0] */
727 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL0
);
728 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
729 divarm
= (tmp
& PMU0_PLL0_PC0_DIV_ARM_MASK
) >> PMU0_PLL0_PC0_DIV_ARM_SHIFT
;
732 /* Calculate Fvco based on xtal freq, pdiv, and wild */
733 pdiv
= tmp
& PMU0_PLL0_PC0_PDIV_MASK
;
735 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL1
);
736 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
738 (tmp
& PMU0_PLL0_PC1_WILD_FRAC_MASK
) >> PMU0_PLL0_PC1_WILD_FRAC_SHIFT
;
739 wbint
= (tmp
& PMU0_PLL0_PC1_WILD_INT_MASK
) >> PMU0_PLL0_PC1_WILD_INT_SHIFT
;
741 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL2
);
742 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
744 (tmp
& PMU0_PLL0_PC2_WILD_INT_MASK
) << PMU0_PLL0_PC2_WILD_INT_SHIFT
;
746 fvco
= (xt
->freq
* wbint
) << 8;
747 fvco
+= (xt
->freq
* (wbfrac
>> 10)) >> 2;
748 fvco
+= (xt
->freq
* (wbfrac
& 0x3ff)) >> 10;
754 PMU_MSG (("sb_pmu0_cpuclk0: wbint %u wbfrac %u fvco %u\n",
755 wbint
, wbfrac
, fvco
));
756 ASSERT (fvco
== PMU0_PLL0_FVCO
);
759 /* Return ARM/SB clock */
760 return PMU0_PLL0_FVCO
/ (divarm
+ PMU0_PLL0_PC0_DIV_ARM_BASE
) * 1000;
763 /* PMU corerev 1 pll programming for BCM4325 */
764 /* setup pll and query clock speed */
775 /* the following table is based on 880Mhz Fvco */
776 #define PMU1_PLL0_FVCO 880000 /* Fvco 880Mhz */
777 static const pmu1_xtaltab0_t
778 BCMINITDATA (pmu1_xtaltab0
)[] =
781 12000, 1, 3, 22, 0x9, 0xFFFFEF},
783 13000, 2, 1, 6, 0xb, 0x483483},
785 14400, 3, 1, 10, 0xa, 0x1C71C7},
787 15360, 4, 1, 5, 0xb, 0x755555},
789 16200, 5, 1, 10, 0x5, 0x6E9E06},
791 16800, 6, 1, 10, 0x5, 0x3Cf3Cf},
793 19200, 7, 1, 9, 0x5, 0x17B425},
795 19800, 8, 1, 11, 0x4, 0xA57EB},
797 20000, 9, 1, 11, 0x4, 0x0},
799 24000, 10, 3, 11, 0xa, 0x0},
801 25000, 11, 5, 16, 0xb, 0x0},
803 26000, 12, 1, 2, 0x10, 0xEC4EC4},
805 30000, 13, 3, 8, 0xb, 0x0},
807 38400, 14, 1, 5, 0x4, 0x955555},
809 40000, 15, 1, 2, 0xb, 0},
814 /* Default to 15360Khz crystal */
815 #define PMU1_XTAL0_DEFAULT 3
818 BCMINITFN (sb_pmu1_alpclk0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
)
820 const pmu1_xtaltab0_t
*xt
;
823 /* Find the frequency in the table */
824 xf
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
826 for (xt
= pmu1_xtaltab0
; xt
->fref
; xt
++)
830 xt
= &pmu1_xtaltab0
[PMU1_XTAL0_DEFAULT
];
832 return xt
->fref
* 1000;
835 /* Set up PLL registers in the PMU as per the crystal speed.
836 * Uses xtalfreq variable, or passed-in default.
839 BCMINITFN (sb_pmu1_pllinit0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
,
842 const pmu1_xtaltab0_t
*xt
;
844 uint32 buf_strength
= 0;
846 /* 4312: assume default works */
847 if (sbh
->chip
== BCM4312_CHIP_ID
)
850 /* Find the frequency in the table */
851 for (xt
= pmu1_xtaltab0
; xt
->fref
; xt
++)
852 if (xt
->fref
== xtal
)
855 xt
= &pmu1_xtaltab0
[PMU1_XTAL0_DEFAULT
];
857 PMU_MSG (("XTAL %d (%d)\n", xtal
, xt
->xf
));
859 /* Check current PLL state */
860 if (((R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
861 PCTL_XTALFREQ_SHIFT
) == xt
->xf
)
863 PMU_MSG (("PLL already programmed for %d.%d MHz\n",
864 (xt
->fref
/ 1000), (xt
->fref
% 1000)));
868 PMU_MSG (("Programming PLL for %d.%d MHz\n", (xt
->fref
/ 1000),
871 /* Make sure the PLL is off */
874 case BCM4325_CHIP_ID
:
875 AND_REG (osh
, &cc
->min_res_mask
,
876 ~(PMURES_BIT (RES4325_BBPLL_PWRSW_PU
) |
877 PMURES_BIT (RES4325_HT_AVAIL
)));
878 AND_REG (osh
, &cc
->max_res_mask
,
879 ~(PMURES_BIT (RES4325_BBPLL_PWRSW_PU
) |
880 PMURES_BIT (RES4325_HT_AVAIL
)));
882 /* Change the BBPLL drive strength to 2 for all channels */
883 buf_strength
= 0x222222;
888 SPINWAIT (R_REG (osh
, &cc
->clk_ctl_st
) & CCS_HTAVAIL
,
889 PMU_MAX_TRANSITION_DLY
);
890 ASSERT (!(R_REG (osh
, &cc
->clk_ctl_st
) & CCS_HTAVAIL
));
892 PMU_MSG (("Done masking\n"));
894 /* Write p1div and p2div to pllcontrol[0] */
895 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL0
);
896 tmp
= R_REG (osh
, &cc
->pllcontrol_data
) &
897 ~(PMU1_PLL0_PC0_P1DIV_MASK
| PMU1_PLL0_PC0_P2DIV_MASK
);
900 p1div
<< PMU1_PLL0_PC0_P1DIV_SHIFT
) & PMU1_PLL0_PC0_P1DIV_MASK
) | ((xt
->
903 PMU1_PLL0_PC0_P2DIV_SHIFT
)
905 PMU1_PLL0_PC0_P2DIV_MASK
);
906 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
908 /* Write ndiv_int and ndiv_mode to pllcontrol[2] */
909 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL2
);
910 tmp
= R_REG (osh
, &cc
->pllcontrol_data
) &
911 ~(PMU1_PLL0_PC2_NDIV_INT_MASK
| PMU1_PLL0_PC2_NDIV_MODE_MASK
);
914 ndiv_int
<< PMU1_PLL0_PC2_NDIV_INT_SHIFT
) & PMU1_PLL0_PC2_NDIV_INT_MASK
)
915 | ((1 << PMU1_PLL0_PC2_NDIV_MODE_SHIFT
) & PMU1_PLL0_PC2_NDIV_MODE_MASK
);
916 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
918 /* Write ndiv_frac to pllcontrol[3] */
919 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL3
);
920 tmp
= R_REG (osh
, &cc
->pllcontrol_data
) & ~PMU1_PLL0_PC3_NDIV_FRAC_MASK
;
921 tmp
|= ((xt
->ndiv_frac
<< PMU1_PLL0_PC3_NDIV_FRAC_SHIFT
) &
922 PMU1_PLL0_PC3_NDIV_FRAC_MASK
);
923 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
927 PMU_MSG (("Adjusting PLL buffer drive strength: %x\n", buf_strength
));
929 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL5
);
930 tmp
= R_REG (osh
, &cc
->pllcontrol_data
) & ~PMU1_PLL0_PC5_CLK_DRV_MASK
;
931 tmp
|= (buf_strength
<< PMU1_PLL0_PC5_CLK_DRV_SHIFT
);
932 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
935 PMU_MSG (("Done pll\n"));
937 /* Write XtalFreq. Set the divisor also. */
938 tmp
= R_REG (osh
, &cc
->pmucontrol
) &
939 ~(PCTL_ILP_DIV_MASK
| PCTL_XTALFREQ_MASK
);
940 tmp
|= (((((xt
->fref
+ 127) / 128) - 1) << PCTL_ILP_DIV_SHIFT
) &
942 ((xt
->xf
<< PCTL_XTALFREQ_SHIFT
) & PCTL_XTALFREQ_MASK
);
943 W_REG (osh
, &cc
->pmucontrol
, tmp
);
948 BCMINITFN (sb_pmu1_cpuclk0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
)
950 const pmu1_xtaltab0_t
*xt
;
951 uint32 xf
, tmp
, m1div
;
953 uint32 ndiv_int
, ndiv_frac
, p2div
, p1div
, fvco
;
956 /* Find the xtal frequency in the table */
957 xf
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
959 for (xt
= pmu1_xtaltab0
; xt
->fref
; xt
++)
963 xt
= &pmu1_xtaltab0
[PMU1_XTAL0_DEFAULT
];
965 /* Read m1div from pllcontrol[1] */
966 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL1
);
967 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
968 m1div
= (tmp
& PMU1_PLL0_PC1_M1DIV_MASK
) >> PMU1_PLL0_PC1_M1DIV_SHIFT
;
971 /* Read p2div/p1div from pllcontrol[0] */
972 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL0
);
973 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
974 p2div
= (tmp
& PMU1_PLL0_PC0_P2DIV_MASK
) >> PMU1_PLL0_PC0_P2DIV_SHIFT
;
975 p1div
= (tmp
& PMU1_PLL0_PC0_P1DIV_MASK
) >> PMU1_PLL0_PC0_P1DIV_SHIFT
;
977 /* Calculate Fvco based on xtal freq and ndiv and pdiv */
978 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL2
);
979 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
981 (tmp
& PMU1_PLL0_PC2_NDIV_INT_MASK
) >> PMU1_PLL0_PC2_NDIV_INT_SHIFT
;
983 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL3
);
984 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
986 (tmp
& PMU1_PLL0_PC3_NDIV_FRAC_MASK
) >> PMU1_PLL0_PC3_NDIV_FRAC_SHIFT
;
988 fvco
= (xt
->fref
* ndiv_int
) << 8;
989 fvco
+= (xt
->fref
* (ndiv_frac
>> 12)) >> 4;
990 fvco
+= (xt
->fref
* (ndiv_frac
& 0xfff)) >> 12;
997 PMU_MSG (("sb_pmu0_cpuclk0: ndiv_int %u ndiv_frac %u "
998 "p2div %u p1div %u fvco %u\n",
999 ndiv_int
, ndiv_frac
, p2div
, p1div
, fvco
));
1000 ASSERT (fvco
== PMU1_PLL0_FVCO
);
1003 /* Return ARM/SB clock */
1004 return PMU1_PLL0_FVCO
/ m1div
* 1000;
1007 void BCMINITFN (sb_pmu_pll_init
) (sb_t
* sbh
, osl_t
* osh
, uint xtalfreq
)
1012 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1014 /* Remember original core before switch to chipc */
1015 origidx
= sb_coreidx (sbh
);
1016 cc
= sb_setcore (sbh
, SB_CC
, 0);
1021 case BCM4328_CHIP_ID
:
1022 sb_pmu0_pllinit0 (sbh
, osh
, cc
, xtalfreq
);
1024 case BCM5354_CHIP_ID
:
1025 sb_pmu0_pllinit0 (sbh
, osh
, cc
, xtalfreq
);
1027 case BCM4325_CHIP_ID
:
1028 sb_pmu1_pllinit0 (sbh
, osh
, cc
, xtalfreq
);
1030 case BCM4312_CHIP_ID
:
1031 sb_pmu1_pllinit0 (sbh
, osh
, cc
, xtalfreq
);
1034 PMU_MSG (("No PLL init done for chip %x rev %d pmurev %d\n",
1035 sbh
->chip
, sbh
->chiprev
, sbh
->pmurev
));
1039 /* Return to original core */
1040 sb_setcoreidx (sbh
, origidx
);
1043 uint32
BCMINITFN (sb_pmu_alp_clock
) (sb_t
* sbh
, osl_t
* osh
)
1047 uint32 clock
= ALP_CLOCK
;
1049 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1051 /* Remember original core before switch to chipc */
1052 origidx
= sb_coreidx (sbh
);
1053 cc
= sb_setcore (sbh
, SB_CC
, 0);
1058 case BCM4328_CHIP_ID
:
1059 clock
= sb_pmu0_alpclk0 (sbh
, osh
, cc
);
1061 case BCM5354_CHIP_ID
:
1062 clock
= sb_pmu0_alpclk0 (sbh
, osh
, cc
);
1064 case BCM4325_CHIP_ID
:
1065 clock
= sb_pmu1_alpclk0 (sbh
, osh
, cc
);
1067 case BCM4312_CHIP_ID
:
1068 clock
= sb_pmu1_alpclk0 (sbh
, osh
, cc
);
1070 clock
= 20000 * 1000;
1073 PMU_MSG (("No ALP clock specified "
1074 "for chip %x rev %d pmurev %d, using default %d Hz\n",
1075 sbh
->chip
, sbh
->chiprev
, sbh
->pmurev
, clock
));
1079 /* Return to original core */
1080 sb_setcoreidx (sbh
, origidx
);
1084 uint
BCMINITFN (sb_pmu_cpu_clock
) (sb_t
* sbh
, osl_t
* osh
)
1088 uint32 clock
= HT_CLOCK
;
1090 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1092 /* Remember original core before switch to chipc */
1093 origidx
= sb_coreidx (sbh
);
1094 cc
= sb_setcore (sbh
, SB_CC
, 0);
1099 case BCM4328_CHIP_ID
:
1100 clock
= sb_pmu0_cpuclk0 (sbh
, osh
, cc
);
1102 case BCM5354_CHIP_ID
:
1103 clock
= sb_pmu0_cpuclk0 (sbh
, osh
, cc
);
1105 case BCM4325_CHIP_ID
:
1106 clock
= sb_pmu1_cpuclk0 (sbh
, osh
, cc
);
1108 case BCM4312_CHIP_ID
:
1109 clock
= sb_pmu1_cpuclk0 (sbh
, osh
, cc
);
1112 PMU_MSG (("No CPU clock specified "
1113 "for chip %x rev %d pmurev %d, using default %d Hz\n",
1114 sbh
->chip
, sbh
->chiprev
, sbh
->pmurev
, clock
));
1118 /* Return to original core */
1119 sb_setcoreidx (sbh
, origidx
);
1123 void BCMINITFN (sb_pmu_init
) (sb_t
* sbh
, osl_t
* osh
)
1128 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1130 /* Remember original core before switch to chipc */
1131 origidx
= sb_coreidx (sbh
);
1132 cc
= sb_setcore (sbh
, SB_CC
, 0);
1135 if (sbh
->pmurev
>= 1)
1137 if (sbh
->chip
== BCM4325_CHIP_ID
&& sbh
->chiprev
<= 1)
1138 AND_REG (osh
, &cc
->pmucontrol
, ~PCTL_NOILP_ON_WAIT
);
1140 OR_REG (osh
, &cc
->pmucontrol
, PCTL_NOILP_ON_WAIT
);
1143 /* Return to original core */
1144 sb_setcoreidx (sbh
, origidx
);
1147 void BCMINITFN (sb_pmu_otp_power
) (sb_t
* sbh
, osl_t
* osh
, bool on
)
1152 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1154 /* Remember original core before switch to chipc */
1155 origidx
= sb_coreidx (sbh
);
1156 cc
= sb_setcore (sbh
, SB_CC
, 0);
1161 case BCM4325_CHIP_ID
:
1164 OR_REG (osh
, &cc
->min_res_mask
, PMURES_BIT (RES4325_LNLDO2_PU
));
1165 if (sbh
->boardflags
& BFL_BUCKBOOST
)
1166 AND_REG (osh
, &cc
->min_res_mask
,
1167 ~PMURES_BIT (RES4325_BUCK_BOOST_PWM
));
1172 if (sbh
->boardflags
& BFL_BUCKBOOST
)
1173 OR_REG (osh
, &cc
->min_res_mask
,
1174 PMURES_BIT (RES4325_BUCK_BOOST_PWM
));
1175 AND_REG (osh
, &cc
->min_res_mask
, ~PMURES_BIT (RES4325_LNLDO2_PU
));
1182 /* Return to original core */
1183 sb_setcoreidx (sbh
, origidx
);
1187 sb_pmu_rcal (sb_t
* sbh
, osl_t
* osh
)
1192 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1194 /* Remember original core before switch to chipc */
1195 origidx
= sb_coreidx (sbh
);
1196 cc
= sb_setcore (sbh
, SB_CC
, 0);
1201 case BCM4325_CHIP_ID
:
1207 W_REG (osh
, &cc
->chipcontrol_addr
, 1);
1208 AND_REG (osh
, &cc
->chipcontrol_data
, ~0x04);
1209 OR_REG (osh
, &cc
->chipcontrol_data
, 0x04);
1211 /* Wait for completion */
1212 SPINWAIT (0 == (R_REG (osh
, &cc
->chipstatus
) & 0x08),
1214 ASSERT (R_REG (osh
, &cc
->chipstatus
) & 0x08);
1216 /* Drop the LSB to convert from 5 bit code to 4 bit code */
1217 rcal_code
= (uint8
) (R_REG (osh
, &cc
->chipstatus
) >> 5) & 0x0f;
1218 PMU_MSG (("RCal completed, status 0x%x, code 0x%x\n",
1219 R_REG (osh
, &cc
->chipstatus
), rcal_code
));
1221 /* Write RCal code into pmu_vreg_ctrl[32:29] */
1222 W_REG (osh
, &cc
->regcontrol_addr
, 0);
1223 val
= R_REG (osh
, &cc
->regcontrol_data
) & ~((uint32
) 0x07 << 29);
1224 val
|= (uint32
) (rcal_code
& 0x07) << 29;
1225 W_REG (osh
, &cc
->regcontrol_data
, val
);
1226 W_REG (osh
, &cc
->regcontrol_addr
, 1);
1227 val
= R_REG (osh
, &cc
->regcontrol_data
) & ~(uint32
) 0x01;
1228 val
|= (uint32
) ((rcal_code
>> 3) & 0x01);
1229 W_REG (osh
, &cc
->regcontrol_data
, val
);
1231 /* Write RCal code into pmu_chip_ctrl[33:30] */
1232 W_REG (osh
, &cc
->chipcontrol_addr
, 0);
1233 val
= R_REG (osh
, &cc
->chipcontrol_data
) & ~((uint32
) 0x03 << 30);
1234 val
|= (uint32
) (rcal_code
& 0x03) << 30;
1235 W_REG (osh
, &cc
->chipcontrol_data
, val
);
1236 W_REG (osh
, &cc
->chipcontrol_addr
, 1);
1237 val
= R_REG (osh
, &cc
->chipcontrol_data
) & ~(uint32
) 0x03;
1238 val
|= (uint32
) ((rcal_code
>> 2) & 0x03);
1239 W_REG (osh
, &cc
->chipcontrol_data
, val
);
1241 /* Set override in pmu_chip_ctrl[29] */
1242 W_REG (osh
, &cc
->chipcontrol_addr
, 0);
1243 OR_REG (osh
, &cc
->chipcontrol_data
, (0x01 << 29));
1245 /* Power off RCal block */
1246 W_REG (osh
, &cc
->chipcontrol_addr
, 1);
1247 AND_REG (osh
, &cc
->chipcontrol_data
, ~0x04);
1255 /* Return to original core */
1256 sb_setcoreidx (sbh
, origidx
);