]> git.openfabrics.org - ~shefty/rdma-dev.git/blob - arch/arm/mach-bcmring/csp/chipc/chipcHw.c
5ac7e2509724f81f37d1270cdfa35ecc55d8f4bc
[~shefty/rdma-dev.git] / arch / arm / mach-bcmring / csp / chipc / chipcHw.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.c
18 *
19 *  @brief   Low level Various CHIP clock controlling routines
20 *
21 *  @note
22 *
23 *   These routines provide basic clock 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
39 /* ---- Private Constants and Types --------------------------------------- */
40
41 /* VPM alignment algorithm uses this */
42 #define MAX_PHASE_ADJUST_COUNT         0xFFFF   /* Max number of times allowed to adjust the phase */
43 #define MAX_PHASE_ALIGN_ATTEMPTS       10       /* Max number of attempt to align the phase */
44
45 /* Local definition of clock type */
46 #define PLL_CLOCK                      1        /* PLL Clock */
47 #define NON_PLL_CLOCK                  2        /* Divider clock */
48
49 static int chipcHw_divide(int num, int denom)
50     __attribute__ ((section(".aramtext")));
51
52 /****************************************************************************/
53 /**
54 *  @brief   Set clock fequency for miscellaneous configurable clocks
55 *
56 *  This function sets clock frequency
57 *
58 *  @return  Configured clock frequency in hertz
59 *
60 */
61 /****************************************************************************/
62 chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock    /*  [ IN ] Configurable clock */
63     ) {
64         volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
65         volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
66         volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
67         uint32_t vcoFreqPll1Hz = 0;     /* Effective VCO frequency for PLL1 in Hz */
68         uint32_t vcoFreqPll2Hz = 0;     /* Effective VCO frequency for PLL2 in Hz */
69         uint32_t dependentClockType = 0;
70         uint32_t vcoHz = 0;
71
72         /* Get VCO frequencies */
73         if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
74                 uint64_t adjustFreq = 0;
75
76                 vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
77                     chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
78                     ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
79                      chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
80
81                 /* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
82                 adjustFreq = (uint64_t) chipcHw_XTAL_FREQ_Hz *
83                         (uint64_t) chipcHw_REG_PLL_DIVIDER_NDIV_f_SS *
84                         chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, (chipcHw_REG_PLL_PREDIVIDER_P2 * (uint64_t) chipcHw_REG_PLL_DIVIDER_FRAC));
85                 vcoFreqPll1Hz += (uint32_t) adjustFreq;
86         } else {
87                 vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
88                     chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
89                     ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
90                      chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
91         }
92         vcoFreqPll2Hz =
93             chipcHw_XTAL_FREQ_Hz *
94                  chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
95             ((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
96              chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
97
98         switch (clock) {
99         case chipcHw_CLOCK_DDR:
100                 pPLLReg = &pChipcHw->DDRClock;
101                 vcoHz = vcoFreqPll1Hz;
102                 break;
103         case chipcHw_CLOCK_ARM:
104                 pPLLReg = &pChipcHw->ARMClock;
105                 vcoHz = vcoFreqPll1Hz;
106                 break;
107         case chipcHw_CLOCK_ESW:
108                 pPLLReg = &pChipcHw->ESWClock;
109                 vcoHz = vcoFreqPll1Hz;
110                 break;
111         case chipcHw_CLOCK_VPM:
112                 pPLLReg = &pChipcHw->VPMClock;
113                 vcoHz = vcoFreqPll1Hz;
114                 break;
115         case chipcHw_CLOCK_ESW125:
116                 pPLLReg = &pChipcHw->ESW125Clock;
117                 vcoHz = vcoFreqPll1Hz;
118                 break;
119         case chipcHw_CLOCK_UART:
120                 pPLLReg = &pChipcHw->UARTClock;
121                 vcoHz = vcoFreqPll1Hz;
122                 break;
123         case chipcHw_CLOCK_SDIO0:
124                 pPLLReg = &pChipcHw->SDIO0Clock;
125                 vcoHz = vcoFreqPll1Hz;
126                 break;
127         case chipcHw_CLOCK_SDIO1:
128                 pPLLReg = &pChipcHw->SDIO1Clock;
129                 vcoHz = vcoFreqPll1Hz;
130                 break;
131         case chipcHw_CLOCK_SPI:
132                 pPLLReg = &pChipcHw->SPIClock;
133                 vcoHz = vcoFreqPll1Hz;
134                 break;
135         case chipcHw_CLOCK_ETM:
136                 pPLLReg = &pChipcHw->ETMClock;
137                 vcoHz = vcoFreqPll1Hz;
138                 break;
139         case chipcHw_CLOCK_USB:
140                 pPLLReg = &pChipcHw->USBClock;
141                 vcoHz = vcoFreqPll2Hz;
142                 break;
143         case chipcHw_CLOCK_LCD:
144                 pPLLReg = &pChipcHw->LCDClock;
145                 vcoHz = vcoFreqPll2Hz;
146                 break;
147         case chipcHw_CLOCK_APM:
148                 pPLLReg = &pChipcHw->APMClock;
149                 vcoHz = vcoFreqPll2Hz;
150                 break;
151         case chipcHw_CLOCK_BUS:
152                 pClockCtrl = &pChipcHw->ACLKClock;
153                 pDependentClock = &pChipcHw->ARMClock;
154                 vcoHz = vcoFreqPll1Hz;
155                 dependentClockType = PLL_CLOCK;
156                 break;
157         case chipcHw_CLOCK_OTP:
158                 pClockCtrl = &pChipcHw->OTPClock;
159                 break;
160         case chipcHw_CLOCK_I2C:
161                 pClockCtrl = &pChipcHw->I2CClock;
162                 break;
163         case chipcHw_CLOCK_I2S0:
164                 pClockCtrl = &pChipcHw->I2S0Clock;
165                 break;
166         case chipcHw_CLOCK_RTBUS:
167                 pClockCtrl = &pChipcHw->RTBUSClock;
168                 pDependentClock = &pChipcHw->ACLKClock;
169                 dependentClockType = NON_PLL_CLOCK;
170                 break;
171         case chipcHw_CLOCK_APM100:
172                 pClockCtrl = &pChipcHw->APM100Clock;
173                 pDependentClock = &pChipcHw->APMClock;
174                 vcoHz = vcoFreqPll2Hz;
175                 dependentClockType = PLL_CLOCK;
176                 break;
177         case chipcHw_CLOCK_TSC:
178                 pClockCtrl = &pChipcHw->TSCClock;
179                 break;
180         case chipcHw_CLOCK_LED:
181                 pClockCtrl = &pChipcHw->LEDClock;
182                 break;
183         case chipcHw_CLOCK_I2S1:
184                 pClockCtrl = &pChipcHw->I2S1Clock;
185                 break;
186         }
187
188         if (pPLLReg) {
189                 /* Obtain PLL clock frequency */
190                 if (*pPLLReg & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
191                         /* Return crystal clock frequency when bypassed */
192                         return chipcHw_XTAL_FREQ_Hz;
193                 } else if (clock == chipcHw_CLOCK_DDR) {
194                         /* DDR frequency is configured in PLLDivider register */
195                         return chipcHw_divide (vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
196                 } else {
197                         /* From chip revision number B0, LCD clock is internally divided by 2 */
198                         if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
199                                 vcoHz >>= 1;
200                         }
201                         /* Obtain PLL clock frequency using VCO dividers */
202                         return chipcHw_divide(vcoHz, ((*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
203                 }
204         } else if (pClockCtrl) {
205                 /* Obtain divider clock frequency */
206                 uint32_t div;
207                 uint32_t freq = 0;
208
209                 if (*pClockCtrl & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
210                         /* Return crystal clock frequency when bypassed */
211                         return chipcHw_XTAL_FREQ_Hz;
212                 } else if (pDependentClock) {
213                         /* Identify the dependent clock frequency */
214                         switch (dependentClockType) {
215                         case PLL_CLOCK:
216                                 if (*pDependentClock & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
217                                         /* Use crystal clock frequency when dependent PLL clock is bypassed */
218                                         freq = chipcHw_XTAL_FREQ_Hz;
219                                 } else {
220                                         /* Obtain PLL clock frequency using VCO dividers */
221                                         div = *pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK;
222                                         freq = div ? chipcHw_divide(vcoHz, div) : 0;
223                                 }
224                                 break;
225                         case NON_PLL_CLOCK:
226                                 if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
227                                         freq = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
228                                 } else {
229                                         if (*pDependentClock & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
230                                                 /* Use crystal clock frequency when dependent divider clock is bypassed */
231                                                 freq = chipcHw_XTAL_FREQ_Hz;
232                                         } else {
233                                                 /* Obtain divider clock frequency using XTAL dividers */
234                                                 div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
235                                                 freq = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, (div ? div : 256));
236                                         }
237                                 }
238                                 break;
239                         }
240                 } else {
241                         /* Dependent on crystal clock */
242                         freq = chipcHw_XTAL_FREQ_Hz;
243                 }
244
245                 div = *pClockCtrl & chipcHw_REG_DIV_CLOCK_DIV_MASK;
246                 return chipcHw_divide(freq, (div ? div : 256));
247         }
248         return 0;
249 }
250
251 /****************************************************************************/
252 /**
253 *  @brief   Set clock fequency for miscellaneous configurable clocks
254 *
255 *  This function sets clock frequency
256 *
257 *  @return  Configured clock frequency in Hz
258 *
259 */
260 /****************************************************************************/
261 chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,   /*  [ IN ] Configurable clock */
262                                        uint32_t freq    /*  [ IN ] Clock frequency in Hz */
263     ) {
264         volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
265         volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
266         volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
267         uint32_t vcoFreqPll1Hz = 0;     /* Effective VCO frequency for PLL1 in Hz */
268         uint32_t desVcoFreqPll1Hz = 0;  /* Desired VCO frequency for PLL1 in Hz */
269         uint32_t vcoFreqPll2Hz = 0;     /* Effective VCO frequency for PLL2 in Hz */
270         uint32_t dependentClockType = 0;
271         uint32_t vcoHz = 0;
272         uint32_t desVcoHz = 0;
273
274         /* Get VCO frequencies */
275         if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
276                 uint64_t adjustFreq = 0;
277
278                 vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
279                     chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
280                     ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
281                      chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
282
283                 /* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
284                 adjustFreq = (uint64_t) chipcHw_XTAL_FREQ_Hz *
285                         (uint64_t) chipcHw_REG_PLL_DIVIDER_NDIV_f_SS *
286                         chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, (chipcHw_REG_PLL_PREDIVIDER_P2 * (uint64_t) chipcHw_REG_PLL_DIVIDER_FRAC));
287                 vcoFreqPll1Hz += (uint32_t) adjustFreq;
288
289                 /* Desired VCO frequency */
290                 desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
291                     chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
292                     (((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
293                       chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) + 1);
294         } else {
295                 vcoFreqPll1Hz = desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
296                     chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
297                     ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
298                      chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
299         }
300         vcoFreqPll2Hz = chipcHw_XTAL_FREQ_Hz * chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
301             ((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
302              chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
303
304         switch (clock) {
305         case chipcHw_CLOCK_DDR:
306                 /* Configure the DDR_ctrl:BUS ratio settings */
307                 {
308                         REG_LOCAL_IRQ_SAVE;
309                         /* Dvide DDR_phy by two to obtain DDR_ctrl clock */
310                         pChipcHw->DDRClock = (pChipcHw->DDRClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((((freq / 2) / chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
311                                 << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
312                         REG_LOCAL_IRQ_RESTORE;
313                 }
314                 pPLLReg = &pChipcHw->DDRClock;
315                 vcoHz = vcoFreqPll1Hz;
316                 desVcoHz = desVcoFreqPll1Hz;
317                 break;
318         case chipcHw_CLOCK_ARM:
319                 pPLLReg = &pChipcHw->ARMClock;
320                 vcoHz = vcoFreqPll1Hz;
321                 desVcoHz = desVcoFreqPll1Hz;
322                 break;
323         case chipcHw_CLOCK_ESW:
324                 pPLLReg = &pChipcHw->ESWClock;
325                 vcoHz = vcoFreqPll1Hz;
326                 desVcoHz = desVcoFreqPll1Hz;
327                 break;
328         case chipcHw_CLOCK_VPM:
329                 /* Configure the VPM:BUS ratio settings */
330                 {
331                         REG_LOCAL_IRQ_SAVE;
332                         pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((chipcHw_divide (freq, chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
333                                 << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
334                         REG_LOCAL_IRQ_RESTORE;
335                 }
336                 pPLLReg = &pChipcHw->VPMClock;
337                 vcoHz = vcoFreqPll1Hz;
338                 desVcoHz = desVcoFreqPll1Hz;
339                 break;
340         case chipcHw_CLOCK_ESW125:
341                 pPLLReg = &pChipcHw->ESW125Clock;
342                 vcoHz = vcoFreqPll1Hz;
343                 desVcoHz = desVcoFreqPll1Hz;
344                 break;
345         case chipcHw_CLOCK_UART:
346                 pPLLReg = &pChipcHw->UARTClock;
347                 vcoHz = vcoFreqPll1Hz;
348                 desVcoHz = desVcoFreqPll1Hz;
349                 break;
350         case chipcHw_CLOCK_SDIO0:
351                 pPLLReg = &pChipcHw->SDIO0Clock;
352                 vcoHz = vcoFreqPll1Hz;
353                 desVcoHz = desVcoFreqPll1Hz;
354                 break;
355         case chipcHw_CLOCK_SDIO1:
356                 pPLLReg = &pChipcHw->SDIO1Clock;
357                 vcoHz = vcoFreqPll1Hz;
358                 desVcoHz = desVcoFreqPll1Hz;
359                 break;
360         case chipcHw_CLOCK_SPI:
361                 pPLLReg = &pChipcHw->SPIClock;
362                 vcoHz = vcoFreqPll1Hz;
363                 desVcoHz = desVcoFreqPll1Hz;
364                 break;
365         case chipcHw_CLOCK_ETM:
366                 pPLLReg = &pChipcHw->ETMClock;
367                 vcoHz = vcoFreqPll1Hz;
368                 desVcoHz = desVcoFreqPll1Hz;
369                 break;
370         case chipcHw_CLOCK_USB:
371                 pPLLReg = &pChipcHw->USBClock;
372                 vcoHz = vcoFreqPll2Hz;
373                 desVcoHz = vcoFreqPll2Hz;
374                 break;
375         case chipcHw_CLOCK_LCD:
376                 pPLLReg = &pChipcHw->LCDClock;
377                 vcoHz = vcoFreqPll2Hz;
378                 desVcoHz = vcoFreqPll2Hz;
379                 break;
380         case chipcHw_CLOCK_APM:
381                 pPLLReg = &pChipcHw->APMClock;
382                 vcoHz = vcoFreqPll2Hz;
383                 desVcoHz = vcoFreqPll2Hz;
384                 break;
385         case chipcHw_CLOCK_BUS:
386                 pClockCtrl = &pChipcHw->ACLKClock;
387                 pDependentClock = &pChipcHw->ARMClock;
388                 vcoHz = vcoFreqPll1Hz;
389                 desVcoHz = desVcoFreqPll1Hz;
390                 dependentClockType = PLL_CLOCK;
391                 break;
392         case chipcHw_CLOCK_OTP:
393                 pClockCtrl = &pChipcHw->OTPClock;
394                 break;
395         case chipcHw_CLOCK_I2C:
396                 pClockCtrl = &pChipcHw->I2CClock;
397                 break;
398         case chipcHw_CLOCK_I2S0:
399                 pClockCtrl = &pChipcHw->I2S0Clock;
400                 break;
401         case chipcHw_CLOCK_RTBUS:
402                 pClockCtrl = &pChipcHw->RTBUSClock;
403                 pDependentClock = &pChipcHw->ACLKClock;
404                 dependentClockType = NON_PLL_CLOCK;
405                 break;
406         case chipcHw_CLOCK_APM100:
407                 pClockCtrl = &pChipcHw->APM100Clock;
408                 pDependentClock = &pChipcHw->APMClock;
409                 vcoHz = vcoFreqPll2Hz;
410                 desVcoHz = vcoFreqPll2Hz;
411                 dependentClockType = PLL_CLOCK;
412                 break;
413         case chipcHw_CLOCK_TSC:
414                 pClockCtrl = &pChipcHw->TSCClock;
415                 break;
416         case chipcHw_CLOCK_LED:
417                 pClockCtrl = &pChipcHw->LEDClock;
418                 break;
419         case chipcHw_CLOCK_I2S1:
420                 pClockCtrl = &pChipcHw->I2S1Clock;
421                 break;
422         }
423
424         if (pPLLReg) {
425                 /* Select XTAL as bypass source */
426                 reg32_modify_and(pPLLReg, ~chipcHw_REG_PLL_CLOCK_SOURCE_GPIO);
427                 reg32_modify_or(pPLLReg, chipcHw_REG_PLL_CLOCK_BYPASS_SELECT);
428                 /* For DDR settings use only the PLL divider clock */
429                 if (pPLLReg == &pChipcHw->DDRClock) {
430                         /* Set M1DIV for PLL1, which controls the DDR clock */
431                         reg32_write(&pChipcHw->PLLDivider, (pChipcHw->PLLDivider & 0x00FFFFFF) | ((chipcHw_REG_PLL_DIVIDER_MDIV (desVcoHz, freq)) << 24));
432                         /* Calculate expected frequency */
433                         freq = chipcHw_divide(vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
434                 } else {
435                         /* From chip revision number B0, LCD clock is internally divided by 2 */
436                         if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
437                                 desVcoHz >>= 1;
438                                 vcoHz >>= 1;
439                         }
440                         /* Set MDIV to change the frequency */
441                         reg32_modify_and(pPLLReg, ~(chipcHw_REG_PLL_CLOCK_MDIV_MASK));
442                         reg32_modify_or(pPLLReg, chipcHw_REG_PLL_DIVIDER_MDIV(desVcoHz, freq));
443                         /* Calculate expected frequency */
444                         freq = chipcHw_divide(vcoHz, ((*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
445                 }
446                 /* Wait for for atleast 200ns as per the protocol to change frequency */
447                 udelay(1);
448                 /* Do not bypass */
449                 reg32_modify_and(pPLLReg, ~chipcHw_REG_PLL_CLOCK_BYPASS_SELECT);
450                 /* Return the configured frequency */
451                 return freq;
452         } else if (pClockCtrl) {
453                 uint32_t divider = 0;
454
455                 /* Divider clock should not be bypassed  */
456                 reg32_modify_and(pClockCtrl,
457                                  ~chipcHw_REG_DIV_CLOCK_BYPASS_SELECT);
458
459                 /* Identify the clock source */
460                 if (pDependentClock) {
461                         switch (dependentClockType) {
462                         case PLL_CLOCK:
463                                 divider = chipcHw_divide(chipcHw_divide (desVcoHz, (*pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK)), freq);
464                                 break;
465                         case NON_PLL_CLOCK:
466                                 {
467                                         uint32_t sourceClock = 0;
468
469                                         if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
470                                                 sourceClock = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
471                                         } else {
472                                                 uint32_t div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
473                                                 sourceClock = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, ((div) ? div : 256));
474                                         }
475                                         divider = chipcHw_divide(sourceClock, freq);
476                                 }
477                                 break;
478                         }
479                 } else {
480                         divider = chipcHw_divide(chipcHw_XTAL_FREQ_Hz, freq);
481                 }
482
483                 if (divider) {
484                         REG_LOCAL_IRQ_SAVE;
485                         /* Set the divider to obtain the required frequency */
486                         *pClockCtrl = (*pClockCtrl & (~chipcHw_REG_DIV_CLOCK_DIV_MASK)) | (((divider > 256) ? chipcHw_REG_DIV_CLOCK_DIV_256 : divider) & chipcHw_REG_DIV_CLOCK_DIV_MASK);
487                         REG_LOCAL_IRQ_RESTORE;
488                         return freq;
489                 }
490         }
491
492         return 0;
493 }
494
495 EXPORT_SYMBOL(chipcHw_setClockFrequency);
496
497 /****************************************************************************/
498 /**
499 *  @brief   Set VPM clock in sync with BUS clock for Chip Rev #A0
500 *
501 *  This function does the phase adjustment between VPM and BUS clock
502 *
503 *  @return >= 0 : On success (# of adjustment required)
504 *            -1 : On failure
505 *
506 */
507 /****************************************************************************/
508 static int vpmPhaseAlignA0(void)
509 {
510         uint32_t phaseControl;
511         uint32_t phaseValue;
512         uint32_t prevPhaseComp;
513         int iter = 0;
514         int adjustCount = 0;
515         int count = 0;
516
517         for (iter = 0; (iter < MAX_PHASE_ALIGN_ATTEMPTS) && (adjustCount < MAX_PHASE_ADJUST_COUNT); iter++) {
518                 phaseControl = (pChipcHw->VPMClock & chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT;
519                 phaseValue = 0;
520                 prevPhaseComp = 0;
521
522                 /* Step 1: Look for falling PH_COMP transition */
523
524                 /* Read the contents of VPM Clock resgister */
525                 phaseValue = pChipcHw->VPMClock;
526                 do {
527                         /* Store previous value of phase comparator */
528                         prevPhaseComp = phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP;
529                         /* Change the value of PH_CTRL. */
530                         reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
531                         /* Wait atleast 20 ns */
532                         udelay(1);
533                         /* Toggle the LOAD_CH after phase control is written. */
534                         pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
535                         /* Read the contents of  VPM Clock resgister. */
536                         phaseValue = pChipcHw->VPMClock;
537
538                         if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
539                                 phaseControl = (0x3F & (phaseControl - 1));
540                         } else {
541                                 /* Increment to the Phase count value for next write, if Phase is not stable. */
542                                 phaseControl = (0x3F & (phaseControl + 1));
543                         }
544                         /* Count number of adjustment made */
545                         adjustCount++;
546                 } while (((prevPhaseComp == (phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP)) || /* Look for a transition */
547                           ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) != 0x0)) &&  /* Look for a falling edge */
548                          (adjustCount < MAX_PHASE_ADJUST_COUNT) /* Do not exceed the limit while trying */
549                     );
550
551                 if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
552                         /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
553                         return -1;
554                 }
555
556                 /* Step 2: Keep moving forward to make sure falling PH_COMP transition was valid */
557
558                 for (count = 0; (count < 5) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
559                         phaseControl = (0x3F & (phaseControl + 1));
560                         reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
561                         /* Wait atleast 20 ns */
562                         udelay(1);
563                         /* Toggle the LOAD_CH after phase control is written. */
564                         pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
565                         phaseValue = pChipcHw->VPMClock;
566                         /* Count number of adjustment made */
567                         adjustCount++;
568                 }
569
570                 if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
571                         /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
572                         return -1;
573                 }
574
575                 if (count != 5) {
576                         /* Detected false transition */
577                         continue;
578                 }
579
580                 /* Step 3: Keep moving backward to make sure falling PH_COMP transition was stable */
581
582                 for (count = 0; (count < 3) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
583                         phaseControl = (0x3F & (phaseControl - 1));
584                         reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
585                         /* Wait atleast 20 ns */
586                         udelay(1);
587                         /* Toggle the LOAD_CH after phase control is written. */
588                         pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
589                         phaseValue = pChipcHw->VPMClock;
590                         /* Count number of adjustment made */
591                         adjustCount++;
592                 }
593
594                 if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
595                         /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
596                         return -1;
597                 }
598
599                 if (count != 3) {
600                         /* Detected noisy transition */
601                         continue;
602                 }
603
604                 /* Step 4: Keep moving backward before the original transition took place. */
605
606                 for (count = 0; (count < 5); count++) {
607                         phaseControl = (0x3F & (phaseControl - 1));
608                         reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
609                         /* Wait atleast 20 ns */
610                         udelay(1);
611                         /* Toggle the LOAD_CH after phase control is written. */
612                         pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
613                         phaseValue = pChipcHw->VPMClock;
614                         /* Count number of adjustment made */
615                         adjustCount++;
616                 }
617
618                 if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
619                         /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
620                         return -1;
621                 }
622
623                 if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0) {
624                         /* Detected false transition */
625                         continue;
626                 }
627
628                 /* Step 5: Re discover the valid transition */
629
630                 do {
631                         /* Store previous value of phase comparator */
632                         prevPhaseComp = phaseValue;
633                         /* Change the value of PH_CTRL. */
634                         reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
635                         /* Wait atleast 20 ns */
636                         udelay(1);
637                         /* Toggle the LOAD_CH after phase control is written. */
638                         pChipcHw->VPMClock ^=
639                             chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
640                         /* Read the contents of  VPM Clock resgister. */
641                         phaseValue = pChipcHw->VPMClock;
642
643                         if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
644                                 phaseControl = (0x3F & (phaseControl - 1));
645                         } else {
646                                 /* Increment to the Phase count value for next write, if Phase is not stable. */
647                                 phaseControl = (0x3F & (phaseControl + 1));
648                         }
649
650                         /* Count number of adjustment made */
651                         adjustCount++;
652                 } while (((prevPhaseComp == (phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP)) || ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) != 0x0)) && (adjustCount < MAX_PHASE_ADJUST_COUNT));
653
654                 if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
655                         /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries  */
656                         return -1;
657                 } else {
658                         /* Valid phase must have detected */
659                         break;
660                 }
661         }
662
663         /* For VPM Phase should be perfectly aligned. */
664         phaseControl = (((pChipcHw->VPMClock >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT) - 1) & 0x3F);
665         {
666                 REG_LOCAL_IRQ_SAVE;
667
668                 pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT);
669                 /* Load new phase value */
670                 pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
671
672                 REG_LOCAL_IRQ_RESTORE;
673         }
674         /* Return the status */
675         return (int)adjustCount;
676 }
677
678 /****************************************************************************/
679 /**
680 *  @brief   Set VPM clock in sync with BUS clock
681 *
682 *  This function does the phase adjustment between VPM and BUS clock
683 *
684 *  @return >= 0 : On success (# of adjustment required)
685 *            -1 : On failure
686 *
687 */
688 /****************************************************************************/
689 int chipcHw_vpmPhaseAlign(void)
690 {
691
692         if (chipcHw_getChipRevisionNumber() == chipcHw_REV_NUMBER_A0) {
693                 return vpmPhaseAlignA0();
694         } else {
695                 uint32_t phaseControl = chipcHw_getVpmPhaseControl();
696                 uint32_t phaseValue = 0;
697                 int adjustCount = 0;
698
699                 /* Disable VPM access */
700                 pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
701                 /* Disable HW VPM phase alignment  */
702                 chipcHw_vpmHwPhaseAlignDisable();
703                 /* Enable SW VPM phase alignment  */
704                 chipcHw_vpmSwPhaseAlignEnable();
705                 /* Adjust VPM phase */
706                 while (adjustCount < MAX_PHASE_ADJUST_COUNT) {
707                         phaseValue = chipcHw_getVpmHwPhaseAlignStatus();
708
709                         /* Adjust phase control value */
710                         if (phaseValue > 0xF) {
711                                 /* Increment phase control value */
712                                 phaseControl++;
713                         } else if (phaseValue < 0xF) {
714                                 /* Decrement phase control value */
715                                 phaseControl--;
716                         } else {
717                                 /* Enable VPM access */
718                                 pChipcHw->Spare1 |= chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
719                                 /* Return adjust count */
720                                 return adjustCount;
721                         }
722                         /* Change the value of PH_CTRL. */
723                         reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
724                         /* Wait atleast 20 ns */
725                         udelay(1);
726                         /* Toggle the LOAD_CH after phase control is written. */
727                         pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
728                         /* Count adjustment */
729                         adjustCount++;
730                 }
731         }
732
733         /* Disable VPM access */
734         pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
735         return -1;
736 }
737
738 /****************************************************************************/
739 /**
740 *  @brief   Local Divide function
741 *
742 *  This function does the divide
743 *
744 *  @return divide value
745 *
746 */
747 /****************************************************************************/
748 static int chipcHw_divide(int num, int denom)
749 {
750         int r;
751         int t = 1;
752
753         /* Shift denom and t up to the largest value to optimize algorithm */
754         /* t contains the units of each divide */
755         while ((denom & 0x40000000) == 0) {     /* fails if denom=0 */
756                 denom = denom << 1;
757                 t = t << 1;
758         }
759
760         /* Initialize the result */
761         r = 0;
762
763         do {
764                 /* Determine if there exists a positive remainder */
765                 if ((num - denom) >= 0) {
766                         /* Accumlate t to the result and calculate a new remainder */
767                         num = num - denom;
768                         r = r + t;
769                 }
770                 /* Continue to shift denom and shift t down to 0 */
771                 denom = denom >> 1;
772                 t = t >> 1;
773         } while (t != 0);
774
775         return r;
776 }