Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Old U-boot compatibility for Acadia
0004  *
0005  * Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
0006  *
0007  * Copyright 2008 IBM Corporation
0008  */
0009 
0010 #include "ops.h"
0011 #include "io.h"
0012 #include "dcr.h"
0013 #include "stdio.h"
0014 #include "4xx.h"
0015 #include "44x.h"
0016 #include "cuboot.h"
0017 
0018 #define TARGET_4xx
0019 #include "ppcboot.h"
0020 
0021 static bd_t bd;
0022 
0023 #define CPR_PERD0_SPIDV_MASK   0x000F0000     /* SPI Clock Divider */
0024 
0025 #define PLLC_SRC_MASK          0x20000000     /* PLL feedback source */
0026 
0027 #define PLLD_FBDV_MASK         0x1F000000     /* PLL feedback divider value */
0028 #define PLLD_FWDVA_MASK        0x000F0000     /* PLL forward divider A value */
0029 #define PLLD_FWDVB_MASK        0x00000700     /* PLL forward divider B value */
0030 
0031 #define PRIMAD_CPUDV_MASK      0x0F000000     /* CPU Clock Divisor Mask */
0032 #define PRIMAD_PLBDV_MASK      0x000F0000     /* PLB Clock Divisor Mask */
0033 #define PRIMAD_OPBDV_MASK      0x00000F00     /* OPB Clock Divisor Mask */
0034 #define PRIMAD_EBCDV_MASK      0x0000000F     /* EBC Clock Divisor Mask */
0035 
0036 #define PERD0_PWMDV_MASK       0xFF000000     /* PWM Divider Mask */
0037 #define PERD0_SPIDV_MASK       0x000F0000     /* SPI Divider Mask */
0038 #define PERD0_U0DV_MASK        0x0000FF00     /* UART 0 Divider Mask */
0039 #define PERD0_U1DV_MASK        0x000000FF     /* UART 1 Divider Mask */
0040 
0041 static void get_clocks(void)
0042 {
0043     unsigned long sysclk, cpr_plld, cpr_pllc, cpr_primad, plloutb, i;
0044     unsigned long pllFwdDiv, pllFwdDivB, pllFbkDiv, pllPlbDiv, pllExtBusDiv;
0045     unsigned long pllOpbDiv, freqEBC, freqUART, freqOPB;
0046     unsigned long div;      /* total divisor udiv * bdiv */
0047     unsigned long umin;     /* minimum udiv */
0048     unsigned short diff;        /* smallest diff */
0049     unsigned long udiv;     /* best udiv */
0050     unsigned short idiff;       /* current diff */
0051     unsigned short ibdiv;       /* current bdiv */
0052     unsigned long est;      /* current estimate */
0053     unsigned long baud;
0054     void *np;
0055 
0056     /* read the sysclk value from the CPLD */
0057     sysclk = (in_8((unsigned char *)0x80000000) == 0xc) ? 66666666 : 33333000;
0058 
0059     /*
0060      * Read PLL Mode registers
0061      */
0062     cpr_plld = CPR0_READ(DCRN_CPR0_PLLD);
0063     cpr_pllc = CPR0_READ(DCRN_CPR0_PLLC);
0064 
0065     /*
0066      * Determine forward divider A
0067      */
0068     pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
0069 
0070     /*
0071      * Determine forward divider B
0072      */
0073     pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
0074     if (pllFwdDivB == 0)
0075         pllFwdDivB = 8;
0076 
0077     /*
0078      * Determine FBK_DIV.
0079      */
0080     pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
0081     if (pllFbkDiv == 0)
0082         pllFbkDiv = 256;
0083 
0084     /*
0085      * Read CPR_PRIMAD register
0086      */
0087     cpr_primad = CPR0_READ(DCRN_CPR0_PRIMAD);
0088 
0089     /*
0090      * Determine PLB_DIV.
0091      */
0092     pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
0093     if (pllPlbDiv == 0)
0094         pllPlbDiv = 16;
0095 
0096     /*
0097      * Determine EXTBUS_DIV.
0098      */
0099     pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
0100     if (pllExtBusDiv == 0)
0101         pllExtBusDiv = 16;
0102 
0103     /*
0104      * Determine OPB_DIV.
0105      */
0106     pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
0107     if (pllOpbDiv == 0)
0108         pllOpbDiv = 16;
0109 
0110     /* There is a bug in U-Boot that prevents us from using
0111      * bd.bi_opbfreq because U-Boot doesn't populate it for
0112      * 405EZ.  We get to calculate it, yay!
0113      */
0114     freqOPB = (sysclk *pllFbkDiv) /pllOpbDiv;
0115 
0116     freqEBC = (sysclk * pllFbkDiv) / pllExtBusDiv;
0117 
0118     plloutb = ((sysclk * ((cpr_pllc & PLLC_SRC_MASK) ?
0119                        pllFwdDivB : pllFwdDiv) *
0120             pllFbkDiv) / pllFwdDivB);
0121 
0122     np = find_node_by_alias("serial0");
0123     if (getprop(np, "current-speed", &baud, sizeof(baud)) != sizeof(baud))
0124         fatal("no current-speed property\n\r");
0125 
0126     udiv = 256;         /* Assume lowest possible serial clk */
0127     div = plloutb / (16 * baud); /* total divisor */
0128     umin = (plloutb / freqOPB) << 1;    /* 2 x OPB divisor */
0129     diff = 256;         /* highest possible */
0130 
0131     /* i is the test udiv value -- start with the largest
0132      * possible (256) to minimize serial clock and constrain
0133      * search to umin.
0134      */
0135     for (i = 256; i > umin; i--) {
0136         ibdiv = div / i;
0137         est = i * ibdiv;
0138         idiff = (est > div) ? (est-div) : (div-est);
0139         if (idiff == 0) {
0140             udiv = i;
0141             break;      /* can't do better */
0142         } else if (idiff < diff) {
0143             udiv = i;       /* best so far */
0144             diff = idiff;   /* update lowest diff*/
0145         }
0146     }
0147     freqUART = plloutb / udiv;
0148 
0149     dt_fixup_cpu_clocks(bd.bi_procfreq, bd.bi_intfreq, bd.bi_plb_busfreq);
0150     dt_fixup_clock("/plb/ebc", freqEBC);
0151     dt_fixup_clock("/plb/opb", freqOPB);
0152     dt_fixup_clock("/plb/opb/serial@ef600300", freqUART);
0153     dt_fixup_clock("/plb/opb/serial@ef600400", freqUART);
0154 }
0155 
0156 static void acadia_fixups(void)
0157 {
0158     dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
0159     get_clocks();
0160     dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr);
0161 }
0162     
0163 void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
0164         unsigned long r6, unsigned long r7)
0165 {
0166     CUBOOT_INIT();
0167     platform_ops.fixups = acadia_fixups;
0168     platform_ops.exit = ibm40x_dbcr_reset;
0169     fdt_init(_dtb_start);
0170     serial_console_init();
0171 }