294 lines
		
	
	
	
		
			9.3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			294 lines
		
	
	
	
		
			9.3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*****************************************************************************
 | ||
|  | * Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved. | ||
|  | * | ||
|  | * Unless you and Broadcom execute a separate written software license | ||
|  | * agreement governing use of this software, this software is licensed to you | ||
|  | * under the terms of the GNU General Public License version 2, available at | ||
|  | * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
 | ||
|  | * | ||
|  | * Notwithstanding the above, under no circumstances may you combine this | ||
|  | * software in any way with any other Broadcom software provided under a | ||
|  | * license other than the GPL, without Broadcom's express prior written | ||
|  | * consent. | ||
|  | *****************************************************************************/ | ||
|  | 
 | ||
|  | /****************************************************************************/ | ||
|  | /**
 | ||
|  | *  @file    chipcHw_init.c | ||
|  | * | ||
|  | *  @brief   Low level CHIPC PLL configuration functions | ||
|  | * | ||
|  | *  @note | ||
|  | * | ||
|  | *   These routines provide basic PLL controlling functionality only. | ||
|  | */ | ||
|  | /****************************************************************************/ | ||
|  | 
 | ||
|  | /* ---- Include Files ---------------------------------------------------- */ | ||
|  | 
 | ||
|  | #include <csp/errno.h>
 | ||
|  | #include <csp/stdint.h>
 | ||
|  | #include <csp/module.h>
 | ||
|  | 
 | ||
|  | #include <mach/csp/chipcHw_def.h>
 | ||
|  | #include <mach/csp/chipcHw_inline.h>
 | ||
|  | 
 | ||
|  | #include <csp/reg.h>
 | ||
|  | #include <csp/delay.h>
 | ||
|  | /* ---- Private Constants and Types --------------------------------------- */ | ||
|  | 
 | ||
|  | /*
 | ||
|  |     Calculation for NDIV_i to obtain VCO frequency | ||
|  |     ----------------------------------------------- | ||
|  | 
 | ||
|  | 	Freq_vco = Freq_ref * (P2 / P1) * (PLL_NDIV_i + PLL_NDIV_f) | ||
|  | 	for Freq_vco = VCO_FREQ_MHz | ||
|  | 		Freq_ref = chipcHw_XTAL_FREQ_Hz | ||
|  | 		PLL_P1 = PLL_P2 = 1 | ||
|  | 		and | ||
|  | 		PLL_NDIV_f = 0 | ||
|  | 
 | ||
|  | 	We get: | ||
|  | 		PLL_NDIV_i = Freq_vco / Freq_ref = VCO_FREQ_MHz / chipcHw_XTAL_FREQ_Hz | ||
|  | 
 | ||
|  |     Calculation for PLL MDIV to obtain frequency Freq_x for channel x | ||
|  |     ----------------------------------------------------------------- | ||
|  | 		Freq_x = chipcHw_XTAL_FREQ_Hz * PLL_NDIV_i / PLL_MDIV_x = VCO_FREQ_MHz / PLL_MDIV_x | ||
|  | 
 | ||
|  | 		PLL_MDIV_x = VCO_FREQ_MHz / Freq_x | ||
|  | */ | ||
|  | 
 | ||
|  | /* ---- Private Variables ------------------------------------------------- */ | ||
|  | /****************************************************************************/ | ||
|  | /**
 | ||
|  | *  @brief  Initializes the PLL2 | ||
|  | * | ||
|  | *  This function initializes the PLL2 | ||
|  | * | ||
|  | */ | ||
|  | /****************************************************************************/ | ||
|  | void chipcHw_pll2Enable(uint32_t vcoFreqHz) | ||
|  | { | ||
|  | 	uint32_t pllPreDivider2 = 0; | ||
|  | 
 | ||
|  | 	{ | ||
|  | 		REG_LOCAL_IRQ_SAVE; | ||
|  | 		pChipcHw->PLLConfig2 = | ||
|  | 		    chipcHw_REG_PLL_CONFIG_D_RESET | | ||
|  | 		    chipcHw_REG_PLL_CONFIG_A_RESET; | ||
|  | 
 | ||
|  | 		pllPreDivider2 = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN | | ||
|  | 		    chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER | | ||
|  | 		    (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) << | ||
|  | 		     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) | | ||
|  | 		    (chipcHw_REG_PLL_PREDIVIDER_P1 << | ||
|  | 		     chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) | | ||
|  | 		    (chipcHw_REG_PLL_PREDIVIDER_P2 << | ||
|  | 		     chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT); | ||
|  | 
 | ||
|  | 		/* Enable CHIPC registers to control the PLL */ | ||
|  | 		pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE; | ||
|  | 
 | ||
|  | 		/* Set pre divider to get desired VCO frequency */ | ||
|  | 		pChipcHw->PLLPreDivider2 = pllPreDivider2; | ||
|  | 		/* Set NDIV Frac */ | ||
|  | 		pChipcHw->PLLDivider2 = chipcHw_REG_PLL_DIVIDER_NDIV_f; | ||
|  | 
 | ||
|  | 		/* This has to be removed once the default values are fixed for PLL2. */ | ||
|  | 		pChipcHw->PLLControl12 = 0x38000700; | ||
|  | 		pChipcHw->PLLControl22 = 0x00000015; | ||
|  | 
 | ||
|  | 		/* Reset PLL2 */ | ||
|  | 		if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) { | ||
|  | 			pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_A_RESET | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_VCO_1601_3200 | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_POWER_DOWN; | ||
|  | 		} else { | ||
|  | 			pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_A_RESET | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_VCO_800_1600 | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_POWER_DOWN; | ||
|  | 		} | ||
|  | 		REG_LOCAL_IRQ_RESTORE; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* Insert certain amount of delay before deasserting ARESET. */ | ||
|  | 	udelay(1); | ||
|  | 
 | ||
|  | 	{ | ||
|  | 		REG_LOCAL_IRQ_SAVE; | ||
|  | 		/* Remove analog reset and Power on the PLL */ | ||
|  | 		pChipcHw->PLLConfig2 &= | ||
|  | 		    ~(chipcHw_REG_PLL_CONFIG_A_RESET | | ||
|  | 		      chipcHw_REG_PLL_CONFIG_POWER_DOWN); | ||
|  | 
 | ||
|  | 		REG_LOCAL_IRQ_RESTORE; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* Wait until PLL is locked */ | ||
|  | 	while (!(pChipcHw->PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED)) | ||
|  | 		; | ||
|  | 
 | ||
|  | 	{ | ||
|  | 		REG_LOCAL_IRQ_SAVE; | ||
|  | 		/* Remove digital reset */ | ||
|  | 		pChipcHw->PLLConfig2 &= ~chipcHw_REG_PLL_CONFIG_D_RESET; | ||
|  | 
 | ||
|  | 		REG_LOCAL_IRQ_RESTORE; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | EXPORT_SYMBOL(chipcHw_pll2Enable); | ||
|  | 
 | ||
|  | /****************************************************************************/ | ||
|  | /**
 | ||
|  | *  @brief  Initializes the PLL1 | ||
|  | * | ||
|  | *  This function initializes the PLL1 | ||
|  | * | ||
|  | */ | ||
|  | /****************************************************************************/ | ||
|  | void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport) | ||
|  | { | ||
|  | 	uint32_t pllPreDivider = 0; | ||
|  | 
 | ||
|  | 	{ | ||
|  | 		REG_LOCAL_IRQ_SAVE; | ||
|  | 
 | ||
|  | 		pChipcHw->PLLConfig = | ||
|  | 		    chipcHw_REG_PLL_CONFIG_D_RESET | | ||
|  | 		    chipcHw_REG_PLL_CONFIG_A_RESET; | ||
|  | 		/* Setting VCO frequency */ | ||
|  | 		if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) { | ||
|  | 			pllPreDivider = | ||
|  | 			    chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASH_1_8 | | ||
|  | 			    ((chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) - | ||
|  | 			      1) << chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) | | ||
|  | 			    (chipcHw_REG_PLL_PREDIVIDER_P1 << | ||
|  | 			     chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) | | ||
|  | 			    (chipcHw_REG_PLL_PREDIVIDER_P2 << | ||
|  | 			     chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT); | ||
|  | 		} else { | ||
|  | 			pllPreDivider = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN | | ||
|  | 			    chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER | | ||
|  | 			    (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) << | ||
|  | 			     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) | | ||
|  | 			    (chipcHw_REG_PLL_PREDIVIDER_P1 << | ||
|  | 			     chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) | | ||
|  | 			    (chipcHw_REG_PLL_PREDIVIDER_P2 << | ||
|  | 			     chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		/* Enable CHIPC registers to control the PLL */ | ||
|  | 		pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE; | ||
|  | 
 | ||
|  | 		/* Set pre divider to get desired VCO frequency */ | ||
|  | 		pChipcHw->PLLPreDivider = pllPreDivider; | ||
|  | 		/* Set NDIV Frac */ | ||
|  | 		if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) { | ||
|  | 			pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV | | ||
|  | 			    chipcHw_REG_PLL_DIVIDER_NDIV_f_SS; | ||
|  | 		} else { | ||
|  | 			pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV | | ||
|  | 			    chipcHw_REG_PLL_DIVIDER_NDIV_f; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		/* Reset PLL1 */ | ||
|  | 		if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) { | ||
|  | 			pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_A_RESET | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_VCO_1601_3200 | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_POWER_DOWN; | ||
|  | 		} else { | ||
|  | 			pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_A_RESET | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_VCO_800_1600 | | ||
|  | 			    chipcHw_REG_PLL_CONFIG_POWER_DOWN; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		REG_LOCAL_IRQ_RESTORE; | ||
|  | 
 | ||
|  | 		/* Insert certain amount of delay before deasserting ARESET. */ | ||
|  | 		udelay(1); | ||
|  | 
 | ||
|  | 		{ | ||
|  | 			REG_LOCAL_IRQ_SAVE; | ||
|  | 			/* Remove analog reset and Power on the PLL */ | ||
|  | 			pChipcHw->PLLConfig &= | ||
|  | 			    ~(chipcHw_REG_PLL_CONFIG_A_RESET | | ||
|  | 			      chipcHw_REG_PLL_CONFIG_POWER_DOWN); | ||
|  | 			REG_LOCAL_IRQ_RESTORE; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		/* Wait until PLL is locked */ | ||
|  | 		while (!(pChipcHw->PLLStatus & chipcHw_REG_PLL_STATUS_LOCKED) | ||
|  | 		       || !(pChipcHw-> | ||
|  | 			    PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED)) | ||
|  | 			; | ||
|  | 
 | ||
|  | 		/* Remove digital reset */ | ||
|  | 		{ | ||
|  | 			REG_LOCAL_IRQ_SAVE; | ||
|  | 			pChipcHw->PLLConfig &= ~chipcHw_REG_PLL_CONFIG_D_RESET; | ||
|  | 			REG_LOCAL_IRQ_RESTORE; | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | EXPORT_SYMBOL(chipcHw_pll1Enable); | ||
|  | 
 | ||
|  | /****************************************************************************/ | ||
|  | /**
 | ||
|  | *  @brief  Initializes the chipc module | ||
|  | * | ||
|  | *  This function initializes the PLLs and core system clocks | ||
|  | * | ||
|  | */ | ||
|  | /****************************************************************************/ | ||
|  | 
 | ||
|  | void chipcHw_Init(chipcHw_INIT_PARAM_t *initParam	/*  [ IN ] Misc chip initialization parameter */ | ||
|  |     ) { | ||
|  | #if !(defined(__KERNEL__) && !defined(STANDALONE))
 | ||
|  | 	delay_init(); | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 	/* Do not program PLL, when warm reset */ | ||
|  | 	if (!(chipcHw_getStickyBits() & chipcHw_REG_STICKY_CHIP_WARM_RESET)) { | ||
|  | 		chipcHw_pll1Enable(initParam->pllVcoFreqHz, | ||
|  | 				   initParam->ssSupport); | ||
|  | 		chipcHw_pll2Enable(initParam->pll2VcoFreqHz); | ||
|  | 	} else { | ||
|  | 		/* Clear sticky bits */ | ||
|  | 		chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_WARM_RESET); | ||
|  | 	} | ||
|  | 	/* Clear sticky bits */ | ||
|  | 	chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET); | ||
|  | 
 | ||
|  | 	/* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */ | ||
|  | 	pChipcHw->ACLKClock = | ||
|  | 	    (pChipcHw-> | ||
|  | 	     ACLKClock & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam-> | ||
|  | 								 armBusRatio & | ||
|  | 								 chipcHw_REG_ACLKClock_CLK_DIV_MASK); | ||
|  | 
 | ||
|  | 	/* Set various core component frequencies. The order in which this is done is important for some. */ | ||
|  | 	/* The RTBUS (DDR PHY) is derived from the BUS, and the BUS from the ARM, and VPM needs to know BUS */ | ||
|  | 	/* frequency to find its ratio with the BUS.  Hence we must set the ARM first, followed by the BUS,  */ | ||
|  | 	/* then VPM and RTBUS. */ | ||
|  | 
 | ||
|  | 	chipcHw_setClockFrequency(chipcHw_CLOCK_ARM, | ||
|  | 				  initParam->busClockFreqHz * | ||
|  | 				  initParam->armBusRatio); | ||
|  | 	chipcHw_setClockFrequency(chipcHw_CLOCK_BUS, initParam->busClockFreqHz); | ||
|  | 	chipcHw_setClockFrequency(chipcHw_CLOCK_VPM, | ||
|  | 				  initParam->busClockFreqHz * | ||
|  | 				  initParam->vpmBusRatio); | ||
|  | 	chipcHw_setClockFrequency(chipcHw_CLOCK_DDR, | ||
|  | 				  initParam->busClockFreqHz * | ||
|  | 				  initParam->ddrBusRatio); | ||
|  | 	chipcHw_setClockFrequency(chipcHw_CLOCK_RTBUS, | ||
|  | 				  initParam->busClockFreqHz / 2); | ||
|  | } |