1 /* 2 * 3 * (C) Copyright 2000-2003 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 * 6 * Copyright (C) 2004-2008, 2012 Freescale Semiconductor, Inc. 7 * TsiChung Liew (Tsi-Chung.Liew@freescale.com) 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <asm/processor.h> 14 15 #include <asm/immap.h> 16 #include <asm/io.h> 17 18 DECLARE_GLOBAL_DATA_PTR; 19 20 /* PLL min/max specifications */ 21 #define MAX_FVCO 500000 /* KHz */ 22 #define MAX_FSYS 80000 /* KHz */ 23 #define MIN_FSYS 58333 /* KHz */ 24 25 #ifdef CONFIG_MCF5301x 26 #define FREF 20000 /* KHz */ 27 #define MAX_MFD 63 /* Multiplier */ 28 #define MIN_MFD 0 /* Multiplier */ 29 #define USBDIV 8 30 31 /* Low Power Divider specifications */ 32 #define MIN_LPD (0) /* Divider (not encoded) */ 33 #define MAX_LPD (15) /* Divider (not encoded) */ 34 #define DEFAULT_LPD (0) /* Divider (not encoded) */ 35 #endif 36 37 #ifdef CONFIG_MCF532x 38 #define FREF 16000 /* KHz */ 39 #define MAX_MFD 135 /* Multiplier */ 40 #define MIN_MFD 88 /* Multiplier */ 41 42 /* Low Power Divider specifications */ 43 #define MIN_LPD (1 << 0) /* Divider (not encoded) */ 44 #define MAX_LPD (1 << 15) /* Divider (not encoded) */ 45 #define DEFAULT_LPD (1 << 1) /* Divider (not encoded) */ 46 #endif 47 48 #define BUSDIV 6 /* Divider */ 49 50 /* Get the value of the current system clock */ 51 int get_sys_clock(void) 52 { 53 ccm_t *ccm = (ccm_t *)(MMAP_CCM); 54 pll_t *pll = (pll_t *)(MMAP_PLL); 55 int divider; 56 57 /* Test to see if device is in LIMP mode */ 58 if (in_be16(&ccm->misccr) & CCM_MISCCR_LIMP) { 59 divider = in_be16(&ccm->cdr) & CCM_CDR_LPDIV(0xF); 60 #ifdef CONFIG_MCF5301x 61 return (FREF / (3 * (1 << divider))); 62 #endif 63 #ifdef CONFIG_MCF532x 64 return (FREF / (2 << divider)); 65 #endif 66 } else { 67 #ifdef CONFIG_MCF5301x 68 u32 pfdr = (in_be32(&pll->pcr) & 0x3F) + 1; 69 u32 refdiv = (1 << ((in_be32(&pll->pcr) & PLL_PCR_REFDIV(7)) >> 8)); 70 u32 busdiv = ((in_be32(&pll->pdr) & 0x00F0) >> 4) + 1; 71 72 return (((FREF * pfdr) / refdiv) / busdiv); 73 #endif 74 #ifdef CONFIG_MCF532x 75 return (FREF * in_8(&pll->pfdr)) / (BUSDIV * 4); 76 #endif 77 } 78 } 79 80 /* 81 * Initialize the Low Power Divider circuit 82 * 83 * Parameters: 84 * div Desired system frequency divider 85 * 86 * Return Value: 87 * The resulting output system frequency 88 */ 89 int clock_limp(int div) 90 { 91 ccm_t *ccm = (ccm_t *)(MMAP_CCM); 92 u32 temp; 93 94 /* Check bounds of divider */ 95 if (div < MIN_LPD) 96 div = MIN_LPD; 97 if (div > MAX_LPD) 98 div = MAX_LPD; 99 100 /* Save of the current value of the SSIDIV so we don't overwrite the value */ 101 temp = (in_be16(&ccm->cdr) & CCM_CDR_SSIDIV(0xFF)); 102 103 /* Apply the divider to the system clock */ 104 out_be16(&ccm->cdr, CCM_CDR_LPDIV(div) | CCM_CDR_SSIDIV(temp)); 105 106 setbits_be16(&ccm->misccr, CCM_MISCCR_LIMP); 107 108 return (FREF / (3 * (1 << div))); 109 } 110 111 /* Exit low power LIMP mode */ 112 int clock_exit_limp(void) 113 { 114 ccm_t *ccm = (ccm_t *)(MMAP_CCM); 115 int fout; 116 117 /* Exit LIMP mode */ 118 clrbits_be16(&ccm->misccr, CCM_MISCCR_LIMP); 119 120 /* Wait for PLL to lock */ 121 while (!(in_be16(&ccm->misccr) & CCM_MISCCR_PLL_LOCK)) 122 ; 123 124 fout = get_sys_clock(); 125 126 return fout; 127 } 128 129 /* Initialize the PLL 130 * 131 * Parameters: 132 * fref PLL reference clock frequency in KHz 133 * fsys Desired PLL output frequency in KHz 134 * flags Operating parameters 135 * 136 * Return Value: 137 * The resulting output system frequency 138 */ 139 int clock_pll(int fsys, int flags) 140 { 141 #ifdef CONFIG_MCF532x 142 u32 *sdram_workaround = (u32 *)(MMAP_SDRAM + 0x80); 143 #endif 144 sdram_t *sdram = (sdram_t *)(MMAP_SDRAM); 145 pll_t *pll = (pll_t *)(MMAP_PLL); 146 int fref, temp, fout, mfd; 147 u32 i; 148 149 fref = FREF; 150 151 if (fsys == 0) { 152 /* Return current PLL output */ 153 #ifdef CONFIG_MCF5301x 154 u32 busdiv = ((in_be32(&pll->pdr) >> 4) & 0x0F) + 1; 155 mfd = (in_be32(&pll->pcr) & 0x3F) + 1; 156 157 return (fref * mfd) / busdiv; 158 #endif 159 #ifdef CONFIG_MCF532x 160 mfd = in_8(&pll->pfdr); 161 162 return (fref * mfd / (BUSDIV * 4)); 163 #endif 164 } 165 166 /* Check bounds of requested system clock */ 167 if (fsys > MAX_FSYS) 168 fsys = MAX_FSYS; 169 170 if (fsys < MIN_FSYS) 171 fsys = MIN_FSYS; 172 173 /* 174 * Multiplying by 100 when calculating the temp value, 175 * and then dividing by 100 to calculate the mfd allows 176 * for exact values without needing to include floating 177 * point libraries. 178 */ 179 temp = (100 * fsys) / fref; 180 #ifdef CONFIG_MCF5301x 181 mfd = (BUSDIV * temp) / 100; 182 183 /* Determine the output frequency for selected values */ 184 fout = ((fref * mfd) / BUSDIV); 185 #endif 186 #ifdef CONFIG_MCF532x 187 mfd = (4 * BUSDIV * temp) / 100; 188 189 /* Determine the output frequency for selected values */ 190 fout = ((fref * mfd) / (BUSDIV * 4)); 191 #endif 192 193 /* must not tamper with SDRAMC if running from SDRAM */ 194 #if !defined(CONFIG_MONITOR_IS_IN_RAM) 195 /* 196 * Check to see if the SDRAM has already been initialized. 197 * If it has then the SDRAM needs to be put into self refresh 198 * mode before reprogramming the PLL. 199 */ 200 if (in_be32(&sdram->ctrl) & SDRAMC_SDCR_REF) 201 clrbits_be32(&sdram->ctrl, SDRAMC_SDCR_CKE); 202 203 /* 204 * Initialize the PLL to generate the new system clock frequency. 205 * The device must be put into LIMP mode to reprogram the PLL. 206 */ 207 208 /* Enter LIMP mode */ 209 clock_limp(DEFAULT_LPD); 210 211 #ifdef CONFIG_MCF5301x 212 out_be32(&pll->pdr, 213 PLL_PDR_OUTDIV1((BUSDIV / 3) - 1) | 214 PLL_PDR_OUTDIV2(BUSDIV - 1) | 215 PLL_PDR_OUTDIV3((BUSDIV / 2) - 1) | 216 PLL_PDR_OUTDIV4(USBDIV - 1)); 217 218 clrbits_be32(&pll->pcr, ~PLL_PCR_FBDIV_UNMASK); 219 setbits_be32(&pll->pcr, PLL_PCR_FBDIV(mfd - 1)); 220 #endif 221 #ifdef CONFIG_MCF532x 222 /* Reprogram PLL for desired fsys */ 223 out_8(&pll->podr, 224 PLL_PODR_CPUDIV(BUSDIV / 3) | PLL_PODR_BUSDIV(BUSDIV)); 225 226 out_8(&pll->pfdr, mfd); 227 #endif 228 229 /* Exit LIMP mode */ 230 clock_exit_limp(); 231 232 /* Return the SDRAM to normal operation if it is in use. */ 233 if (in_be32(&sdram->ctrl) & SDRAMC_SDCR_REF) 234 setbits_be32(&sdram->ctrl, SDRAMC_SDCR_CKE); 235 236 #ifdef CONFIG_MCF532x 237 /* 238 * software workaround for SDRAM opeartion after exiting LIMP 239 * mode errata 240 */ 241 out_be32(sdram_workaround, CONFIG_SYS_SDRAM_BASE); 242 #endif 243 244 /* wait for DQS logic to relock */ 245 for (i = 0; i < 0x200; i++) ; 246 #endif /* !defined(CONFIG_MONITOR_IS_IN_RAM) */ 247 248 return fout; 249 } 250 251 /* get_clocks() fills in gd->cpu_clock and gd->bus_clk */ 252 int get_clocks(void) 253 { 254 gd->bus_clk = clock_pll(CONFIG_SYS_CLK / 1000, 0) * 1000; 255 gd->cpu_clk = (gd->bus_clk * 3); 256 257 #ifdef CONFIG_SYS_I2C_FSL 258 gd->arch.i2c1_clk = gd->bus_clk; 259 #endif 260 261 return (0); 262 } 263