1 /*****************************************************************************
2 * Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
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").
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
13 *****************************************************************************/
15 /****************************************************************************/
19 * @brief Low level Various CHIP clock controlling routines
23 * These routines provide basic clock controlling functionality only.
25 /****************************************************************************/
27 /* ---- Include Files ---------------------------------------------------- */
29 #include <linux/errno.h>
30 #include <linux/types.h>
31 #include <linux/export.h>
33 #include <mach/csp/chipcHw_def.h>
34 #include <mach/csp/chipcHw_inline.h>
36 #include <mach/csp/reg.h>
37 #include <linux/delay.h>
39 /* ---- Private Constants and Types --------------------------------------- */
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 */
45 /* Local definition of clock type */
46 #define PLL_CLOCK 1 /* PLL Clock */
47 #define NON_PLL_CLOCK 2 /* Divider clock */
49 static int chipcHw_divide(int num
, int denom
)
50 __attribute__ ((section(".aramtext")));
52 /****************************************************************************/
54 * @brief Set clock fequency for miscellaneous configurable clocks
56 * This function sets clock frequency
58 * @return Configured clock frequency in hertz
61 /****************************************************************************/
62 chipcHw_freq
chipcHw_getClockFrequency(chipcHw_CLOCK_e clock
/* [ IN ] Configurable clock */
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;
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;
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
);
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
;
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
);
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
);
99 case chipcHw_CLOCK_DDR
:
100 pPLLReg
= &pChipcHw
->DDRClock
;
101 vcoHz
= vcoFreqPll1Hz
;
103 case chipcHw_CLOCK_ARM
:
104 pPLLReg
= &pChipcHw
->ARMClock
;
105 vcoHz
= vcoFreqPll1Hz
;
107 case chipcHw_CLOCK_ESW
:
108 pPLLReg
= &pChipcHw
->ESWClock
;
109 vcoHz
= vcoFreqPll1Hz
;
111 case chipcHw_CLOCK_VPM
:
112 pPLLReg
= &pChipcHw
->VPMClock
;
113 vcoHz
= vcoFreqPll1Hz
;
115 case chipcHw_CLOCK_ESW125
:
116 pPLLReg
= &pChipcHw
->ESW125Clock
;
117 vcoHz
= vcoFreqPll1Hz
;
119 case chipcHw_CLOCK_UART
:
120 pPLLReg
= &pChipcHw
->UARTClock
;
121 vcoHz
= vcoFreqPll1Hz
;
123 case chipcHw_CLOCK_SDIO0
:
124 pPLLReg
= &pChipcHw
->SDIO0Clock
;
125 vcoHz
= vcoFreqPll1Hz
;
127 case chipcHw_CLOCK_SDIO1
:
128 pPLLReg
= &pChipcHw
->SDIO1Clock
;
129 vcoHz
= vcoFreqPll1Hz
;
131 case chipcHw_CLOCK_SPI
:
132 pPLLReg
= &pChipcHw
->SPIClock
;
133 vcoHz
= vcoFreqPll1Hz
;
135 case chipcHw_CLOCK_ETM
:
136 pPLLReg
= &pChipcHw
->ETMClock
;
137 vcoHz
= vcoFreqPll1Hz
;
139 case chipcHw_CLOCK_USB
:
140 pPLLReg
= &pChipcHw
->USBClock
;
141 vcoHz
= vcoFreqPll2Hz
;
143 case chipcHw_CLOCK_LCD
:
144 pPLLReg
= &pChipcHw
->LCDClock
;
145 vcoHz
= vcoFreqPll2Hz
;
147 case chipcHw_CLOCK_APM
:
148 pPLLReg
= &pChipcHw
->APMClock
;
149 vcoHz
= vcoFreqPll2Hz
;
151 case chipcHw_CLOCK_BUS
:
152 pClockCtrl
= &pChipcHw
->ACLKClock
;
153 pDependentClock
= &pChipcHw
->ARMClock
;
154 vcoHz
= vcoFreqPll1Hz
;
155 dependentClockType
= PLL_CLOCK
;
157 case chipcHw_CLOCK_OTP
:
158 pClockCtrl
= &pChipcHw
->OTPClock
;
160 case chipcHw_CLOCK_I2C
:
161 pClockCtrl
= &pChipcHw
->I2CClock
;
163 case chipcHw_CLOCK_I2S0
:
164 pClockCtrl
= &pChipcHw
->I2S0Clock
;
166 case chipcHw_CLOCK_RTBUS
:
167 pClockCtrl
= &pChipcHw
->RTBUSClock
;
168 pDependentClock
= &pChipcHw
->ACLKClock
;
169 dependentClockType
= NON_PLL_CLOCK
;
171 case chipcHw_CLOCK_APM100
:
172 pClockCtrl
= &pChipcHw
->APM100Clock
;
173 pDependentClock
= &pChipcHw
->APMClock
;
174 vcoHz
= vcoFreqPll2Hz
;
175 dependentClockType
= PLL_CLOCK
;
177 case chipcHw_CLOCK_TSC
:
178 pClockCtrl
= &pChipcHw
->TSCClock
;
180 case chipcHw_CLOCK_LED
:
181 pClockCtrl
= &pChipcHw
->LEDClock
;
183 case chipcHw_CLOCK_I2S1
:
184 pClockCtrl
= &pChipcHw
->I2S1Clock
;
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));
197 /* From chip revision number B0, LCD clock is internally divided by 2 */
198 if ((pPLLReg
== &pChipcHw
->LCDClock
) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0
)) {
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));
204 } else if (pClockCtrl
) {
205 /* Obtain divider clock frequency */
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
) {
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
;
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;
226 if (pDependentClock
== &pChipcHw
->ACLKClock
) {
227 freq
= chipcHw_getClockFrequency (chipcHw_CLOCK_BUS
);
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
;
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));
241 /* Dependent on crystal clock */
242 freq
= chipcHw_XTAL_FREQ_Hz
;
245 div
= readl(pClockCtrl
) & chipcHw_REG_DIV_CLOCK_DIV_MASK
;
246 return chipcHw_divide(freq
, (div
? div
: 256));
251 /****************************************************************************/
253 * @brief Set clock fequency for miscellaneous configurable clocks
255 * This function sets clock frequency
257 * @return Configured clock frequency in Hz
260 /****************************************************************************/
261 chipcHw_freq
chipcHw_setClockFrequency(chipcHw_CLOCK_e clock
, /* [ IN ] Configurable clock */
262 uint32_t freq
/* [ IN ] Clock frequency in Hz */
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;
272 uint32_t desVcoHz
= 0;
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;
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
);
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
;
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);
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
);
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
);
305 case chipcHw_CLOCK_DDR
:
306 /* Configure the DDR_ctrl:BUS ratio settings */
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
;
313 pPLLReg
= &pChipcHw
->DDRClock
;
314 vcoHz
= vcoFreqPll1Hz
;
315 desVcoHz
= desVcoFreqPll1Hz
;
317 case chipcHw_CLOCK_ARM
:
318 pPLLReg
= &pChipcHw
->ARMClock
;
319 vcoHz
= vcoFreqPll1Hz
;
320 desVcoHz
= desVcoFreqPll1Hz
;
322 case chipcHw_CLOCK_ESW
:
323 pPLLReg
= &pChipcHw
->ESWClock
;
324 vcoHz
= vcoFreqPll1Hz
;
325 desVcoHz
= desVcoFreqPll1Hz
;
327 case chipcHw_CLOCK_VPM
:
328 /* Configure the VPM:BUS ratio settings */
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
;
334 pPLLReg
= &pChipcHw
->VPMClock
;
335 vcoHz
= vcoFreqPll1Hz
;
336 desVcoHz
= desVcoFreqPll1Hz
;
338 case chipcHw_CLOCK_ESW125
:
339 pPLLReg
= &pChipcHw
->ESW125Clock
;
340 vcoHz
= vcoFreqPll1Hz
;
341 desVcoHz
= desVcoFreqPll1Hz
;
343 case chipcHw_CLOCK_UART
:
344 pPLLReg
= &pChipcHw
->UARTClock
;
345 vcoHz
= vcoFreqPll1Hz
;
346 desVcoHz
= desVcoFreqPll1Hz
;
348 case chipcHw_CLOCK_SDIO0
:
349 pPLLReg
= &pChipcHw
->SDIO0Clock
;
350 vcoHz
= vcoFreqPll1Hz
;
351 desVcoHz
= desVcoFreqPll1Hz
;
353 case chipcHw_CLOCK_SDIO1
:
354 pPLLReg
= &pChipcHw
->SDIO1Clock
;
355 vcoHz
= vcoFreqPll1Hz
;
356 desVcoHz
= desVcoFreqPll1Hz
;
358 case chipcHw_CLOCK_SPI
:
359 pPLLReg
= &pChipcHw
->SPIClock
;
360 vcoHz
= vcoFreqPll1Hz
;
361 desVcoHz
= desVcoFreqPll1Hz
;
363 case chipcHw_CLOCK_ETM
:
364 pPLLReg
= &pChipcHw
->ETMClock
;
365 vcoHz
= vcoFreqPll1Hz
;
366 desVcoHz
= desVcoFreqPll1Hz
;
368 case chipcHw_CLOCK_USB
:
369 pPLLReg
= &pChipcHw
->USBClock
;
370 vcoHz
= vcoFreqPll2Hz
;
371 desVcoHz
= vcoFreqPll2Hz
;
373 case chipcHw_CLOCK_LCD
:
374 pPLLReg
= &pChipcHw
->LCDClock
;
375 vcoHz
= vcoFreqPll2Hz
;
376 desVcoHz
= vcoFreqPll2Hz
;
378 case chipcHw_CLOCK_APM
:
379 pPLLReg
= &pChipcHw
->APMClock
;
380 vcoHz
= vcoFreqPll2Hz
;
381 desVcoHz
= vcoFreqPll2Hz
;
383 case chipcHw_CLOCK_BUS
:
384 pClockCtrl
= &pChipcHw
->ACLKClock
;
385 pDependentClock
= &pChipcHw
->ARMClock
;
386 vcoHz
= vcoFreqPll1Hz
;
387 desVcoHz
= desVcoFreqPll1Hz
;
388 dependentClockType
= PLL_CLOCK
;
390 case chipcHw_CLOCK_OTP
:
391 pClockCtrl
= &pChipcHw
->OTPClock
;
393 case chipcHw_CLOCK_I2C
:
394 pClockCtrl
= &pChipcHw
->I2CClock
;
396 case chipcHw_CLOCK_I2S0
:
397 pClockCtrl
= &pChipcHw
->I2S0Clock
;
399 case chipcHw_CLOCK_RTBUS
:
400 pClockCtrl
= &pChipcHw
->RTBUSClock
;
401 pDependentClock
= &pChipcHw
->ACLKClock
;
402 dependentClockType
= NON_PLL_CLOCK
;
404 case chipcHw_CLOCK_APM100
:
405 pClockCtrl
= &pChipcHw
->APM100Clock
;
406 pDependentClock
= &pChipcHw
->APMClock
;
407 vcoHz
= vcoFreqPll2Hz
;
408 desVcoHz
= vcoFreqPll2Hz
;
409 dependentClockType
= PLL_CLOCK
;
411 case chipcHw_CLOCK_TSC
:
412 pClockCtrl
= &pChipcHw
->TSCClock
;
414 case chipcHw_CLOCK_LED
:
415 pClockCtrl
= &pChipcHw
->LEDClock
;
417 case chipcHw_CLOCK_I2S1
:
418 pClockCtrl
= &pChipcHw
->I2S1Clock
;
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));
433 /* From chip revision number B0, LCD clock is internally divided by 2 */
434 if ((pPLLReg
== &pChipcHw
->LCDClock
) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0
)) {
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));
444 /* Wait for for atleast 200ns as per the protocol to change frequency */
447 reg32_modify_and(pPLLReg
, ~chipcHw_REG_PLL_CLOCK_BYPASS_SELECT
);
448 /* Return the configured frequency */
450 } else if (pClockCtrl
) {
451 uint32_t divider
= 0;
453 /* Divider clock should not be bypassed */
454 reg32_modify_and(pClockCtrl
,
455 ~chipcHw_REG_DIV_CLOCK_BYPASS_SELECT
);
457 /* Identify the clock source */
458 if (pDependentClock
) {
459 switch (dependentClockType
) {
461 divider
= chipcHw_divide(chipcHw_divide (desVcoHz
, (readl(pDependentClock
) & chipcHw_REG_PLL_CLOCK_MDIV_MASK
)), freq
);
465 uint32_t sourceClock
= 0;
467 if (pDependentClock
== &pChipcHw
->ACLKClock
) {
468 sourceClock
= chipcHw_getClockFrequency (chipcHw_CLOCK_BUS
);
470 uint32_t div
= readl(pDependentClock
) & chipcHw_REG_DIV_CLOCK_DIV_MASK
;
471 sourceClock
= chipcHw_divide (chipcHw_XTAL_FREQ_Hz
, ((div
) ? div
: 256));
473 divider
= chipcHw_divide(sourceClock
, freq
);
478 divider
= chipcHw_divide(chipcHw_XTAL_FREQ_Hz
, freq
);
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
;
493 EXPORT_SYMBOL(chipcHw_setClockFrequency
);
495 /****************************************************************************/
497 * @brief Set VPM clock in sync with BUS clock for Chip Rev #A0
499 * This function does the phase adjustment between VPM and BUS clock
501 * @return >= 0 : On success (# of adjustment required)
505 /****************************************************************************/
506 static int vpmPhaseAlignA0(void)
508 uint32_t phaseControl
;
510 uint32_t prevPhaseComp
;
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
;
520 /* Step 1: Look for falling PH_COMP transition */
522 /* Read the contents of VPM Clock resgister */
523 phaseValue
= readl(&pChipcHw
->VPMClock
);
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 */
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
);
537 if ((phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
) == 0x0) {
538 phaseControl
= (0x3F & (phaseControl
- 1));
540 /* Increment to the Phase count value for next write, if Phase is not stable. */
541 phaseControl
= (0x3F & (phaseControl
+ 1));
543 /* Count number of adjustment made */
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 */
550 if (adjustCount
>= MAX_PHASE_ADJUST_COUNT
) {
551 /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
555 /* Step 2: Keep moving forward to make sure falling PH_COMP transition was valid */
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 */
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 */
570 if (adjustCount
>= MAX_PHASE_ADJUST_COUNT
) {
571 /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
576 /* Detected false transition */
580 /* Step 3: Keep moving backward to make sure falling PH_COMP transition was stable */
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 */
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 */
595 if (adjustCount
>= MAX_PHASE_ADJUST_COUNT
) {
596 /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
601 /* Detected noisy transition */
605 /* Step 4: Keep moving backward before the original transition took place. */
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 */
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 */
620 if (adjustCount
>= MAX_PHASE_ADJUST_COUNT
) {
621 /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
625 if ((phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
) == 0) {
626 /* Detected false transition */
630 /* Step 5: Re discover the valid transition */
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 */
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
);
645 if ((phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
) == 0x0) {
646 phaseControl
= (0x3F & (phaseControl
- 1));
648 /* Increment to the Phase count value for next write, if Phase is not stable. */
649 phaseControl
= (0x3F & (phaseControl
+ 1));
652 /* Count number of adjustment made */
654 } while (((prevPhaseComp
== (phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
)) || ((phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
) != 0x0)) && (adjustCount
< MAX_PHASE_ADJUST_COUNT
));
656 if (adjustCount
>= MAX_PHASE_ADJUST_COUNT
) {
657 /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
660 /* Valid phase must have detected */
665 /* For VPM Phase should be perfectly aligned. */
666 phaseControl
= (((readl(&pChipcHw
->VPMClock
) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT
) - 1) & 0x3F);
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
);
674 REG_LOCAL_IRQ_RESTORE
;
676 /* Return the status */
677 return (int)adjustCount
;
680 /****************************************************************************/
682 * @brief Set VPM clock in sync with BUS clock
684 * This function does the phase adjustment between VPM and BUS clock
686 * @return >= 0 : On success (# of adjustment required)
690 /****************************************************************************/
691 int chipcHw_vpmPhaseAlign(void)
694 if (chipcHw_getChipRevisionNumber() == chipcHw_REV_NUMBER_A0
) {
695 return vpmPhaseAlignA0();
697 uint32_t phaseControl
= chipcHw_getVpmPhaseControl();
698 uint32_t phaseValue
= 0;
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();
711 /* Adjust phase control value */
712 if (phaseValue
> 0xF) {
713 /* Increment phase control value */
715 } else if (phaseValue
< 0xF) {
716 /* Decrement phase control value */
719 /* Enable VPM access */
720 writel(readl(&pChipcHw
->Spare1
) | chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE
, &pChipcHw
->Spare1
);
721 /* Return adjust count */
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 */
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 */
736 /* Disable VPM access */
737 writel(readl(&pChipcHw
->Spare1
) & ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE
, &pChipcHw
->Spare1
);
741 /****************************************************************************/
743 * @brief Local Divide function
745 * This function does the divide
747 * @return divide value
750 /****************************************************************************/
751 static int chipcHw_divide(int num
, int denom
)
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 */
763 /* Initialize the result */
767 /* Determine if there exists a positive remainder */
768 if ((num
- denom
) >= 0) {
769 /* Accumlate t to the result and calculate a new remainder */
773 /* Continue to shift denom and shift t down to 0 */