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.
24 #define PMU_ERROR(args)
27 #define PMU_MSG(args) printf args
33 /* PMU rev 0 pll control for BCM4328 and BCM5354 */
34 static void sb_pmu0_pllinit0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
,
36 static uint32
sb_pmu0_alpclk0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
);
37 static uint32
sb_pmu0_cpuclk0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
);
38 /* PMU rev 0 pll control for BCM4325 BCM4329 */
39 static void sb_pmu1_pllinit0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
,
41 static uint32
sb_pmu1_cpuclk0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
);
42 static uint32
sb_pmu1_alpclk0 (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
);
44 /* Setup switcher voltage */
46 BCMINITFN (sb_pmu_set_switcher_voltage
) (sb_t
* sbh
, osl_t
* osh
,
47 uint8 bb_voltage
, uint8 rf_voltage
)
52 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
54 /* Remember original core before switch to chipc */
55 origidx
= sb_coreidx (sbh
);
56 cc
= sb_setcore (sbh
, SB_CC
, 0);
59 W_REG (osh
, &cc
->regcontrol_addr
, 0x01);
60 W_REG (osh
, &cc
->regcontrol_data
, (uint32
) (bb_voltage
& 0x1f) << 22);
62 W_REG (osh
, &cc
->regcontrol_addr
, 0x00);
63 W_REG (osh
, &cc
->regcontrol_data
, (uint32
) (rf_voltage
& 0x1f) << 14);
65 /* Return to original core */
66 sb_setcoreidx (sbh
, origidx
);
70 sb_pmu_set_ldo_voltage (sb_t
* sbh
, osl_t
* osh
, uint8 ldo
, uint8 voltage
)
72 uint8 sr_cntl_shift
, rc_shift
, shift
, mask
;
75 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
83 case SET_LDO_VOLTAGE_LDO1
:
89 case SET_LDO_VOLTAGE_LDO2
:
95 case SET_LDO_VOLTAGE_LDO3
:
101 case SET_LDO_VOLTAGE_PAREF
:
112 case BCM4312_CHIP_ID
:
115 case SET_LDO_VOLTAGE_PAREF
:
131 shift
= sr_cntl_shift
+ rc_shift
;
133 sb_corereg (sbh
, SB_CC_IDX
, OFFSETOF (chipcregs_t
, regcontrol_addr
),
135 sb_corereg (sbh
, SB_CC_IDX
, OFFSETOF (chipcregs_t
, regcontrol_data
),
136 mask
<< shift
, (voltage
& mask
) << shift
);
140 sb_pmu_paref_ldo_enable (sb_t
* sbh
, osl_t
* osh
, bool enable
)
144 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
148 case BCM4328_CHIP_ID
:
149 ldo
= RES4328_PA_REF_LDO
;
151 case BCM5354_CHIP_ID
:
152 ldo
= RES5354_PA_REF_LDO
;
154 case BCM4312_CHIP_ID
:
155 ldo
= RES4312_PA_REF_LDO
;
161 sb_corereg (sbh
, SB_CC_IDX
, OFFSETOF (chipcregs_t
, min_res_mask
),
162 PMURES_BIT (ldo
), enable
? PMURES_BIT (ldo
) : 0);
165 uint16
BCMINITFN (sb_pmu_fast_pwrup_delay
) (sb_t
* sbh
, osl_t
* osh
)
167 uint16 delay
= PMU_MAX_TRANSITION_DLY
;
169 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
173 case BCM4328_CHIP_ID
:
177 case BCM4325_CHIP_ID
:
178 case BCM4312_CHIP_ID
:
187 PMU_MSG (("No PMU fast power up delay specified "
188 "for chip %x rev %d, using default %d us\n",
189 sbh
->chip
, sbh
->chiprev
, delay
));
196 uint32
BCMINITFN (sb_pmu_force_ilp
) (sb_t
* sbh
, osl_t
* osh
, bool force
)
200 uint32 oldpmucontrol
;
202 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
204 /* Remember original core before switch to chipc */
205 origidx
= sb_coreidx (sbh
);
206 cc
= sb_setcore (sbh
, SB_CC
, 0);
209 oldpmucontrol
= R_REG (osh
, &cc
->pmucontrol
);
211 W_REG (osh
, &cc
->pmucontrol
, oldpmucontrol
&
212 ~(PCTL_HT_REQ_EN
| PCTL_ALP_REQ_EN
));
214 W_REG (osh
, &cc
->pmucontrol
, oldpmucontrol
|
215 (PCTL_HT_REQ_EN
| PCTL_ALP_REQ_EN
));
217 /* Return to original core */
218 sb_setcoreidx (sbh
, origidx
);
220 return oldpmucontrol
;
223 /* Setup min/max resources and up/down timers */
233 int8 action
; /* 0 - set, 1 - add, -1 - remove */
237 static const pmu_res_updown_t
238 BCMINITDATA (bcm4328a0_res_updown
)[] =
241 RES4328_EXT_SWITCHER_PWM
, 0x0101},
243 RES4328_BB_SWITCHER_PWM
, 0x1f01},
245 RES4328_BB_SWITCHER_BURST
, 0x010f},
247 RES4328_BB_EXT_SWITCHER_BURST
, 0x0101},
249 RES4328_ILP_REQUEST
, 0x0202},
251 RES4328_RADIO_SWITCHER_PWM
, 0x0f01},
253 RES4328_RADIO_SWITCHER_BURST
, 0x0f01},
255 RES4328_ROM_SWITCH
, 0x0101},
257 RES4328_PA_REF_LDO
, 0x0f01},
259 RES4328_RADIO_LDO
, 0x0f01},
261 RES4328_AFE_LDO
, 0x0f01},
263 RES4328_PLL_LDO
, 0x0f01},
265 RES4328_BG_FILTBYP
, 0x0101},
267 RES4328_TX_FILTBYP
, 0x0101},
269 RES4328_RX_FILTBYP
, 0x0101},
271 RES4328_XTAL_PU
, 0x0101},
273 RES4328_XTAL_EN
, 0xa001},
275 RES4328_BB_PLL_FILTBYP
, 0x0101},
277 RES4328_RF_PLL_FILTBYP
, 0x0101},
279 RES4328_BB_PLL_PU
, 0x0701}
282 static const pmu_res_depend_t
283 BCMINITDATA (bcm4328a0_res_depend
)[] =
285 /* Adjust ILP request resource not to force ext/BB switchers into burst mode */
287 RES4328_ILP_REQUEST
, 0,
288 PMURES_BIT (RES4328_EXT_SWITCHER_PWM
) |
289 PMURES_BIT (RES4328_BB_SWITCHER_PWM
)}
292 #ifdef BCMQT /* for power save on slow QT/small beacon interval */
293 static const pmu_res_updown_t
294 BCMINITDATA (bcm4325a0_res_updown_qt
)[] =
297 RES4325_HT_AVAIL
, 0x0300},
299 RES4325_BBPLL_PWRSW_PU
, 0x0101},
301 RES4325_RFPLL_PWRSW_PU
, 0x0101},
303 RES4325_ALP_AVAIL
, 0x0100},
305 RES4325_XTAL_PU
, 0x1000},
307 RES4325_LNLDO1_PU
, 0x0800},
309 RES4325_CLDO_CBUCK_PWM
, 0x0101},
311 RES4325_CBUCK_PWM
, 0x0803}
314 static const pmu_res_updown_t
315 BCMINITDATA (bcm4325a0_res_updown
)[] =
318 RES4325_XTAL_PU
, 0x1501}
322 static const pmu_res_depend_t
323 BCMINITDATA (bcm4325a0_res_depend
)[] =
325 /* Adjust HT Avail resource dependencies */
328 PMURES_BIT (RES4325_RX_PWRSW_PU
) | PMURES_BIT (RES4325_TX_PWRSW_PU
) |
329 PMURES_BIT (RES4325_LOGEN_PWRSW_PU
) | PMURES_BIT (RES4325_AFE_PWRSW_PU
)}
332 void BCMINITFN (sb_pmu_res_init
) (sb_t
* sbh
, osl_t
* osh
)
336 const pmu_res_updown_t
*pmu_res_updown_table
= NULL
;
337 int pmu_res_updown_table_sz
= 0;
338 const pmu_res_depend_t
*pmu_res_depend_table
= NULL
;
339 int pmu_res_depend_table_sz
= 0;
340 uint32 min_mask
= 0, max_mask
= 0;
342 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
344 /* Remember original core before switch to chipc */
345 origidx
= sb_coreidx (sbh
);
346 cc
= sb_setcore (sbh
, SB_CC
, 0);
351 case BCM4328_CHIP_ID
:
352 /* Down to ILP request excluding ROM */
353 min_mask
= PMURES_BIT (RES4328_EXT_SWITCHER_PWM
) |
354 PMURES_BIT (RES4328_BB_SWITCHER_PWM
) | PMURES_BIT (RES4328_XTAL_EN
);
357 min_mask
|= PMURES_BIT (RES4328_ROM_SWITCH
);
359 /* Allow (but don't require) PLL to turn on */
361 pmu_res_updown_table
= bcm4328a0_res_updown
;
362 pmu_res_updown_table_sz
= ARRAYSIZE (bcm4328a0_res_updown
);
363 pmu_res_depend_table
= bcm4328a0_res_depend
;
364 pmu_res_depend_table_sz
= ARRAYSIZE (bcm4328a0_res_depend
);
366 case BCM4312_CHIP_ID
:
368 * min_mask = 0xcbb; max_mask = 0x7ffff;
369 * pmu_res_updown_table_sz = 0;
370 * pmu_res_depend_table_sz = 0;
373 case BCM5354_CHIP_ID
:
374 /* Allow (but don't require) PLL to turn on */
378 case BCM4325_CHIP_ID
:
379 /* Leave OTP powered up and power it down later. */
381 PMURES_BIT (RES4325_CBUCK_BURST
) | PMURES_BIT (RES4325_LNLDO2_PU
);
382 if (((sbh
->chipst
& CST4325_PMUTOP_2B_MASK
) >>
383 CST4325_PMUTOP_2B_SHIFT
) == 1)
384 min_mask
|= PMURES_BIT (RES4325_CLDO_CBUCK_BURST
);
385 /* Allow (but don't require) PLL to turn on */
388 pmu_res_updown_table
= bcm4325a0_res_updown_qt
;
389 pmu_res_updown_table_sz
= ARRAYSIZE (bcm4325a0_res_updown_qt
);
391 pmu_res_updown_table
= bcm4325a0_res_updown
;
392 pmu_res_updown_table_sz
= ARRAYSIZE (bcm4325a0_res_updown
);
393 pmu_res_depend_table
= bcm4325a0_res_depend
;
394 pmu_res_depend_table_sz
= ARRAYSIZE (bcm4325a0_res_depend
);
402 /* Program up/down timers */
403 while (pmu_res_updown_table_sz
--)
405 ASSERT (pmu_res_updown_table
);
406 W_REG (osh
, &cc
->res_table_sel
,
407 pmu_res_updown_table
[pmu_res_updown_table_sz
].resnum
);
408 W_REG (osh
, &cc
->res_updn_timer
,
409 pmu_res_updown_table
[pmu_res_updown_table_sz
].updown
);
412 /* Program resource dependencies table */
413 while (pmu_res_depend_table_sz
--)
415 ASSERT (pmu_res_depend_table
);
416 W_REG (osh
, &cc
->res_table_sel
,
417 pmu_res_depend_table
[pmu_res_depend_table_sz
].resnum
);
418 switch (pmu_res_depend_table
[pmu_res_depend_table_sz
].action
)
421 W_REG (osh
, &cc
->res_dep_mask
,
422 pmu_res_depend_table
[pmu_res_depend_table_sz
].depend_mask
);
425 OR_REG (osh
, &cc
->res_dep_mask
,
426 pmu_res_depend_table
[pmu_res_depend_table_sz
].depend_mask
);
429 AND_REG (osh
, &cc
->res_dep_mask
,
430 ~pmu_res_depend_table
[pmu_res_depend_table_sz
].
439 /* program min resource mask */
442 PMU_MSG (("Changing min_res_mask to 0x%x\n", min_mask
));
443 W_REG (osh
, &cc
->min_res_mask
, min_mask
);
445 /* program max resource mask */
448 PMU_MSG (("Changing max_res_mask to 0x%x\n", max_mask
));
449 W_REG (osh
, &cc
->max_res_mask
, max_mask
);
452 /* Return to original core */
453 sb_setcoreidx (sbh
, origidx
);
456 /* setup pll and query clock speed */
465 /* the following table is based on 880Mhz Fvco */
466 #define PMU0_PLL0_FVCO 880000 /* Fvco 880Mhz */
467 static const pmu0_xtaltab0_t
468 BCMINITDATA (pmu0_xtaltab0
)[] =
471 12000, 1, 73, 349525},
473 13000, 2, 67, 725937},
475 14400, 3, 61, 116508},
477 15360, 4, 57, 305834},
479 16200, 5, 54, 336579},
481 16800, 6, 52, 399457},
483 19200, 7, 45, 873813},
485 19800, 8, 44, 466033},
489 25000, 10, 70, 419430},
491 26000, 11, 67, 725937},
493 30000, 12, 58, 699050},
495 38400, 13, 45, 873813},
503 #define PMU0_XTAL0_DEFAULT 11
505 #define PMU0_XTAL0_DEFAULT 8
510 * Set new backplane PLL clock frequency
512 static void BCMINITFN (sb_pmu0_sbclk4328
) (sb_t
* sbh
, int freq
)
514 uint32 tmp
, oldmax
, oldmin
, origidx
;
517 /* Remember original core before switch to chipc */
518 origidx
= sb_coreidx (sbh
);
519 cc
= sb_setcore (sbh
, SB_CC
, 0);
522 /* Set new backplane PLL clock */
523 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL0
);
524 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
525 tmp
&= ~(PMU0_PLL0_PC0_DIV_ARM_MASK
);
526 tmp
|= freq
<< PMU0_PLL0_PC0_DIV_ARM_SHIFT
;
527 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
529 /* Power cycle BB_PLL_PU by disabling/enabling it to take on new freq */
531 oldmin
= R_REG (osh
, &cc
->min_res_mask
);
532 oldmax
= R_REG (osh
, &cc
->max_res_mask
);
533 W_REG (osh
, &cc
->min_res_mask
, oldmin
& ~PMURES_BIT (RES4328_BB_PLL_PU
));
534 W_REG (osh
, &cc
->max_res_mask
, oldmax
& ~PMURES_BIT (RES4328_BB_PLL_PU
));
536 /* It takes over several hundred usec to re-enable the PLL since the
537 * sequencer state machines run on ILP clock. Set delay at 450us to be safe.
539 * Be sure PLL is powered down first before re-enabling it.
542 OSL_DELAY (PLL_DELAY
);
543 SPINWAIT ((R_REG (osh
, &cc
->res_state
) & PMURES_BIT (RES4328_BB_PLL_PU
)),
546 if (R_REG (osh
, &cc
->res_state
) & PMURES_BIT (RES4328_BB_PLL_PU
))
548 /* If BB_PLL not powered down yet, new backplane PLL clock
549 * may not take effect.
551 * Still early during bootup so no serial output here.
553 PMU_ERROR (("Fatal: BB_PLL not power down yet!\n"));
555 (R_REG (osh
, &cc
->res_state
) & PMURES_BIT (RES4328_BB_PLL_PU
)));
559 W_REG (osh
, &cc
->max_res_mask
, oldmax
);
561 /* Return to original core */
562 sb_setcoreidx (sbh
, origidx
);
564 #endif /* BCMUSBDEV */
566 /* Set up PLL registers in the PMU as per the crystal speed.
567 * Uses xtalfreq variable, or passed-in default.
570 BCMINITFN (sb_pmu0_pllinit0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
,
574 const pmu0_xtaltab0_t
*xt
;
576 if ((sb_chip (sbh
) == BCM5354_CHIP_ID
) && (xtal
== 0))
578 /* 5354 has xtal freq of 25MHz */
582 /* Find the frequency in the table */
583 for (xt
= pmu0_xtaltab0
; xt
->freq
; xt
++)
584 if (xt
->freq
== xtal
)
587 xt
= &pmu0_xtaltab0
[PMU0_XTAL0_DEFAULT
];
589 PMU_MSG (("XTAL %d (%d)\n", xtal
, xt
->xf
));
591 /* Check current PLL state */
592 tmp
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
596 PMU_MSG (("PLL already programmed for %d.%d MHz\n",
597 (xt
->freq
/ 1000), (xt
->freq
% 1000)));
600 if (sbh
->chip
== BCM4328_CHIP_ID
)
601 sb_pmu0_sbclk4328 (sbh
, PMU0_PLL0_PC0_DIV_ARM_88MHZ
);
608 PMU_MSG (("Reprogramming PLL for %d.%d MHz (was %d.%dMHz)\n",
609 (xt
->freq
/ 1000), (xt
->freq
% 1000),
610 (pmu0_xtaltab0
[tmp
- 1].freq
/ 1000),
611 (pmu0_xtaltab0
[tmp
- 1].freq
% 1000)));
615 PMU_MSG (("Programming PLL for %d.%d MHz\n", (xt
->freq
/ 1000),
619 /* Make sure the PLL is off */
622 case BCM4328_CHIP_ID
:
623 AND_REG (osh
, &cc
->min_res_mask
, ~PMURES_BIT (RES4328_BB_PLL_PU
));
624 AND_REG (osh
, &cc
->max_res_mask
, ~PMURES_BIT (RES4328_BB_PLL_PU
));
626 case BCM5354_CHIP_ID
:
627 AND_REG (osh
, &cc
->min_res_mask
, ~PMURES_BIT (RES5354_BB_PLL_PU
));
628 AND_REG (osh
, &cc
->max_res_mask
, ~PMURES_BIT (RES5354_BB_PLL_PU
));
633 SPINWAIT (R_REG (osh
, &cc
->clk_ctl_st
) & CCS0_HTAVAIL
,
634 PMU_MAX_TRANSITION_DLY
);
635 ASSERT (!(R_REG (osh
, &cc
->clk_ctl_st
) & CCS0_HTAVAIL
));
637 PMU_MSG (("Done masking\n"));
639 /* Write PDIV in pllcontrol[0] */
640 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL0
);
641 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
642 if (xt
->freq
>= PMU0_PLL0_PC0_PDIV_FREQ
)
643 tmp
|= PMU0_PLL0_PC0_PDIV_MASK
;
645 tmp
&= ~PMU0_PLL0_PC0_PDIV_MASK
;
646 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
648 /* Write WILD in pllcontrol[1] */
649 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL1
);
650 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
652 ((tmp
& ~(PMU0_PLL0_PC1_WILD_INT_MASK
| PMU0_PLL0_PC1_WILD_FRAC_MASK
)) |
654 wbint
<< PMU0_PLL0_PC1_WILD_INT_SHIFT
) & PMU0_PLL0_PC1_WILD_INT_MASK
)
655 | ((xt
->wbfrac
<< PMU0_PLL0_PC1_WILD_FRAC_SHIFT
) &
656 PMU0_PLL0_PC1_WILD_FRAC_MASK
)));
658 tmp
|= PMU0_PLL0_PC1_STOP_MOD
;
660 tmp
&= ~PMU0_PLL0_PC1_STOP_MOD
;
661 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
663 /* Write WILD in pllcontrol[2] */
664 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL2
);
665 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
666 tmp
= ((tmp
& ~PMU0_PLL0_PC2_WILD_INT_MASK
) |
667 ((xt
->wbint
>> PMU0_PLL0_PC2_WILD_INT_SHIFT
) &
668 PMU0_PLL0_PC2_WILD_INT_MASK
));
669 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
671 PMU_MSG (("Done pll\n"));
673 /* Write XtalFreq. Set the divisor also. */
674 tmp
= R_REG (osh
, &cc
->pmucontrol
);
675 tmp
= ((tmp
& ~PCTL_ILP_DIV_MASK
) |
676 (((((xt
->freq
+ 127) / 128) - 1) << PCTL_ILP_DIV_SHIFT
) &
678 tmp
= ((tmp
& ~PCTL_XTALFREQ_MASK
) |
679 ((xt
->xf
<< PCTL_XTALFREQ_SHIFT
) & PCTL_XTALFREQ_MASK
));
680 W_REG (osh
, &cc
->pmucontrol
, tmp
);
684 BCMINITFN (sb_pmu0_alpclk0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
)
686 const pmu0_xtaltab0_t
*xt
;
689 /* Find the frequency in the table */
690 xf
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
692 for (xt
= pmu0_xtaltab0
; xt
->freq
; xt
++)
696 xt
= &pmu0_xtaltab0
[PMU0_XTAL0_DEFAULT
];
698 return xt
->freq
* 1000;
702 BCMINITFN (sb_pmu0_cpuclk0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
)
704 const pmu0_xtaltab0_t
*xt
;
705 uint32 xf
, tmp
, divarm
;
707 uint32 pdiv
, wbint
, wbfrac
, fvco
;
710 if (sb_chip (sbh
) == BCM5354_CHIP_ID
)
712 /* 5354 gets sb clock of 120MHz from main pll */
716 /* Find the xtal frequency in the table */
717 xf
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
719 for (xt
= pmu0_xtaltab0
; xt
->freq
; xt
++)
723 xt
= &pmu0_xtaltab0
[PMU0_XTAL0_DEFAULT
];
725 /* Read divarm from pllcontrol[0] */
726 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL0
);
727 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
728 divarm
= (tmp
& PMU0_PLL0_PC0_DIV_ARM_MASK
) >> PMU0_PLL0_PC0_DIV_ARM_SHIFT
;
731 /* Calculate Fvco based on xtal freq, pdiv, and wild */
732 pdiv
= tmp
& PMU0_PLL0_PC0_PDIV_MASK
;
734 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL1
);
735 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
737 (tmp
& PMU0_PLL0_PC1_WILD_FRAC_MASK
) >> PMU0_PLL0_PC1_WILD_FRAC_SHIFT
;
738 wbint
= (tmp
& PMU0_PLL0_PC1_WILD_INT_MASK
) >> PMU0_PLL0_PC1_WILD_INT_SHIFT
;
740 W_REG (osh
, &cc
->pllcontrol_addr
, PMU0_PLL0_PLLCTL2
);
741 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
743 (tmp
& PMU0_PLL0_PC2_WILD_INT_MASK
) << PMU0_PLL0_PC2_WILD_INT_SHIFT
;
745 fvco
= (xt
->freq
* wbint
) << 8;
746 fvco
+= (xt
->freq
* (wbfrac
>> 10)) >> 2;
747 fvco
+= (xt
->freq
* (wbfrac
& 0x3ff)) >> 10;
753 PMU_MSG (("sb_pmu0_cpuclk0: wbint %u wbfrac %u fvco %u\n",
754 wbint
, wbfrac
, fvco
));
755 ASSERT (fvco
== PMU0_PLL0_FVCO
);
758 /* Return ARM/SB clock */
759 return PMU0_PLL0_FVCO
/ (divarm
+ PMU0_PLL0_PC0_DIV_ARM_BASE
) * 1000;
762 /* PMU corerev 1 pll programming for BCM4325 */
763 /* setup pll and query clock speed */
774 /* the following table is based on 880Mhz Fvco */
775 #define PMU1_PLL0_FVCO 880000 /* Fvco 880Mhz */
776 static const pmu1_xtaltab0_t
777 BCMINITDATA (pmu1_xtaltab0
)[] =
780 12000, 1, 3, 22, 0x9, 0xFFFFEF},
782 13000, 2, 1, 6, 0xb, 0x483483},
784 14400, 3, 1, 10, 0xa, 0x1C71C7},
786 15360, 4, 1, 5, 0xb, 0x755555},
788 16200, 5, 1, 10, 0x5, 0x6E9E06},
790 16800, 6, 1, 10, 0x5, 0x3Cf3Cf},
792 19200, 7, 1, 9, 0x5, 0x17B425},
794 19800, 8, 1, 11, 0x4, 0xA57EB},
796 20000, 9, 1, 11, 0x4, 0x0},
798 24000, 10, 3, 11, 0xa, 0x0},
800 25000, 11, 5, 16, 0xb, 0x0},
802 26000, 12, 1, 2, 0x10, 0xEC4EC4},
804 30000, 13, 3, 8, 0xb, 0x0},
806 38400, 14, 1, 5, 0x4, 0x955555},
808 40000, 15, 1, 2, 0xb, 0},
813 /* Default to 15360Khz crystal */
814 #define PMU1_XTAL0_DEFAULT 3
817 BCMINITFN (sb_pmu1_alpclk0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
)
819 const pmu1_xtaltab0_t
*xt
;
822 /* Find the frequency in the table */
823 xf
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
825 for (xt
= pmu1_xtaltab0
; xt
->fref
; xt
++)
829 xt
= &pmu1_xtaltab0
[PMU1_XTAL0_DEFAULT
];
831 return xt
->fref
* 1000;
834 /* Set up PLL registers in the PMU as per the crystal speed.
835 * Uses xtalfreq variable, or passed-in default.
838 BCMINITFN (sb_pmu1_pllinit0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
,
841 const pmu1_xtaltab0_t
*xt
;
843 uint32 buf_strength
= 0;
845 /* 4312: assume default works */
846 if (sbh
->chip
== BCM4312_CHIP_ID
)
849 /* Find the frequency in the table */
850 for (xt
= pmu1_xtaltab0
; xt
->fref
; xt
++)
851 if (xt
->fref
== xtal
)
854 xt
= &pmu1_xtaltab0
[PMU1_XTAL0_DEFAULT
];
856 PMU_MSG (("XTAL %d (%d)\n", xtal
, xt
->xf
));
858 /* Check current PLL state */
859 if (((R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
860 PCTL_XTALFREQ_SHIFT
) == xt
->xf
)
862 PMU_MSG (("PLL already programmed for %d.%d MHz\n",
863 (xt
->fref
/ 1000), (xt
->fref
% 1000)));
867 PMU_MSG (("Programming PLL for %d.%d MHz\n", (xt
->fref
/ 1000),
870 /* Make sure the PLL is off */
873 case BCM4325_CHIP_ID
:
874 AND_REG (osh
, &cc
->min_res_mask
,
875 ~(PMURES_BIT (RES4325_BBPLL_PWRSW_PU
) |
876 PMURES_BIT (RES4325_HT_AVAIL
)));
877 AND_REG (osh
, &cc
->max_res_mask
,
878 ~(PMURES_BIT (RES4325_BBPLL_PWRSW_PU
) |
879 PMURES_BIT (RES4325_HT_AVAIL
)));
881 /* Change the BBPLL drive strength to 2 for all channels */
882 buf_strength
= 0x222222;
887 SPINWAIT (R_REG (osh
, &cc
->clk_ctl_st
) & CCS_HTAVAIL
,
888 PMU_MAX_TRANSITION_DLY
);
889 ASSERT (!(R_REG (osh
, &cc
->clk_ctl_st
) & CCS_HTAVAIL
));
891 PMU_MSG (("Done masking\n"));
893 /* Write p1div and p2div to pllcontrol[0] */
894 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL0
);
895 tmp
= R_REG (osh
, &cc
->pllcontrol_data
) &
896 ~(PMU1_PLL0_PC0_P1DIV_MASK
| PMU1_PLL0_PC0_P2DIV_MASK
);
899 p1div
<< PMU1_PLL0_PC0_P1DIV_SHIFT
) & PMU1_PLL0_PC0_P1DIV_MASK
) | ((xt
->
902 PMU1_PLL0_PC0_P2DIV_SHIFT
)
904 PMU1_PLL0_PC0_P2DIV_MASK
);
905 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
907 /* Write ndiv_int and ndiv_mode to pllcontrol[2] */
908 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL2
);
909 tmp
= R_REG (osh
, &cc
->pllcontrol_data
) &
910 ~(PMU1_PLL0_PC2_NDIV_INT_MASK
| PMU1_PLL0_PC2_NDIV_MODE_MASK
);
913 ndiv_int
<< PMU1_PLL0_PC2_NDIV_INT_SHIFT
) & PMU1_PLL0_PC2_NDIV_INT_MASK
)
914 | ((1 << PMU1_PLL0_PC2_NDIV_MODE_SHIFT
) & PMU1_PLL0_PC2_NDIV_MODE_MASK
);
915 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
917 /* Write ndiv_frac to pllcontrol[3] */
918 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL3
);
919 tmp
= R_REG (osh
, &cc
->pllcontrol_data
) & ~PMU1_PLL0_PC3_NDIV_FRAC_MASK
;
920 tmp
|= ((xt
->ndiv_frac
<< PMU1_PLL0_PC3_NDIV_FRAC_SHIFT
) &
921 PMU1_PLL0_PC3_NDIV_FRAC_MASK
);
922 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
926 PMU_MSG (("Adjusting PLL buffer drive strength: %x\n", buf_strength
));
928 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL5
);
929 tmp
= R_REG (osh
, &cc
->pllcontrol_data
) & ~PMU1_PLL0_PC5_CLK_DRV_MASK
;
930 tmp
|= (buf_strength
<< PMU1_PLL0_PC5_CLK_DRV_SHIFT
);
931 W_REG (osh
, &cc
->pllcontrol_data
, tmp
);
934 PMU_MSG (("Done pll\n"));
936 /* Write XtalFreq. Set the divisor also. */
937 tmp
= R_REG (osh
, &cc
->pmucontrol
) &
938 ~(PCTL_ILP_DIV_MASK
| PCTL_XTALFREQ_MASK
);
939 tmp
|= (((((xt
->fref
+ 127) / 128) - 1) << PCTL_ILP_DIV_SHIFT
) &
941 ((xt
->xf
<< PCTL_XTALFREQ_SHIFT
) & PCTL_XTALFREQ_MASK
);
942 W_REG (osh
, &cc
->pmucontrol
, tmp
);
947 BCMINITFN (sb_pmu1_cpuclk0
) (sb_t
* sbh
, osl_t
* osh
, chipcregs_t
* cc
)
949 const pmu1_xtaltab0_t
*xt
;
950 uint32 xf
, tmp
, m1div
;
952 uint32 ndiv_int
, ndiv_frac
, p2div
, p1div
, fvco
;
955 /* Find the xtal frequency in the table */
956 xf
= (R_REG (osh
, &cc
->pmucontrol
) & PCTL_XTALFREQ_MASK
) >>
958 for (xt
= pmu1_xtaltab0
; xt
->fref
; xt
++)
962 xt
= &pmu1_xtaltab0
[PMU1_XTAL0_DEFAULT
];
964 /* Read m1div from pllcontrol[1] */
965 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL1
);
966 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
967 m1div
= (tmp
& PMU1_PLL0_PC1_M1DIV_MASK
) >> PMU1_PLL0_PC1_M1DIV_SHIFT
;
970 /* Read p2div/p1div from pllcontrol[0] */
971 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL0
);
972 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
973 p2div
= (tmp
& PMU1_PLL0_PC0_P2DIV_MASK
) >> PMU1_PLL0_PC0_P2DIV_SHIFT
;
974 p1div
= (tmp
& PMU1_PLL0_PC0_P1DIV_MASK
) >> PMU1_PLL0_PC0_P1DIV_SHIFT
;
976 /* Calculate Fvco based on xtal freq and ndiv and pdiv */
977 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL2
);
978 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
980 (tmp
& PMU1_PLL0_PC2_NDIV_INT_MASK
) >> PMU1_PLL0_PC2_NDIV_INT_SHIFT
;
982 W_REG (osh
, &cc
->pllcontrol_addr
, PMU1_PLL0_PLLCTL3
);
983 tmp
= R_REG (osh
, &cc
->pllcontrol_data
);
985 (tmp
& PMU1_PLL0_PC3_NDIV_FRAC_MASK
) >> PMU1_PLL0_PC3_NDIV_FRAC_SHIFT
;
987 fvco
= (xt
->fref
* ndiv_int
) << 8;
988 fvco
+= (xt
->fref
* (ndiv_frac
>> 12)) >> 4;
989 fvco
+= (xt
->fref
* (ndiv_frac
& 0xfff)) >> 12;
996 PMU_MSG (("sb_pmu0_cpuclk0: ndiv_int %u ndiv_frac %u "
997 "p2div %u p1div %u fvco %u\n",
998 ndiv_int
, ndiv_frac
, p2div
, p1div
, fvco
));
999 ASSERT (fvco
== PMU1_PLL0_FVCO
);
1002 /* Return ARM/SB clock */
1003 return PMU1_PLL0_FVCO
/ m1div
* 1000;
1006 void BCMINITFN (sb_pmu_pll_init
) (sb_t
* sbh
, osl_t
* osh
, uint xtalfreq
)
1011 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1013 /* Remember original core before switch to chipc */
1014 origidx
= sb_coreidx (sbh
);
1015 cc
= sb_setcore (sbh
, SB_CC
, 0);
1020 case BCM4328_CHIP_ID
:
1021 sb_pmu0_pllinit0 (sbh
, osh
, cc
, xtalfreq
);
1023 case BCM5354_CHIP_ID
:
1024 sb_pmu0_pllinit0 (sbh
, osh
, cc
, xtalfreq
);
1026 case BCM4325_CHIP_ID
:
1027 sb_pmu1_pllinit0 (sbh
, osh
, cc
, xtalfreq
);
1029 case BCM4312_CHIP_ID
:
1030 sb_pmu1_pllinit0 (sbh
, osh
, cc
, xtalfreq
);
1033 PMU_MSG (("No PLL init done for chip %x rev %d pmurev %d\n",
1034 sbh
->chip
, sbh
->chiprev
, sbh
->pmurev
));
1038 /* Return to original core */
1039 sb_setcoreidx (sbh
, origidx
);
1042 uint32
BCMINITFN (sb_pmu_alp_clock
) (sb_t
* sbh
, osl_t
* osh
)
1046 uint32 clock
= ALP_CLOCK
;
1048 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1050 /* Remember original core before switch to chipc */
1051 origidx
= sb_coreidx (sbh
);
1052 cc
= sb_setcore (sbh
, SB_CC
, 0);
1057 case BCM4328_CHIP_ID
:
1058 clock
= sb_pmu0_alpclk0 (sbh
, osh
, cc
);
1060 case BCM5354_CHIP_ID
:
1061 clock
= sb_pmu0_alpclk0 (sbh
, osh
, cc
);
1063 case BCM4325_CHIP_ID
:
1064 clock
= sb_pmu1_alpclk0 (sbh
, osh
, cc
);
1066 case BCM4312_CHIP_ID
:
1067 clock
= sb_pmu1_alpclk0 (sbh
, osh
, cc
);
1069 clock
= 20000 * 1000;
1072 PMU_MSG (("No ALP clock specified "
1073 "for chip %x rev %d pmurev %d, using default %d Hz\n",
1074 sbh
->chip
, sbh
->chiprev
, sbh
->pmurev
, clock
));
1078 /* Return to original core */
1079 sb_setcoreidx (sbh
, origidx
);
1083 uint
BCMINITFN (sb_pmu_cpu_clock
) (sb_t
* sbh
, osl_t
* osh
)
1087 uint32 clock
= HT_CLOCK
;
1089 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1091 /* Remember original core before switch to chipc */
1092 origidx
= sb_coreidx (sbh
);
1093 cc
= sb_setcore (sbh
, SB_CC
, 0);
1098 case BCM4328_CHIP_ID
:
1099 clock
= sb_pmu0_cpuclk0 (sbh
, osh
, cc
);
1101 case BCM5354_CHIP_ID
:
1102 clock
= sb_pmu0_cpuclk0 (sbh
, osh
, cc
);
1104 case BCM4325_CHIP_ID
:
1105 clock
= sb_pmu1_cpuclk0 (sbh
, osh
, cc
);
1107 case BCM4312_CHIP_ID
:
1108 clock
= sb_pmu1_cpuclk0 (sbh
, osh
, cc
);
1111 PMU_MSG (("No CPU clock specified "
1112 "for chip %x rev %d pmurev %d, using default %d Hz\n",
1113 sbh
->chip
, sbh
->chiprev
, sbh
->pmurev
, clock
));
1117 /* Return to original core */
1118 sb_setcoreidx (sbh
, origidx
);
1122 void BCMINITFN (sb_pmu_init
) (sb_t
* sbh
, osl_t
* osh
)
1127 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1129 /* Remember original core before switch to chipc */
1130 origidx
= sb_coreidx (sbh
);
1131 cc
= sb_setcore (sbh
, SB_CC
, 0);
1134 if (sbh
->pmurev
>= 1)
1136 if (sbh
->chip
== BCM4325_CHIP_ID
&& sbh
->chiprev
<= 1)
1137 AND_REG (osh
, &cc
->pmucontrol
, ~PCTL_NOILP_ON_WAIT
);
1139 OR_REG (osh
, &cc
->pmucontrol
, PCTL_NOILP_ON_WAIT
);
1142 /* Return to original core */
1143 sb_setcoreidx (sbh
, origidx
);
1146 void BCMINITFN (sb_pmu_otp_power
) (sb_t
* sbh
, osl_t
* osh
, bool on
)
1151 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1153 /* Remember original core before switch to chipc */
1154 origidx
= sb_coreidx (sbh
);
1155 cc
= sb_setcore (sbh
, SB_CC
, 0);
1160 case BCM4325_CHIP_ID
:
1163 OR_REG (osh
, &cc
->min_res_mask
, PMURES_BIT (RES4325_LNLDO2_PU
));
1164 if (sbh
->boardflags
& BFL_BUCKBOOST
)
1165 AND_REG (osh
, &cc
->min_res_mask
,
1166 ~PMURES_BIT (RES4325_BUCK_BOOST_PWM
));
1171 if (sbh
->boardflags
& BFL_BUCKBOOST
)
1172 OR_REG (osh
, &cc
->min_res_mask
,
1173 PMURES_BIT (RES4325_BUCK_BOOST_PWM
));
1174 AND_REG (osh
, &cc
->min_res_mask
, ~PMURES_BIT (RES4325_LNLDO2_PU
));
1181 /* Return to original core */
1182 sb_setcoreidx (sbh
, origidx
);
1186 sb_pmu_rcal (sb_t
* sbh
, osl_t
* osh
)
1191 ASSERT (sbh
->cccaps
& CC_CAP_PMU
);
1193 /* Remember original core before switch to chipc */
1194 origidx
= sb_coreidx (sbh
);
1195 cc
= sb_setcore (sbh
, SB_CC
, 0);
1200 case BCM4325_CHIP_ID
:
1206 W_REG (osh
, &cc
->chipcontrol_addr
, 1);
1207 AND_REG (osh
, &cc
->chipcontrol_data
, ~0x04);
1208 OR_REG (osh
, &cc
->chipcontrol_data
, 0x04);
1210 /* Wait for completion */
1211 SPINWAIT (0 == (R_REG (osh
, &cc
->chipstatus
) & 0x08),
1213 ASSERT (R_REG (osh
, &cc
->chipstatus
) & 0x08);
1215 /* Drop the LSB to convert from 5 bit code to 4 bit code */
1216 rcal_code
= (uint8
) (R_REG (osh
, &cc
->chipstatus
) >> 5) & 0x0f;
1217 PMU_MSG (("RCal completed, status 0x%x, code 0x%x\n",
1218 R_REG (osh
, &cc
->chipstatus
), rcal_code
));
1220 /* Write RCal code into pmu_vreg_ctrl[32:29] */
1221 W_REG (osh
, &cc
->regcontrol_addr
, 0);
1222 val
= R_REG (osh
, &cc
->regcontrol_data
) & ~((uint32
) 0x07 << 29);
1223 val
|= (uint32
) (rcal_code
& 0x07) << 29;
1224 W_REG (osh
, &cc
->regcontrol_data
, val
);
1225 W_REG (osh
, &cc
->regcontrol_addr
, 1);
1226 val
= R_REG (osh
, &cc
->regcontrol_data
) & ~(uint32
) 0x01;
1227 val
|= (uint32
) ((rcal_code
>> 3) & 0x01);
1228 W_REG (osh
, &cc
->regcontrol_data
, val
);
1230 /* Write RCal code into pmu_chip_ctrl[33:30] */
1231 W_REG (osh
, &cc
->chipcontrol_addr
, 0);
1232 val
= R_REG (osh
, &cc
->chipcontrol_data
) & ~((uint32
) 0x03 << 30);
1233 val
|= (uint32
) (rcal_code
& 0x03) << 30;
1234 W_REG (osh
, &cc
->chipcontrol_data
, val
);
1235 W_REG (osh
, &cc
->chipcontrol_addr
, 1);
1236 val
= R_REG (osh
, &cc
->chipcontrol_data
) & ~(uint32
) 0x03;
1237 val
|= (uint32
) ((rcal_code
>> 2) & 0x03);
1238 W_REG (osh
, &cc
->chipcontrol_data
, val
);
1240 /* Set override in pmu_chip_ctrl[29] */
1241 W_REG (osh
, &cc
->chipcontrol_addr
, 0);
1242 OR_REG (osh
, &cc
->chipcontrol_data
, (0x01 << 29));
1244 /* Power off RCal block */
1245 W_REG (osh
, &cc
->chipcontrol_addr
, 1);
1246 AND_REG (osh
, &cc
->chipcontrol_data
, ~0x04);
1254 /* Return to original core */
1255 sb_setcoreidx (sbh
, origidx
);