• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/mach-bcmring/csp/chipc/
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/****************************************************************************/
70void 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
143EXPORT_SYMBOL(chipcHw_pll2Enable);
144
145/****************************************************************************/
146/**
147*  @brief  Initializes the PLL1
148*
149*  This function initializes the PLL1
150*
151*/
152/****************************************************************************/
153void 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
240EXPORT_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
251void 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