diff options
Diffstat (limited to 'arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c')
-rw-r--r-- | arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c new file mode 100644 index 000000000000..367df75d4bb3 --- /dev/null +++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c @@ -0,0 +1,293 @@ +/***************************************************************************** +* 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); +} |