add SDHC support in mmc driver
[u-boot-openmoko/mini2440.git] / cpu / mcf532x / speed.c
blob001b9f42d64f3bf2e6f8fd03e30d0e914b1ca8f6
1 /*
3 * (C) Copyright 2000-2003
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6 * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
7 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
9 * See file CREDITS for list of people who contributed to this
10 * project.
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
28 #include <common.h>
29 #include <asm/processor.h>
31 #include <asm/immap.h>
33 DECLARE_GLOBAL_DATA_PTR;
35 /* PLL min/max specifications */
36 #define MAX_FVCO 500000 /* KHz */
37 #define MAX_FSYS 80000 /* KHz */
38 #define MIN_FSYS 58333 /* KHz */
39 #define FREF 16000 /* KHz */
40 #define MAX_MFD 135 /* Multiplier */
41 #define MIN_MFD 88 /* Multiplier */
42 #define BUSDIV 6 /* Divider */
44 * Low Power Divider specifications
46 #define MIN_LPD (1 << 0) /* Divider (not encoded) */
47 #define MAX_LPD (1 << 15) /* Divider (not encoded) */
48 #define DEFAULT_LPD (1 << 1) /* Divider (not encoded) */
51 * Get the value of the current system clock
53 * Parameters:
54 * none
56 * Return Value:
57 * The current output system frequency
59 int get_sys_clock(void)
61 volatile ccm_t *ccm = (volatile ccm_t *)(MMAP_CCM);
62 volatile pll_t *pll = (volatile pll_t *)(MMAP_PLL);
63 int divider;
65 /* Test to see if device is in LIMP mode */
66 if (ccm->misccr & CCM_MISCCR_LIMP) {
67 divider = ccm->cdr & CCM_CDR_LPDIV(0xF);
68 return (FREF / (2 << divider));
69 } else {
70 return ((FREF * pll->pfdr) / (BUSDIV * 4));
75 * Initialize the Low Power Divider circuit
77 * Parameters:
78 * div Desired system frequency divider
80 * Return Value:
81 * The resulting output system frequency
83 int clock_limp(int div)
85 volatile ccm_t *ccm = (volatile ccm_t *)(MMAP_CCM);
86 u32 temp;
88 /* Check bounds of divider */
89 if (div < MIN_LPD)
90 div = MIN_LPD;
91 if (div > MAX_LPD)
92 div = MAX_LPD;
94 /* Save of the current value of the SSIDIV so we don't overwrite the value */
95 temp = (ccm->cdr & CCM_CDR_SSIDIV(0xF));
97 /* Apply the divider to the system clock */
98 ccm->cdr = (CCM_CDR_LPDIV(div) | CCM_CDR_SSIDIV(temp));
100 ccm->misccr |= CCM_MISCCR_LIMP;
102 return (FREF / (3 * (1 << div)));
106 * Exit low power LIMP mode
108 * Parameters:
109 * div Desired system frequency divider
111 * Return Value:
112 * The resulting output system frequency
114 int clock_exit_limp(void)
116 volatile ccm_t *ccm = (volatile ccm_t *)(MMAP_CCM);
117 int fout;
119 /* Exit LIMP mode */
120 ccm->misccr &= (~CCM_MISCCR_LIMP);
122 /* Wait for PLL to lock */
123 while (!(ccm->misccr & CCM_MISCCR_PLL_LOCK)) ;
125 fout = get_sys_clock();
127 return fout;
130 /* Initialize the PLL
132 * Parameters:
133 * fref PLL reference clock frequency in KHz
134 * fsys Desired PLL output frequency in KHz
135 * flags Operating parameters
137 * Return Value:
138 * The resulting output system frequency
140 int clock_pll(int fsys, int flags)
142 volatile u32 *sdram_workaround = (volatile u32 *)(MMAP_SDRAM + 0x80);
143 volatile pll_t *pll = (volatile pll_t *)(MMAP_PLL);
144 int fref, temp, fout, mfd;
145 u32 i;
147 fref = FREF;
149 if (fsys == 0) {
150 /* Return current PLL output */
151 mfd = pll->pfdr;
153 return (fref * mfd / (BUSDIV * 4));
156 /* Check bounds of requested system clock */
157 if (fsys > MAX_FSYS)
158 fsys = MAX_FSYS;
160 if (fsys < MIN_FSYS)
161 fsys = MIN_FSYS;
163 /* Multiplying by 100 when calculating the temp value,
164 and then dividing by 100 to calculate the mfd allows
165 for exact values without needing to include floating
166 point libraries. */
167 temp = (100 * fsys) / fref;
168 mfd = (4 * BUSDIV * temp) / 100;
170 /* Determine the output frequency for selected values */
171 fout = ((fref * mfd) / (BUSDIV * 4));
174 * Check to see if the SDRAM has already been initialized.
175 * If it has then the SDRAM needs to be put into self refresh
176 * mode before reprogramming the PLL.
180 * Initialize the PLL to generate the new system clock frequency.
181 * The device must be put into LIMP mode to reprogram the PLL.
184 /* Enter LIMP mode */
185 clock_limp(DEFAULT_LPD);
187 /* Reprogram PLL for desired fsys */
188 pll->podr = (PLL_PODR_CPUDIV(BUSDIV / 3) | PLL_PODR_BUSDIV(BUSDIV));
190 pll->pfdr = mfd;
192 /* Exit LIMP mode */
193 clock_exit_limp();
196 * Return the SDRAM to normal operation if it is in use.
199 /* software workaround for SDRAM opeartion after exiting LIMP mode errata */
200 *sdram_workaround = CFG_SDRAM_BASE;
202 /* wait for DQS logic to relock */
203 for (i = 0; i < 0x200; i++) ;
205 return fout;
209 * get_clocks() fills in gd->cpu_clock and gd->bus_clk
211 int get_clocks(void)
213 gd->bus_clk = clock_pll(CFG_CLK / 1000, 0) * 1000;
214 gd->cpu_clk = (gd->bus_clk * 3);
215 return (0);