1a4145534SPeter Tyser /* 2a4145534SPeter Tyser * 3*198cafbfSAlison Wang * Copyright (C) 2004-2007, 2012 Freescale Semiconductor, Inc. 4a4145534SPeter Tyser * TsiChung Liew (Tsi-Chung.Liew@freescale.com) 5a4145534SPeter Tyser * 6a4145534SPeter Tyser * See file CREDITS for list of people who contributed to this 7a4145534SPeter Tyser * project. 8a4145534SPeter Tyser * 9a4145534SPeter Tyser * This program is free software; you can redistribute it and/or 10a4145534SPeter Tyser * modify it under the terms of the GNU General Public License as 11a4145534SPeter Tyser * published by the Free Software Foundation; either version 2 of 12a4145534SPeter Tyser * the License, or (at your option) any later version. 13a4145534SPeter Tyser * 14a4145534SPeter Tyser * This program is distributed in the hope that it will be useful, 15a4145534SPeter Tyser * but WITHOUT ANY WARRANTY; without even the implied warranty of 16a4145534SPeter Tyser * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17a4145534SPeter Tyser * GNU General Public License for more details. 18a4145534SPeter Tyser * 19a4145534SPeter Tyser * You should have received a copy of the GNU General Public License 20a4145534SPeter Tyser * along with this program; if not, write to the Free Software 21a4145534SPeter Tyser * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22a4145534SPeter Tyser * MA 02111-1307 USA 23a4145534SPeter Tyser */ 24a4145534SPeter Tyser 25a4145534SPeter Tyser #include <common.h> 26a4145534SPeter Tyser #include <asm/processor.h> 27a4145534SPeter Tyser 28a4145534SPeter Tyser #include <asm/immap.h> 29*198cafbfSAlison Wang #include <asm/io.h> 30a4145534SPeter Tyser 31a4145534SPeter Tyser DECLARE_GLOBAL_DATA_PTR; 32a4145534SPeter Tyser 33a4145534SPeter Tyser /* 34a4145534SPeter Tyser * Low Power Divider specifications 35a4145534SPeter Tyser */ 36a4145534SPeter Tyser #define CLOCK_LPD_MIN (1 << 0) /* Divider (decoded) */ 37a4145534SPeter Tyser #define CLOCK_LPD_MAX (1 << 15) /* Divider (decoded) */ 38a4145534SPeter Tyser 39a4145534SPeter Tyser #define CLOCK_PLL_FVCO_MAX 540000000 40a4145534SPeter Tyser #define CLOCK_PLL_FVCO_MIN 300000000 41a4145534SPeter Tyser 42a4145534SPeter Tyser #define CLOCK_PLL_FSYS_MAX 266666666 43a4145534SPeter Tyser #define CLOCK_PLL_FSYS_MIN 100000000 44a4145534SPeter Tyser #define MHZ 1000000 45a4145534SPeter Tyser 46a4145534SPeter Tyser void clock_enter_limp(int lpdiv) 47a4145534SPeter Tyser { 48*198cafbfSAlison Wang ccm_t *ccm = (ccm_t *)MMAP_CCM; 49a4145534SPeter Tyser int i, j; 50a4145534SPeter Tyser 51a4145534SPeter Tyser /* Check bounds of divider */ 52a4145534SPeter Tyser if (lpdiv < CLOCK_LPD_MIN) 53a4145534SPeter Tyser lpdiv = CLOCK_LPD_MIN; 54a4145534SPeter Tyser if (lpdiv > CLOCK_LPD_MAX) 55a4145534SPeter Tyser lpdiv = CLOCK_LPD_MAX; 56a4145534SPeter Tyser 57a4145534SPeter Tyser /* Round divider down to nearest power of two */ 58a4145534SPeter Tyser for (i = 0, j = lpdiv; j != 1; j >>= 1, i++) ; 59a4145534SPeter Tyser 60a4145534SPeter Tyser /* Apply the divider to the system clock */ 61*198cafbfSAlison Wang clrsetbits_be16(&ccm->cdr, 0x0f00, CCM_CDR_LPDIV(i)); 62a4145534SPeter Tyser 63a4145534SPeter Tyser /* Enable Limp Mode */ 64*198cafbfSAlison Wang setbits_be16(&ccm->misccr, CCM_MISCCR_LIMP); 65a4145534SPeter Tyser } 66a4145534SPeter Tyser 67a4145534SPeter Tyser /* 68a4145534SPeter Tyser * brief Exit Limp mode 69a4145534SPeter Tyser * warning The PLL should be set and locked prior to exiting Limp mode 70a4145534SPeter Tyser */ 71a4145534SPeter Tyser void clock_exit_limp(void) 72a4145534SPeter Tyser { 73*198cafbfSAlison Wang ccm_t *ccm = (ccm_t *)MMAP_CCM; 74*198cafbfSAlison Wang pll_t *pll = (pll_t *)MMAP_PLL; 75a4145534SPeter Tyser 76a4145534SPeter Tyser /* Exit Limp mode */ 77*198cafbfSAlison Wang clrbits_be16(&ccm->misccr, CCM_MISCCR_LIMP); 78a4145534SPeter Tyser 79a4145534SPeter Tyser /* Wait for the PLL to lock */ 80*198cafbfSAlison Wang while (!(in_be32(&pll->psr) & PLL_PSR_LOCK)) 81*198cafbfSAlison Wang ; 82a4145534SPeter Tyser } 83a4145534SPeter Tyser 84a4145534SPeter Tyser /* 85a4145534SPeter Tyser * get_clocks() fills in gd->cpu_clock and gd->bus_clk 86a4145534SPeter Tyser */ 87a4145534SPeter Tyser int get_clocks(void) 88a4145534SPeter Tyser { 89a4145534SPeter Tyser 90*198cafbfSAlison Wang ccm_t *ccm = (ccm_t *)MMAP_CCM; 91*198cafbfSAlison Wang pll_t *pll = (pll_t *)MMAP_PLL; 92a4145534SPeter Tyser int pllmult_nopci[] = { 20, 10, 24, 18, 12, 6, 16, 8 }; 93a4145534SPeter Tyser int pllmult_pci[] = { 12, 6, 16, 8 }; 94a4145534SPeter Tyser int vco = 0, bPci, temp, fbtemp, pcrvalue; 95a4145534SPeter Tyser int *pPllmult = NULL; 96a4145534SPeter Tyser u16 fbpll_mask; 97a4145534SPeter Tyser 98a4145534SPeter Tyser #ifdef CONFIG_M54455EVB 99*198cafbfSAlison Wang u8 *cpld = (u8 *)(CONFIG_SYS_CS2_BASE + 3); 100a4145534SPeter Tyser #endif 101a4145534SPeter Tyser u8 bootmode; 102a4145534SPeter Tyser 103a4145534SPeter Tyser /* To determine PCI is present or not */ 104*198cafbfSAlison Wang if (((in_be16(&ccm->ccr) & CCM_CCR_360_FBCONFIG_MASK) == 0x00e0) || 105*198cafbfSAlison Wang ((in_be16(&ccm->ccr) & CCM_CCR_360_FBCONFIG_MASK) == 0x0060)) { 106a4145534SPeter Tyser pPllmult = &pllmult_pci[0]; 107a4145534SPeter Tyser fbpll_mask = 3; /* 11b */ 108a4145534SPeter Tyser bPci = 1; 109a4145534SPeter Tyser } else { 110a4145534SPeter Tyser pPllmult = &pllmult_nopci[0]; 111a4145534SPeter Tyser fbpll_mask = 7; /* 111b */ 112a4145534SPeter Tyser #ifdef CONFIG_PCI 113a4145534SPeter Tyser gd->pci_clk = 0; 114a4145534SPeter Tyser #endif 115a4145534SPeter Tyser bPci = 0; 116a4145534SPeter Tyser } 117a4145534SPeter Tyser 118a4145534SPeter Tyser #ifdef CONFIG_M54455EVB 119*198cafbfSAlison Wang bootmode = (in_8(cpld) & 0x03); 120a4145534SPeter Tyser 121a4145534SPeter Tyser if (bootmode != 3) { 122a4145534SPeter Tyser /* Temporary read from CCR- fixed fb issue, must be the same clock 123a4145534SPeter Tyser as pci or input clock, causing cpld/fpga read inconsistancy */ 124a4145534SPeter Tyser fbtemp = pPllmult[ccm->ccr & fbpll_mask]; 125a4145534SPeter Tyser 126a4145534SPeter Tyser /* Break down into small pieces, code still in flex bus */ 127*198cafbfSAlison Wang pcrvalue = in_be32(&pll->pcr) & 0xFFFFF0FF; 128a4145534SPeter Tyser temp = fbtemp - 1; 129a4145534SPeter Tyser pcrvalue |= PLL_PCR_OUTDIV3(temp); 130a4145534SPeter Tyser 131*198cafbfSAlison Wang out_be32(&pll->pcr, pcrvalue); 132a4145534SPeter Tyser } 133a4145534SPeter Tyser #endif 134a4145534SPeter Tyser #ifdef CONFIG_M54451EVB 135a4145534SPeter Tyser /* No external logic to read the bootmode, hard coded from built */ 136a4145534SPeter Tyser #ifdef CONFIG_CF_SBF 137a4145534SPeter Tyser bootmode = 3; 138a4145534SPeter Tyser #else 139a4145534SPeter Tyser bootmode = 2; 140a4145534SPeter Tyser 141a4145534SPeter Tyser /* default value is 16 mul, set to 20 mul */ 142*198cafbfSAlison Wang pcrvalue = (in_be32(&pll->pcr) & 0x00FFFFFF) | 0x14000000; 143*198cafbfSAlison Wang out_be32(&pll->pcr, pcrvalue); 144*198cafbfSAlison Wang while ((in_be32(&pll->psr) & PLL_PSR_LOCK) != PLL_PSR_LOCK) 145*198cafbfSAlison Wang ; 146a4145534SPeter Tyser #endif 147a4145534SPeter Tyser #endif 148a4145534SPeter Tyser 149a4145534SPeter Tyser if (bootmode == 0) { 150a4145534SPeter Tyser /* RCON mode */ 151a4145534SPeter Tyser vco = pPllmult[ccm->rcon & fbpll_mask] * CONFIG_SYS_INPUT_CLKSRC; 152a4145534SPeter Tyser 153a4145534SPeter Tyser if ((vco < CLOCK_PLL_FVCO_MIN) || (vco > CLOCK_PLL_FVCO_MAX)) { 154a4145534SPeter Tyser /* invaild range, re-set in PCR */ 155*198cafbfSAlison Wang int temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV2_MASK) >> 4) + 1; 156a4145534SPeter Tyser int i, j, bus; 157a4145534SPeter Tyser 158*198cafbfSAlison Wang j = (in_be32(&pll->pcr) & 0xFF000000) >> 24; 159a4145534SPeter Tyser for (i = j; i < 0xFF; i++) { 160a4145534SPeter Tyser vco = i * CONFIG_SYS_INPUT_CLKSRC; 161a4145534SPeter Tyser if (vco >= CLOCK_PLL_FVCO_MIN) { 162a4145534SPeter Tyser bus = vco / temp; 163a4145534SPeter Tyser if (bus <= CLOCK_PLL_FSYS_MIN - MHZ) 164a4145534SPeter Tyser continue; 165a4145534SPeter Tyser else 166a4145534SPeter Tyser break; 167a4145534SPeter Tyser } 168a4145534SPeter Tyser } 169*198cafbfSAlison Wang pcrvalue = in_be32(&pll->pcr) & 0x00FF00FF; 170a4145534SPeter Tyser fbtemp = ((i - 1) << 8) | ((i - 1) << 12); 171a4145534SPeter Tyser pcrvalue |= ((i << 24) | fbtemp); 172a4145534SPeter Tyser 173*198cafbfSAlison Wang out_be32(&pll->pcr, pcrvalue); 174a4145534SPeter Tyser } 175a4145534SPeter Tyser gd->vco_clk = vco; /* Vco clock */ 176a4145534SPeter Tyser } else if (bootmode == 2) { 177a4145534SPeter Tyser /* Normal mode */ 178*198cafbfSAlison Wang vco = ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC; 179a4145534SPeter Tyser if ((vco < CLOCK_PLL_FVCO_MIN) || (vco > CLOCK_PLL_FVCO_MAX)) { 180a4145534SPeter Tyser /* Default value */ 181*198cafbfSAlison Wang pcrvalue = (in_be32(&pll->pcr) & 0x00FFFFFF); 182*198cafbfSAlison Wang pcrvalue |= pPllmult[in_be16(&ccm->ccr) & fbpll_mask] << 24; 183*198cafbfSAlison Wang out_be32(&pll->pcr, pcrvalue); 184*198cafbfSAlison Wang vco = ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC; 185a4145534SPeter Tyser } 186a4145534SPeter Tyser gd->vco_clk = vco; /* Vco clock */ 187a4145534SPeter Tyser } else if (bootmode == 3) { 188a4145534SPeter Tyser /* serial mode */ 189*198cafbfSAlison Wang vco = ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC; 190a4145534SPeter Tyser gd->vco_clk = vco; /* Vco clock */ 191a4145534SPeter Tyser } 192a4145534SPeter Tyser 193*198cafbfSAlison Wang if ((in_be16(&ccm->ccr) & CCM_MISCCR_LIMP) == CCM_MISCCR_LIMP) { 194a4145534SPeter Tyser /* Limp mode */ 195a4145534SPeter Tyser } else { 196a4145534SPeter Tyser gd->inp_clk = CONFIG_SYS_INPUT_CLKSRC; /* Input clock */ 197a4145534SPeter Tyser 198*198cafbfSAlison Wang temp = (in_be32(&pll->pcr) & PLL_PCR_OUTDIV1_MASK) + 1; 199a4145534SPeter Tyser gd->cpu_clk = vco / temp; /* cpu clock */ 200a4145534SPeter Tyser 201*198cafbfSAlison Wang temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV2_MASK) >> 4) + 1; 202a4145534SPeter Tyser gd->bus_clk = vco / temp; /* bus clock */ 203a4145534SPeter Tyser 204*198cafbfSAlison Wang temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV3_MASK) >> 8) + 1; 205a4145534SPeter Tyser gd->flb_clk = vco / temp; /* FlexBus clock */ 206a4145534SPeter Tyser 207a4145534SPeter Tyser #ifdef CONFIG_PCI 208a4145534SPeter Tyser if (bPci) { 209*198cafbfSAlison Wang temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV4_MASK) >> 12) + 1; 210a4145534SPeter Tyser gd->pci_clk = vco / temp; /* PCI clock */ 211a4145534SPeter Tyser } 212a4145534SPeter Tyser #endif 213a4145534SPeter Tyser } 214a4145534SPeter Tyser 215a4145534SPeter Tyser #ifdef CONFIG_FSL_I2C 216a4145534SPeter Tyser gd->i2c1_clk = gd->bus_clk; 217a4145534SPeter Tyser #endif 218a4145534SPeter Tyser 219a4145534SPeter Tyser return (0); 220a4145534SPeter Tyser } 221