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 */