• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/mach-bcmring/csp/chipc/
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
49static 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/****************************************************************************/
62chipcHw_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/****************************************************************************/
261chipcHw_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
495EXPORT_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/****************************************************************************/
508static 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/****************************************************************************/
689int 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/****************************************************************************/
748static 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	/* Intialize 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