Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2007 David Gibson, IBM Corporation.
0004  *
0005  * Based on earlier code:
0006  *   Matt Porter <mporter@kernel.crashing.org>
0007  *   Copyright 2002-2005 MontaVista Software Inc.
0008  *
0009  *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
0010  *   Copyright (c) 2003, 2004 Zultys Technologies
0011  *
0012  * Copyright (C) 2009 Wind River Systems, Inc.
0013  *   Updated for supporting PPC405EX on Kilauea.
0014  *   Tiejun Chen <tiejun.chen@windriver.com>
0015  */
0016 #include <stddef.h>
0017 #include "types.h"
0018 #include "string.h"
0019 #include "stdio.h"
0020 #include "ops.h"
0021 #include "reg.h"
0022 #include "dcr.h"
0023 
0024 static unsigned long chip_11_errata(unsigned long memsize)
0025 {
0026     unsigned long pvr;
0027 
0028     pvr = mfpvr();
0029 
0030     switch (pvr & 0xf0000ff0) {
0031         case 0x40000850:
0032         case 0x400008d0:
0033         case 0x200008d0:
0034             memsize -= 4096;
0035             break;
0036         default:
0037             break;
0038     }
0039 
0040     return memsize;
0041 }
0042 
0043 /* Read the 4xx SDRAM controller to get size of system memory. */
0044 void ibm4xx_sdram_fixup_memsize(void)
0045 {
0046     int i;
0047     unsigned long memsize, bank_config;
0048 
0049     memsize = 0;
0050     for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) {
0051         bank_config = SDRAM0_READ(sdram_bxcr[i]);
0052         if (bank_config & SDRAM_CONFIG_BANK_ENABLE)
0053             memsize += SDRAM_CONFIG_BANK_SIZE(bank_config);
0054     }
0055 
0056     memsize = chip_11_errata(memsize);
0057     dt_fixup_memory(0, memsize);
0058 }
0059 
0060 /* Read the 440SPe MQ controller to get size of system memory. */
0061 #define DCRN_MQ0_B0BAS      0x40
0062 #define DCRN_MQ0_B1BAS      0x41
0063 #define DCRN_MQ0_B2BAS      0x42
0064 #define DCRN_MQ0_B3BAS      0x43
0065 
0066 static u64 ibm440spe_decode_bas(u32 bas)
0067 {
0068     u64 base = ((u64)(bas & 0xFFE00000u)) << 2;
0069 
0070     /* open coded because I'm paranoid about invalid values */
0071     switch ((bas >> 4) & 0xFFF) {
0072     case 0:
0073         return 0;
0074     case 0xffc:
0075         return base + 0x000800000ull;
0076     case 0xff8:
0077         return base + 0x001000000ull;
0078     case 0xff0:
0079         return base + 0x002000000ull;
0080     case 0xfe0:
0081         return base + 0x004000000ull;
0082     case 0xfc0:
0083         return base + 0x008000000ull;
0084     case 0xf80:
0085         return base + 0x010000000ull;
0086     case 0xf00:
0087         return base + 0x020000000ull;
0088     case 0xe00:
0089         return base + 0x040000000ull;
0090     case 0xc00:
0091         return base + 0x080000000ull;
0092     case 0x800:
0093         return base + 0x100000000ull;
0094     }
0095     printf("Memory BAS value 0x%08x unsupported !\n", bas);
0096     return 0;
0097 }
0098 
0099 void ibm440spe_fixup_memsize(void)
0100 {
0101     u64 banktop, memsize = 0;
0102 
0103     /* Ultimately, we should directly construct the memory node
0104      * so we are able to handle holes in the memory address space
0105      */
0106     banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B0BAS));
0107     if (banktop > memsize)
0108         memsize = banktop;
0109     banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B1BAS));
0110     if (banktop > memsize)
0111         memsize = banktop;
0112     banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B2BAS));
0113     if (banktop > memsize)
0114         memsize = banktop;
0115     banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B3BAS));
0116     if (banktop > memsize)
0117         memsize = banktop;
0118 
0119     dt_fixup_memory(0, memsize);
0120 }
0121 
0122 
0123 /* 4xx DDR1/2 Denali memory controller support */
0124 /* DDR0 registers */
0125 #define DDR0_02         2
0126 #define DDR0_08         8
0127 #define DDR0_10         10
0128 #define DDR0_14         14
0129 #define DDR0_42         42
0130 #define DDR0_43         43
0131 
0132 /* DDR0_02 */
0133 #define DDR_START       0x1
0134 #define DDR_START_SHIFT     0
0135 #define DDR_MAX_CS_REG      0x3
0136 #define DDR_MAX_CS_REG_SHIFT    24
0137 #define DDR_MAX_COL_REG     0xf
0138 #define DDR_MAX_COL_REG_SHIFT   16
0139 #define DDR_MAX_ROW_REG     0xf
0140 #define DDR_MAX_ROW_REG_SHIFT   8
0141 /* DDR0_08 */
0142 #define DDR_DDR2_MODE       0x1
0143 #define DDR_DDR2_MODE_SHIFT 0
0144 /* DDR0_10 */
0145 #define DDR_CS_MAP      0x3
0146 #define DDR_CS_MAP_SHIFT    8
0147 /* DDR0_14 */
0148 #define DDR_REDUC       0x1
0149 #define DDR_REDUC_SHIFT     16
0150 /* DDR0_42 */
0151 #define DDR_APIN        0x7
0152 #define DDR_APIN_SHIFT      24
0153 /* DDR0_43 */
0154 #define DDR_COL_SZ      0x7
0155 #define DDR_COL_SZ_SHIFT    8
0156 #define DDR_BANK8       0x1
0157 #define DDR_BANK8_SHIFT     0
0158 
0159 #define DDR_GET_VAL(val, mask, shift)   (((val) >> (shift)) & (mask))
0160 
0161 /*
0162  * Some U-Boot versions set the number of chipselects to two
0163  * for Sequoia/Rainier boards while they only have one chipselect
0164  * hardwired. Hardcode the number of chipselects to one
0165  * for sequioa/rainer board models or read the actual value
0166  * from the memory controller register DDR0_10 otherwise.
0167  */
0168 static inline u32 ibm4xx_denali_get_cs(void)
0169 {
0170     void *devp;
0171     char model[64];
0172     u32 val, cs;
0173 
0174     devp = finddevice("/");
0175     if (!devp)
0176         goto read_cs;
0177 
0178     if (getprop(devp, "model", model, sizeof(model)) <= 0)
0179         goto read_cs;
0180 
0181     model[sizeof(model)-1] = 0;
0182 
0183     if (!strcmp(model, "amcc,sequoia") ||
0184         !strcmp(model, "amcc,rainier"))
0185         return 1;
0186 
0187 read_cs:
0188     /* get CS value */
0189     val = SDRAM0_READ(DDR0_10);
0190 
0191     val = DDR_GET_VAL(val, DDR_CS_MAP, DDR_CS_MAP_SHIFT);
0192     cs = 0;
0193     while (val) {
0194         if (val & 0x1)
0195             cs++;
0196         val = val >> 1;
0197     }
0198     return cs;
0199 }
0200 
0201 void ibm4xx_denali_fixup_memsize(void)
0202 {
0203     u32 val, max_cs, max_col, max_row;
0204     u32 cs, col, row, bank, dpath;
0205     unsigned long memsize;
0206 
0207     val = SDRAM0_READ(DDR0_02);
0208     if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT))
0209         fatal("DDR controller is not initialized\n");
0210 
0211     /* get maximum cs col and row values */
0212     max_cs  = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT);
0213     max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT);
0214     max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT);
0215 
0216     cs = ibm4xx_denali_get_cs();
0217     if (!cs)
0218         fatal("No memory installed\n");
0219     if (cs > max_cs)
0220         fatal("DDR wrong CS configuration\n");
0221 
0222     /* get data path bytes */
0223     val = SDRAM0_READ(DDR0_14);
0224 
0225     if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT))
0226         dpath = 4; /* 32 bits */
0227     else
0228         dpath = 8; /* 64 bits */
0229 
0230     /* get address pins (rows) */
0231     val = SDRAM0_READ(DDR0_42);
0232 
0233     row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT);
0234     if (row > max_row)
0235         fatal("DDR wrong APIN configuration\n");
0236     row = max_row - row;
0237 
0238     /* get collomn size and banks */
0239     val = SDRAM0_READ(DDR0_43);
0240 
0241     col = DDR_GET_VAL(val, DDR_COL_SZ, DDR_COL_SZ_SHIFT);
0242     if (col > max_col)
0243         fatal("DDR wrong COL configuration\n");
0244     col = max_col - col;
0245 
0246     if (DDR_GET_VAL(val, DDR_BANK8, DDR_BANK8_SHIFT))
0247         bank = 8; /* 8 banks */
0248     else
0249         bank = 4; /* 4 banks */
0250 
0251     memsize = cs * (1 << (col+row)) * bank * dpath;
0252     memsize = chip_11_errata(memsize);
0253     dt_fixup_memory(0, memsize);
0254 }
0255 
0256 #define SPRN_DBCR0_40X 0x3F2
0257 #define SPRN_DBCR0_44X 0x134
0258 #define DBCR0_RST_SYSTEM 0x30000000
0259 
0260 void ibm44x_dbcr_reset(void)
0261 {
0262     unsigned long tmp;
0263 
0264     asm volatile (
0265         "mfspr  %0,%1\n"
0266         "oris   %0,%0,%2@h\n"
0267         "mtspr  %1,%0"
0268         : "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM)
0269         );
0270 
0271 }
0272 
0273 void ibm40x_dbcr_reset(void)
0274 {
0275     unsigned long tmp;
0276 
0277     asm volatile (
0278         "mfspr  %0,%1\n"
0279         "oris   %0,%0,%2@h\n"
0280         "mtspr  %1,%0"
0281         : "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM)
0282         );
0283 }
0284 
0285 #define EMAC_RESET 0x20000000
0286 void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1)
0287 {
0288     /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
0289      * do this for us
0290      */
0291     if (emac0)
0292         *emac0 = EMAC_RESET;
0293     if (emac1)
0294         *emac1 = EMAC_RESET;
0295 
0296     mtdcr(DCRN_MAL0_CFG, MAL_RESET);
0297     while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET)
0298         ; /* loop until reset takes effect */
0299 }
0300 
0301 /* Read 4xx EBC bus bridge registers to get mappings of the peripheral
0302  * banks into the OPB address space */
0303 void ibm4xx_fixup_ebc_ranges(const char *ebc)
0304 {
0305     void *devp;
0306     u32 bxcr;
0307     u32 ranges[EBC_NUM_BANKS*4];
0308     u32 *p = ranges;
0309     int i;
0310 
0311     for (i = 0; i < EBC_NUM_BANKS; i++) {
0312         mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i));
0313         bxcr = mfdcr(DCRN_EBC0_CFGDATA);
0314 
0315         if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) {
0316             *p++ = i;
0317             *p++ = 0;
0318             *p++ = bxcr & EBC_BXCR_BAS;
0319             *p++ = EBC_BXCR_BANK_SIZE(bxcr);
0320         }
0321     }
0322 
0323     devp = finddevice(ebc);
0324     if (! devp)
0325         fatal("Couldn't locate EBC node %s\n\r", ebc);
0326 
0327     setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32));
0328 }
0329 
0330 /* Calculate 440GP clocks */
0331 void ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
0332 {
0333     u32 sys0 = mfdcr(DCRN_CPC0_SYS0);
0334     u32 cr0 = mfdcr(DCRN_CPC0_CR0);
0335     u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
0336     u32 opdv = CPC0_SYS0_OPDV(sys0);
0337     u32 epdv = CPC0_SYS0_EPDV(sys0);
0338 
0339     if (sys0 & CPC0_SYS0_BYPASS) {
0340         /* Bypass system PLL */
0341         cpu = plb = sys_clk;
0342     } else {
0343         if (sys0 & CPC0_SYS0_EXTSL)
0344             /* PerClk */
0345             m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv;
0346         else
0347             /* CPU clock */
0348             m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0);
0349         cpu = sys_clk * m / CPC0_SYS0_FWDVA(sys0);
0350         plb = sys_clk * m / CPC0_SYS0_FWDVB(sys0);
0351     }
0352 
0353     opb = plb / opdv;
0354     ebc = opb / epdv;
0355 
0356     /* FIXME: Check if this is for all 440GP, or just Ebony */
0357     if ((mfpvr() & 0xf0000fff) == 0x40000440)
0358         /* Rev. B 440GP, use external system clock */
0359         tb = sys_clk;
0360     else
0361         /* Rev. C 440GP, errata force us to use internal clock */
0362         tb = cpu;
0363 
0364     if (cr0 & CPC0_CR0_U0EC)
0365         /* External UART clock */
0366         uart0 = ser_clk;
0367     else
0368         /* Internal UART clock */
0369         uart0 = plb / CPC0_CR0_UDIV(cr0);
0370 
0371     if (cr0 & CPC0_CR0_U1EC)
0372         /* External UART clock */
0373         uart1 = ser_clk;
0374     else
0375         /* Internal UART clock */
0376         uart1 = plb / CPC0_CR0_UDIV(cr0);
0377 
0378     printf("PPC440GP: SysClk = %dMHz (%x)\n\r",
0379            (sys_clk + 500000) / 1000000, sys_clk);
0380 
0381     dt_fixup_cpu_clocks(cpu, tb, 0);
0382 
0383     dt_fixup_clock("/plb", plb);
0384     dt_fixup_clock("/plb/opb", opb);
0385     dt_fixup_clock("/plb/opb/ebc", ebc);
0386     dt_fixup_clock("/plb/opb/serial@40000200", uart0);
0387     dt_fixup_clock("/plb/opb/serial@40000300", uart1);
0388 }
0389 
0390 #define SPRN_CCR1 0x378
0391 
0392 static inline u32 __fix_zero(u32 v, u32 def)
0393 {
0394     return v ? v : def;
0395 }
0396 
0397 static unsigned int __ibm440eplike_fixup_clocks(unsigned int sys_clk,
0398                         unsigned int tmr_clk,
0399                         int per_clk_from_opb)
0400 {
0401     /* PLL config */
0402     u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
0403     u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
0404 
0405     /* Dividers */
0406     u32 fbdv   = __fix_zero((plld >> 24) & 0x1f, 32);
0407     u32 fwdva  = __fix_zero((plld >> 16) & 0xf, 16);
0408     u32 fwdvb  = __fix_zero((plld >> 8) & 7, 8);
0409     u32 lfbdv  = __fix_zero(plld & 0x3f, 64);
0410     u32 pradv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMAD) >> 24) & 7, 8);
0411     u32 prbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMBD) >> 24) & 7, 8);
0412     u32 opbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_OPBD) >> 24) & 3, 4);
0413     u32 perdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PERD) >> 24) & 3, 4);
0414 
0415     /* Input clocks for primary dividers */
0416     u32 clk_a, clk_b;
0417 
0418     /* Resulting clocks */
0419     u32 cpu, plb, opb, ebc, vco;
0420 
0421     /* Timebase */
0422     u32 ccr1, tb = tmr_clk;
0423 
0424     if (pllc & 0x40000000) {
0425         u32 m;
0426 
0427         /* Feedback path */
0428         switch ((pllc >> 24) & 7) {
0429         case 0:
0430             /* PLLOUTx */
0431             m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
0432             break;
0433         case 1:
0434             /* CPU */
0435             m = fwdva * pradv0;
0436             break;
0437         case 5:
0438             /* PERClk */
0439             m = fwdvb * prbdv0 * opbdv0 * perdv0;
0440             break;
0441         default:
0442             printf("WARNING ! Invalid PLL feedback source !\n");
0443             goto bypass;
0444         }
0445         m *= fbdv;
0446         vco = sys_clk * m;
0447         clk_a = vco / fwdva;
0448         clk_b = vco / fwdvb;
0449     } else {
0450 bypass:
0451         /* Bypass system PLL */
0452         vco = 0;
0453         clk_a = clk_b = sys_clk;
0454     }
0455 
0456     cpu = clk_a / pradv0;
0457     plb = clk_b / prbdv0;
0458     opb = plb / opbdv0;
0459     ebc = (per_clk_from_opb ? opb : plb) / perdv0;
0460 
0461     /* Figure out timebase.  Either CPU or default TmrClk */
0462     ccr1 = mfspr(SPRN_CCR1);
0463 
0464     /* If passed a 0 tmr_clk, force CPU clock */
0465     if (tb == 0) {
0466         ccr1 &= ~0x80u;
0467         mtspr(SPRN_CCR1, ccr1);
0468     }
0469     if ((ccr1 & 0x0080) == 0)
0470         tb = cpu;
0471 
0472     dt_fixup_cpu_clocks(cpu, tb, 0);
0473     dt_fixup_clock("/plb", plb);
0474     dt_fixup_clock("/plb/opb", opb);
0475     dt_fixup_clock("/plb/opb/ebc", ebc);
0476 
0477     return plb;
0478 }
0479 
0480 static void eplike_fixup_uart_clk(int index, const char *path,
0481                   unsigned int ser_clk,
0482                   unsigned int plb_clk)
0483 {
0484     unsigned int sdr;
0485     unsigned int clock;
0486 
0487     switch (index) {
0488     case 0:
0489         sdr = SDR0_READ(DCRN_SDR0_UART0);
0490         break;
0491     case 1:
0492         sdr = SDR0_READ(DCRN_SDR0_UART1);
0493         break;
0494     case 2:
0495         sdr = SDR0_READ(DCRN_SDR0_UART2);
0496         break;
0497     case 3:
0498         sdr = SDR0_READ(DCRN_SDR0_UART3);
0499         break;
0500     default:
0501         return;
0502     }
0503 
0504     if (sdr & 0x00800000u)
0505         clock = ser_clk;
0506     else
0507         clock = plb_clk / __fix_zero(sdr & 0xff, 256);
0508 
0509     dt_fixup_clock(path, clock);
0510 }
0511 
0512 void ibm440ep_fixup_clocks(unsigned int sys_clk,
0513                unsigned int ser_clk,
0514                unsigned int tmr_clk)
0515 {
0516     unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0);
0517 
0518     /* serial clocks need fixup based on int/ext */
0519     eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk);
0520     eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk);
0521     eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk);
0522     eplike_fixup_uart_clk(3, "/plb/opb/serial@ef600600", ser_clk, plb_clk);
0523 }
0524 
0525 void ibm440gx_fixup_clocks(unsigned int sys_clk,
0526                unsigned int ser_clk,
0527                unsigned int tmr_clk)
0528 {
0529     unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
0530 
0531     /* serial clocks need fixup based on int/ext */
0532     eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk);
0533     eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk);
0534 }
0535 
0536 void ibm440spe_fixup_clocks(unsigned int sys_clk,
0537                 unsigned int ser_clk,
0538                 unsigned int tmr_clk)
0539 {
0540     unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
0541 
0542     /* serial clocks need fixup based on int/ext */
0543     eplike_fixup_uart_clk(0, "/plb/opb/serial@f0000200", ser_clk, plb_clk);
0544     eplike_fixup_uart_clk(1, "/plb/opb/serial@f0000300", ser_clk, plb_clk);
0545     eplike_fixup_uart_clk(2, "/plb/opb/serial@f0000600", ser_clk, plb_clk);
0546 }
0547 
0548 void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
0549 {
0550     u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
0551     u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
0552     u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
0553     u32 psr = mfdcr(DCRN_405_CPC0_PSR);
0554     u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
0555     u32 fwdv, fwdvb, fbdv, cbdv, opdv, epdv, ppdv, udiv;
0556 
0557     fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
0558     fbdv = (pllmr & 0x1e000000) >> 25;
0559     if (fbdv == 0)
0560         fbdv = 16;
0561     cbdv = ((pllmr & 0x00060000) >> 17) + 1; /* CPU:PLB */
0562     opdv = ((pllmr & 0x00018000) >> 15) + 1; /* PLB:OPB */
0563     ppdv = ((pllmr & 0x00006000) >> 13) + 1; /* PLB:PCI */
0564     epdv = ((pllmr & 0x00001800) >> 11) + 2; /* PLB:EBC */
0565     udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
0566 
0567     /* check for 405GPr */
0568     if ((mfpvr() & 0xfffffff0) == (0x50910951 & 0xfffffff0)) {
0569         fwdvb = 8 - (pllmr & 0x00000007);
0570         if (!(psr & 0x00001000)) /* PCI async mode enable == 0 */
0571             if (psr & 0x00000020) /* New mode enable */
0572                 m = fwdvb * 2 * ppdv;
0573             else
0574                 m = fwdvb * cbdv * ppdv;
0575         else if (psr & 0x00000020) /* New mode enable */
0576             if (psr & 0x00000800) /* PerClk synch mode */
0577                 m = fwdvb * 2 * epdv;
0578             else
0579                 m = fbdv * fwdv;
0580         else if (epdv == fbdv)
0581             m = fbdv * cbdv * epdv;
0582         else
0583             m = fbdv * fwdvb * cbdv;
0584 
0585         cpu = sys_clk * m / fwdv;
0586         plb = sys_clk * m / (fwdvb * cbdv);
0587     } else {
0588         m = fwdv * fbdv * cbdv;
0589         cpu = sys_clk * m / fwdv;
0590         plb = cpu / cbdv;
0591     }
0592     opb = plb / opdv;
0593     ebc = plb / epdv;
0594 
0595     if (cpc0_cr0 & 0x80)
0596         /* uart0 uses the external clock */
0597         uart0 = ser_clk;
0598     else
0599         uart0 = cpu / udiv;
0600 
0601     if (cpc0_cr0 & 0x40)
0602         /* uart1 uses the external clock */
0603         uart1 = ser_clk;
0604     else
0605         uart1 = cpu / udiv;
0606 
0607     /* setup the timebase clock to tick at the cpu frequency */
0608     cpc0_cr1 = cpc0_cr1 & ~0x00800000;
0609     mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
0610     tb = cpu;
0611 
0612     dt_fixup_cpu_clocks(cpu, tb, 0);
0613     dt_fixup_clock("/plb", plb);
0614     dt_fixup_clock("/plb/opb", opb);
0615     dt_fixup_clock("/plb/ebc", ebc);
0616     dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
0617     dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
0618 }
0619 
0620 
0621 void ibm405ep_fixup_clocks(unsigned int sys_clk)
0622 {
0623     u32 pllmr0 = mfdcr(DCRN_CPC0_PLLMR0);
0624     u32 pllmr1 = mfdcr(DCRN_CPC0_PLLMR1);
0625     u32 cpc0_ucr = mfdcr(DCRN_CPC0_UCR);
0626     u32 cpu, plb, opb, ebc, uart0, uart1;
0627     u32 fwdva, fwdvb, fbdv, cbdv, opdv, epdv;
0628     u32 pllmr0_ccdv, tb, m;
0629 
0630     fwdva = 8 - ((pllmr1 & 0x00070000) >> 16);
0631     fwdvb = 8 - ((pllmr1 & 0x00007000) >> 12);
0632     fbdv = (pllmr1 & 0x00f00000) >> 20;
0633     if (fbdv == 0)
0634         fbdv = 16;
0635 
0636     cbdv = ((pllmr0 & 0x00030000) >> 16) + 1; /* CPU:PLB */
0637     epdv = ((pllmr0 & 0x00000300) >> 8) + 2;  /* PLB:EBC */
0638     opdv = ((pllmr0 & 0x00003000) >> 12) + 1; /* PLB:OPB */
0639 
0640     m = fbdv * fwdvb;
0641 
0642     pllmr0_ccdv = ((pllmr0 & 0x00300000) >> 20) + 1;
0643     if (pllmr1 & 0x80000000)
0644         cpu = sys_clk * m / (fwdva * pllmr0_ccdv);
0645     else
0646         cpu = sys_clk / pllmr0_ccdv;
0647 
0648     plb = cpu / cbdv;
0649     opb = plb / opdv;
0650     ebc = plb / epdv;
0651     tb = cpu;
0652     uart0 = cpu / (cpc0_ucr & 0x0000007f);
0653     uart1 = cpu / ((cpc0_ucr & 0x00007f00) >> 8);
0654 
0655     dt_fixup_cpu_clocks(cpu, tb, 0);
0656     dt_fixup_clock("/plb", plb);
0657     dt_fixup_clock("/plb/opb", opb);
0658     dt_fixup_clock("/plb/ebc", ebc);
0659     dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
0660     dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
0661 }
0662 
0663 static u8 ibm405ex_fwdv_multi_bits[] = {
0664     /* values for:  1 - 16 */
0665     0x01, 0x02, 0x0e, 0x09, 0x04, 0x0b, 0x10, 0x0d, 0x0c, 0x05,
0666     0x06, 0x0f, 0x0a, 0x07, 0x08, 0x03
0667 };
0668 
0669 u32 ibm405ex_get_fwdva(unsigned long cpr_fwdv)
0670 {
0671     u32 index;
0672 
0673     for (index = 0; index < ARRAY_SIZE(ibm405ex_fwdv_multi_bits); index++)
0674         if (cpr_fwdv == (u32)ibm405ex_fwdv_multi_bits[index])
0675             return index + 1;
0676 
0677     return 0;
0678 }
0679 
0680 static u8 ibm405ex_fbdv_multi_bits[] = {
0681     /* values for:  1 - 100 */
0682     0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
0683     0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
0684     0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
0685     0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
0686     0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
0687     0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
0688     0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
0689     0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
0690     0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
0691     0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
0692     /* values for:  101 - 200 */
0693     0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
0694     0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
0695     0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
0696     0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
0697     0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
0698     0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
0699     0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
0700     0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
0701     0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
0702     0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
0703     /* values for:  201 - 255 */
0704     0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
0705     0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
0706     0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
0707     0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
0708     0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
0709     0x03, 0x87, 0x0f, 0x9f, 0x3f  /* END */
0710 };
0711 
0712 u32 ibm405ex_get_fbdv(unsigned long cpr_fbdv)
0713 {
0714     u32 index;
0715 
0716     for (index = 0; index < ARRAY_SIZE(ibm405ex_fbdv_multi_bits); index++)
0717         if (cpr_fbdv == (u32)ibm405ex_fbdv_multi_bits[index])
0718             return index + 1;
0719 
0720     return 0;
0721 }
0722 
0723 void ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk)
0724 {
0725     /* PLL config */
0726     u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
0727     u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
0728     u32 cpud  = CPR0_READ(DCRN_CPR0_PRIMAD);
0729     u32 plbd  = CPR0_READ(DCRN_CPR0_PRIMBD);
0730     u32 opbd  = CPR0_READ(DCRN_CPR0_OPBD);
0731     u32 perd  = CPR0_READ(DCRN_CPR0_PERD);
0732 
0733     /* Dividers */
0734     u32 fbdv   = ibm405ex_get_fbdv(__fix_zero((plld >> 24) & 0xff, 1));
0735 
0736     u32 fwdva  = ibm405ex_get_fwdva(__fix_zero((plld >> 16) & 0x0f, 1));
0737 
0738     u32 cpudv0 = __fix_zero((cpud >> 24) & 7, 8);
0739 
0740     /* PLBDV0 is hardwared to 010. */
0741     u32 plbdv0 = 2;
0742     u32 plb2xdv0 = __fix_zero((plbd >> 16) & 7, 8);
0743 
0744     u32 opbdv0 = __fix_zero((opbd >> 24) & 3, 4);
0745 
0746     u32 perdv0 = __fix_zero((perd >> 24) & 3, 4);
0747 
0748     /* Resulting clocks */
0749     u32 cpu, plb, opb, ebc, vco, tb, uart0, uart1;
0750 
0751     /* PLL's VCO is the source for primary forward ? */
0752     if (pllc & 0x40000000) {
0753         u32 m;
0754 
0755         /* Feedback path */
0756         switch ((pllc >> 24) & 7) {
0757         case 0:
0758             /* PLLOUTx */
0759             m = fbdv;
0760             break;
0761         case 1:
0762             /* CPU */
0763             m = fbdv * fwdva * cpudv0;
0764             break;
0765         case 5:
0766             /* PERClk */
0767             m = fbdv * fwdva * plb2xdv0 * plbdv0 * opbdv0 * perdv0;
0768             break;
0769         default:
0770             printf("WARNING ! Invalid PLL feedback source !\n");
0771             goto bypass;
0772         }
0773 
0774         vco = (unsigned int)(sys_clk * m);
0775     } else {
0776 bypass:
0777         /* Bypass system PLL */
0778         vco = 0;
0779     }
0780 
0781     /* CPU = VCO / ( FWDVA x CPUDV0) */
0782     cpu = vco / (fwdva * cpudv0);
0783     /* PLB = VCO / ( FWDVA x PLB2XDV0 x PLBDV0) */
0784     plb = vco / (fwdva * plb2xdv0 * plbdv0);
0785     /* OPB = PLB / OPBDV0 */
0786     opb = plb / opbdv0;
0787     /* EBC = OPB / PERDV0 */
0788     ebc = opb / perdv0;
0789 
0790     tb = cpu;
0791     uart0 = uart1 = uart_clk;
0792 
0793     dt_fixup_cpu_clocks(cpu, tb, 0);
0794     dt_fixup_clock("/plb", plb);
0795     dt_fixup_clock("/plb/opb", opb);
0796     dt_fixup_clock("/plb/opb/ebc", ebc);
0797     dt_fixup_clock("/plb/opb/serial@ef600200", uart0);
0798     dt_fixup_clock("/plb/opb/serial@ef600300", uart1);
0799 }