uboot/arch/m68k/cpu/mcf5445x/speed.c
<<
>>
Prefs
   1/*
   2 *
   3 * Copyright (C) 2004-2007, 2012 Freescale Semiconductor, Inc.
   4 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <common.h>
  10#include <asm/processor.h>
  11
  12#include <asm/immap.h>
  13#include <asm/io.h>
  14
  15DECLARE_GLOBAL_DATA_PTR;
  16
  17/*
  18 * Low Power Divider specifications
  19 */
  20#define CLOCK_LPD_MIN           (1 << 0)        /* Divider (decoded) */
  21#define CLOCK_LPD_MAX           (1 << 15)       /* Divider (decoded) */
  22
  23#define CLOCK_PLL_FVCO_MAX      540000000
  24#define CLOCK_PLL_FVCO_MIN      300000000
  25
  26#define CLOCK_PLL_FSYS_MAX      266666666
  27#define CLOCK_PLL_FSYS_MIN      100000000
  28#define MHZ                     1000000
  29
  30void clock_enter_limp(int lpdiv)
  31{
  32        ccm_t *ccm = (ccm_t *)MMAP_CCM;
  33        int i, j;
  34
  35        /* Check bounds of divider */
  36        if (lpdiv < CLOCK_LPD_MIN)
  37                lpdiv = CLOCK_LPD_MIN;
  38        if (lpdiv > CLOCK_LPD_MAX)
  39                lpdiv = CLOCK_LPD_MAX;
  40
  41        /* Round divider down to nearest power of two */
  42        for (i = 0, j = lpdiv; j != 1; j >>= 1, i++) ;
  43
  44#ifdef CONFIG_MCF5445x
  45        /* Apply the divider to the system clock */
  46        clrsetbits_be16(&ccm->cdr, 0x0f00, CCM_CDR_LPDIV(i));
  47#endif
  48
  49        /* Enable Limp Mode */
  50        setbits_be16(&ccm->misccr, CCM_MISCCR_LIMP);
  51}
  52
  53/*
  54 * brief   Exit Limp mode
  55 * warning The PLL should be set and locked prior to exiting Limp mode
  56 */
  57void clock_exit_limp(void)
  58{
  59        ccm_t *ccm = (ccm_t *)MMAP_CCM;
  60        pll_t *pll = (pll_t *)MMAP_PLL;
  61
  62        /* Exit Limp mode */
  63        clrbits_be16(&ccm->misccr, CCM_MISCCR_LIMP);
  64
  65        /* Wait for the PLL to lock */
  66        while (!(in_be32(&pll->psr) & PLL_PSR_LOCK))
  67                ;
  68}
  69
  70#ifdef CONFIG_MCF5441x
  71void setup_5441x_clocks(void)
  72{
  73        ccm_t *ccm = (ccm_t *)MMAP_CCM;
  74        pll_t *pll = (pll_t *)MMAP_PLL;
  75        int temp, vco = 0, bootmod_ccr, pdr;
  76
  77        bootmod_ccr = (in_be16(&ccm->ccr) & CCM_CCR_BOOTMOD) >> 14;
  78
  79        switch (bootmod_ccr) {
  80        case 0:
  81                out_be32(&pll->pcr, 0x00000013);
  82                out_be32(&pll->pdr, 0x00e70c61);
  83                clock_exit_limp();
  84                break;
  85        case 2:
  86                break;
  87        case 3:
  88                break;
  89        }
  90
  91        /*Change frequency for Modelo SER1 USB host*/
  92#ifdef CONFIG_LOW_MCFCLK
  93        temp = in_be32(&pll->pcr);
  94        temp &= ~0x3f;
  95        temp |= 5;
  96        out_be32(&pll->pcr, temp);
  97
  98        temp = in_be32(&pll->pdr);
  99        temp &= ~0x001f0000;
 100        temp |= 0x00040000;
 101        out_be32(&pll->pdr, temp);
 102        __asm__("tpf");
 103#endif
 104
 105        setbits_be16(&ccm->misccr2, 0x02);
 106
 107        vco =  ((in_be32(&pll->pcr) & PLL_CR_FBKDIV_BITS) + 1) *
 108                CONFIG_SYS_INPUT_CLKSRC;
 109        gd->arch.vco_clk = vco;
 110
 111        gd->arch.inp_clk = CONFIG_SYS_INPUT_CLKSRC;     /* Input clock */
 112
 113        pdr = in_be32(&pll->pdr);
 114        temp = (pdr & PLL_DR_OUTDIV1_BITS) + 1;
 115        gd->cpu_clk = vco / temp;       /* cpu clock */
 116        gd->arch.flb_clk = vco / temp;  /* FlexBus clock */
 117        gd->arch.flb_clk >>= 1;
 118        if (in_be16(&ccm->misccr2) & 2)         /* fsys/4 */
 119                gd->arch.flb_clk >>= 1;
 120
 121        temp = ((pdr & PLL_DR_OUTDIV2_BITS) >> 5) + 1;
 122        gd->bus_clk = vco / temp;       /* bus clock */
 123
 124}
 125#endif
 126
 127#ifdef CONFIG_MCF5445x
 128void setup_5445x_clocks(void)
 129{
 130        ccm_t *ccm = (ccm_t *)MMAP_CCM;
 131        pll_t *pll = (pll_t *)MMAP_PLL;
 132        int pllmult_nopci[] = { 20, 10, 24, 18, 12, 6, 16, 8 };
 133        int pllmult_pci[] = { 12, 6, 16, 8 };
 134        int vco = 0, temp, fbtemp, pcrvalue;
 135        int *pPllmult = NULL;
 136        u16 fbpll_mask;
 137#ifdef CONFIG_PCI
 138        int bPci;
 139#endif
 140
 141#ifdef CONFIG_M54455EVB
 142        u8 *cpld = (u8 *)(CONFIG_SYS_CS2_BASE + 3);
 143#endif
 144        u8 bootmode;
 145
 146        /* To determine PCI is present or not */
 147        if (((in_be16(&ccm->ccr) & CCM_CCR_360_FBCONFIG_MASK) == 0x00e0) ||
 148            ((in_be16(&ccm->ccr) & CCM_CCR_360_FBCONFIG_MASK) == 0x0060)) {
 149                pPllmult = &pllmult_pci[0];
 150                fbpll_mask = 3;         /* 11b */
 151#ifdef CONFIG_PCI
 152                bPci = 1;
 153#endif
 154        } else {
 155                pPllmult = &pllmult_nopci[0];
 156                fbpll_mask = 7;         /* 111b */
 157#ifdef CONFIG_PCI
 158                gd->pci_clk = 0;
 159                bPci = 0;
 160#endif
 161        }
 162
 163#ifdef CONFIG_M54455EVB
 164        bootmode = (in_8(cpld) & 0x03);
 165
 166        if (bootmode != 3) {
 167                /* Temporary read from CCR- fixed fb issue, must be the same clock
 168                   as pci or input clock, causing cpld/fpga read inconsistancy */
 169                fbtemp = pPllmult[ccm->ccr & fbpll_mask];
 170
 171                /* Break down into small pieces, code still in flex bus */
 172                pcrvalue = in_be32(&pll->pcr) & 0xFFFFF0FF;
 173                temp = fbtemp - 1;
 174                pcrvalue |= PLL_PCR_OUTDIV3(temp);
 175
 176                out_be32(&pll->pcr, pcrvalue);
 177        }
 178#endif
 179#ifdef CONFIG_M54451EVB
 180        /* No external logic to read the bootmode, hard coded from built */
 181#ifdef CONFIG_CF_SBF
 182        bootmode = 3;
 183#else
 184        bootmode = 2;
 185
 186        /* default value is 16 mul, set to 20 mul */
 187        pcrvalue = (in_be32(&pll->pcr) & 0x00FFFFFF) | 0x14000000;
 188        out_be32(&pll->pcr, pcrvalue);
 189        while ((in_be32(&pll->psr) & PLL_PSR_LOCK) != PLL_PSR_LOCK)
 190                ;
 191#endif
 192#endif
 193
 194        if (bootmode == 0) {
 195                /* RCON mode */
 196                vco = pPllmult[ccm->rcon & fbpll_mask] * CONFIG_SYS_INPUT_CLKSRC;
 197
 198                if ((vco < CLOCK_PLL_FVCO_MIN) || (vco > CLOCK_PLL_FVCO_MAX)) {
 199                        /* invaild range, re-set in PCR */
 200                        int temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV2_MASK) >> 4) + 1;
 201                        int i, j, bus;
 202
 203                        j = (in_be32(&pll->pcr) & 0xFF000000) >> 24;
 204                        for (i = j; i < 0xFF; i++) {
 205                                vco = i * CONFIG_SYS_INPUT_CLKSRC;
 206                                if (vco >= CLOCK_PLL_FVCO_MIN) {
 207                                        bus = vco / temp;
 208                                        if (bus <= CLOCK_PLL_FSYS_MIN - MHZ)
 209                                                continue;
 210                                        else
 211                                                break;
 212                                }
 213                        }
 214                        pcrvalue = in_be32(&pll->pcr) & 0x00FF00FF;
 215                        fbtemp = ((i - 1) << 8) | ((i - 1) << 12);
 216                        pcrvalue |= ((i << 24) | fbtemp);
 217
 218                        out_be32(&pll->pcr, pcrvalue);
 219                }
 220                gd->arch.vco_clk = vco; /* Vco clock */
 221        } else if (bootmode == 2) {
 222                /* Normal mode */
 223                vco =  ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC;
 224                if ((vco < CLOCK_PLL_FVCO_MIN) || (vco > CLOCK_PLL_FVCO_MAX)) {
 225                        /* Default value */
 226                        pcrvalue = (in_be32(&pll->pcr) & 0x00FFFFFF);
 227                        pcrvalue |= pPllmult[in_be16(&ccm->ccr) & fbpll_mask] << 24;
 228                        out_be32(&pll->pcr, pcrvalue);
 229                        vco = ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC;
 230                }
 231                gd->arch.vco_clk = vco; /* Vco clock */
 232        } else if (bootmode == 3) {
 233                /* serial mode */
 234                vco =  ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC;
 235                gd->arch.vco_clk = vco; /* Vco clock */
 236        }
 237
 238        if ((in_be16(&ccm->ccr) & CCM_MISCCR_LIMP) == CCM_MISCCR_LIMP) {
 239                /* Limp mode */
 240        } else {
 241                gd->arch.inp_clk = CONFIG_SYS_INPUT_CLKSRC; /* Input clock */
 242
 243                temp = (in_be32(&pll->pcr) & PLL_PCR_OUTDIV1_MASK) + 1;
 244                gd->cpu_clk = vco / temp;       /* cpu clock */
 245
 246                temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV2_MASK) >> 4) + 1;
 247                gd->bus_clk = vco / temp;       /* bus clock */
 248
 249                temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV3_MASK) >> 8) + 1;
 250                gd->arch.flb_clk = vco / temp;  /* FlexBus clock */
 251
 252#ifdef CONFIG_PCI
 253                if (bPci) {
 254                        temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV4_MASK) >> 12) + 1;
 255                        gd->pci_clk = vco / temp;       /* PCI clock */
 256                }
 257#endif
 258        }
 259
 260#ifdef CONFIG_SYS_I2C_FSL
 261        gd->arch.i2c1_clk = gd->bus_clk;
 262#endif
 263}
 264#endif
 265
 266/* get_clocks() fills in gd->cpu_clock and gd->bus_clk */
 267int get_clocks(void)
 268{
 269#ifdef CONFIG_MCF5441x
 270        setup_5441x_clocks();
 271#endif
 272#ifdef CONFIG_MCF5445x
 273        setup_5445x_clocks();
 274#endif
 275
 276#ifdef CONFIG_SYS_FSL_I2C
 277        gd->arch.i2c1_clk = gd->bus_clk;
 278#endif
 279
 280        return (0);
 281}
 282