blob: c4ba7ec669299363509f64ce51c4e6fa0caf85b7 [file] [log] [blame]
TsiChung Liewf6afe722007-06-18 13:50:13 -05001/*
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 */
58int 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 */
82int 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 */
113int 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 */
139int 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 */
215int 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}