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