1 /*****************************************************************************
2 * Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2, available at
7 * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
9 * Notwithstanding the above, under no circumstances may you combine this
10 * software in any way with any other Broadcom software provided under a
11 * license other than the GPL, without Broadcom's express prior written
13 *****************************************************************************/
15 /****************************************************************************/
17 * @file chipcHw_init.c
19 * @brief Low level CHIPC PLL configuration functions
23 * These routines provide basic PLL controlling functionality only.
25 /****************************************************************************/
27 /* ---- Include Files ---------------------------------------------------- */
29 #include <csp/errno.h>
30 #include <csp/stdint.h>
31 #include <csp/module.h>
33 #include <mach/csp/chipcHw_def.h>
34 #include <mach/csp/chipcHw_inline.h>
37 #include <csp/delay.h>
38 /* ---- Private Constants and Types --------------------------------------- */
41 Calculation for NDIV_i to obtain VCO frequency
42 -----------------------------------------------
44 Freq_vco = Freq_ref * (P2 / P1) * (PLL_NDIV_i + PLL_NDIV_f)
45 for Freq_vco = VCO_FREQ_MHz
46 Freq_ref = chipcHw_XTAL_FREQ_Hz
52 PLL_NDIV_i = Freq_vco / Freq_ref = VCO_FREQ_MHz / chipcHw_XTAL_FREQ_Hz
54 Calculation for PLL MDIV to obtain frequency Freq_x for channel x
55 -----------------------------------------------------------------
56 Freq_x = chipcHw_XTAL_FREQ_Hz * PLL_NDIV_i / PLL_MDIV_x = VCO_FREQ_MHz / PLL_MDIV_x
58 PLL_MDIV_x = VCO_FREQ_MHz / Freq_x
61 /* ---- Private Variables ------------------------------------------------- */
62 /****************************************************************************/
64 * @brief Initializes the PLL2
66 * This function initializes the PLL2
69 /****************************************************************************/
70 void chipcHw_pll2Enable(uint32_t vcoFreqHz
)
72 uint32_t pllPreDivider2
= 0;
76 pChipcHw
->PLLConfig2
=
77 chipcHw_REG_PLL_CONFIG_D_RESET
|
78 chipcHw_REG_PLL_CONFIG_A_RESET
;
80 pllPreDivider2
= chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN
|
81 chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER
|
82 (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz
) <<
83 chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT
) |
84 (chipcHw_REG_PLL_PREDIVIDER_P1
<<
85 chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT
) |
86 (chipcHw_REG_PLL_PREDIVIDER_P2
<<
87 chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT
);
89 /* Enable CHIPC registers to control the PLL */
90 pChipcHw
->PLLStatus
|= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE
;
92 /* Set pre divider to get desired VCO frequency */
93 pChipcHw
->PLLPreDivider2
= pllPreDivider2
;
95 pChipcHw
->PLLDivider2
= chipcHw_REG_PLL_DIVIDER_NDIV_f
;
97 /* This has to be removed once the default values are fixed for PLL2. */
98 pChipcHw
->PLLControl12
= 0x38000700;
99 pChipcHw
->PLLControl22
= 0x00000015;
102 if (vcoFreqHz
> chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ
) {
103 pChipcHw
->PLLConfig2
= chipcHw_REG_PLL_CONFIG_D_RESET
|
104 chipcHw_REG_PLL_CONFIG_A_RESET
|
105 chipcHw_REG_PLL_CONFIG_VCO_1601_3200
|
106 chipcHw_REG_PLL_CONFIG_POWER_DOWN
;
108 pChipcHw
->PLLConfig2
= chipcHw_REG_PLL_CONFIG_D_RESET
|
109 chipcHw_REG_PLL_CONFIG_A_RESET
|
110 chipcHw_REG_PLL_CONFIG_VCO_800_1600
|
111 chipcHw_REG_PLL_CONFIG_POWER_DOWN
;
113 REG_LOCAL_IRQ_RESTORE
;
116 /* Insert certain amount of delay before deasserting ARESET. */
121 /* Remove analog reset and Power on the PLL */
122 pChipcHw
->PLLConfig2
&=
123 ~(chipcHw_REG_PLL_CONFIG_A_RESET
|
124 chipcHw_REG_PLL_CONFIG_POWER_DOWN
);
126 REG_LOCAL_IRQ_RESTORE
;
130 /* Wait until PLL is locked */
131 while (!(pChipcHw
->PLLStatus2
& chipcHw_REG_PLL_STATUS_LOCKED
))
136 /* Remove digital reset */
137 pChipcHw
->PLLConfig2
&= ~chipcHw_REG_PLL_CONFIG_D_RESET
;
139 REG_LOCAL_IRQ_RESTORE
;
143 EXPORT_SYMBOL(chipcHw_pll2Enable
);
145 /****************************************************************************/
147 * @brief Initializes the PLL1
149 * This function initializes the PLL1
152 /****************************************************************************/
153 void chipcHw_pll1Enable(uint32_t vcoFreqHz
, chipcHw_SPREAD_SPECTRUM_e ssSupport
)
155 uint32_t pllPreDivider
= 0;
160 pChipcHw
->PLLConfig
=
161 chipcHw_REG_PLL_CONFIG_D_RESET
|
162 chipcHw_REG_PLL_CONFIG_A_RESET
;
163 /* Setting VCO frequency */
164 if (ssSupport
== chipcHw_SPREAD_SPECTRUM_ALLOW
) {
166 chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASH_1_8
|
167 ((chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz
) -
168 1) << chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT
) |
169 (chipcHw_REG_PLL_PREDIVIDER_P1
<<
170 chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT
) |
171 (chipcHw_REG_PLL_PREDIVIDER_P2
<<
172 chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT
);
174 pllPreDivider
= chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN
|
175 chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER
|
176 (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz
) <<
177 chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT
) |
178 (chipcHw_REG_PLL_PREDIVIDER_P1
<<
179 chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT
) |
180 (chipcHw_REG_PLL_PREDIVIDER_P2
<<
181 chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT
);
184 /* Enable CHIPC registers to control the PLL */
185 pChipcHw
->PLLStatus
|= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE
;
187 /* Set pre divider to get desired VCO frequency */
188 pChipcHw
->PLLPreDivider
= pllPreDivider
;
190 if (ssSupport
== chipcHw_SPREAD_SPECTRUM_ALLOW
) {
191 pChipcHw
->PLLDivider
= chipcHw_REG_PLL_DIVIDER_M1DIV
|
192 chipcHw_REG_PLL_DIVIDER_NDIV_f_SS
;
194 pChipcHw
->PLLDivider
= chipcHw_REG_PLL_DIVIDER_M1DIV
|
195 chipcHw_REG_PLL_DIVIDER_NDIV_f
;
199 if (vcoFreqHz
> chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ
) {
200 pChipcHw
->PLLConfig
= chipcHw_REG_PLL_CONFIG_D_RESET
|
201 chipcHw_REG_PLL_CONFIG_A_RESET
|
202 chipcHw_REG_PLL_CONFIG_VCO_1601_3200
|
203 chipcHw_REG_PLL_CONFIG_POWER_DOWN
;
205 pChipcHw
->PLLConfig
= chipcHw_REG_PLL_CONFIG_D_RESET
|
206 chipcHw_REG_PLL_CONFIG_A_RESET
|
207 chipcHw_REG_PLL_CONFIG_VCO_800_1600
|
208 chipcHw_REG_PLL_CONFIG_POWER_DOWN
;
211 REG_LOCAL_IRQ_RESTORE
;
213 /* Insert certain amount of delay before deasserting ARESET. */
218 /* Remove analog reset and Power on the PLL */
219 pChipcHw
->PLLConfig
&=
220 ~(chipcHw_REG_PLL_CONFIG_A_RESET
|
221 chipcHw_REG_PLL_CONFIG_POWER_DOWN
);
222 REG_LOCAL_IRQ_RESTORE
;
225 /* Wait until PLL is locked */
226 while (!(pChipcHw
->PLLStatus
& chipcHw_REG_PLL_STATUS_LOCKED
)
228 PLLStatus2
& chipcHw_REG_PLL_STATUS_LOCKED
))
231 /* Remove digital reset */
234 pChipcHw
->PLLConfig
&= ~chipcHw_REG_PLL_CONFIG_D_RESET
;
235 REG_LOCAL_IRQ_RESTORE
;
240 EXPORT_SYMBOL(chipcHw_pll1Enable
);
242 /****************************************************************************/
244 * @brief Initializes the chipc module
246 * This function initializes the PLLs and core system clocks
249 /****************************************************************************/
251 void chipcHw_Init(chipcHw_INIT_PARAM_t
*initParam
/* [ IN ] Misc chip initialization parameter */
253 #if !(defined(__KERNEL__) && !defined(STANDALONE))
257 /* Do not program PLL, when warm reset */
258 if (!(chipcHw_getStickyBits() & chipcHw_REG_STICKY_CHIP_WARM_RESET
)) {
259 chipcHw_pll1Enable(initParam
->pllVcoFreqHz
,
260 initParam
->ssSupport
);
261 chipcHw_pll2Enable(initParam
->pll2VcoFreqHz
);
263 /* Clear sticky bits */
264 chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_WARM_RESET
);
266 /* Clear sticky bits */
267 chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET
);
269 /* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */
270 pChipcHw
->ACLKClock
=
272 ACLKClock
& ~chipcHw_REG_ACLKClock_CLK_DIV_MASK
) | (initParam
->
274 chipcHw_REG_ACLKClock_CLK_DIV_MASK
);
276 /* Set various core component frequencies. The order in which this is done is important for some. */
277 /* The RTBUS (DDR PHY) is derived from the BUS, and the BUS from the ARM, and VPM needs to know BUS */
278 /* frequency to find its ratio with the BUS. Hence we must set the ARM first, followed by the BUS, */
279 /* then VPM and RTBUS. */
281 chipcHw_setClockFrequency(chipcHw_CLOCK_ARM
,
282 initParam
->busClockFreqHz
*
283 initParam
->armBusRatio
);
284 chipcHw_setClockFrequency(chipcHw_CLOCK_BUS
, initParam
->busClockFreqHz
);
285 chipcHw_setClockFrequency(chipcHw_CLOCK_VPM
,
286 initParam
->busClockFreqHz
*
287 initParam
->vpmBusRatio
);
288 chipcHw_setClockFrequency(chipcHw_CLOCK_DDR
,
289 initParam
->busClockFreqHz
*
290 initParam
->ddrBusRatio
);
291 chipcHw_setClockFrequency(chipcHw_CLOCK_RTBUS
,
292 initParam
->busClockFreqHz
/ 2);