]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/mcf532x/speed.c
rename CFG_ macros to CONFIG_SYS
[karo-tx-uboot.git] / cpu / mcf532x / speed.c
1 /*
2  *
3  * (C) Copyright 2000-2003
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  *
6  * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
7  * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
8  *
9  * See file CREDITS for list of people who contributed to this
10  * project.
11  *
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.
16  *
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.
21  *
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
26  */
27
28 #include <common.h>
29 #include <asm/processor.h>
30
31 #include <asm/immap.h>
32
33 DECLARE_GLOBAL_DATA_PTR;
34
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 */
43 /*
44  * Low Power Divider specifications
45  */
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) */
49
50 /*
51  * Get the value of the current system clock
52  *
53  * Parameters:
54  *  none
55  *
56  * Return Value:
57  *  The current output system frequency
58  */
59 int get_sys_clock(void)
60 {
61         volatile ccm_t *ccm = (volatile ccm_t *)(MMAP_CCM);
62         volatile pll_t *pll = (volatile pll_t *)(MMAP_PLL);
63         int divider;
64
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));
71         }
72 }
73
74 /*
75  * Initialize the Low Power Divider circuit
76  *
77  * Parameters:
78  *  div     Desired system frequency divider
79  *
80  * Return Value:
81  *  The resulting output system frequency
82  */
83 int clock_limp(int div)
84 {
85         volatile ccm_t *ccm = (volatile ccm_t *)(MMAP_CCM);
86         u32 temp;
87
88         /* Check bounds of divider */
89         if (div < MIN_LPD)
90                 div = MIN_LPD;
91         if (div > MAX_LPD)
92                 div = MAX_LPD;
93
94         /* Save of the current value of the SSIDIV so we don't overwrite the value */
95         temp = (ccm->cdr & CCM_CDR_SSIDIV(0xF));
96
97         /* Apply the divider to the system clock */
98         ccm->cdr = (CCM_CDR_LPDIV(div) | CCM_CDR_SSIDIV(temp));
99
100         ccm->misccr |= CCM_MISCCR_LIMP;
101
102         return (FREF / (3 * (1 << div)));
103 }
104
105 /*
106  * Exit low power LIMP mode
107  *
108  * Parameters:
109  *  div     Desired system frequency divider
110  *
111  * Return Value:
112  *  The resulting output system frequency
113  */
114 int clock_exit_limp(void)
115 {
116         volatile ccm_t *ccm = (volatile ccm_t *)(MMAP_CCM);
117         int fout;
118
119         /* Exit LIMP mode */
120         ccm->misccr &= (~CCM_MISCCR_LIMP);
121
122         /* Wait for PLL to lock */
123         while (!(ccm->misccr & CCM_MISCCR_PLL_LOCK)) ;
124
125         fout = get_sys_clock();
126
127         return fout;
128 }
129
130 /* Initialize the PLL
131  *
132  * Parameters:
133  *  fref    PLL reference clock frequency in KHz
134  *  fsys    Desired PLL output frequency in KHz
135  *  flags   Operating parameters
136  *
137  * Return Value:
138  *  The resulting output system frequency
139  */
140 int clock_pll(int fsys, int flags)
141 {
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;
146
147         fref = FREF;
148
149         if (fsys == 0) {
150                 /* Return current PLL output */
151                 mfd = pll->pfdr;
152
153                 return (fref * mfd / (BUSDIV * 4));
154         }
155
156         /* Check bounds of requested system clock */
157         if (fsys > MAX_FSYS)
158                 fsys = MAX_FSYS;
159
160         if (fsys < MIN_FSYS)
161                 fsys = MIN_FSYS;
162
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;
169
170         /* Determine the output frequency for selected values */
171         fout = ((fref * mfd) / (BUSDIV * 4));
172
173         /*
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.
177          */
178
179         /*
180          * Initialize the PLL to generate the new system clock frequency.
181          * The device must be put into LIMP mode to reprogram the PLL.
182          */
183
184         /* Enter LIMP mode */
185         clock_limp(DEFAULT_LPD);
186
187         /* Reprogram PLL for desired fsys */
188         pll->podr = (PLL_PODR_CPUDIV(BUSDIV / 3) | PLL_PODR_BUSDIV(BUSDIV));
189
190         pll->pfdr = mfd;
191
192         /* Exit LIMP mode */
193         clock_exit_limp();
194
195         /*
196          * Return the SDRAM to normal operation if it is in use.
197          */
198
199         /* software workaround for SDRAM opeartion after exiting LIMP mode errata */
200         *sdram_workaround = CONFIG_SYS_SDRAM_BASE;
201
202         /* wait for DQS logic to relock */
203         for (i = 0; i < 0x200; i++) ;
204
205         return fout;
206 }
207
208 /*
209  * get_clocks() fills in gd->cpu_clock and gd->bus_clk
210  */
211 int get_clocks(void)
212 {
213         gd->bus_clk = clock_pll(CONFIG_SYS_CLK / 1000, 0) * 1000;
214         gd->cpu_clk = (gd->bus_clk * 3);
215
216 #ifdef CONFIG_FSL_I2C
217         gd->i2c1_clk = gd->bus_clk;
218 #endif
219
220         return (0);
221 }