uboot/arch/powerpc/cpu/ppc4xx/speed.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2000-2008
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 *
   5 * See file CREDITS for list of people who contributed to this
   6 * project.
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 * MA 02111-1307 USA
  22 */
  23
  24#include <common.h>
  25#include <ppc_asm.tmpl>
  26#include <asm/ppc4xx.h>
  27#include <asm/processor.h>
  28
  29DECLARE_GLOBAL_DATA_PTR;
  30
  31#define ONE_BILLION        1000000000
  32#ifdef DEBUG
  33#define DEBUGF(fmt,args...) printf(fmt ,##args)
  34#else
  35#define DEBUGF(fmt,args...)
  36#endif
  37
  38#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  39
  40#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
  41
  42void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
  43{
  44        unsigned long pllmr;
  45        unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
  46        uint pvr = get_pvr();
  47        unsigned long psr;
  48        unsigned long m;
  49
  50        /*
  51         * Read PLL Mode register
  52         */
  53        pllmr = mfdcr (CPC0_PLLMR);
  54
  55        /*
  56         * Read Pin Strapping register
  57         */
  58        psr = mfdcr (CPC0_PSR);
  59
  60        /*
  61         * Determine FWD_DIV.
  62         */
  63        sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
  64
  65        /*
  66         * Determine FBK_DIV.
  67         */
  68        sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
  69        if (sysInfo->pllFbkDiv == 0) {
  70                sysInfo->pllFbkDiv = 16;
  71        }
  72
  73        /*
  74         * Determine PLB_DIV.
  75         */
  76        sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
  77
  78        /*
  79         * Determine PCI_DIV.
  80         */
  81        sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
  82
  83        /*
  84         * Determine EXTBUS_DIV.
  85         */
  86        sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
  87
  88        /*
  89         * Determine OPB_DIV.
  90         */
  91        sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
  92
  93        /*
  94         * Check if PPC405GPr used (mask minor revision field)
  95         */
  96        if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
  97                /*
  98                 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
  99                 */
 100                sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
 101
 102                /*
 103                 * Determine factor m depending on PLL feedback clock source
 104                 */
 105                if (!(psr & PSR_PCI_ASYNC_EN)) {
 106                        if (psr & PSR_NEW_MODE_EN) {
 107                                /*
 108                                 * sync pci clock used as feedback (new mode)
 109                                 */
 110                                m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
 111                        } else {
 112                                /*
 113                                 * sync pci clock used as feedback (legacy mode)
 114                                 */
 115                                m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
 116                        }
 117                } else if (psr & PSR_NEW_MODE_EN) {
 118                        if (psr & PSR_PERCLK_SYNC_MODE_EN) {
 119                                /*
 120                                 * PerClk used as feedback (new mode)
 121                                 */
 122                                m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
 123                        } else {
 124                                /*
 125                                 * CPU clock used as feedback (new mode)
 126                                 */
 127                                m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
 128                        }
 129                } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
 130                        /*
 131                         * PerClk used as feedback (legacy mode)
 132                         */
 133                        m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
 134                } else {
 135                        /*
 136                         * PLB clock used as feedback (legacy mode)
 137                         */
 138                        m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
 139                }
 140
 141                sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
 142                        (unsigned long long)sysClkPeriodPs;
 143                sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
 144                sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
 145        } else {
 146                /*
 147                 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
 148                 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
 149                 * to make sure it is within the proper range.
 150                 *    spec:    VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
 151                 * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
 152                 */
 153                if (sysInfo->pllFwdDiv == 1) {
 154                        sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
 155                        sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
 156                } else {
 157                        sysInfo->freqVCOHz = ( 1000000000000LL *
 158                                               (unsigned long long)sysInfo->pllFwdDiv *
 159                                               (unsigned long long)sysInfo->pllFbkDiv *
 160                                               (unsigned long long)sysInfo->pllPlbDiv
 161                                ) / (unsigned long long)sysClkPeriodPs;
 162                        sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
 163                                                           sysInfo->pllFbkDiv)) * 10000;
 164                        sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
 165                }
 166        }
 167
 168        sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
 169        sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
 170        sysInfo->freqUART = sysInfo->freqProcessor;
 171}
 172
 173
 174/********************************************
 175 * get_PCI_freq
 176 * return PCI bus freq in Hz
 177 *********************************************/
 178ulong get_PCI_freq (void)
 179{
 180        ulong val;
 181        PPC4xx_SYS_INFO sys_info;
 182
 183        get_sys_info (&sys_info);
 184        val = sys_info.freqPLB / sys_info.pllPciDiv;
 185        return val;
 186}
 187
 188
 189#elif defined(CONFIG_440)
 190
 191#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
 192    defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
 193static u8 pll_fwdv_multi_bits[] = {
 194        /* values for:  1 - 16 */
 195        0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
 196        0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
 197};
 198
 199u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
 200{
 201        u32 index;
 202
 203        for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
 204                if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
 205                        return index + 1;
 206
 207        return 0;
 208}
 209
 210static u8 pll_fbdv_multi_bits[] = {
 211        /* values for:  1 - 100 */
 212        0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
 213        0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
 214        0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
 215        0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
 216        0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
 217        0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
 218        0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
 219        0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
 220        0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
 221        0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
 222        /* values for:  101 - 200 */
 223        0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
 224        0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
 225        0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
 226        0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
 227        0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
 228        0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
 229        0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
 230        0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
 231        0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
 232        0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
 233        /* values for:  201 - 255 */
 234        0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
 235        0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
 236        0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
 237        0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
 238        0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
 239        0x03, 0x87, 0x0f, 0x9f, 0x3f  /* END */
 240};
 241
 242u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
 243{
 244        u32 index;
 245
 246        for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
 247                if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
 248                        return index + 1;
 249
 250        return 0;
 251}
 252
 253#if defined(CONFIG_APM821XX)
 254
 255void get_sys_info(sys_info_t *sysInfo)
 256{
 257        unsigned long plld;
 258        unsigned long temp;
 259        unsigned long mul;
 260        unsigned long cpudv;
 261        unsigned long plb2dv;
 262        unsigned long ddr2dv;
 263
 264        /* Calculate Forward divisor A and Feeback divisor */
 265        mfcpr(CPR0_PLLD, plld);
 266
 267        temp = CPR0_PLLD_FWDVA(plld);
 268        sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
 269
 270        temp = CPR0_PLLD_FDV(plld);
 271        sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
 272
 273        /* Calculate OPB clock divisor */
 274        mfcpr(CPR0_OPBD, temp);
 275        temp = CPR0_OPBD_OPBDV(temp);
 276        sysInfo->pllOpbDiv = temp ? temp : 4;
 277
 278        /* Calculate Peripheral clock divisor */
 279        mfcpr(CPR0_PERD, temp);
 280        temp = CPR0_PERD_PERDV(temp);
 281        sysInfo->pllExtBusDiv = temp ? temp : 4;
 282
 283        /* Calculate CPU clock divisor */
 284        mfcpr(CPR0_CPUD, temp);
 285        temp = CPR0_CPUD_CPUDV(temp);
 286        cpudv = temp ? temp : 8;
 287
 288        /* Calculate PLB2 clock divisor */
 289        mfcpr(CPR0_PLB2D, temp);
 290        temp = CPR0_PLB2D_PLB2DV(temp);
 291        plb2dv = temp ? temp : 4;
 292
 293        /* Calculate DDR2 clock divisor */
 294        mfcpr(CPR0_DDR2D, temp);
 295        temp = CPR0_DDR2D_DDR2DV(temp);
 296        ddr2dv = temp ? temp : 4;
 297
 298        /* Calculate 'M' based on feedback source */
 299        mfcpr(CPR0_PLLC, temp);
 300        temp = CPR0_PLLC_SEL(temp);
 301        if (temp == 0) {
 302                /* PLL internal feedback */
 303                mul = sysInfo->pllFbkDiv;
 304        } else {
 305                /* PLL PerClk feedback */
 306                mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
 307                        * plb2dv * 2 * sysInfo->pllOpbDiv *
 308                          sysInfo->pllExtBusDiv;
 309        }
 310
 311        /* Now calculate the individual clocks */
 312        sysInfo->freqVCOMhz = (mul * CONFIG_SYS_CLK_FREQ) + (mul >> 1);
 313        sysInfo->freqProcessor = sysInfo->freqVCOMhz /
 314                sysInfo->pllFwdDivA / cpudv;
 315        sysInfo->freqPLB = sysInfo->freqVCOMhz /
 316                sysInfo->pllFwdDivA / cpudv / plb2dv / 2;
 317        sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
 318        sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
 319        sysInfo->freqDDR = sysInfo->freqVCOMhz /
 320                sysInfo->pllFwdDivA / cpudv / ddr2dv / 2;
 321        sysInfo->freqUART = sysInfo->freqPLB;
 322}
 323
 324#else
 325/*
 326 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
 327 *            with latest EAS
 328 */
 329void get_sys_info (sys_info_t * sysInfo)
 330{
 331        unsigned long strp0;
 332        unsigned long strp1;
 333        unsigned long temp;
 334        unsigned long m;
 335        unsigned long plbedv0;
 336
 337        /* Extract configured divisors */
 338        mfsdr(SDR0_SDSTP0, strp0);
 339        mfsdr(SDR0_SDSTP1, strp1);
 340
 341        temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
 342        sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
 343
 344        temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
 345        sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
 346
 347        temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
 348        sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
 349
 350        temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
 351        sysInfo->pllOpbDiv = temp ? temp : 4;
 352
 353        /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
 354        temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
 355        sysInfo->pllExtBusDiv = temp ? temp : 4;
 356
 357        temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
 358        plbedv0 = temp ? temp: 8;
 359
 360        /* Calculate 'M' based on feedback source */
 361        temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
 362        if (temp == 0) {
 363                /* PLL internal feedback */
 364                m = sysInfo->pllFbkDiv;
 365        } else {
 366                /* PLL PerClk feedback */
 367                m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
 368                        sysInfo->pllExtBusDiv;
 369        }
 370
 371        /* Now calculate the individual clocks */
 372        sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
 373        sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
 374        sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
 375        sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
 376        sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
 377        sysInfo->freqDDR = sysInfo->freqPLB;
 378        sysInfo->freqUART = sysInfo->freqPLB;
 379
 380        return;
 381}
 382#endif
 383
 384#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
 385    defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
 386void get_sys_info (sys_info_t *sysInfo)
 387{
 388        unsigned long temp;
 389        unsigned long reg;
 390        unsigned long lfdiv;
 391        unsigned long m;
 392        unsigned long prbdv0;
 393        /*
 394          WARNING: ASSUMES the following:
 395          ENG=1
 396          PRADV0=1
 397          PRBDV0=1
 398        */
 399
 400        /* Decode CPR0_PLLD0 for divisors */
 401        mfcpr(CPR0_PLLD, reg);
 402        temp = (reg & PLLD_FWDVA_MASK) >> 16;
 403        sysInfo->pllFwdDivA = temp ? temp : 16;
 404        temp = (reg & PLLD_FWDVB_MASK) >> 8;
 405        sysInfo->pllFwdDivB = temp ? temp: 8 ;
 406        temp = (reg & PLLD_FBDV_MASK) >> 24;
 407        sysInfo->pllFbkDiv = temp ? temp : 32;
 408        lfdiv = reg & PLLD_LFBDV_MASK;
 409
 410        mfcpr(CPR0_OPBD0, reg);
 411        temp = (reg & OPBDDV_MASK) >> 24;
 412        sysInfo->pllOpbDiv = temp ? temp : 4;
 413
 414        mfcpr(CPR0_PERD, reg);
 415        temp = (reg & PERDV_MASK) >> 24;
 416        sysInfo->pllExtBusDiv = temp ? temp : 8;
 417
 418        mfcpr(CPR0_PRIMBD0, reg);
 419        temp = (reg & PRBDV_MASK) >> 24;
 420        prbdv0 = temp ? temp : 8;
 421
 422        mfcpr(CPR0_SPCID, reg);
 423        temp = (reg & SPCID_MASK) >> 24;
 424        sysInfo->pllPciDiv = temp ? temp : 4;
 425
 426        /* Calculate 'M' based on feedback source */
 427        mfsdr(SDR0_SDSTP0, reg);
 428        temp = (reg & PLLSYS0_SEL_MASK) >> 27;
 429        if (temp == 0) { /* PLL output */
 430                /* Figure which pll to use */
 431                mfcpr(CPR0_PLLC, reg);
 432                temp = (reg & PLLC_SRC_MASK) >> 29;
 433                if (!temp) /* PLLOUTA */
 434                        m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
 435                else       /* PLLOUTB */
 436                        m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
 437        }
 438        else if (temp == 1) /* CPU output */
 439                m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
 440        else /* PerClk */
 441                m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
 442
 443        /* Now calculate the individual clocks */
 444        sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
 445        sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
 446        sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
 447        sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
 448        sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
 449        sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
 450        sysInfo->freqUART = sysInfo->freqPLB;
 451
 452        /* Figure which timer source to use */
 453        if (mfspr(SPRN_CCR1) & 0x0080) {
 454                /* External Clock, assume same as SYS_CLK */
 455                temp = sysInfo->freqProcessor / 2;  /* Max extern clock speed */
 456                if (CONFIG_SYS_CLK_FREQ > temp)
 457                        sysInfo->freqTmrClk = temp;
 458                else
 459                        sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
 460        }
 461        else  /* Internal clock */
 462                sysInfo->freqTmrClk = sysInfo->freqProcessor;
 463}
 464
 465/********************************************
 466 * get_PCI_freq
 467 * return PCI bus freq in Hz
 468 *********************************************/
 469ulong get_PCI_freq (void)
 470{
 471        sys_info_t sys_info;
 472        get_sys_info (&sys_info);
 473        return sys_info.freqPCI;
 474}
 475
 476#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
 477        && !defined(CONFIG_XILINX_440)
 478void get_sys_info (sys_info_t * sysInfo)
 479{
 480        unsigned long strp0;
 481        unsigned long temp;
 482        unsigned long m;
 483
 484        /* Extract configured divisors */
 485        strp0 = mfdcr( CPC0_STRP0 );
 486        sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
 487        sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
 488        temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
 489        sysInfo->pllFbkDiv = temp ? temp : 16;
 490        sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
 491        sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
 492
 493        /* Calculate 'M' based on feedback source */
 494        if( strp0 & PLLSYS0_EXTSL_MASK )
 495                m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
 496        else
 497                m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
 498
 499        /* Now calculate the individual clocks */
 500        sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
 501        sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
 502        sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
 503        if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
 504                sysInfo->freqPLB >>= 1;
 505        sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
 506        sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
 507        sysInfo->freqUART = sysInfo->freqPLB;
 508}
 509#else
 510
 511#if !defined(CONFIG_XILINX_440)
 512void get_sys_info (sys_info_t * sysInfo)
 513{
 514        unsigned long strp0;
 515        unsigned long strp1;
 516        unsigned long temp;
 517        unsigned long temp1;
 518        unsigned long lfdiv;
 519        unsigned long m;
 520        unsigned long prbdv0;
 521
 522#if defined(CONFIG_YUCCA)
 523        unsigned long sys_freq;
 524        unsigned long sys_per=0;
 525        unsigned long msr;
 526        unsigned long pci_clock_per;
 527        unsigned long sdr_ddrpll;
 528
 529        /*-------------------------------------------------------------------------+
 530         | Get the system clock period.
 531         +-------------------------------------------------------------------------*/
 532        sys_per = determine_sysper();
 533
 534        msr = (mfmsr () & ~(MSR_EE));   /* disable interrupts */
 535
 536        /*-------------------------------------------------------------------------+
 537         | Calculate the system clock speed from the period.
 538         +-------------------------------------------------------------------------*/
 539        sys_freq = (ONE_BILLION / sys_per) * 1000;
 540#endif
 541
 542        /* Extract configured divisors */
 543        mfsdr( SDR0_SDSTP0,strp0 );
 544        mfsdr( SDR0_SDSTP1,strp1 );
 545
 546        temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
 547        sysInfo->pllFwdDivA = temp ? temp : 16 ;
 548        temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
 549        sysInfo->pllFwdDivB = temp ? temp: 8 ;
 550        temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
 551        sysInfo->pllFbkDiv = temp ? temp : 32;
 552        temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
 553        sysInfo->pllOpbDiv = temp ? temp : 4;
 554        temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
 555        sysInfo->pllExtBusDiv = temp ? temp : 4;
 556        prbdv0 = (strp0 >> 2) & 0x7;
 557
 558        /* Calculate 'M' based on feedback source */
 559        temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
 560        temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
 561        lfdiv = temp1 ? temp1 : 64;
 562        if (temp == 0) { /* PLL output */
 563                /* Figure which pll to use */
 564                temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
 565                if (!temp)
 566                        m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
 567                else
 568                        m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
 569        }
 570        else if (temp == 1) /* CPU output */
 571                m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
 572        else /* PerClk */
 573                m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
 574
 575        /* Now calculate the individual clocks */
 576#if defined(CONFIG_YUCCA)
 577        sysInfo->freqVCOMhz = (m * sys_freq) ;
 578#else
 579        sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
 580#endif
 581        sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
 582        sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
 583        sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
 584        sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
 585
 586#if defined(CONFIG_YUCCA)
 587        /* Determine PCI Clock Period */
 588        pci_clock_per = determine_pci_clock_per();
 589        sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
 590        mfsdr(SDR0_DDR0, sdr_ddrpll);
 591        sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
 592#endif
 593
 594        sysInfo->freqUART = sysInfo->freqPLB;
 595}
 596
 597#endif
 598#endif /* CONFIG_XILINX_440 */
 599
 600#if defined(CONFIG_YUCCA)
 601unsigned long determine_sysper(void)
 602{
 603        unsigned int fpga_clocking_reg;
 604        unsigned int master_clock_selection;
 605        unsigned long master_clock_per = 0;
 606        unsigned long fb_div_selection;
 607        unsigned int vco_div_reg_value;
 608        unsigned long vco_div_selection;
 609        unsigned long sys_per = 0;
 610        int extClkVal;
 611
 612        /*-------------------------------------------------------------------------+
 613         | Read FPGA reg 0 and reg 1 to get FPGA reg information
 614         +-------------------------------------------------------------------------*/
 615        fpga_clocking_reg = in16(FPGA_REG16);
 616
 617
 618        /* Determine Master Clock Source Selection */
 619        master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
 620
 621        switch(master_clock_selection) {
 622                case FPGA_REG16_MASTER_CLK_66_66:
 623                        master_clock_per = PERIOD_66_66MHZ;
 624                        break;
 625                case FPGA_REG16_MASTER_CLK_50:
 626                        master_clock_per = PERIOD_50_00MHZ;
 627                        break;
 628                case FPGA_REG16_MASTER_CLK_33_33:
 629                        master_clock_per = PERIOD_33_33MHZ;
 630                        break;
 631                case FPGA_REG16_MASTER_CLK_25:
 632                        master_clock_per = PERIOD_25_00MHZ;
 633                        break;
 634                case FPGA_REG16_MASTER_CLK_EXT:
 635                        if ((extClkVal==EXTCLK_33_33)
 636                                        && (extClkVal==EXTCLK_50)
 637                                        && (extClkVal==EXTCLK_66_66)
 638                                        && (extClkVal==EXTCLK_83)) {
 639                                /* calculate master clock period from external clock value */
 640                                master_clock_per=(ONE_BILLION/extClkVal) * 1000;
 641                        } else {
 642                                /* Unsupported */
 643                                DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
 644                                hang();
 645                        }
 646                        break;
 647                default:
 648                        /* Unsupported */
 649                        DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
 650                        hang();
 651                        break;
 652        }
 653
 654        /* Determine FB divisors values */
 655        if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
 656                if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
 657                        fb_div_selection = FPGA_FB_DIV_6;
 658                else
 659                        fb_div_selection = FPGA_FB_DIV_12;
 660        } else {
 661                if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
 662                        fb_div_selection = FPGA_FB_DIV_10;
 663                else
 664                        fb_div_selection = FPGA_FB_DIV_20;
 665        }
 666
 667        /* Determine VCO divisors values */
 668        vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
 669
 670        switch(vco_div_reg_value) {
 671                case FPGA_REG16_VCO_DIV_4:
 672                        vco_div_selection = FPGA_VCO_DIV_4;
 673                        break;
 674                case FPGA_REG16_VCO_DIV_6:
 675                        vco_div_selection = FPGA_VCO_DIV_6;
 676                        break;
 677                case FPGA_REG16_VCO_DIV_8:
 678                        vco_div_selection = FPGA_VCO_DIV_8;
 679                        break;
 680                case FPGA_REG16_VCO_DIV_10:
 681                default:
 682                        vco_div_selection = FPGA_VCO_DIV_10;
 683                        break;
 684        }
 685
 686        if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
 687                switch(master_clock_per) {
 688                        case PERIOD_25_00MHZ:
 689                                if (fb_div_selection == FPGA_FB_DIV_12) {
 690                                        if (vco_div_selection == FPGA_VCO_DIV_4)
 691                                                sys_per = PERIOD_75_00MHZ;
 692                                        if (vco_div_selection == FPGA_VCO_DIV_6)
 693                                                sys_per = PERIOD_50_00MHZ;
 694                                }
 695                                break;
 696                        case PERIOD_33_33MHZ:
 697                                if (fb_div_selection == FPGA_FB_DIV_6) {
 698                                        if (vco_div_selection == FPGA_VCO_DIV_4)
 699                                                sys_per = PERIOD_50_00MHZ;
 700                                        if (vco_div_selection == FPGA_VCO_DIV_6)
 701                                                sys_per = PERIOD_33_33MHZ;
 702                                }
 703                                if (fb_div_selection == FPGA_FB_DIV_10) {
 704                                        if (vco_div_selection == FPGA_VCO_DIV_4)
 705                                                sys_per = PERIOD_83_33MHZ;
 706                                        if (vco_div_selection == FPGA_VCO_DIV_10)
 707                                                sys_per = PERIOD_33_33MHZ;
 708                                }
 709                                if (fb_div_selection == FPGA_FB_DIV_12) {
 710                                        if (vco_div_selection == FPGA_VCO_DIV_4)
 711                                                sys_per = PERIOD_100_00MHZ;
 712                                        if (vco_div_selection == FPGA_VCO_DIV_6)
 713                                                sys_per = PERIOD_66_66MHZ;
 714                                        if (vco_div_selection == FPGA_VCO_DIV_8)
 715                                                sys_per = PERIOD_50_00MHZ;
 716                                }
 717                                break;
 718                        case PERIOD_50_00MHZ:
 719                                if (fb_div_selection == FPGA_FB_DIV_6) {
 720                                        if (vco_div_selection == FPGA_VCO_DIV_4)
 721                                                sys_per = PERIOD_75_00MHZ;
 722                                        if (vco_div_selection == FPGA_VCO_DIV_6)
 723                                                sys_per = PERIOD_50_00MHZ;
 724                                }
 725                                if (fb_div_selection == FPGA_FB_DIV_10) {
 726                                        if (vco_div_selection == FPGA_VCO_DIV_6)
 727                                                sys_per = PERIOD_83_33MHZ;
 728                                        if (vco_div_selection == FPGA_VCO_DIV_10)
 729                                                sys_per = PERIOD_50_00MHZ;
 730                                }
 731                                if (fb_div_selection == FPGA_FB_DIV_12) {
 732                                        if (vco_div_selection == FPGA_VCO_DIV_6)
 733                                                sys_per = PERIOD_100_00MHZ;
 734                                        if (vco_div_selection == FPGA_VCO_DIV_8)
 735                                                sys_per = PERIOD_75_00MHZ;
 736                                }
 737                                break;
 738                        case PERIOD_66_66MHZ:
 739                                if (fb_div_selection == FPGA_FB_DIV_6) {
 740                                        if (vco_div_selection == FPGA_VCO_DIV_4)
 741                                                sys_per = PERIOD_100_00MHZ;
 742                                        if (vco_div_selection == FPGA_VCO_DIV_6)
 743                                                sys_per = PERIOD_66_66MHZ;
 744                                        if (vco_div_selection == FPGA_VCO_DIV_8)
 745                                                sys_per = PERIOD_50_00MHZ;
 746                                }
 747                                if (fb_div_selection == FPGA_FB_DIV_10) {
 748                                        if (vco_div_selection == FPGA_VCO_DIV_8)
 749                                                sys_per = PERIOD_83_33MHZ;
 750                                        if (vco_div_selection == FPGA_VCO_DIV_10)
 751                                                sys_per = PERIOD_66_66MHZ;
 752                                }
 753                                if (fb_div_selection == FPGA_FB_DIV_12) {
 754                                        if (vco_div_selection == FPGA_VCO_DIV_8)
 755                                                sys_per = PERIOD_100_00MHZ;
 756                                }
 757                                break;
 758                        default:
 759                                break;
 760                }
 761
 762                if (sys_per == 0) {
 763                        /* Other combinations are not supported */
 764                        DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
 765                        hang();
 766                }
 767        } else {
 768                /* calcul system clock without cheking */
 769                /* if engineering option clock no check is selected */
 770                /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
 771                sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
 772        }
 773
 774        return(sys_per);
 775}
 776
 777/*-------------------------------------------------------------------------+
 778| determine_pci_clock_per.
 779+-------------------------------------------------------------------------*/
 780unsigned long determine_pci_clock_per(void)
 781{
 782        unsigned long pci_clock_selection,  pci_period;
 783
 784        /*-------------------------------------------------------------------------+
 785         | Read FPGA reg 6 to get PCI 0 FPGA reg information
 786         +-------------------------------------------------------------------------*/
 787        pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
 788
 789
 790        pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
 791
 792        switch (pci_clock_selection) {
 793                case FPGA_REG16_PCI0_CLK_133_33:
 794                        pci_period = PERIOD_133_33MHZ;
 795                        break;
 796                case FPGA_REG16_PCI0_CLK_100:
 797                        pci_period = PERIOD_100_00MHZ;
 798                        break;
 799                case FPGA_REG16_PCI0_CLK_66_66:
 800                        pci_period = PERIOD_66_66MHZ;
 801                        break;
 802                default:
 803                        pci_period = PERIOD_33_33MHZ;;
 804                        break;
 805        }
 806
 807        return(pci_period);
 808}
 809#endif
 810
 811#elif defined(CONFIG_XILINX_405)
 812extern void get_sys_info (sys_info_t * sysInfo);
 813extern ulong get_PCI_freq (void);
 814
 815#elif defined(CONFIG_AP1000)
 816void get_sys_info (sys_info_t * sysInfo)
 817{
 818        sysInfo->freqProcessor = 240 * 1000 * 1000;
 819        sysInfo->freqPLB = 80 * 1000 * 1000;
 820        sysInfo->freqPCI = 33 * 1000 * 1000;
 821}
 822
 823#elif defined(CONFIG_405)
 824
 825void get_sys_info (sys_info_t * sysInfo)
 826{
 827        sysInfo->freqVCOMhz=3125000;
 828        sysInfo->freqProcessor=12*1000*1000;
 829        sysInfo->freqPLB=50*1000*1000;
 830        sysInfo->freqPCI=66*1000*1000;
 831}
 832
 833#elif defined(CONFIG_405EP)
 834void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
 835{
 836        unsigned long pllmr0;
 837        unsigned long pllmr1;
 838        unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
 839        unsigned long m;
 840        unsigned long pllmr0_ccdv;
 841
 842        /*
 843         * Read PLL Mode registers
 844         */
 845        pllmr0 = mfdcr (CPC0_PLLMR0);
 846        pllmr1 = mfdcr (CPC0_PLLMR1);
 847
 848        /*
 849         * Determine forward divider A
 850         */
 851        sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
 852
 853        /*
 854         * Determine forward divider B (should be equal to A)
 855         */
 856        sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
 857
 858        /*
 859         * Determine FBK_DIV.
 860         */
 861        sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
 862        if (sysInfo->pllFbkDiv == 0)
 863                sysInfo->pllFbkDiv = 16;
 864
 865        /*
 866         * Determine PLB_DIV.
 867         */
 868        sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
 869
 870        /*
 871         * Determine PCI_DIV.
 872         */
 873        sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
 874
 875        /*
 876         * Determine EXTBUS_DIV.
 877         */
 878        sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
 879
 880        /*
 881         * Determine OPB_DIV.
 882         */
 883        sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
 884
 885        /*
 886         * Determine the M factor
 887         */
 888        m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
 889
 890        /*
 891         * Determine VCO clock frequency
 892         */
 893        sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
 894                (unsigned long long)sysClkPeriodPs;
 895
 896        /*
 897         * Determine CPU clock frequency
 898         */
 899        pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
 900        if (pllmr1 & PLLMR1_SSCS_MASK) {
 901                /*
 902                 * This is true if FWDVA == FWDVB:
 903                 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
 904                 *      / pllmr0_ccdv;
 905                 */
 906                sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
 907                        / sysInfo->pllFwdDiv / pllmr0_ccdv;
 908        } else {
 909                sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
 910        }
 911
 912        /*
 913         * Determine PLB clock frequency
 914         */
 915        sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
 916
 917        sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
 918
 919        sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
 920
 921        sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
 922}
 923
 924
 925/********************************************
 926 * get_PCI_freq
 927 * return PCI bus freq in Hz
 928 *********************************************/
 929ulong get_PCI_freq (void)
 930{
 931        ulong val;
 932        PPC4xx_SYS_INFO sys_info;
 933
 934        get_sys_info (&sys_info);
 935        val = sys_info.freqPLB / sys_info.pllPciDiv;
 936        return val;
 937}
 938
 939#elif defined(CONFIG_405EZ)
 940void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
 941{
 942        unsigned long cpr_plld;
 943        unsigned long cpr_pllc;
 944        unsigned long cpr_primad;
 945        unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
 946        unsigned long primad_cpudv;
 947        unsigned long m;
 948        unsigned long plloutb;
 949
 950        /*
 951         * Read PLL Mode registers
 952         */
 953        mfcpr(CPR0_PLLD, cpr_plld);
 954        mfcpr(CPR0_PLLC, cpr_pllc);
 955
 956        /*
 957         * Determine forward divider A
 958         */
 959        sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
 960
 961        /*
 962         * Determine forward divider B
 963         */
 964        sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
 965        if (sysInfo->pllFwdDivB == 0)
 966                sysInfo->pllFwdDivB = 8;
 967
 968        /*
 969         * Determine FBK_DIV.
 970         */
 971        sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
 972        if (sysInfo->pllFbkDiv == 0)
 973                sysInfo->pllFbkDiv = 256;
 974
 975        /*
 976         * Read CPR_PRIMAD register
 977         */
 978        mfcpr(CPR0_PRIMAD, cpr_primad);
 979
 980        /*
 981         * Determine PLB_DIV.
 982         */
 983        sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
 984        if (sysInfo->pllPlbDiv == 0)
 985                sysInfo->pllPlbDiv = 16;
 986
 987        /*
 988         * Determine EXTBUS_DIV.
 989         */
 990        sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
 991        if (sysInfo->pllExtBusDiv == 0)
 992                sysInfo->pllExtBusDiv = 16;
 993
 994        /*
 995         * Determine OPB_DIV.
 996         */
 997        sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
 998        if (sysInfo->pllOpbDiv == 0)
 999                sysInfo->pllOpbDiv = 16;
1000
1001        /*
1002         * Determine the M factor
1003         */
1004        if (cpr_pllc & PLLC_SRC_MASK)
1005                m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
1006        else
1007                m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
1008
1009        /*
1010         * Determine VCO clock frequency
1011         */
1012        sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1013                (unsigned long long)sysClkPeriodPs;
1014
1015        /*
1016         * Determine CPU clock frequency
1017         */
1018        primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
1019        if (primad_cpudv == 0)
1020                primad_cpudv = 16;
1021
1022        sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
1023                sysInfo->pllFwdDiv / primad_cpudv;
1024
1025        /*
1026         * Determine PLB clock frequency
1027         */
1028        sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1029                sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1030
1031        sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1032                sysInfo->pllOpbDiv;
1033
1034        sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1035                sysInfo->pllExtBusDiv;
1036
1037        plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1038                sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1039                sysInfo->pllFwdDivB);
1040        sysInfo->freqUART = plloutb;
1041}
1042
1043#elif defined(CONFIG_405EX)
1044
1045/*
1046 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1047 *   We need the specs!!!!
1048 */
1049static unsigned char get_fbdv(unsigned char index)
1050{
1051        unsigned char ret = 0;
1052        /* This is table should be 256 bytes.
1053         * Only take first 52 values.
1054         */
1055        unsigned char fbdv_tb[] = {
1056                0x00, 0xff, 0x7f, 0xfd,
1057                0x7a, 0xf5, 0x6a, 0xd5,
1058                0x2a, 0xd4, 0x29, 0xd3,
1059                0x26, 0xcc, 0x19, 0xb3,
1060                0x67, 0xce, 0x1d, 0xbb,
1061                0x77, 0xee, 0x5d, 0xba,
1062                0x74, 0xe9, 0x52, 0xa5,
1063                0x4b, 0x96, 0x2c, 0xd8,
1064                0x31, 0xe3, 0x46, 0x8d,
1065                0x1b, 0xb7, 0x6f, 0xde,
1066                0x3d, 0xfb, 0x76, 0xed,
1067                0x5a, 0xb5, 0x6b, 0xd6,
1068                0x2d, 0xdb, 0x36, 0xec,
1069
1070        };
1071
1072        if ((index & 0x7f) == 0)
1073                return 1;
1074        while (ret < sizeof (fbdv_tb)) {
1075                if (fbdv_tb[ret] == index)
1076                        break;
1077                ret++;
1078        }
1079        ret++;
1080
1081        return ret;
1082}
1083
1084#define PLL_FBK_PLL_LOCAL       0
1085#define PLL_FBK_CPU             1
1086#define PLL_FBK_PERCLK          5
1087
1088void get_sys_info (sys_info_t * sysInfo)
1089{
1090        unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1091        unsigned long m = 1;
1092        unsigned int  tmp;
1093        unsigned char fwdva[16] = {
1094                1, 2, 14, 9, 4, 11, 16, 13,
1095                12, 5, 6, 15, 10, 7, 8, 3,
1096        };
1097        unsigned char sel, cpudv0, plb2xDiv;
1098
1099        mfcpr(CPR0_PLLD, tmp);
1100
1101        /*
1102         * Determine forward divider A
1103         */
1104        sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)];       /* FWDVA */
1105
1106        /*
1107         * Determine FBK_DIV.
1108         */
1109        sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1110
1111        /*
1112         * Determine PLBDV0
1113         */
1114        sysInfo->pllPlbDiv = 2;
1115
1116        /*
1117         * Determine PERDV0
1118         */
1119        mfcpr(CPR0_PERD, tmp);
1120        tmp = (tmp >> 24) & 0x03;
1121        sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1122
1123        /*
1124         * Determine OPBDV0
1125         */
1126        mfcpr(CPR0_OPBD0, tmp);
1127        tmp = (tmp >> 24) & 0x03;
1128        sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1129
1130        /* Determine PLB2XDV0 */
1131        mfcpr(CPR0_PLBD, tmp);
1132        tmp = (tmp >> 16) & 0x07;
1133        plb2xDiv = (tmp == 0) ? 8 : tmp;
1134
1135        /* Determine CPUDV0 */
1136        mfcpr(CPR0_CPUD, tmp);
1137        tmp = (tmp >> 24) & 0x07;
1138        cpudv0 = (tmp == 0) ? 8 : tmp;
1139
1140        /* Determine SEL(5:7) in CPR0_PLLC */
1141        mfcpr(CPR0_PLLC, tmp);
1142        sel = (tmp >> 24) & 0x07;
1143
1144        /*
1145         * Determine the M factor
1146         * PLL local: M = FBDV
1147         * CPU clock: M = FBDV * FWDVA * CPUDV0
1148         * PerClk       : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1149         *
1150         */
1151        switch (sel) {
1152        case PLL_FBK_CPU:
1153                m = sysInfo->pllFwdDiv * cpudv0;
1154                break;
1155        case PLL_FBK_PERCLK:
1156                m = sysInfo->pllFwdDiv * plb2xDiv * 2
1157                        * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1158                break;
1159        case PLL_FBK_PLL_LOCAL:
1160                break;
1161        default:
1162                printf("%s unknown m\n", __FUNCTION__);
1163                return;
1164
1165        }
1166        m *= sysInfo->pllFbkDiv;
1167
1168        /*
1169         * Determine VCO clock frequency
1170         */
1171        sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1172                (unsigned long long)sysClkPeriodPs;
1173
1174        /*
1175         * Determine CPU clock frequency
1176         */
1177        sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1178
1179        /*
1180         * Determine PLB clock frequency, ddr1x should be the same
1181         */
1182        sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1183        sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1184        sysInfo->freqDDR = sysInfo->freqPLB;
1185        sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1186        sysInfo->freqUART = sysInfo->freqPLB;
1187}
1188
1189#endif
1190
1191int get_clocks (void)
1192{
1193#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1194    defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1195    defined(CONFIG_405EX) || defined(CONFIG_405) || \
1196    defined(CONFIG_440)
1197        sys_info_t sys_info;
1198
1199        get_sys_info (&sys_info);
1200        gd->cpu_clk = sys_info.freqProcessor;
1201        gd->bus_clk = sys_info.freqPLB;
1202
1203#endif  /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1204
1205#ifdef CONFIG_IOP480
1206        gd->cpu_clk = 66000000;
1207        gd->bus_clk = 66000000;
1208#endif
1209        return (0);
1210}
1211
1212
1213/********************************************
1214 * get_bus_freq
1215 * return PLB bus freq in Hz
1216 *********************************************/
1217ulong get_bus_freq (ulong dummy)
1218{
1219        ulong val;
1220
1221#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1222    defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1223    defined(CONFIG_405EX) || defined(CONFIG_405) || \
1224    defined(CONFIG_440)
1225        sys_info_t sys_info;
1226
1227        get_sys_info (&sys_info);
1228        val = sys_info.freqPLB;
1229
1230#elif defined(CONFIG_IOP480)
1231
1232        val = 66;
1233
1234#else
1235# error get_bus_freq() not implemented
1236#endif
1237
1238        return val;
1239}
1240
1241#if !defined(CONFIG_IOP480)
1242ulong get_OPB_freq (void)
1243{
1244        PPC4xx_SYS_INFO sys_info;
1245
1246        get_sys_info (&sys_info);
1247
1248        return sys_info.freqOPB;
1249}
1250#endif
1251