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
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,
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
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
);
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
));
70 return ((FREF
* pll
->pfdr
) / (BUSDIV
* 4));
75 * Initialize the Low Power Divider circuit
78 * div Desired system frequency divider
81 * The resulting output system frequency
83 int clock_limp(int div
)
85 volatile ccm_t
*ccm
= (volatile ccm_t
*)(MMAP_CCM
);
88 /* Check bounds of divider */
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
109 * div Desired system frequency divider
112 * The resulting output system frequency
114 int clock_exit_limp(void)
116 volatile ccm_t
*ccm
= (volatile ccm_t
*)(MMAP_CCM
);
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();
130 /* Initialize the PLL
133 * fref PLL reference clock frequency in KHz
134 * fsys Desired PLL output frequency in KHz
135 * flags Operating parameters
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
;
150 /* Return current PLL output */
153 return (fref
* mfd
/ (BUSDIV
* 4));
156 /* Check bounds of requested system clock */
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
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
));
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
++) ;
209 * get_clocks() fills in gd->cpu_clock and gd->bus_clk
213 gd
->bus_clk
= clock_pll(CFG_CLK
/ 1000, 0) * 1000;
214 gd
->cpu_clk
= (gd
->bus_clk
* 3);