]> git.openfabrics.org - ~shefty/rdma-dev.git/blob - arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
ARM: bcmring: use proper MMIO accessors
[~shefty/rdma-dev.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 <linux/errno.h>
30 #include <linux/types.h>
31 #include <linux/export.h>
32
33 #include <mach/csp/chipcHw_def.h>
34 #include <mach/csp/chipcHw_inline.h>
35
36 #include <mach/csp/reg.h>
37 #include <linux/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                 writel(chipcHw_REG_PLL_CONFIG_D_RESET |
77                        chipcHw_REG_PLL_CONFIG_A_RESET,
78                         &pChipcHw->PLLConfig2);
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                 writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
91
92                 /* Set pre divider to get desired VCO frequency */
93                 writel(pllPreDivider2, &pChipcHw->PLLPreDivider2);
94                 /* Set NDIV Frac */
95                 writel(chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider2);
96
97                 /* This has to be removed once the default values are fixed for PLL2. */
98                 writel(0x38000700, &pChipcHw->PLLControl12);
99                 writel(0x00000015, &pChipcHw->PLLControl22);
100
101                 /* Reset PLL2 */
102                 if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
103                         writel(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                             &pChipcHw->PLLConfig2);
108                 } else {
109                         writel(chipcHw_REG_PLL_CONFIG_D_RESET |
110                             chipcHw_REG_PLL_CONFIG_A_RESET |
111                             chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
112                             chipcHw_REG_PLL_CONFIG_POWER_DOWN,
113                             &pChipcHw->PLLConfig2);
114                 }
115                 REG_LOCAL_IRQ_RESTORE;
116         }
117
118         /* Insert certain amount of delay before deasserting ARESET. */
119         udelay(1);
120
121         {
122                 REG_LOCAL_IRQ_SAVE;
123                 /* Remove analog reset and Power on the PLL */
124                 writel(readl(&pChipcHw->PLLConfig2) &
125                     ~(chipcHw_REG_PLL_CONFIG_A_RESET |
126                       chipcHw_REG_PLL_CONFIG_POWER_DOWN),
127                       &pChipcHw->PLLConfig2);
128
129                 REG_LOCAL_IRQ_RESTORE;
130
131         }
132
133         /* Wait until PLL is locked */
134         while (!(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
135                 ;
136
137         {
138                 REG_LOCAL_IRQ_SAVE;
139                 /* Remove digital reset */
140                 writel(readl(&pChipcHw->PLLConfig2) &
141                         ~chipcHw_REG_PLL_CONFIG_D_RESET,
142                         &pChipcHw->PLLConfig2);
143
144                 REG_LOCAL_IRQ_RESTORE;
145         }
146 }
147
148 EXPORT_SYMBOL(chipcHw_pll2Enable);
149
150 /****************************************************************************/
151 /**
152 *  @brief  Initializes the PLL1
153 *
154 *  This function initializes the PLL1
155 *
156 */
157 /****************************************************************************/
158 void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
159 {
160         uint32_t pllPreDivider = 0;
161
162         {
163                 REG_LOCAL_IRQ_SAVE;
164
165                 writel(chipcHw_REG_PLL_CONFIG_D_RESET |
166                     chipcHw_REG_PLL_CONFIG_A_RESET,
167                     &pChipcHw->PLLConfig);
168                 /* Setting VCO frequency */
169                 if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
170                         pllPreDivider =
171                             chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASH_1_8 |
172                             ((chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) -
173                               1) << chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) |
174                             (chipcHw_REG_PLL_PREDIVIDER_P1 <<
175                              chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) |
176                             (chipcHw_REG_PLL_PREDIVIDER_P2 <<
177                              chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
178                 } else {
179                         pllPreDivider = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN |
180                             chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER |
181                             (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) <<
182                              chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) |
183                             (chipcHw_REG_PLL_PREDIVIDER_P1 <<
184                              chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) |
185                             (chipcHw_REG_PLL_PREDIVIDER_P2 <<
186                              chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
187                 }
188
189                 /* Enable CHIPC registers to control the PLL */
190                 writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
191
192                 /* Set pre divider to get desired VCO frequency */
193                 writel(pllPreDivider, &pChipcHw->PLLPreDivider);
194                 /* Set NDIV Frac */
195                 if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
196                         writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f_SS, &pChipcHw->PLLDivider);
197                 } else {
198                         writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider);
199                 }
200
201                 /* Reset PLL1 */
202                 if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
203                         writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_1601_3200 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
204                 } else {
205                         writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_800_1600 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
206                 }
207
208                 REG_LOCAL_IRQ_RESTORE;
209
210                 /* Insert certain amount of delay before deasserting ARESET. */
211                 udelay(1);
212
213                 {
214                         REG_LOCAL_IRQ_SAVE;
215                         /* Remove analog reset and Power on the PLL */
216                         writel(readl(&pChipcHw->PLLConfig) & ~(chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_POWER_DOWN), &pChipcHw->PLLConfig);
217                         REG_LOCAL_IRQ_RESTORE;
218                 }
219
220                 /* Wait until PLL is locked */
221                 while (!(readl(&pChipcHw->PLLStatus) & chipcHw_REG_PLL_STATUS_LOCKED)
222                        || !(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
223                         ;
224
225                 /* Remove digital reset */
226                 {
227                         REG_LOCAL_IRQ_SAVE;
228                         writel(readl(&pChipcHw->PLLConfig) & ~chipcHw_REG_PLL_CONFIG_D_RESET, &pChipcHw->PLLConfig);
229                         REG_LOCAL_IRQ_RESTORE;
230                 }
231         }
232 }
233
234 EXPORT_SYMBOL(chipcHw_pll1Enable);
235
236 /****************************************************************************/
237 /**
238 *  @brief  Initializes the chipc module
239 *
240 *  This function initializes the PLLs and core system clocks
241 *
242 */
243 /****************************************************************************/
244
245 void chipcHw_Init(chipcHw_INIT_PARAM_t *initParam       /*  [ IN ] Misc chip initialization parameter */
246     ) {
247 #if !(defined(__KERNEL__) && !defined(STANDALONE))
248         delay_init();
249 #endif
250
251         /* Do not program PLL, when warm reset */
252         if (!(chipcHw_getStickyBits() & chipcHw_REG_STICKY_CHIP_WARM_RESET)) {
253                 chipcHw_pll1Enable(initParam->pllVcoFreqHz,
254                                    initParam->ssSupport);
255                 chipcHw_pll2Enable(initParam->pll2VcoFreqHz);
256         } else {
257                 /* Clear sticky bits */
258                 chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_WARM_RESET);
259         }
260         /* Clear sticky bits */
261         chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET);
262
263         /* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */
264         writel((readl(&pChipcHw->ACLKClock) & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam-> armBusRatio & chipcHw_REG_ACLKClock_CLK_DIV_MASK), &pChipcHw->ACLKClock);
265
266         /* Set various core component frequencies. The order in which this is done is important for some. */
267         /* The RTBUS (DDR PHY) is derived from the BUS, and the BUS from the ARM, and VPM needs to know BUS */
268         /* frequency to find its ratio with the BUS.  Hence we must set the ARM first, followed by the BUS,  */
269         /* then VPM and RTBUS. */
270
271         chipcHw_setClockFrequency(chipcHw_CLOCK_ARM,
272                                   initParam->busClockFreqHz *
273                                   initParam->armBusRatio);
274         chipcHw_setClockFrequency(chipcHw_CLOCK_BUS, initParam->busClockFreqHz);
275         chipcHw_setClockFrequency(chipcHw_CLOCK_VPM,
276                                   initParam->busClockFreqHz *
277                                   initParam->vpmBusRatio);
278         chipcHw_setClockFrequency(chipcHw_CLOCK_DDR,
279                                   initParam->busClockFreqHz *
280                                   initParam->ddrBusRatio);
281         chipcHw_setClockFrequency(chipcHw_CLOCK_RTBUS,
282                                   initParam->busClockFreqHz / 2);
283 }