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_init.c 18* 19* @brief Low level CHIPC PLL configuration functions 20* 21* @note 22* 23* These routines provide basic PLL 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/* ---- Private Constants and Types --------------------------------------- */ 39 40/* 41 Calculation for NDIV_i to obtain VCO frequency 42 ----------------------------------------------- 43 44 Freq_vco = Freq_ref * (P2 / P1) * (PLL_NDIV_i + PLL_NDIV_f) 45 for Freq_vco = VCO_FREQ_MHz 46 Freq_ref = chipcHw_XTAL_FREQ_Hz 47 PLL_P1 = PLL_P2 = 1 48 and 49 PLL_NDIV_f = 0 50 51 We get: 52 PLL_NDIV_i = Freq_vco / Freq_ref = VCO_FREQ_MHz / chipcHw_XTAL_FREQ_Hz 53 54 Calculation for PLL MDIV to obtain frequency Freq_x for channel x 55 ----------------------------------------------------------------- 56 Freq_x = chipcHw_XTAL_FREQ_Hz * PLL_NDIV_i / PLL_MDIV_x = VCO_FREQ_MHz / PLL_MDIV_x 57 58 PLL_MDIV_x = VCO_FREQ_MHz / Freq_x 59*/ 60 61/* ---- Private Variables ------------------------------------------------- */ 62/****************************************************************************/ 63/** 64* @brief Initializes the PLL2 65* 66* This function initializes the PLL2 67* 68*/ 69/****************************************************************************/ 70void chipcHw_pll2Enable(uint32_t vcoFreqHz) 71{ 72 uint32_t pllPreDivider2 = 0; 73 74 { 75 REG_LOCAL_IRQ_SAVE; 76 pChipcHw->PLLConfig2 = 77 chipcHw_REG_PLL_CONFIG_D_RESET | 78 chipcHw_REG_PLL_CONFIG_A_RESET; 79 80 pllPreDivider2 = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN | 81 chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER | 82 (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) << 83 chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) | 84 (chipcHw_REG_PLL_PREDIVIDER_P1 << 85 chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) | 86 (chipcHw_REG_PLL_PREDIVIDER_P2 << 87 chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT); 88 89 /* Enable CHIPC registers to control the PLL */ 90 pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE; 91 92 /* Set pre divider to get desired VCO frequency */ 93 pChipcHw->PLLPreDivider2 = pllPreDivider2; 94 /* Set NDIV Frac */ 95 pChipcHw->PLLDivider2 = chipcHw_REG_PLL_DIVIDER_NDIV_f; 96 97 /* This has to be removed once the default values are fixed for PLL2. */ 98 pChipcHw->PLLControl12 = 0x38000700; 99 pChipcHw->PLLControl22 = 0x00000015; 100 101 /* Reset PLL2 */ 102 if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) { 103 pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET | 104 chipcHw_REG_PLL_CONFIG_A_RESET | 105 chipcHw_REG_PLL_CONFIG_VCO_1601_3200 | 106 chipcHw_REG_PLL_CONFIG_POWER_DOWN; 107 } else { 108 pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET | 109 chipcHw_REG_PLL_CONFIG_A_RESET | 110 chipcHw_REG_PLL_CONFIG_VCO_800_1600 | 111 chipcHw_REG_PLL_CONFIG_POWER_DOWN; 112 } 113 REG_LOCAL_IRQ_RESTORE; 114 } 115 116 /* Insert certain amount of delay before deasserting ARESET. */ 117 udelay(1); 118 119 { 120 REG_LOCAL_IRQ_SAVE; 121 /* Remove analog reset and Power on the PLL */ 122 pChipcHw->PLLConfig2 &= 123 ~(chipcHw_REG_PLL_CONFIG_A_RESET | 124 chipcHw_REG_PLL_CONFIG_POWER_DOWN); 125 126 REG_LOCAL_IRQ_RESTORE; 127 128 } 129 130 /* Wait until PLL is locked */ 131 while (!(pChipcHw->PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED)) 132 ; 133 134 { 135 REG_LOCAL_IRQ_SAVE; 136 /* Remove digital reset */ 137 pChipcHw->PLLConfig2 &= ~chipcHw_REG_PLL_CONFIG_D_RESET; 138 139 REG_LOCAL_IRQ_RESTORE; 140 } 141} 142 143EXPORT_SYMBOL(chipcHw_pll2Enable); 144 145/****************************************************************************/ 146/** 147* @brief Initializes the PLL1 148* 149* This function initializes the PLL1 150* 151*/ 152/****************************************************************************/ 153void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport) 154{ 155 uint32_t pllPreDivider = 0; 156 157 { 158 REG_LOCAL_IRQ_SAVE; 159 160 pChipcHw->PLLConfig = 161 chipcHw_REG_PLL_CONFIG_D_RESET | 162 chipcHw_REG_PLL_CONFIG_A_RESET; 163 /* Setting VCO frequency */ 164 if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) { 165 pllPreDivider = 166 chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASH_1_8 | 167 ((chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) - 168 1) << chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) | 169 (chipcHw_REG_PLL_PREDIVIDER_P1 << 170 chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) | 171 (chipcHw_REG_PLL_PREDIVIDER_P2 << 172 chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT); 173 } else { 174 pllPreDivider = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN | 175 chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER | 176 (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) << 177 chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) | 178 (chipcHw_REG_PLL_PREDIVIDER_P1 << 179 chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) | 180 (chipcHw_REG_PLL_PREDIVIDER_P2 << 181 chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT); 182 } 183 184 /* Enable CHIPC registers to control the PLL */ 185 pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE; 186 187 /* Set pre divider to get desired VCO frequency */ 188 pChipcHw->PLLPreDivider = pllPreDivider; 189 /* Set NDIV Frac */ 190 if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) { 191 pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV | 192 chipcHw_REG_PLL_DIVIDER_NDIV_f_SS; 193 } else { 194 pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV | 195 chipcHw_REG_PLL_DIVIDER_NDIV_f; 196 } 197 198 /* Reset PLL1 */ 199 if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) { 200 pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET | 201 chipcHw_REG_PLL_CONFIG_A_RESET | 202 chipcHw_REG_PLL_CONFIG_VCO_1601_3200 | 203 chipcHw_REG_PLL_CONFIG_POWER_DOWN; 204 } else { 205 pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET | 206 chipcHw_REG_PLL_CONFIG_A_RESET | 207 chipcHw_REG_PLL_CONFIG_VCO_800_1600 | 208 chipcHw_REG_PLL_CONFIG_POWER_DOWN; 209 } 210 211 REG_LOCAL_IRQ_RESTORE; 212 213 /* Insert certain amount of delay before deasserting ARESET. */ 214 udelay(1); 215 216 { 217 REG_LOCAL_IRQ_SAVE; 218 /* Remove analog reset and Power on the PLL */ 219 pChipcHw->PLLConfig &= 220 ~(chipcHw_REG_PLL_CONFIG_A_RESET | 221 chipcHw_REG_PLL_CONFIG_POWER_DOWN); 222 REG_LOCAL_IRQ_RESTORE; 223 } 224 225 /* Wait until PLL is locked */ 226 while (!(pChipcHw->PLLStatus & chipcHw_REG_PLL_STATUS_LOCKED) 227 || !(pChipcHw-> 228 PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED)) 229 ; 230 231 /* Remove digital reset */ 232 { 233 REG_LOCAL_IRQ_SAVE; 234 pChipcHw->PLLConfig &= ~chipcHw_REG_PLL_CONFIG_D_RESET; 235 REG_LOCAL_IRQ_RESTORE; 236 } 237 } 238} 239 240EXPORT_SYMBOL(chipcHw_pll1Enable); 241 242/****************************************************************************/ 243/** 244* @brief Initializes the chipc module 245* 246* This function initializes the PLLs and core system clocks 247* 248*/ 249/****************************************************************************/ 250 251void chipcHw_Init(chipcHw_INIT_PARAM_t *initParam /* [ IN ] Misc chip initialization parameter */ 252 ) { 253#if !(defined(__KERNEL__) && !defined(STANDALONE)) 254 delay_init(); 255#endif 256 257 /* Do not program PLL, when warm reset */ 258 if (!(chipcHw_getStickyBits() & chipcHw_REG_STICKY_CHIP_WARM_RESET)) { 259 chipcHw_pll1Enable(initParam->pllVcoFreqHz, 260 initParam->ssSupport); 261 chipcHw_pll2Enable(initParam->pll2VcoFreqHz); 262 } else { 263 /* Clear sticky bits */ 264 chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_WARM_RESET); 265 } 266 /* Clear sticky bits */ 267 chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET); 268 269 /* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */ 270 pChipcHw->ACLKClock = 271 (pChipcHw-> 272 ACLKClock & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam-> 273 armBusRatio & 274 chipcHw_REG_ACLKClock_CLK_DIV_MASK); 275 276 /* Set various core component frequencies. The order in which this is done is important for some. */ 277 /* The RTBUS (DDR PHY) is derived from the BUS, and the BUS from the ARM, and VPM needs to know BUS */ 278 /* frequency to find its ratio with the BUS. Hence we must set the ARM first, followed by the BUS, */ 279 /* then VPM and RTBUS. */ 280 281 chipcHw_setClockFrequency(chipcHw_CLOCK_ARM, 282 initParam->busClockFreqHz * 283 initParam->armBusRatio); 284 chipcHw_setClockFrequency(chipcHw_CLOCK_BUS, initParam->busClockFreqHz); 285 chipcHw_setClockFrequency(chipcHw_CLOCK_VPM, 286 initParam->busClockFreqHz * 287 initParam->vpmBusRatio); 288 chipcHw_setClockFrequency(chipcHw_CLOCK_DDR, 289 initParam->busClockFreqHz * 290 initParam->ddrBusRatio); 291 chipcHw_setClockFrequency(chipcHw_CLOCK_RTBUS, 292 initParam->busClockFreqHz / 2); 293} 294