]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/mcf532x/speed.c
Added M5329AFEE and M5329BFEE Platforms
[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/m5329.h>
32 #include <asm/immap_5329.h>
33
34 /* PLL min/max specifications */
35 #define MAX_FVCO            500000      /* KHz */
36 #define MAX_FSYS            80000       /* KHz */
37 #define MIN_FSYS            58333       /* KHz */
38 #define FREF                    16000   /* KHz */
39 #define MAX_MFD             135 /* Multiplier */
40 #define MIN_MFD             88  /* Multiplier */
41 #define BUSDIV                  6       /* Divider */
42 /*
43  * Low Power Divider specifications
44  */
45 #define MIN_LPD     (1 << 0)    /* Divider (not encoded) */
46 #define MAX_LPD     (1 << 15)   /* Divider (not encoded) */
47 #define DEFAULT_LPD (1 << 1)    /* Divider (not encoded) */
48
49 /*
50  * Get the value of the current system clock
51  *
52  * Parameters:
53  *  none
54  *
55  * Return Value:
56  *  The current output system frequency
57  */
58 int get_sys_clock(void)
59 {
60         volatile ccm_t *ccm = (volatile ccm_t *)(MMAP_CCM);
61         volatile pll_t *pll = (volatile pll_t *)(MMAP_PLL);
62         int divider;
63
64         /* Test to see if device is in LIMP mode */
65         if (ccm->misccr & CCM_MISCCR_LIMP) {
66                 divider = ccm->cdr & CCM_CDR_LPDIV(0xF);
67                 return (FREF / (2 << divider));
68         } else {
69                 return ((FREF * pll->pfdr) / (BUSDIV * 4));
70         }
71 }
72
73 /*
74  * Initialize the Low Power Divider circuit
75  *
76  * Parameters:
77  *  div     Desired system frequency divider
78  *
79  * Return Value:
80  *  The resulting output system frequency
81  */
82 int clock_limp(int div)
83 {
84         volatile ccm_t *ccm = (volatile ccm_t *)(MMAP_CCM);
85         u32 temp;
86
87         /* Check bounds of divider */
88         if (div < MIN_LPD)
89                 div = MIN_LPD;
90         if (div > MAX_LPD)
91                 div = MAX_LPD;
92
93         /* Save of the current value of the SSIDIV so we don't overwrite the value */
94         temp = (ccm->cdr & CCM_CDR_SSIDIV(0xF));
95
96         /* Apply the divider to the system clock */
97         ccm->cdr = (CCM_CDR_LPDIV(div) | CCM_CDR_SSIDIV(temp));
98
99         ccm->misccr |= CCM_MISCCR_LIMP;
100
101         return (FREF / (3 * (1 << div)));
102 }
103
104 /*
105  * Exit low power LIMP mode
106  *
107  * Parameters:
108  *  div     Desired system frequency divider
109  *
110  * Return Value:
111  *  The resulting output system frequency
112  */
113 int clock_exit_limp(void)
114 {
115         volatile ccm_t *ccm = (volatile ccm_t *)(MMAP_CCM);
116         int fout;
117
118         /* Exit LIMP mode */
119         ccm->misccr &= (~CCM_MISCCR_LIMP);
120
121         /* Wait for PLL to lock */
122         while (!(ccm->misccr & CCM_MISCCR_PLL_LOCK)) ;
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         volatile u32 *sdram_workaround = (volatile u32 *)(MMAP_SDRAM + 0x80);
142         volatile pll_t *pll = (volatile pll_t *)(MMAP_PLL);
143         int fref, temp, fout, mfd;
144         u32 i;
145
146         fref = FREF;
147
148         if (fsys == 0) {
149                 /* Return current PLL output */
150                 mfd = pll->pfdr;
151
152                 return (fref * mfd / (BUSDIV * 4));
153         }
154
155         /* Check bounds of requested system clock */
156         if (fsys > MAX_FSYS)
157                 fsys = MAX_FSYS;
158
159         if (fsys < MIN_FSYS)
160                 fsys = MIN_FSYS;
161
162         /* Multiplying by 100 when calculating the temp value,
163            and then dividing by 100 to calculate the mfd allows
164            for exact values without needing to include floating
165            point libraries. */
166         temp = (100 * fsys) / fref;
167         mfd = (4 * BUSDIV * temp) / 100;
168
169         /* Determine the output frequency for selected values */
170         fout = ((fref * mfd) / (BUSDIV * 4));
171
172         /*
173          * Check to see if the SDRAM has already been initialized.
174          * If it has then the SDRAM needs to be put into self refresh
175          * mode before reprogramming the PLL.
176          */
177         /* Put SDRAM into self refresh mode */
178 /*      if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
179                 MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_CKE;*/
180
181         /*
182          * Initialize the PLL to generate the new system clock frequency.
183          * The device must be put into LIMP mode to reprogram the PLL.
184          */
185
186         /* Enter LIMP mode */
187         clock_limp(DEFAULT_LPD);
188
189         /* Reprogram PLL for desired fsys */
190         pll->podr = (PLL_PODR_CPUDIV(BUSDIV / 3) | PLL_PODR_BUSDIV(BUSDIV));
191
192         pll->pfdr = mfd;
193
194         /* Exit LIMP mode */
195         clock_exit_limp();
196
197         /*
198          * Return the SDRAM to normal operation if it is in use.
199          */
200         /* Exit self refresh mode */
201 /*      if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
202         MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_CKE;*/
203
204         /* software workaround for SDRAM opeartion after exiting LIMP mode errata */
205         *sdram_workaround = CFG_SDRAM_BASE;
206         /* wait for DQS logic to relock */
207         for (i = 0; i < 0x200; i++) ;
208
209         return fout;
210 }
211
212 /*
213  * get_clocks() fills in gd->cpu_clock and gd->bus_clk
214  */
215 int get_clocks(void)
216 {
217         DECLARE_GLOBAL_DATA_PTR;
218
219         gd->bus_clk = clock_pll(CFG_CLK / 1000, 0) * 1000;
220         gd->cpu_clk = (gd->bus_clk * 3);
221         return (0);
222 }