Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6.git] / arch / arm / mach-bcmring / csp / chipc / chipcHw_init.c
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 /****************************************************************************/
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 /****************************************************************************/
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
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 }