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