Merge branch 'multiplatform/platform-data' into next/multiplatform
[platform/kernel/linux-arm64.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         uint32_t __iomem *pPLLReg = NULL;
65         uint32_t __iomem *pClockCtrl = NULL;
66         uint32_t __iomem *pDependentClock = NULL;
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 ((readl(&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                     ((readl(&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                     ((readl(&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             ((readl(&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 (readl(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, (((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) ? ((readl(&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, ((readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ?  (readl(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 (readl(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 (readl(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 = readl(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 == &pChipcHw->ACLKClock) {
227                                         freq = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
228                                 } else {
229                                         if (readl(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 = readl(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 = readl(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         uint32_t __iomem *pPLLReg = NULL;
265         uint32_t __iomem *pClockCtrl = NULL;
266         uint32_t __iomem *pDependentClock = NULL;
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 ((readl(&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                     ((readl(&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                     (((readl(&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                     ((readl(&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             ((readl(&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                         writel((readl(&pChipcHw->DDRClock) & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((((freq / 2) / chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1) << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT), &pChipcHw->DDRClock);
311                         REG_LOCAL_IRQ_RESTORE;
312                 }
313                 pPLLReg = &pChipcHw->DDRClock;
314                 vcoHz = vcoFreqPll1Hz;
315                 desVcoHz = desVcoFreqPll1Hz;
316                 break;
317         case chipcHw_CLOCK_ARM:
318                 pPLLReg = &pChipcHw->ARMClock;
319                 vcoHz = vcoFreqPll1Hz;
320                 desVcoHz = desVcoFreqPll1Hz;
321                 break;
322         case chipcHw_CLOCK_ESW:
323                 pPLLReg = &pChipcHw->ESWClock;
324                 vcoHz = vcoFreqPll1Hz;
325                 desVcoHz = desVcoFreqPll1Hz;
326                 break;
327         case chipcHw_CLOCK_VPM:
328                 /* Configure the VPM:BUS ratio settings */
329                 {
330                         REG_LOCAL_IRQ_SAVE;
331                         writel((readl(&pChipcHw->VPMClock) & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((chipcHw_divide (freq, chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1) << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT), &pChipcHw->VPMClock);
332                         REG_LOCAL_IRQ_RESTORE;
333                 }
334                 pPLLReg = &pChipcHw->VPMClock;
335                 vcoHz = vcoFreqPll1Hz;
336                 desVcoHz = desVcoFreqPll1Hz;
337                 break;
338         case chipcHw_CLOCK_ESW125:
339                 pPLLReg = &pChipcHw->ESW125Clock;
340                 vcoHz = vcoFreqPll1Hz;
341                 desVcoHz = desVcoFreqPll1Hz;
342                 break;
343         case chipcHw_CLOCK_UART:
344                 pPLLReg = &pChipcHw->UARTClock;
345                 vcoHz = vcoFreqPll1Hz;
346                 desVcoHz = desVcoFreqPll1Hz;
347                 break;
348         case chipcHw_CLOCK_SDIO0:
349                 pPLLReg = &pChipcHw->SDIO0Clock;
350                 vcoHz = vcoFreqPll1Hz;
351                 desVcoHz = desVcoFreqPll1Hz;
352                 break;
353         case chipcHw_CLOCK_SDIO1:
354                 pPLLReg = &pChipcHw->SDIO1Clock;
355                 vcoHz = vcoFreqPll1Hz;
356                 desVcoHz = desVcoFreqPll1Hz;
357                 break;
358         case chipcHw_CLOCK_SPI:
359                 pPLLReg = &pChipcHw->SPIClock;
360                 vcoHz = vcoFreqPll1Hz;
361                 desVcoHz = desVcoFreqPll1Hz;
362                 break;
363         case chipcHw_CLOCK_ETM:
364                 pPLLReg = &pChipcHw->ETMClock;
365                 vcoHz = vcoFreqPll1Hz;
366                 desVcoHz = desVcoFreqPll1Hz;
367                 break;
368         case chipcHw_CLOCK_USB:
369                 pPLLReg = &pChipcHw->USBClock;
370                 vcoHz = vcoFreqPll2Hz;
371                 desVcoHz = vcoFreqPll2Hz;
372                 break;
373         case chipcHw_CLOCK_LCD:
374                 pPLLReg = &pChipcHw->LCDClock;
375                 vcoHz = vcoFreqPll2Hz;
376                 desVcoHz = vcoFreqPll2Hz;
377                 break;
378         case chipcHw_CLOCK_APM:
379                 pPLLReg = &pChipcHw->APMClock;
380                 vcoHz = vcoFreqPll2Hz;
381                 desVcoHz = vcoFreqPll2Hz;
382                 break;
383         case chipcHw_CLOCK_BUS:
384                 pClockCtrl = &pChipcHw->ACLKClock;
385                 pDependentClock = &pChipcHw->ARMClock;
386                 vcoHz = vcoFreqPll1Hz;
387                 desVcoHz = desVcoFreqPll1Hz;
388                 dependentClockType = PLL_CLOCK;
389                 break;
390         case chipcHw_CLOCK_OTP:
391                 pClockCtrl = &pChipcHw->OTPClock;
392                 break;
393         case chipcHw_CLOCK_I2C:
394                 pClockCtrl = &pChipcHw->I2CClock;
395                 break;
396         case chipcHw_CLOCK_I2S0:
397                 pClockCtrl = &pChipcHw->I2S0Clock;
398                 break;
399         case chipcHw_CLOCK_RTBUS:
400                 pClockCtrl = &pChipcHw->RTBUSClock;
401                 pDependentClock = &pChipcHw->ACLKClock;
402                 dependentClockType = NON_PLL_CLOCK;
403                 break;
404         case chipcHw_CLOCK_APM100:
405                 pClockCtrl = &pChipcHw->APM100Clock;
406                 pDependentClock = &pChipcHw->APMClock;
407                 vcoHz = vcoFreqPll2Hz;
408                 desVcoHz = vcoFreqPll2Hz;
409                 dependentClockType = PLL_CLOCK;
410                 break;
411         case chipcHw_CLOCK_TSC:
412                 pClockCtrl = &pChipcHw->TSCClock;
413                 break;
414         case chipcHw_CLOCK_LED:
415                 pClockCtrl = &pChipcHw->LEDClock;
416                 break;
417         case chipcHw_CLOCK_I2S1:
418                 pClockCtrl = &pChipcHw->I2S1Clock;
419                 break;
420         }
421
422         if (pPLLReg) {
423                 /* Select XTAL as bypass source */
424                 reg32_modify_and(pPLLReg, ~chipcHw_REG_PLL_CLOCK_SOURCE_GPIO);
425                 reg32_modify_or(pPLLReg, chipcHw_REG_PLL_CLOCK_BYPASS_SELECT);
426                 /* For DDR settings use only the PLL divider clock */
427                 if (pPLLReg == &pChipcHw->DDRClock) {
428                         /* Set M1DIV for PLL1, which controls the DDR clock */
429                         reg32_write(&pChipcHw->PLLDivider, (readl(&pChipcHw->PLLDivider) & 0x00FFFFFF) | ((chipcHw_REG_PLL_DIVIDER_MDIV (desVcoHz, freq)) << 24));
430                         /* Calculate expected frequency */
431                         freq = chipcHw_divide(vcoHz, (((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) ? ((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) : 256));
432                 } else {
433                         /* From chip revision number B0, LCD clock is internally divided by 2 */
434                         if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
435                                 desVcoHz >>= 1;
436                                 vcoHz >>= 1;
437                         }
438                         /* Set MDIV to change the frequency */
439                         reg32_modify_and(pPLLReg, ~(chipcHw_REG_PLL_CLOCK_MDIV_MASK));
440                         reg32_modify_or(pPLLReg, chipcHw_REG_PLL_DIVIDER_MDIV(desVcoHz, freq));
441                         /* Calculate expected frequency */
442                         freq = chipcHw_divide(vcoHz, ((readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
443                 }
444                 /* Wait for for atleast 200ns as per the protocol to change frequency */
445                 udelay(1);
446                 /* Do not bypass */
447                 reg32_modify_and(pPLLReg, ~chipcHw_REG_PLL_CLOCK_BYPASS_SELECT);
448                 /* Return the configured frequency */
449                 return freq;
450         } else if (pClockCtrl) {
451                 uint32_t divider = 0;
452
453                 /* Divider clock should not be bypassed  */
454                 reg32_modify_and(pClockCtrl,
455                                  ~chipcHw_REG_DIV_CLOCK_BYPASS_SELECT);
456
457                 /* Identify the clock source */
458                 if (pDependentClock) {
459                         switch (dependentClockType) {
460                         case PLL_CLOCK:
461                                 divider = chipcHw_divide(chipcHw_divide (desVcoHz, (readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_MDIV_MASK)), freq);
462                                 break;
463                         case NON_PLL_CLOCK:
464                                 {
465                                         uint32_t sourceClock = 0;
466
467                                         if (pDependentClock == &pChipcHw->ACLKClock) {
468                                                 sourceClock = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
469                                         } else {
470                                                 uint32_t div = readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
471                                                 sourceClock = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, ((div) ? div : 256));
472                                         }
473                                         divider = chipcHw_divide(sourceClock, freq);
474                                 }
475                                 break;
476                         }
477                 } else {
478                         divider = chipcHw_divide(chipcHw_XTAL_FREQ_Hz, freq);
479                 }
480
481                 if (divider) {
482                         REG_LOCAL_IRQ_SAVE;
483                         /* Set the divider to obtain the required frequency */
484                         writel((readl(pClockCtrl) & (~chipcHw_REG_DIV_CLOCK_DIV_MASK)) | (((divider > 256) ? chipcHw_REG_DIV_CLOCK_DIV_256 : divider) & chipcHw_REG_DIV_CLOCK_DIV_MASK), pClockCtrl);
485                         REG_LOCAL_IRQ_RESTORE;
486                         return freq;
487                 }
488         }
489
490         return 0;
491 }
492
493 EXPORT_SYMBOL(chipcHw_setClockFrequency);
494
495 /****************************************************************************/
496 /**
497 *  @brief   Set VPM clock in sync with BUS clock for Chip Rev #A0
498 *
499 *  This function does the phase adjustment between VPM and BUS clock
500 *
501 *  @return >= 0 : On success (# of adjustment required)
502 *            -1 : On failure
503 *
504 */
505 /****************************************************************************/
506 static int vpmPhaseAlignA0(void)
507 {
508         uint32_t phaseControl;
509         uint32_t phaseValue;
510         uint32_t prevPhaseComp;
511         int iter = 0;
512         int adjustCount = 0;
513         int count = 0;
514
515         for (iter = 0; (iter < MAX_PHASE_ALIGN_ATTEMPTS) && (adjustCount < MAX_PHASE_ADJUST_COUNT); iter++) {
516                 phaseControl = (readl(&pChipcHw->VPMClock) & chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT;
517                 phaseValue = 0;
518                 prevPhaseComp = 0;
519
520                 /* Step 1: Look for falling PH_COMP transition */
521
522                 /* Read the contents of VPM Clock resgister */
523                 phaseValue = readl(&pChipcHw->VPMClock);
524                 do {
525                         /* Store previous value of phase comparator */
526                         prevPhaseComp = phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP;
527                         /* Change the value of PH_CTRL. */
528                         reg32_write(&pChipcHw->VPMClock,
529                         (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
530                         /* Wait atleast 20 ns */
531                         udelay(1);
532                         /* Toggle the LOAD_CH after phase control is written. */
533                         writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
534                         /* Read the contents of  VPM Clock resgister. */
535                         phaseValue = readl(&pChipcHw->VPMClock);
536
537                         if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
538                                 phaseControl = (0x3F & (phaseControl - 1));
539                         } else {
540                                 /* Increment to the Phase count value for next write, if Phase is not stable. */
541                                 phaseControl = (0x3F & (phaseControl + 1));
542                         }
543                         /* Count number of adjustment made */
544                         adjustCount++;
545                 } while (((prevPhaseComp == (phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP)) || /* Look for a transition */
546                           ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) != 0x0)) &&  /* Look for a falling edge */
547                          (adjustCount < MAX_PHASE_ADJUST_COUNT) /* Do not exceed the limit while trying */
548                     );
549
550                 if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
551                         /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
552                         return -1;
553                 }
554
555                 /* Step 2: Keep moving forward to make sure falling PH_COMP transition was valid */
556
557                 for (count = 0; (count < 5) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
558                         phaseControl = (0x3F & (phaseControl + 1));
559                         reg32_write(&pChipcHw->VPMClock,
560                         (readl(&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                         writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
565                         phaseValue = readl(&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,
585                         (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
586                         /* Wait atleast 20 ns */
587                         udelay(1);
588                         /* Toggle the LOAD_CH after phase control is written. */
589                         writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
590                         phaseValue = readl(&pChipcHw->VPMClock);
591                         /* Count number of adjustment made */
592                         adjustCount++;
593                 }
594
595                 if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
596                         /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
597                         return -1;
598                 }
599
600                 if (count != 3) {
601                         /* Detected noisy transition */
602                         continue;
603                 }
604
605                 /* Step 4: Keep moving backward before the original transition took place. */
606
607                 for (count = 0; (count < 5); count++) {
608                         phaseControl = (0x3F & (phaseControl - 1));
609                         reg32_write(&pChipcHw->VPMClock,
610                         (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
611                         /* Wait atleast 20 ns */
612                         udelay(1);
613                         /* Toggle the LOAD_CH after phase control is written. */
614                         writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
615                         phaseValue = readl(&pChipcHw->VPMClock);
616                         /* Count number of adjustment made */
617                         adjustCount++;
618                 }
619
620                 if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
621                         /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
622                         return -1;
623                 }
624
625                 if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0) {
626                         /* Detected false transition */
627                         continue;
628                 }
629
630                 /* Step 5: Re discover the valid transition */
631
632                 do {
633                         /* Store previous value of phase comparator */
634                         prevPhaseComp = phaseValue;
635                         /* Change the value of PH_CTRL. */
636                         reg32_write(&pChipcHw->VPMClock,
637                         (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
638                         /* Wait atleast 20 ns */
639                         udelay(1);
640                         /* Toggle the LOAD_CH after phase control is written. */
641                         writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
642                         /* Read the contents of  VPM Clock resgister. */
643                         phaseValue = readl(&pChipcHw->VPMClock);
644
645                         if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
646                                 phaseControl = (0x3F & (phaseControl - 1));
647                         } else {
648                                 /* Increment to the Phase count value for next write, if Phase is not stable. */
649                                 phaseControl = (0x3F & (phaseControl + 1));
650                         }
651
652                         /* Count number of adjustment made */
653                         adjustCount++;
654                 } while (((prevPhaseComp == (phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP)) || ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) != 0x0)) && (adjustCount < MAX_PHASE_ADJUST_COUNT));
655
656                 if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
657                         /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries  */
658                         return -1;
659                 } else {
660                         /* Valid phase must have detected */
661                         break;
662                 }
663         }
664
665         /* For VPM Phase should be perfectly aligned. */
666         phaseControl = (((readl(&pChipcHw->VPMClock) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT) - 1) & 0x3F);
667         {
668                 REG_LOCAL_IRQ_SAVE;
669
670                 writel((readl(&pChipcHw->VPMClock) & ~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT), &pChipcHw->VPMClock);
671                 /* Load new phase value */
672                 writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
673
674                 REG_LOCAL_IRQ_RESTORE;
675         }
676         /* Return the status */
677         return (int)adjustCount;
678 }
679
680 /****************************************************************************/
681 /**
682 *  @brief   Set VPM clock in sync with BUS clock
683 *
684 *  This function does the phase adjustment between VPM and BUS clock
685 *
686 *  @return >= 0 : On success (# of adjustment required)
687 *            -1 : On failure
688 *
689 */
690 /****************************************************************************/
691 int chipcHw_vpmPhaseAlign(void)
692 {
693
694         if (chipcHw_getChipRevisionNumber() == chipcHw_REV_NUMBER_A0) {
695                 return vpmPhaseAlignA0();
696         } else {
697                 uint32_t phaseControl = chipcHw_getVpmPhaseControl();
698                 uint32_t phaseValue = 0;
699                 int adjustCount = 0;
700
701                 /* Disable VPM access */
702                 writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
703                 /* Disable HW VPM phase alignment  */
704                 chipcHw_vpmHwPhaseAlignDisable();
705                 /* Enable SW VPM phase alignment  */
706                 chipcHw_vpmSwPhaseAlignEnable();
707                 /* Adjust VPM phase */
708                 while (adjustCount < MAX_PHASE_ADJUST_COUNT) {
709                         phaseValue = chipcHw_getVpmHwPhaseAlignStatus();
710
711                         /* Adjust phase control value */
712                         if (phaseValue > 0xF) {
713                                 /* Increment phase control value */
714                                 phaseControl++;
715                         } else if (phaseValue < 0xF) {
716                                 /* Decrement phase control value */
717                                 phaseControl--;
718                         } else {
719                                 /* Enable VPM access */
720                                 writel(readl(&pChipcHw->Spare1) | chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
721                                 /* Return adjust count */
722                                 return adjustCount;
723                         }
724                         /* Change the value of PH_CTRL. */
725                         reg32_write(&pChipcHw->VPMClock,
726                         (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
727                         /* Wait atleast 20 ns */
728                         udelay(1);
729                         /* Toggle the LOAD_CH after phase control is written. */
730                         writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
731                         /* Count adjustment */
732                         adjustCount++;
733                 }
734         }
735
736         /* Disable VPM access */
737         writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
738         return -1;
739 }
740
741 /****************************************************************************/
742 /**
743 *  @brief   Local Divide function
744 *
745 *  This function does the divide
746 *
747 *  @return divide value
748 *
749 */
750 /****************************************************************************/
751 static int chipcHw_divide(int num, int denom)
752 {
753         int r;
754         int t = 1;
755
756         /* Shift denom and t up to the largest value to optimize algorithm */
757         /* t contains the units of each divide */
758         while ((denom & 0x40000000) == 0) {     /* fails if denom=0 */
759                 denom = denom << 1;
760                 t = t << 1;
761         }
762
763         /* Initialize the result */
764         r = 0;
765
766         do {
767                 /* Determine if there exists a positive remainder */
768                 if ((num - denom) >= 0) {
769                         /* Accumlate t to the result and calculate a new remainder */
770                         num = num - denom;
771                         r = r + t;
772                 }
773                 /* Continue to shift denom and shift t down to 0 */
774                 denom = denom >> 1;
775                 t = t >> 1;
776         } while (t != 0);
777
778         return r;
779 }