1 /*****************************************************************************
2 * Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
3 *
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").
8 *
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
12 * consent.
13 *****************************************************************************/
14 
15 /****************************************************************************/
16 /**
17 *  @file    chipcHw_init.c
18 *
19 *  @brief   Low level CHIPC PLL configuration functions
20 *
21 *  @note
22 *
23 *   These routines provide basic PLL controlling functionality only.
24 */
25 /****************************************************************************/
26 
27 /* ---- Include Files ---------------------------------------------------- */
28 
29 #include <csp/errno.h>
30 #include <csp/stdint.h>
31 #include <csp/module.h>
32 
33 #include <mach/csp/chipcHw_def.h>
34 #include <mach/csp/chipcHw_inline.h>
35 
36 #include <csp/reg.h>
37 #include <csp/delay.h>
38 /* ---- Private Constants and Types --------------------------------------- */
39 
40 /*
41     Calculation for NDIV_i to obtain VCO frequency
42     -----------------------------------------------
43 
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
47 		PLL_P1 = PLL_P2 = 1
48 		and
49 		PLL_NDIV_f = 0
50 
51 	We get:
52 		PLL_NDIV_i = Freq_vco / Freq_ref = VCO_FREQ_MHz / chipcHw_XTAL_FREQ_Hz
53 
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
57 
58 		PLL_MDIV_x = VCO_FREQ_MHz / Freq_x
59 */
60 
61 /* ---- Private Variables ------------------------------------------------- */
62 /****************************************************************************/
63 /**
64 *  @brief  Initializes the PLL2
65 *
66 *  This function initializes the PLL2
67 *
68 */
69 /****************************************************************************/
chipcHw_pll2Enable(uint32_t vcoFreqHz)70 void chipcHw_pll2Enable(uint32_t vcoFreqHz)
71 {
72 	uint32_t pllPreDivider2 = 0;
73 
74 	{
75 		REG_LOCAL_IRQ_SAVE;
76 		pChipcHw->PLLConfig2 =
77 		    chipcHw_REG_PLL_CONFIG_D_RESET |
78 		    chipcHw_REG_PLL_CONFIG_A_RESET;
79 
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);
88 
89 		/* Enable CHIPC registers to control the PLL */
90 		pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
91 
92 		/* Set pre divider to get desired VCO frequency */
93 		pChipcHw->PLLPreDivider2 = pllPreDivider2;
94 		/* Set NDIV Frac */
95 		pChipcHw->PLLDivider2 = chipcHw_REG_PLL_DIVIDER_NDIV_f;
96 
97 		/* This has to be removed once the default values are fixed for PLL2. */
98 		pChipcHw->PLLControl12 = 0x38000700;
99 		pChipcHw->PLLControl22 = 0x00000015;
100 
101 		/* Reset PLL2 */
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;
107 		} else {
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;
112 		}
113 		REG_LOCAL_IRQ_RESTORE;
114 	}
115 
116 	/* Insert certain amount of delay before deasserting ARESET. */
117 	udelay(1);
118 
119 	{
120 		REG_LOCAL_IRQ_SAVE;
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);
125 
126 		REG_LOCAL_IRQ_RESTORE;
127 
128 	}
129 
130 	/* Wait until PLL is locked */
131 	while (!(pChipcHw->PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
132 		;
133 
134 	{
135 		REG_LOCAL_IRQ_SAVE;
136 		/* Remove digital reset */
137 		pChipcHw->PLLConfig2 &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
138 
139 		REG_LOCAL_IRQ_RESTORE;
140 	}
141 }
142 
143 EXPORT_SYMBOL(chipcHw_pll2Enable);
144 
145 /****************************************************************************/
146 /**
147 *  @brief  Initializes the PLL1
148 *
149 *  This function initializes the PLL1
150 *
151 */
152 /****************************************************************************/
chipcHw_pll1Enable(uint32_t vcoFreqHz,chipcHw_SPREAD_SPECTRUM_e ssSupport)153 void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
154 {
155 	uint32_t pllPreDivider = 0;
156 
157 	{
158 		REG_LOCAL_IRQ_SAVE;
159 
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) {
165 			pllPreDivider =
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);
173 		} else {
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);
182 		}
183 
184 		/* Enable CHIPC registers to control the PLL */
185 		pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
186 
187 		/* Set pre divider to get desired VCO frequency */
188 		pChipcHw->PLLPreDivider = pllPreDivider;
189 		/* Set NDIV Frac */
190 		if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
191 			pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
192 			    chipcHw_REG_PLL_DIVIDER_NDIV_f_SS;
193 		} else {
194 			pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
195 			    chipcHw_REG_PLL_DIVIDER_NDIV_f;
196 		}
197 
198 		/* Reset PLL1 */
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;
204 		} else {
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;
209 		}
210 
211 		REG_LOCAL_IRQ_RESTORE;
212 
213 		/* Insert certain amount of delay before deasserting ARESET. */
214 		udelay(1);
215 
216 		{
217 			REG_LOCAL_IRQ_SAVE;
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;
223 		}
224 
225 		/* Wait until PLL is locked */
226 		while (!(pChipcHw->PLLStatus & chipcHw_REG_PLL_STATUS_LOCKED)
227 		       || !(pChipcHw->
228 			    PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
229 			;
230 
231 		/* Remove digital reset */
232 		{
233 			REG_LOCAL_IRQ_SAVE;
234 			pChipcHw->PLLConfig &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
235 			REG_LOCAL_IRQ_RESTORE;
236 		}
237 	}
238 }
239 
240 EXPORT_SYMBOL(chipcHw_pll1Enable);
241 
242 /****************************************************************************/
243 /**
244 *  @brief  Initializes the chipc module
245 *
246 *  This function initializes the PLLs and core system clocks
247 *
248 */
249 /****************************************************************************/
250 
chipcHw_Init(chipcHw_INIT_PARAM_t * initParam)251 void chipcHw_Init(chipcHw_INIT_PARAM_t *initParam	/*  [ IN ] Misc chip initialization parameter */
252     ) {
253 #if !(defined(__KERNEL__) && !defined(STANDALONE))
254 	delay_init();
255 #endif
256 
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);
262 	} else {
263 		/* Clear sticky bits */
264 		chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_WARM_RESET);
265 	}
266 	/* Clear sticky bits */
267 	chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET);
268 
269 	/* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */
270 	pChipcHw->ACLKClock =
271 	    (pChipcHw->
272 	     ACLKClock & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam->
273 								 armBusRatio &
274 								 chipcHw_REG_ACLKClock_CLK_DIV_MASK);
275 
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. */
280 
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);
293 }
294