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