blob: b94a9eda48266e30e6d4bab3bcb9a81bd589ac27 [file] [log] [blame]
TsiChungLiewc8758102008-01-14 17:46:19 -06001/*
2 *
Alison Wang849fc422012-03-26 21:49:03 +00003 * Copyright (C) 2004-2007, 2012 Freescale Semiconductor, Inc.
TsiChungLiewc8758102008-01-14 17:46:19 -06004 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
5 *
6 * See file CREDITS for list of people who contributed to this
7 * project.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 */
24
25#include <common.h>
26#include <asm/processor.h>
27
28#include <asm/immap.h>
Alison Wang849fc422012-03-26 21:49:03 +000029#include <asm/io.h>
TsiChungLiewc8758102008-01-14 17:46:19 -060030
31DECLARE_GLOBAL_DATA_PTR;
32
33/*
34 * Low Power Divider specifications
35 */
36#define CLOCK_LPD_MIN (1 << 0) /* Divider (decoded) */
37#define CLOCK_LPD_MAX (1 << 15) /* Divider (decoded) */
38
39#define CLOCK_PLL_FVCO_MAX 540000000
40#define CLOCK_PLL_FVCO_MIN 300000000
41
42#define CLOCK_PLL_FSYS_MAX 266666666
43#define CLOCK_PLL_FSYS_MIN 100000000
44#define MHZ 1000000
45
46void clock_enter_limp(int lpdiv)
47{
Alison Wang849fc422012-03-26 21:49:03 +000048 ccm_t *ccm = (ccm_t *)MMAP_CCM;
TsiChungLiewc8758102008-01-14 17:46:19 -060049 int i, j;
50
51 /* Check bounds of divider */
52 if (lpdiv < CLOCK_LPD_MIN)
53 lpdiv = CLOCK_LPD_MIN;
54 if (lpdiv > CLOCK_LPD_MAX)
55 lpdiv = CLOCK_LPD_MAX;
56
57 /* Round divider down to nearest power of two */
58 for (i = 0, j = lpdiv; j != 1; j >>= 1, i++) ;
59
60 /* Apply the divider to the system clock */
Alison Wang849fc422012-03-26 21:49:03 +000061 clrsetbits_be16(&ccm->cdr, 0x0f00, CCM_CDR_LPDIV(i));
TsiChungLiewc8758102008-01-14 17:46:19 -060062
63 /* Enable Limp Mode */
Alison Wang849fc422012-03-26 21:49:03 +000064 setbits_be16(&ccm->misccr, CCM_MISCCR_LIMP);
TsiChungLiewc8758102008-01-14 17:46:19 -060065}
66
67/*
68 * brief Exit Limp mode
69 * warning The PLL should be set and locked prior to exiting Limp mode
70 */
71void clock_exit_limp(void)
72{
Alison Wang849fc422012-03-26 21:49:03 +000073 ccm_t *ccm = (ccm_t *)MMAP_CCM;
74 pll_t *pll = (pll_t *)MMAP_PLL;
TsiChungLiewc8758102008-01-14 17:46:19 -060075
76 /* Exit Limp mode */
Alison Wang849fc422012-03-26 21:49:03 +000077 clrbits_be16(&ccm->misccr, CCM_MISCCR_LIMP);
TsiChungLiewc8758102008-01-14 17:46:19 -060078
79 /* Wait for the PLL to lock */
Alison Wang849fc422012-03-26 21:49:03 +000080 while (!(in_be32(&pll->psr) & PLL_PSR_LOCK))
81 ;
TsiChungLiewc8758102008-01-14 17:46:19 -060082}
83
84/*
85 * get_clocks() fills in gd->cpu_clock and gd->bus_clk
86 */
87int get_clocks(void)
88{
89
Alison Wang849fc422012-03-26 21:49:03 +000090 ccm_t *ccm = (ccm_t *)MMAP_CCM;
91 pll_t *pll = (pll_t *)MMAP_PLL;
TsiChungLiewc8758102008-01-14 17:46:19 -060092 int vco, temp, pcrvalue, pfdr;
93 u8 bootmode;
94
Alison Wang849fc422012-03-26 21:49:03 +000095 pcrvalue = in_be32(&pll->pcr) & 0xFF0F0FFF;
TsiChungLiewc8758102008-01-14 17:46:19 -060096 pfdr = pcrvalue >> 24;
97
TsiChung Liewa21d0c22008-10-21 15:37:02 +000098 if (pfdr == 0x1E)
99 bootmode = 0; /* Normal Mode */
100
101#ifdef CONFIG_CF_SBF
102 bootmode = 3; /* Serial Mode */
103#endif
104
105 if (bootmode == 0) {
106 /* Normal mode */
Alison Wang849fc422012-03-26 21:49:03 +0000107 vco = ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC;
TsiChung Liewa21d0c22008-10-21 15:37:02 +0000108 if ((vco < CLOCK_PLL_FVCO_MIN) || (vco > CLOCK_PLL_FVCO_MAX)) {
109 /* Default value */
Alison Wang849fc422012-03-26 21:49:03 +0000110 pcrvalue = (in_be32(&pll->pcr) & 0x00FFFFFF);
TsiChung Liewa21d0c22008-10-21 15:37:02 +0000111 pcrvalue |= 0x1E << 24;
Alison Wang849fc422012-03-26 21:49:03 +0000112 out_be32(&pll->pcr, pcrvalue);
TsiChung Liewa21d0c22008-10-21 15:37:02 +0000113 vco =
Alison Wang849fc422012-03-26 21:49:03 +0000114 ((in_be32(&pll->pcr) & 0xFF000000) >> 24) *
TsiChung Liewa21d0c22008-10-21 15:37:02 +0000115 CONFIG_SYS_INPUT_CLKSRC;
116 }
117 gd->vco_clk = vco; /* Vco clock */
118 } else if (bootmode == 3) {
TsiChungLiewc8758102008-01-14 17:46:19 -0600119 /* serial mode */
Alison Wang849fc422012-03-26 21:49:03 +0000120 vco = ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC;
TsiChung Liewa21d0c22008-10-21 15:37:02 +0000121 gd->vco_clk = vco; /* Vco clock */
TsiChungLiewc8758102008-01-14 17:46:19 -0600122 }
123
Alison Wang849fc422012-03-26 21:49:03 +0000124 if ((in_be16(&ccm->ccr) & CCM_MISCCR_LIMP) == CCM_MISCCR_LIMP) {
TsiChungLiewc8758102008-01-14 17:46:19 -0600125 /* Limp mode */
126 } else {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200127 gd->inp_clk = CONFIG_SYS_INPUT_CLKSRC; /* Input clock */
TsiChungLiewc8758102008-01-14 17:46:19 -0600128
Alison Wang849fc422012-03-26 21:49:03 +0000129 temp = (in_be32(&pll->pcr) & PLL_PCR_OUTDIV1_MASK) + 1;
TsiChungLiewc8758102008-01-14 17:46:19 -0600130 gd->cpu_clk = vco / temp; /* cpu clock */
131
Alison Wang849fc422012-03-26 21:49:03 +0000132 temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV2_MASK) >> 4) + 1;
TsiChungLiewc8758102008-01-14 17:46:19 -0600133 gd->flb_clk = vco / temp; /* flexbus clock */
134 gd->bus_clk = gd->flb_clk;
135 }
136
TsiChung Lieweec567a2008-08-19 03:01:19 +0600137#ifdef CONFIG_FSL_I2C
138 gd->i2c1_clk = gd->bus_clk;
139#endif
140
TsiChungLiewc8758102008-01-14 17:46:19 -0600141 return (0);
142}