linux/arch/powerpc/boot/4xx.c
<<
>>
Prefs
   1/*
   2 * Copyright 2007 David Gibson, IBM Corporation.
   3 *
   4 * Based on earlier code:
   5 *   Matt Porter <mporter@kernel.crashing.org>
   6 *   Copyright 2002-2005 MontaVista Software Inc.
   7 *
   8 *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
   9 *   Copyright (c) 2003, 2004 Zultys Technologies
  10 *
  11 * Copyright (C) 2009 Wind River Systems, Inc.
  12 *   Updated for supporting PPC405EX on Kilauea.
  13 *   Tiejun Chen <tiejun.chen@windriver.com>
  14 *
  15 * This program is free software; you can redistribute it and/or
  16 * modify it under the terms of the GNU General Public License
  17 * as published by the Free Software Foundation; either version
  18 * 2 of the License, or (at your option) any later version.
  19 */
  20#include <stddef.h>
  21#include "types.h"
  22#include "string.h"
  23#include "stdio.h"
  24#include "ops.h"
  25#include "reg.h"
  26#include "dcr.h"
  27
  28static unsigned long chip_11_errata(unsigned long memsize)
  29{
  30        unsigned long pvr;
  31
  32        pvr = mfpvr();
  33
  34        switch (pvr & 0xf0000ff0) {
  35                case 0x40000850:
  36                case 0x400008d0:
  37                case 0x200008d0:
  38                        memsize -= 4096;
  39                        break;
  40                default:
  41                        break;
  42        }
  43
  44        return memsize;
  45}
  46
  47/* Read the 4xx SDRAM controller to get size of system memory. */
  48void ibm4xx_sdram_fixup_memsize(void)
  49{
  50        int i;
  51        unsigned long memsize, bank_config;
  52
  53        memsize = 0;
  54        for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) {
  55                bank_config = SDRAM0_READ(sdram_bxcr[i]);
  56                if (bank_config & SDRAM_CONFIG_BANK_ENABLE)
  57                        memsize += SDRAM_CONFIG_BANK_SIZE(bank_config);
  58        }
  59
  60        memsize = chip_11_errata(memsize);
  61        dt_fixup_memory(0, memsize);
  62}
  63
  64/* Read the 440SPe MQ controller to get size of system memory. */
  65#define DCRN_MQ0_B0BAS          0x40
  66#define DCRN_MQ0_B1BAS          0x41
  67#define DCRN_MQ0_B2BAS          0x42
  68#define DCRN_MQ0_B3BAS          0x43
  69
  70static u64 ibm440spe_decode_bas(u32 bas)
  71{
  72        u64 base = ((u64)(bas & 0xFFE00000u)) << 2;
  73
  74        /* open coded because I'm paranoid about invalid values */
  75        switch ((bas >> 4) & 0xFFF) {
  76        case 0:
  77                return 0;
  78        case 0xffc:
  79                return base + 0x000800000ull;
  80        case 0xff8:
  81                return base + 0x001000000ull;
  82        case 0xff0:
  83                return base + 0x002000000ull;
  84        case 0xfe0:
  85                return base + 0x004000000ull;
  86        case 0xfc0:
  87                return base + 0x008000000ull;
  88        case 0xf80:
  89                return base + 0x010000000ull;
  90        case 0xf00:
  91                return base + 0x020000000ull;
  92        case 0xe00:
  93                return base + 0x040000000ull;
  94        case 0xc00:
  95                return base + 0x080000000ull;
  96        case 0x800:
  97                return base + 0x100000000ull;
  98        }
  99        printf("Memory BAS value 0x%08x unsupported !\n", bas);
 100        return 0;
 101}
 102
 103void ibm440spe_fixup_memsize(void)
 104{
 105        u64 banktop, memsize = 0;
 106
 107        /* Ultimately, we should directly construct the memory node
 108         * so we are able to handle holes in the memory address space
 109         */
 110        banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B0BAS));
 111        if (banktop > memsize)
 112                memsize = banktop;
 113        banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B1BAS));
 114        if (banktop > memsize)
 115                memsize = banktop;
 116        banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B2BAS));
 117        if (banktop > memsize)
 118                memsize = banktop;
 119        banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B3BAS));
 120        if (banktop > memsize)
 121                memsize = banktop;
 122
 123        dt_fixup_memory(0, memsize);
 124}
 125
 126
 127/* 4xx DDR1/2 Denali memory controller support */
 128/* DDR0 registers */
 129#define DDR0_02                 2
 130#define DDR0_08                 8
 131#define DDR0_10                 10
 132#define DDR0_14                 14
 133#define DDR0_42                 42
 134#define DDR0_43                 43
 135
 136/* DDR0_02 */
 137#define DDR_START               0x1
 138#define DDR_START_SHIFT         0
 139#define DDR_MAX_CS_REG          0x3
 140#define DDR_MAX_CS_REG_SHIFT    24
 141#define DDR_MAX_COL_REG         0xf
 142#define DDR_MAX_COL_REG_SHIFT   16
 143#define DDR_MAX_ROW_REG         0xf
 144#define DDR_MAX_ROW_REG_SHIFT   8
 145/* DDR0_08 */
 146#define DDR_DDR2_MODE           0x1
 147#define DDR_DDR2_MODE_SHIFT     0
 148/* DDR0_10 */
 149#define DDR_CS_MAP              0x3
 150#define DDR_CS_MAP_SHIFT        8
 151/* DDR0_14 */
 152#define DDR_REDUC               0x1
 153#define DDR_REDUC_SHIFT         16
 154/* DDR0_42 */
 155#define DDR_APIN                0x7
 156#define DDR_APIN_SHIFT          24
 157/* DDR0_43 */
 158#define DDR_COL_SZ              0x7
 159#define DDR_COL_SZ_SHIFT        8
 160#define DDR_BANK8               0x1
 161#define DDR_BANK8_SHIFT         0
 162
 163#define DDR_GET_VAL(val, mask, shift)   (((val) >> (shift)) & (mask))
 164
 165/*
 166 * Some U-Boot versions set the number of chipselects to two
 167 * for Sequoia/Rainier boards while they only have one chipselect
 168 * hardwired. Hardcode the number of chipselects to one
 169 * for sequioa/rainer board models or read the actual value
 170 * from the memory controller register DDR0_10 otherwise.
 171 */
 172static inline u32 ibm4xx_denali_get_cs(void)
 173{
 174        void *devp;
 175        char model[64];
 176        u32 val, cs;
 177
 178        devp = finddevice("/");
 179        if (!devp)
 180                goto read_cs;
 181
 182        if (getprop(devp, "model", model, sizeof(model)) <= 0)
 183                goto read_cs;
 184
 185        model[sizeof(model)-1] = 0;
 186
 187        if (!strcmp(model, "amcc,sequoia") ||
 188            !strcmp(model, "amcc,rainier"))
 189                return 1;
 190
 191read_cs:
 192        /* get CS value */
 193        val = SDRAM0_READ(DDR0_10);
 194
 195        val = DDR_GET_VAL(val, DDR_CS_MAP, DDR_CS_MAP_SHIFT);
 196        cs = 0;
 197        while (val) {
 198                if (val & 0x1)
 199                        cs++;
 200                val = val >> 1;
 201        }
 202        return cs;
 203}
 204
 205void ibm4xx_denali_fixup_memsize(void)
 206{
 207        u32 val, max_cs, max_col, max_row;
 208        u32 cs, col, row, bank, dpath;
 209        unsigned long memsize;
 210
 211        val = SDRAM0_READ(DDR0_02);
 212        if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT))
 213                fatal("DDR controller is not initialized\n");
 214
 215        /* get maximum cs col and row values */
 216        max_cs  = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT);
 217        max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT);
 218        max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT);
 219
 220        cs = ibm4xx_denali_get_cs();
 221        if (!cs)
 222                fatal("No memory installed\n");
 223        if (cs > max_cs)
 224                fatal("DDR wrong CS configuration\n");
 225
 226        /* get data path bytes */
 227        val = SDRAM0_READ(DDR0_14);
 228
 229        if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT))
 230                dpath = 4; /* 32 bits */
 231        else
 232                dpath = 8; /* 64 bits */
 233
 234        /* get address pins (rows) */
 235        val = SDRAM0_READ(DDR0_42);
 236
 237        row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT);
 238        if (row > max_row)
 239                fatal("DDR wrong APIN configuration\n");
 240        row = max_row - row;
 241
 242        /* get collomn size and banks */
 243        val = SDRAM0_READ(DDR0_43);
 244
 245        col = DDR_GET_VAL(val, DDR_COL_SZ, DDR_COL_SZ_SHIFT);
 246        if (col > max_col)
 247                fatal("DDR wrong COL configuration\n");
 248        col = max_col - col;
 249
 250        if (DDR_GET_VAL(val, DDR_BANK8, DDR_BANK8_SHIFT))
 251                bank = 8; /* 8 banks */
 252        else
 253                bank = 4; /* 4 banks */
 254
 255        memsize = cs * (1 << (col+row)) * bank * dpath;
 256        memsize = chip_11_errata(memsize);
 257        dt_fixup_memory(0, memsize);
 258}
 259
 260#define SPRN_DBCR0_40X 0x3F2
 261#define SPRN_DBCR0_44X 0x134
 262#define DBCR0_RST_SYSTEM 0x30000000
 263
 264void ibm44x_dbcr_reset(void)
 265{
 266        unsigned long tmp;
 267
 268        asm volatile (
 269                "mfspr  %0,%1\n"
 270                "oris   %0,%0,%2@h\n"
 271                "mtspr  %1,%0"
 272                : "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM)
 273                );
 274
 275}
 276
 277void ibm40x_dbcr_reset(void)
 278{
 279        unsigned long tmp;
 280
 281        asm volatile (
 282                "mfspr  %0,%1\n"
 283                "oris   %0,%0,%2@h\n"
 284                "mtspr  %1,%0"
 285                : "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM)
 286                );
 287}
 288
 289#define EMAC_RESET 0x20000000
 290void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1)
 291{
 292        /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
 293         * do this for us
 294         */
 295        if (emac0)
 296                *emac0 = EMAC_RESET;
 297        if (emac1)
 298                *emac1 = EMAC_RESET;
 299
 300        mtdcr(DCRN_MAL0_CFG, MAL_RESET);
 301        while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET)
 302                ; /* loop until reset takes effect */
 303}
 304
 305/* Read 4xx EBC bus bridge registers to get mappings of the peripheral
 306 * banks into the OPB address space */
 307void ibm4xx_fixup_ebc_ranges(const char *ebc)
 308{
 309        void *devp;
 310        u32 bxcr;
 311        u32 ranges[EBC_NUM_BANKS*4];
 312        u32 *p = ranges;
 313        int i;
 314
 315        for (i = 0; i < EBC_NUM_BANKS; i++) {
 316                mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i));
 317                bxcr = mfdcr(DCRN_EBC0_CFGDATA);
 318
 319                if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) {
 320                        *p++ = i;
 321                        *p++ = 0;
 322                        *p++ = bxcr & EBC_BXCR_BAS;
 323                        *p++ = EBC_BXCR_BANK_SIZE(bxcr);
 324                }
 325        }
 326
 327        devp = finddevice(ebc);
 328        if (! devp)
 329                fatal("Couldn't locate EBC node %s\n\r", ebc);
 330
 331        setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32));
 332}
 333
 334/* Calculate 440GP clocks */
 335void ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
 336{
 337        u32 sys0 = mfdcr(DCRN_CPC0_SYS0);
 338        u32 cr0 = mfdcr(DCRN_CPC0_CR0);
 339        u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
 340        u32 opdv = CPC0_SYS0_OPDV(sys0);
 341        u32 epdv = CPC0_SYS0_EPDV(sys0);
 342
 343        if (sys0 & CPC0_SYS0_BYPASS) {
 344                /* Bypass system PLL */
 345                cpu = plb = sys_clk;
 346        } else {
 347                if (sys0 & CPC0_SYS0_EXTSL)
 348                        /* PerClk */
 349                        m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv;
 350                else
 351                        /* CPU clock */
 352                        m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0);
 353                cpu = sys_clk * m / CPC0_SYS0_FWDVA(sys0);
 354                plb = sys_clk * m / CPC0_SYS0_FWDVB(sys0);
 355        }
 356
 357        opb = plb / opdv;
 358        ebc = opb / epdv;
 359
 360        /* FIXME: Check if this is for all 440GP, or just Ebony */
 361        if ((mfpvr() & 0xf0000fff) == 0x40000440)
 362                /* Rev. B 440GP, use external system clock */
 363                tb = sys_clk;
 364        else
 365                /* Rev. C 440GP, errata force us to use internal clock */
 366                tb = cpu;
 367
 368        if (cr0 & CPC0_CR0_U0EC)
 369                /* External UART clock */
 370                uart0 = ser_clk;
 371        else
 372                /* Internal UART clock */
 373                uart0 = plb / CPC0_CR0_UDIV(cr0);
 374
 375        if (cr0 & CPC0_CR0_U1EC)
 376                /* External UART clock */
 377                uart1 = ser_clk;
 378        else
 379                /* Internal UART clock */
 380                uart1 = plb / CPC0_CR0_UDIV(cr0);
 381
 382        printf("PPC440GP: SysClk = %dMHz (%x)\n\r",
 383               (sys_clk + 500000) / 1000000, sys_clk);
 384
 385        dt_fixup_cpu_clocks(cpu, tb, 0);
 386
 387        dt_fixup_clock("/plb", plb);
 388        dt_fixup_clock("/plb/opb", opb);
 389        dt_fixup_clock("/plb/opb/ebc", ebc);
 390        dt_fixup_clock("/plb/opb/serial@40000200", uart0);
 391        dt_fixup_clock("/plb/opb/serial@40000300", uart1);
 392}
 393
 394#define SPRN_CCR1 0x378
 395
 396static inline u32 __fix_zero(u32 v, u32 def)
 397{
 398        return v ? v : def;
 399}
 400
 401static unsigned int __ibm440eplike_fixup_clocks(unsigned int sys_clk,
 402                                                unsigned int tmr_clk,
 403                                                int per_clk_from_opb)
 404{
 405        /* PLL config */
 406        u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
 407        u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
 408
 409        /* Dividers */
 410        u32 fbdv   = __fix_zero((plld >> 24) & 0x1f, 32);
 411        u32 fwdva  = __fix_zero((plld >> 16) & 0xf, 16);
 412        u32 fwdvb  = __fix_zero((plld >> 8) & 7, 8);
 413        u32 lfbdv  = __fix_zero(plld & 0x3f, 64);
 414        u32 pradv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMAD) >> 24) & 7, 8);
 415        u32 prbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMBD) >> 24) & 7, 8);
 416        u32 opbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_OPBD) >> 24) & 3, 4);
 417        u32 perdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PERD) >> 24) & 3, 4);
 418
 419        /* Input clocks for primary dividers */
 420        u32 clk_a, clk_b;
 421
 422        /* Resulting clocks */
 423        u32 cpu, plb, opb, ebc, vco;
 424
 425        /* Timebase */
 426        u32 ccr1, tb = tmr_clk;
 427
 428        if (pllc & 0x40000000) {
 429                u32 m;
 430
 431                /* Feedback path */
 432                switch ((pllc >> 24) & 7) {
 433                case 0:
 434                        /* PLLOUTx */
 435                        m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
 436                        break;
 437                case 1:
 438                        /* CPU */
 439                        m = fwdva * pradv0;
 440                        break;
 441                case 5:
 442                        /* PERClk */
 443                        m = fwdvb * prbdv0 * opbdv0 * perdv0;
 444                        break;
 445                default:
 446                        printf("WARNING ! Invalid PLL feedback source !\n");
 447                        goto bypass;
 448                }
 449                m *= fbdv;
 450                vco = sys_clk * m;
 451                clk_a = vco / fwdva;
 452                clk_b = vco / fwdvb;
 453        } else {
 454bypass:
 455                /* Bypass system PLL */
 456                vco = 0;
 457                clk_a = clk_b = sys_clk;
 458        }
 459
 460        cpu = clk_a / pradv0;
 461        plb = clk_b / prbdv0;
 462        opb = plb / opbdv0;
 463        ebc = (per_clk_from_opb ? opb : plb) / perdv0;
 464
 465        /* Figure out timebase.  Either CPU or default TmrClk */
 466        ccr1 = mfspr(SPRN_CCR1);
 467
 468        /* If passed a 0 tmr_clk, force CPU clock */
 469        if (tb == 0) {
 470                ccr1 &= ~0x80u;
 471                mtspr(SPRN_CCR1, ccr1);
 472        }
 473        if ((ccr1 & 0x0080) == 0)
 474                tb = cpu;
 475
 476        dt_fixup_cpu_clocks(cpu, tb, 0);
 477        dt_fixup_clock("/plb", plb);
 478        dt_fixup_clock("/plb/opb", opb);
 479        dt_fixup_clock("/plb/opb/ebc", ebc);
 480
 481        return plb;
 482}
 483
 484static void eplike_fixup_uart_clk(int index, const char *path,
 485                                  unsigned int ser_clk,
 486                                  unsigned int plb_clk)
 487{
 488        unsigned int sdr;
 489        unsigned int clock;
 490
 491        switch (index) {
 492        case 0:
 493                sdr = SDR0_READ(DCRN_SDR0_UART0);
 494                break;
 495        case 1:
 496                sdr = SDR0_READ(DCRN_SDR0_UART1);
 497                break;
 498        case 2:
 499                sdr = SDR0_READ(DCRN_SDR0_UART2);
 500                break;
 501        case 3:
 502                sdr = SDR0_READ(DCRN_SDR0_UART3);
 503                break;
 504        default:
 505                return;
 506        }
 507
 508        if (sdr & 0x00800000u)
 509                clock = ser_clk;
 510        else
 511                clock = plb_clk / __fix_zero(sdr & 0xff, 256);
 512
 513        dt_fixup_clock(path, clock);
 514}
 515
 516void ibm440ep_fixup_clocks(unsigned int sys_clk,
 517                           unsigned int ser_clk,
 518                           unsigned int tmr_clk)
 519{
 520        unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0);
 521
 522        /* serial clocks need fixup based on int/ext */
 523        eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk);
 524        eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk);
 525        eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk);
 526        eplike_fixup_uart_clk(3, "/plb/opb/serial@ef600600", ser_clk, plb_clk);
 527}
 528
 529void ibm440gx_fixup_clocks(unsigned int sys_clk,
 530                           unsigned int ser_clk,
 531                           unsigned int tmr_clk)
 532{
 533        unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
 534
 535        /* serial clocks need fixup based on int/ext */
 536        eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk);
 537        eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk);
 538}
 539
 540void ibm440spe_fixup_clocks(unsigned int sys_clk,
 541                            unsigned int ser_clk,
 542                            unsigned int tmr_clk)
 543{
 544        unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
 545
 546        /* serial clocks need fixup based on int/ext */
 547        eplike_fixup_uart_clk(0, "/plb/opb/serial@f0000200", ser_clk, plb_clk);
 548        eplike_fixup_uart_clk(1, "/plb/opb/serial@f0000300", ser_clk, plb_clk);
 549        eplike_fixup_uart_clk(2, "/plb/opb/serial@f0000600", ser_clk, plb_clk);
 550}
 551
 552void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
 553{
 554        u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
 555        u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
 556        u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
 557        u32 psr = mfdcr(DCRN_405_CPC0_PSR);
 558        u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
 559        u32 fwdv, fwdvb, fbdv, cbdv, opdv, epdv, ppdv, udiv;
 560
 561        fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
 562        fbdv = (pllmr & 0x1e000000) >> 25;
 563        if (fbdv == 0)
 564                fbdv = 16;
 565        cbdv = ((pllmr & 0x00060000) >> 17) + 1; /* CPU:PLB */
 566        opdv = ((pllmr & 0x00018000) >> 15) + 1; /* PLB:OPB */
 567        ppdv = ((pllmr & 0x00006000) >> 13) + 1; /* PLB:PCI */
 568        epdv = ((pllmr & 0x00001800) >> 11) + 2; /* PLB:EBC */
 569        udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
 570
 571        /* check for 405GPr */
 572        if ((mfpvr() & 0xfffffff0) == (0x50910951 & 0xfffffff0)) {
 573                fwdvb = 8 - (pllmr & 0x00000007);
 574                if (!(psr & 0x00001000)) /* PCI async mode enable == 0 */
 575                        if (psr & 0x00000020) /* New mode enable */
 576                                m = fwdvb * 2 * ppdv;
 577                        else
 578                                m = fwdvb * cbdv * ppdv;
 579                else if (psr & 0x00000020) /* New mode enable */
 580                        if (psr & 0x00000800) /* PerClk synch mode */
 581                                m = fwdvb * 2 * epdv;
 582                        else
 583                                m = fbdv * fwdv;
 584                else if (epdv == fbdv)
 585                        m = fbdv * cbdv * epdv;
 586                else
 587                        m = fbdv * fwdvb * cbdv;
 588
 589                cpu = sys_clk * m / fwdv;
 590                plb = sys_clk * m / (fwdvb * cbdv);
 591        } else {
 592                m = fwdv * fbdv * cbdv;
 593                cpu = sys_clk * m / fwdv;
 594                plb = cpu / cbdv;
 595        }
 596        opb = plb / opdv;
 597        ebc = plb / epdv;
 598
 599        if (cpc0_cr0 & 0x80)
 600                /* uart0 uses the external clock */
 601                uart0 = ser_clk;
 602        else
 603                uart0 = cpu / udiv;
 604
 605        if (cpc0_cr0 & 0x40)
 606                /* uart1 uses the external clock */
 607                uart1 = ser_clk;
 608        else
 609                uart1 = cpu / udiv;
 610
 611        /* setup the timebase clock to tick at the cpu frequency */
 612        cpc0_cr1 = cpc0_cr1 & ~0x00800000;
 613        mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
 614        tb = cpu;
 615
 616        dt_fixup_cpu_clocks(cpu, tb, 0);
 617        dt_fixup_clock("/plb", plb);
 618        dt_fixup_clock("/plb/opb", opb);
 619        dt_fixup_clock("/plb/ebc", ebc);
 620        dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
 621        dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
 622}
 623
 624
 625void ibm405ep_fixup_clocks(unsigned int sys_clk)
 626{
 627        u32 pllmr0 = mfdcr(DCRN_CPC0_PLLMR0);
 628        u32 pllmr1 = mfdcr(DCRN_CPC0_PLLMR1);
 629        u32 cpc0_ucr = mfdcr(DCRN_CPC0_UCR);
 630        u32 cpu, plb, opb, ebc, uart0, uart1;
 631        u32 fwdva, fwdvb, fbdv, cbdv, opdv, epdv;
 632        u32 pllmr0_ccdv, tb, m;
 633
 634        fwdva = 8 - ((pllmr1 & 0x00070000) >> 16);
 635        fwdvb = 8 - ((pllmr1 & 0x00007000) >> 12);
 636        fbdv = (pllmr1 & 0x00f00000) >> 20;
 637        if (fbdv == 0)
 638                fbdv = 16;
 639
 640        cbdv = ((pllmr0 & 0x00030000) >> 16) + 1; /* CPU:PLB */
 641        epdv = ((pllmr0 & 0x00000300) >> 8) + 2;  /* PLB:EBC */
 642        opdv = ((pllmr0 & 0x00003000) >> 12) + 1; /* PLB:OPB */
 643
 644        m = fbdv * fwdvb;
 645
 646        pllmr0_ccdv = ((pllmr0 & 0x00300000) >> 20) + 1;
 647        if (pllmr1 & 0x80000000)
 648                cpu = sys_clk * m / (fwdva * pllmr0_ccdv);
 649        else
 650                cpu = sys_clk / pllmr0_ccdv;
 651
 652        plb = cpu / cbdv;
 653        opb = plb / opdv;
 654        ebc = plb / epdv;
 655        tb = cpu;
 656        uart0 = cpu / (cpc0_ucr & 0x0000007f);
 657        uart1 = cpu / ((cpc0_ucr & 0x00007f00) >> 8);
 658
 659        dt_fixup_cpu_clocks(cpu, tb, 0);
 660        dt_fixup_clock("/plb", plb);
 661        dt_fixup_clock("/plb/opb", opb);
 662        dt_fixup_clock("/plb/ebc", ebc);
 663        dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
 664        dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
 665}
 666
 667static u8 ibm405ex_fwdv_multi_bits[] = {
 668        /* values for:  1 - 16 */
 669        0x01, 0x02, 0x0e, 0x09, 0x04, 0x0b, 0x10, 0x0d, 0x0c, 0x05,
 670        0x06, 0x0f, 0x0a, 0x07, 0x08, 0x03
 671};
 672
 673u32 ibm405ex_get_fwdva(unsigned long cpr_fwdv)
 674{
 675        u32 index;
 676
 677        for (index = 0; index < ARRAY_SIZE(ibm405ex_fwdv_multi_bits); index++)
 678                if (cpr_fwdv == (u32)ibm405ex_fwdv_multi_bits[index])
 679                        return index + 1;
 680
 681        return 0;
 682}
 683
 684static u8 ibm405ex_fbdv_multi_bits[] = {
 685        /* values for:  1 - 100 */
 686        0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
 687        0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
 688        0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
 689        0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
 690        0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
 691        0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
 692        0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
 693        0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
 694        0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
 695        0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
 696        /* values for:  101 - 200 */
 697        0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
 698        0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
 699        0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
 700        0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
 701        0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
 702        0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
 703        0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
 704        0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
 705        0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
 706        0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
 707        /* values for:  201 - 255 */
 708        0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
 709        0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
 710        0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
 711        0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
 712        0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
 713        0x03, 0x87, 0x0f, 0x9f, 0x3f  /* END */
 714};
 715
 716u32 ibm405ex_get_fbdv(unsigned long cpr_fbdv)
 717{
 718        u32 index;
 719
 720        for (index = 0; index < ARRAY_SIZE(ibm405ex_fbdv_multi_bits); index++)
 721                if (cpr_fbdv == (u32)ibm405ex_fbdv_multi_bits[index])
 722                        return index + 1;
 723
 724        return 0;
 725}
 726
 727void ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk)
 728{
 729        /* PLL config */
 730        u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
 731        u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
 732        u32 cpud  = CPR0_READ(DCRN_CPR0_PRIMAD);
 733        u32 plbd  = CPR0_READ(DCRN_CPR0_PRIMBD);
 734        u32 opbd  = CPR0_READ(DCRN_CPR0_OPBD);
 735        u32 perd  = CPR0_READ(DCRN_CPR0_PERD);
 736
 737        /* Dividers */
 738        u32 fbdv   = ibm405ex_get_fbdv(__fix_zero((plld >> 24) & 0xff, 1));
 739
 740        u32 fwdva  = ibm405ex_get_fwdva(__fix_zero((plld >> 16) & 0x0f, 1));
 741
 742        u32 cpudv0 = __fix_zero((cpud >> 24) & 7, 8);
 743
 744        /* PLBDV0 is hardwared to 010. */
 745        u32 plbdv0 = 2;
 746        u32 plb2xdv0 = __fix_zero((plbd >> 16) & 7, 8);
 747
 748        u32 opbdv0 = __fix_zero((opbd >> 24) & 3, 4);
 749
 750        u32 perdv0 = __fix_zero((perd >> 24) & 3, 4);
 751
 752        /* Resulting clocks */
 753        u32 cpu, plb, opb, ebc, vco, tb, uart0, uart1;
 754
 755        /* PLL's VCO is the source for primary forward ? */
 756        if (pllc & 0x40000000) {
 757                u32 m;
 758
 759                /* Feedback path */
 760                switch ((pllc >> 24) & 7) {
 761                case 0:
 762                        /* PLLOUTx */
 763                        m = fbdv;
 764                        break;
 765                case 1:
 766                        /* CPU */
 767                        m = fbdv * fwdva * cpudv0;
 768                        break;
 769                case 5:
 770                        /* PERClk */
 771                        m = fbdv * fwdva * plb2xdv0 * plbdv0 * opbdv0 * perdv0;
 772                        break;
 773                default:
 774                        printf("WARNING ! Invalid PLL feedback source !\n");
 775                        goto bypass;
 776                }
 777
 778                vco = (unsigned int)(sys_clk * m);
 779        } else {
 780bypass:
 781                /* Bypass system PLL */
 782                vco = 0;
 783        }
 784
 785        /* CPU = VCO / ( FWDVA x CPUDV0) */
 786        cpu = vco / (fwdva * cpudv0);
 787        /* PLB = VCO / ( FWDVA x PLB2XDV0 x PLBDV0) */
 788        plb = vco / (fwdva * plb2xdv0 * plbdv0);
 789        /* OPB = PLB / OPBDV0 */
 790        opb = plb / opbdv0;
 791        /* EBC = OPB / PERDV0 */
 792        ebc = opb / perdv0;
 793
 794        tb = cpu;
 795        uart0 = uart1 = uart_clk;
 796
 797        dt_fixup_cpu_clocks(cpu, tb, 0);
 798        dt_fixup_clock("/plb", plb);
 799        dt_fixup_clock("/plb/opb", opb);
 800        dt_fixup_clock("/plb/opb/ebc", ebc);
 801        dt_fixup_clock("/plb/opb/serial@ef600200", uart0);
 802        dt_fixup_clock("/plb/opb/serial@ef600300", uart1);
 803}
 804