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 <csp/errno.h>
30 #include <csp/stdint.h>
31 #include <csp/module.h>
33 #include <mach/csp/chipcHw_def.h>
34 #include <mach/csp/chipcHw_inline.h>
37 #include <csp/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 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;
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;
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
);
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 ((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 ((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 (*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));
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
, ((*pPLLReg
& chipcHw_REG_PLL_CLOCK_MDIV_MASK
) ? (*pPLLReg
& chipcHw_REG_PLL_CLOCK_MDIV_MASK
) : 256));
204 } else if (pClockCtrl
) {
205 /* Obtain divider clock frequency */
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
) {
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
;
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;
226 if (pDependentClock
== (uint32_t *) &pChipcHw
->ACLKClock
) {
227 freq
= chipcHw_getClockFrequency (chipcHw_CLOCK_BUS
);
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
;
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));
241 /* Dependent on crystal clock */
242 freq
= chipcHw_XTAL_FREQ_Hz
;
245 div
= *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 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;
272 uint32_t desVcoHz
= 0;
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;
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
);
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 (((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 ((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 ((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 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
;
314 pPLLReg
= &pChipcHw
->DDRClock
;
315 vcoHz
= vcoFreqPll1Hz
;
316 desVcoHz
= desVcoFreqPll1Hz
;
318 case chipcHw_CLOCK_ARM
:
319 pPLLReg
= &pChipcHw
->ARMClock
;
320 vcoHz
= vcoFreqPll1Hz
;
321 desVcoHz
= desVcoFreqPll1Hz
;
323 case chipcHw_CLOCK_ESW
:
324 pPLLReg
= &pChipcHw
->ESWClock
;
325 vcoHz
= vcoFreqPll1Hz
;
326 desVcoHz
= desVcoFreqPll1Hz
;
328 case chipcHw_CLOCK_VPM
:
329 /* Configure the VPM:BUS ratio settings */
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
;
336 pPLLReg
= &pChipcHw
->VPMClock
;
337 vcoHz
= vcoFreqPll1Hz
;
338 desVcoHz
= desVcoFreqPll1Hz
;
340 case chipcHw_CLOCK_ESW125
:
341 pPLLReg
= &pChipcHw
->ESW125Clock
;
342 vcoHz
= vcoFreqPll1Hz
;
343 desVcoHz
= desVcoFreqPll1Hz
;
345 case chipcHw_CLOCK_UART
:
346 pPLLReg
= &pChipcHw
->UARTClock
;
347 vcoHz
= vcoFreqPll1Hz
;
348 desVcoHz
= desVcoFreqPll1Hz
;
350 case chipcHw_CLOCK_SDIO0
:
351 pPLLReg
= &pChipcHw
->SDIO0Clock
;
352 vcoHz
= vcoFreqPll1Hz
;
353 desVcoHz
= desVcoFreqPll1Hz
;
355 case chipcHw_CLOCK_SDIO1
:
356 pPLLReg
= &pChipcHw
->SDIO1Clock
;
357 vcoHz
= vcoFreqPll1Hz
;
358 desVcoHz
= desVcoFreqPll1Hz
;
360 case chipcHw_CLOCK_SPI
:
361 pPLLReg
= &pChipcHw
->SPIClock
;
362 vcoHz
= vcoFreqPll1Hz
;
363 desVcoHz
= desVcoFreqPll1Hz
;
365 case chipcHw_CLOCK_ETM
:
366 pPLLReg
= &pChipcHw
->ETMClock
;
367 vcoHz
= vcoFreqPll1Hz
;
368 desVcoHz
= desVcoFreqPll1Hz
;
370 case chipcHw_CLOCK_USB
:
371 pPLLReg
= &pChipcHw
->USBClock
;
372 vcoHz
= vcoFreqPll2Hz
;
373 desVcoHz
= vcoFreqPll2Hz
;
375 case chipcHw_CLOCK_LCD
:
376 pPLLReg
= &pChipcHw
->LCDClock
;
377 vcoHz
= vcoFreqPll2Hz
;
378 desVcoHz
= vcoFreqPll2Hz
;
380 case chipcHw_CLOCK_APM
:
381 pPLLReg
= &pChipcHw
->APMClock
;
382 vcoHz
= vcoFreqPll2Hz
;
383 desVcoHz
= vcoFreqPll2Hz
;
385 case chipcHw_CLOCK_BUS
:
386 pClockCtrl
= &pChipcHw
->ACLKClock
;
387 pDependentClock
= &pChipcHw
->ARMClock
;
388 vcoHz
= vcoFreqPll1Hz
;
389 desVcoHz
= desVcoFreqPll1Hz
;
390 dependentClockType
= PLL_CLOCK
;
392 case chipcHw_CLOCK_OTP
:
393 pClockCtrl
= &pChipcHw
->OTPClock
;
395 case chipcHw_CLOCK_I2C
:
396 pClockCtrl
= &pChipcHw
->I2CClock
;
398 case chipcHw_CLOCK_I2S0
:
399 pClockCtrl
= &pChipcHw
->I2S0Clock
;
401 case chipcHw_CLOCK_RTBUS
:
402 pClockCtrl
= &pChipcHw
->RTBUSClock
;
403 pDependentClock
= &pChipcHw
->ACLKClock
;
404 dependentClockType
= NON_PLL_CLOCK
;
406 case chipcHw_CLOCK_APM100
:
407 pClockCtrl
= &pChipcHw
->APM100Clock
;
408 pDependentClock
= &pChipcHw
->APMClock
;
409 vcoHz
= vcoFreqPll2Hz
;
410 desVcoHz
= vcoFreqPll2Hz
;
411 dependentClockType
= PLL_CLOCK
;
413 case chipcHw_CLOCK_TSC
:
414 pClockCtrl
= &pChipcHw
->TSCClock
;
416 case chipcHw_CLOCK_LED
:
417 pClockCtrl
= &pChipcHw
->LEDClock
;
419 case chipcHw_CLOCK_I2S1
:
420 pClockCtrl
= &pChipcHw
->I2S1Clock
;
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));
435 /* From chip revision number B0, LCD clock is internally divided by 2 */
436 if ((pPLLReg
== &pChipcHw
->LCDClock
) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0
)) {
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));
446 /* Wait for for atleast 200ns as per the protocol to change frequency */
449 reg32_modify_and(pPLLReg
, ~chipcHw_REG_PLL_CLOCK_BYPASS_SELECT
);
450 /* Return the configured frequency */
452 } else if (pClockCtrl
) {
453 uint32_t divider
= 0;
455 /* Divider clock should not be bypassed */
456 reg32_modify_and(pClockCtrl
,
457 ~chipcHw_REG_DIV_CLOCK_BYPASS_SELECT
);
459 /* Identify the clock source */
460 if (pDependentClock
) {
461 switch (dependentClockType
) {
463 divider
= chipcHw_divide(chipcHw_divide (desVcoHz
, (*pDependentClock
& chipcHw_REG_PLL_CLOCK_MDIV_MASK
)), freq
);
467 uint32_t sourceClock
= 0;
469 if (pDependentClock
== (uint32_t *) &pChipcHw
->ACLKClock
) {
470 sourceClock
= chipcHw_getClockFrequency (chipcHw_CLOCK_BUS
);
472 uint32_t div
= *pDependentClock
& chipcHw_REG_DIV_CLOCK_DIV_MASK
;
473 sourceClock
= chipcHw_divide (chipcHw_XTAL_FREQ_Hz
, ((div
) ? div
: 256));
475 divider
= chipcHw_divide(sourceClock
, freq
);
480 divider
= chipcHw_divide(chipcHw_XTAL_FREQ_Hz
, freq
);
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
;
495 EXPORT_SYMBOL(chipcHw_setClockFrequency
);
497 /****************************************************************************/
499 * @brief Set VPM clock in sync with BUS clock for Chip Rev #A0
501 * This function does the phase adjustment between VPM and BUS clock
503 * @return >= 0 : On success (# of adjustment required)
507 /****************************************************************************/
508 static int vpmPhaseAlignA0(void)
510 uint32_t phaseControl
;
512 uint32_t prevPhaseComp
;
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
;
522 /* Step 1: Look for falling PH_COMP transition */
524 /* Read the contents of VPM Clock resgister */
525 phaseValue
= pChipcHw
->VPMClock
;
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 */
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
;
538 if ((phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
) == 0x0) {
539 phaseControl
= (0x3F & (phaseControl
- 1));
541 /* Increment to the Phase count value for next write, if Phase is not stable. */
542 phaseControl
= (0x3F & (phaseControl
+ 1));
544 /* Count number of adjustment made */
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 */
551 if (adjustCount
>= MAX_PHASE_ADJUST_COUNT
) {
552 /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
556 /* Step 2: Keep moving forward to make sure falling PH_COMP transition was valid */
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 */
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 */
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
, (pChipcHw
->VPMClock
& (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK
)) | (phaseControl
<< chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT
));
585 /* Wait atleast 20 ns */
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 */
594 if (adjustCount
>= MAX_PHASE_ADJUST_COUNT
) {
595 /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
600 /* Detected noisy transition */
604 /* Step 4: Keep moving backward before the original transition took place. */
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 */
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 */
618 if (adjustCount
>= MAX_PHASE_ADJUST_COUNT
) {
619 /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
623 if ((phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
) == 0) {
624 /* Detected false transition */
628 /* Step 5: Re discover the valid transition */
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 */
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
;
643 if ((phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
) == 0x0) {
644 phaseControl
= (0x3F & (phaseControl
- 1));
646 /* Increment to the Phase count value for next write, if Phase is not stable. */
647 phaseControl
= (0x3F & (phaseControl
+ 1));
650 /* Count number of adjustment made */
652 } while (((prevPhaseComp
== (phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
)) || ((phaseValue
& chipcHw_REG_PLL_CLOCK_PHASE_COMP
) != 0x0)) && (adjustCount
< MAX_PHASE_ADJUST_COUNT
));
654 if (adjustCount
>= MAX_PHASE_ADJUST_COUNT
) {
655 /* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
658 /* Valid phase must have detected */
663 /* For VPM Phase should be perfectly aligned. */
664 phaseControl
= (((pChipcHw
->VPMClock
>> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT
) - 1) & 0x3F);
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
;
672 REG_LOCAL_IRQ_RESTORE
;
674 /* Return the status */
675 return (int)adjustCount
;
678 /****************************************************************************/
680 * @brief Set VPM clock in sync with BUS clock
682 * This function does the phase adjustment between VPM and BUS clock
684 * @return >= 0 : On success (# of adjustment required)
688 /****************************************************************************/
689 int chipcHw_vpmPhaseAlign(void)
692 if (chipcHw_getChipRevisionNumber() == chipcHw_REV_NUMBER_A0
) {
693 return vpmPhaseAlignA0();
695 uint32_t phaseControl
= chipcHw_getVpmPhaseControl();
696 uint32_t phaseValue
= 0;
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();
709 /* Adjust phase control value */
710 if (phaseValue
> 0xF) {
711 /* Increment phase control value */
713 } else if (phaseValue
< 0xF) {
714 /* Decrement phase control value */
717 /* Enable VPM access */
718 pChipcHw
->Spare1
|= chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE
;
719 /* Return adjust count */
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 */
726 /* Toggle the LOAD_CH after phase control is written. */
727 pChipcHw
->VPMClock
^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE
;
728 /* Count adjustment */
733 /* Disable VPM access */
734 pChipcHw
->Spare1
&= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE
;
738 /****************************************************************************/
740 * @brief Local Divide function
742 * This function does the divide
744 * @return divide value
747 /****************************************************************************/
748 static int chipcHw_divide(int num
, int denom
)
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 */
760 /* Initialize the result */
764 /* Determine if there exists a positive remainder */
765 if ((num
- denom
) >= 0) {
766 /* Accumlate t to the result and calculate a new remainder */
770 /* Continue to shift denom and shift t down to 0 */