blob: 594716b6cae768378dd591bfd7751585e09a79a8 [file] [log] [blame]
TsiChungLiew8ae158c2007-08-16 15:05:11 -05001/*
2 *
Alison Wang198cafb2012-03-26 21:49:08 +00003 * Copyright (C) 2004-2007, 2012 Freescale Semiconductor, Inc.
TsiChungLiew8ae158c2007-08-16 15:05:11 -05004 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
5 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
TsiChungLiew8ae158c2007-08-16 15:05:11 -05007 */
8
9#include <common.h>
10#include <asm/processor.h>
11
12#include <asm/immap.h>
Alison Wang198cafb2012-03-26 21:49:08 +000013#include <asm/io.h>
TsiChungLiew8ae158c2007-08-16 15:05:11 -050014
15DECLARE_GLOBAL_DATA_PTR;
16
17/*
18 * Low Power Divider specifications
19 */
20#define CLOCK_LPD_MIN (1 << 0) /* Divider (decoded) */
21#define CLOCK_LPD_MAX (1 << 15) /* Divider (decoded) */
22
23#define CLOCK_PLL_FVCO_MAX 540000000
24#define CLOCK_PLL_FVCO_MIN 300000000
25
26#define CLOCK_PLL_FSYS_MAX 266666666
27#define CLOCK_PLL_FSYS_MIN 100000000
28#define MHZ 1000000
29
30void clock_enter_limp(int lpdiv)
31{
Alison Wang198cafb2012-03-26 21:49:08 +000032 ccm_t *ccm = (ccm_t *)MMAP_CCM;
TsiChungLiew8ae158c2007-08-16 15:05:11 -050033 int i, j;
34
35 /* Check bounds of divider */
36 if (lpdiv < CLOCK_LPD_MIN)
37 lpdiv = CLOCK_LPD_MIN;
38 if (lpdiv > CLOCK_LPD_MAX)
39 lpdiv = CLOCK_LPD_MAX;
40
41 /* Round divider down to nearest power of two */
42 for (i = 0, j = lpdiv; j != 1; j >>= 1, i++) ;
43
Alison Wang45370e12012-10-18 19:25:51 +000044#ifdef CONFIG_MCF5445x
TsiChungLiew8ae158c2007-08-16 15:05:11 -050045 /* Apply the divider to the system clock */
Alison Wang198cafb2012-03-26 21:49:08 +000046 clrsetbits_be16(&ccm->cdr, 0x0f00, CCM_CDR_LPDIV(i));
Alison Wang45370e12012-10-18 19:25:51 +000047#endif
TsiChungLiew8ae158c2007-08-16 15:05:11 -050048
49 /* Enable Limp Mode */
Alison Wang198cafb2012-03-26 21:49:08 +000050 setbits_be16(&ccm->misccr, CCM_MISCCR_LIMP);
TsiChungLiew8ae158c2007-08-16 15:05:11 -050051}
52
53/*
54 * brief Exit Limp mode
55 * warning The PLL should be set and locked prior to exiting Limp mode
56 */
57void clock_exit_limp(void)
58{
Alison Wang198cafb2012-03-26 21:49:08 +000059 ccm_t *ccm = (ccm_t *)MMAP_CCM;
60 pll_t *pll = (pll_t *)MMAP_PLL;
TsiChungLiew8ae158c2007-08-16 15:05:11 -050061
62 /* Exit Limp mode */
Alison Wang198cafb2012-03-26 21:49:08 +000063 clrbits_be16(&ccm->misccr, CCM_MISCCR_LIMP);
TsiChungLiew8ae158c2007-08-16 15:05:11 -050064
65 /* Wait for the PLL to lock */
Alison Wang198cafb2012-03-26 21:49:08 +000066 while (!(in_be32(&pll->psr) & PLL_PSR_LOCK))
67 ;
TsiChungLiew8ae158c2007-08-16 15:05:11 -050068}
69
Alison Wang45370e12012-10-18 19:25:51 +000070#ifdef CONFIG_MCF5441x
71void setup_5441x_clocks(void)
TsiChungLiew8ae158c2007-08-16 15:05:11 -050072{
Alison Wang45370e12012-10-18 19:25:51 +000073 ccm_t *ccm = (ccm_t *)MMAP_CCM;
74 pll_t *pll = (pll_t *)MMAP_PLL;
75 int temp, vco = 0, bootmod_ccr, pdr;
TsiChung Liew9f751552008-07-23 20:38:53 -050076
Alison Wang45370e12012-10-18 19:25:51 +000077 bootmod_ccr = (in_be16(&ccm->ccr) & CCM_CCR_BOOTMOD) >> 14;
78
79 switch (bootmod_ccr) {
80 case 0:
81 out_be32(&pll->pcr, 0x00000013);
82 out_be32(&pll->pdr, 0x00e70c61);
83 clock_exit_limp();
84 break;
85 case 2:
86 break;
87 case 3:
88 break;
89 }
90
91 /*Change frequency for Modelo SER1 USB host*/
92#ifdef CONFIG_LOW_MCFCLK
93 temp = in_be32(&pll->pcr);
94 temp &= ~0x3f;
95 temp |= 5;
96 out_be32(&pll->pcr, temp);
97
98 temp = in_be32(&pll->pdr);
99 temp &= ~0x001f0000;
100 temp |= 0x00040000;
101 out_be32(&pll->pdr, temp);
102 __asm__("tpf");
103#endif
104
105 setbits_be16(&ccm->misccr2, 0x02);
106
107 vco = ((in_be32(&pll->pcr) & PLL_CR_FBKDIV_BITS) + 1) *
108 CONFIG_SYS_INPUT_CLKSRC;
Jason Jin1b9591c2013-06-26 10:21:31 +0800109 gd->arch.vco_clk = vco;
Alison Wang45370e12012-10-18 19:25:51 +0000110
Jason Jin1b9591c2013-06-26 10:21:31 +0800111 gd->arch.inp_clk = CONFIG_SYS_INPUT_CLKSRC; /* Input clock */
Alison Wang45370e12012-10-18 19:25:51 +0000112
113 pdr = in_be32(&pll->pdr);
114 temp = (pdr & PLL_DR_OUTDIV1_BITS) + 1;
115 gd->cpu_clk = vco / temp; /* cpu clock */
Jason Jin1b9591c2013-06-26 10:21:31 +0800116 gd->arch.flb_clk = vco / temp; /* FlexBus clock */
117 gd->arch.flb_clk >>= 1;
Alison Wang45370e12012-10-18 19:25:51 +0000118 if (in_be16(ccm->misccr2) & 2) /* fsys/4 */
Jason Jin1b9591c2013-06-26 10:21:31 +0800119 gd->arch.flb_clk >>= 1;
Alison Wang45370e12012-10-18 19:25:51 +0000120
121 temp = ((pdr & PLL_DR_OUTDIV2_BITS) >> 5) + 1;
122 gd->bus_clk = vco / temp; /* bus clock */
123
124}
125#endif
126
127#ifdef CONFIG_MCF5445x
128void setup_5445x_clocks(void)
129{
Alison Wang198cafb2012-03-26 21:49:08 +0000130 ccm_t *ccm = (ccm_t *)MMAP_CCM;
131 pll_t *pll = (pll_t *)MMAP_PLL;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500132 int pllmult_nopci[] = { 20, 10, 24, 18, 12, 6, 16, 8 };
133 int pllmult_pci[] = { 12, 6, 16, 8 };
Marek Vasutc1568ca52012-10-03 13:28:45 +0000134 int vco = 0, temp, fbtemp, pcrvalue;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500135 int *pPllmult = NULL;
136 u16 fbpll_mask;
Marek Vasutc1568ca52012-10-03 13:28:45 +0000137#ifdef CONFIG_PCI
138 int bPci;
139#endif
TsiChung Liew9f751552008-07-23 20:38:53 -0500140
141#ifdef CONFIG_M54455EVB
Alison Wang198cafb2012-03-26 21:49:08 +0000142 u8 *cpld = (u8 *)(CONFIG_SYS_CS2_BASE + 3);
TsiChung Liew9f751552008-07-23 20:38:53 -0500143#endif
144 u8 bootmode;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500145
146 /* To determine PCI is present or not */
Alison Wang198cafb2012-03-26 21:49:08 +0000147 if (((in_be16(&ccm->ccr) & CCM_CCR_360_FBCONFIG_MASK) == 0x00e0) ||
148 ((in_be16(&ccm->ccr) & CCM_CCR_360_FBCONFIG_MASK) == 0x0060)) {
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500149 pPllmult = &pllmult_pci[0];
TsiChung Liew9f751552008-07-23 20:38:53 -0500150 fbpll_mask = 3; /* 11b */
Marek Vasutc1568ca52012-10-03 13:28:45 +0000151#ifdef CONFIG_PCI
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500152 bPci = 1;
Marek Vasutc1568ca52012-10-03 13:28:45 +0000153#endif
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500154 } else {
155 pPllmult = &pllmult_nopci[0];
TsiChung Liew9f751552008-07-23 20:38:53 -0500156 fbpll_mask = 7; /* 111b */
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500157#ifdef CONFIG_PCI
158 gd->pci_clk = 0;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500159 bPci = 0;
Marek Vasutc1568ca52012-10-03 13:28:45 +0000160#endif
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500161 }
162
163#ifdef CONFIG_M54455EVB
Alison Wang198cafb2012-03-26 21:49:08 +0000164 bootmode = (in_8(cpld) & 0x03);
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500165
TsiChung Liew9f751552008-07-23 20:38:53 -0500166 if (bootmode != 3) {
167 /* Temporary read from CCR- fixed fb issue, must be the same clock
168 as pci or input clock, causing cpld/fpga read inconsistancy */
169 fbtemp = pPllmult[ccm->ccr & fbpll_mask];
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500170
TsiChung Liew9f751552008-07-23 20:38:53 -0500171 /* Break down into small pieces, code still in flex bus */
Alison Wang198cafb2012-03-26 21:49:08 +0000172 pcrvalue = in_be32(&pll->pcr) & 0xFFFFF0FF;
TsiChung Liew9f751552008-07-23 20:38:53 -0500173 temp = fbtemp - 1;
174 pcrvalue |= PLL_PCR_OUTDIV3(temp);
175
Alison Wang198cafb2012-03-26 21:49:08 +0000176 out_be32(&pll->pcr, pcrvalue);
TsiChung Liew9f751552008-07-23 20:38:53 -0500177 }
178#endif
179#ifdef CONFIG_M54451EVB
180 /* No external logic to read the bootmode, hard coded from built */
181#ifdef CONFIG_CF_SBF
182 bootmode = 3;
183#else
184 bootmode = 2;
185
186 /* default value is 16 mul, set to 20 mul */
Alison Wang198cafb2012-03-26 21:49:08 +0000187 pcrvalue = (in_be32(&pll->pcr) & 0x00FFFFFF) | 0x14000000;
188 out_be32(&pll->pcr, pcrvalue);
189 while ((in_be32(&pll->psr) & PLL_PSR_LOCK) != PLL_PSR_LOCK)
190 ;
TsiChung Liew9f751552008-07-23 20:38:53 -0500191#endif
192#endif
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500193
TsiChung Liew9f751552008-07-23 20:38:53 -0500194 if (bootmode == 0) {
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500195 /* RCON mode */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200196 vco = pPllmult[ccm->rcon & fbpll_mask] * CONFIG_SYS_INPUT_CLKSRC;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500197
198 if ((vco < CLOCK_PLL_FVCO_MIN) || (vco > CLOCK_PLL_FVCO_MAX)) {
199 /* invaild range, re-set in PCR */
Alison Wang198cafb2012-03-26 21:49:08 +0000200 int temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV2_MASK) >> 4) + 1;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500201 int i, j, bus;
202
Alison Wang198cafb2012-03-26 21:49:08 +0000203 j = (in_be32(&pll->pcr) & 0xFF000000) >> 24;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500204 for (i = j; i < 0xFF; i++) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200205 vco = i * CONFIG_SYS_INPUT_CLKSRC;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500206 if (vco >= CLOCK_PLL_FVCO_MIN) {
207 bus = vco / temp;
208 if (bus <= CLOCK_PLL_FSYS_MIN - MHZ)
209 continue;
210 else
211 break;
212 }
213 }
Alison Wang198cafb2012-03-26 21:49:08 +0000214 pcrvalue = in_be32(&pll->pcr) & 0x00FF00FF;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500215 fbtemp = ((i - 1) << 8) | ((i - 1) << 12);
216 pcrvalue |= ((i << 24) | fbtemp);
217
Alison Wang198cafb2012-03-26 21:49:08 +0000218 out_be32(&pll->pcr, pcrvalue);
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500219 }
Simon Glass7e2592f2012-12-13 20:49:07 +0000220 gd->arch.vco_clk = vco; /* Vco clock */
TsiChung Liew9f751552008-07-23 20:38:53 -0500221 } else if (bootmode == 2) {
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500222 /* Normal mode */
Alison Wang198cafb2012-03-26 21:49:08 +0000223 vco = ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC;
TsiChung Liew9f751552008-07-23 20:38:53 -0500224 if ((vco < CLOCK_PLL_FVCO_MIN) || (vco > CLOCK_PLL_FVCO_MAX)) {
225 /* Default value */
Alison Wang198cafb2012-03-26 21:49:08 +0000226 pcrvalue = (in_be32(&pll->pcr) & 0x00FFFFFF);
227 pcrvalue |= pPllmult[in_be16(&ccm->ccr) & fbpll_mask] << 24;
228 out_be32(&pll->pcr, pcrvalue);
229 vco = ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC;
TsiChung Liew9f751552008-07-23 20:38:53 -0500230 }
Simon Glass7e2592f2012-12-13 20:49:07 +0000231 gd->arch.vco_clk = vco; /* Vco clock */
TsiChung Liew9f751552008-07-23 20:38:53 -0500232 } else if (bootmode == 3) {
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500233 /* serial mode */
Alison Wang198cafb2012-03-26 21:49:08 +0000234 vco = ((in_be32(&pll->pcr) & 0xFF000000) >> 24) * CONFIG_SYS_INPUT_CLKSRC;
Simon Glass7e2592f2012-12-13 20:49:07 +0000235 gd->arch.vco_clk = vco; /* Vco clock */
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500236 }
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500237
Alison Wang198cafb2012-03-26 21:49:08 +0000238 if ((in_be16(&ccm->ccr) & CCM_MISCCR_LIMP) == CCM_MISCCR_LIMP) {
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500239 /* Limp mode */
240 } else {
Simon Glass7e2592f2012-12-13 20:49:07 +0000241 gd->arch.inp_clk = CONFIG_SYS_INPUT_CLKSRC; /* Input clock */
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500242
Alison Wang198cafb2012-03-26 21:49:08 +0000243 temp = (in_be32(&pll->pcr) & PLL_PCR_OUTDIV1_MASK) + 1;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500244 gd->cpu_clk = vco / temp; /* cpu clock */
245
Alison Wang198cafb2012-03-26 21:49:08 +0000246 temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV2_MASK) >> 4) + 1;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500247 gd->bus_clk = vco / temp; /* bus clock */
248
Alison Wang198cafb2012-03-26 21:49:08 +0000249 temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV3_MASK) >> 8) + 1;
Simon Glass7e2592f2012-12-13 20:49:07 +0000250 gd->arch.flb_clk = vco / temp; /* FlexBus clock */
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500251
252#ifdef CONFIG_PCI
253 if (bPci) {
Alison Wang198cafb2012-03-26 21:49:08 +0000254 temp = ((in_be32(&pll->pcr) & PLL_PCR_OUTDIV4_MASK) >> 12) + 1;
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500255 gd->pci_clk = vco / temp; /* PCI clock */
256 }
257#endif
258 }
259
TsiChung Lieweec567a2008-08-19 03:01:19 +0600260#ifdef CONFIG_FSL_I2C
Simon Glass609e6ec2012-12-13 20:48:49 +0000261 gd->arch.i2c1_clk = gd->bus_clk;
TsiChung Lieweec567a2008-08-19 03:01:19 +0600262#endif
Alison Wang45370e12012-10-18 19:25:51 +0000263}
264#endif
265
266/* get_clocks() fills in gd->cpu_clock and gd->bus_clk */
267int get_clocks(void)
268{
269#ifdef CONFIG_MCF5441x
270 setup_5441x_clocks();
271#endif
272#ifdef CONFIG_MCF5445x
273 setup_5445x_clocks();
274#endif
275
276#ifdef CONFIG_FSL_I2C
Simon Glass609e6ec2012-12-13 20:48:49 +0000277 gd->arch.i2c1_clk = gd->bus_clk;
Alison Wang45370e12012-10-18 19:25:51 +0000278#endif
TsiChung Lieweec567a2008-08-19 03:01:19 +0600279
TsiChungLiew8ae158c2007-08-16 15:05:11 -0500280 return (0);
281}