linux/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
<<
>>
Prefs
   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