aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2009-01-26 09:41:16 -0500
committerSascha Hauer <s.hauer@pengutronix.de>2009-03-13 05:33:46 -0400
commita2865197a5dad23c619c84f44b7fdf7fdbef3f9c (patch)
treee62afa2bf72a8bad1cbfd400f79b92a13617fac6
parent5512e88f3a1f1b498fd07181f14596ee117b3471 (diff)
[ARM] MXC: Use a single function for decoding a PLL
We had 3 versions of this function in clock support for MX1/2/3 Use a single one instead. I picked the one from the MX3 as it seems to calculate more accurate as the other ones. Also, on MX27 and MX31 mfn can be negative, this hasn't been handled correctly on MX27 since now. This patch has been tested on MX27 and MX31 and produces the same clock frequencies for me. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--arch/arm/mach-mx1/clock.c31
-rw-r--r--arch/arm/mach-mx2/clock_imx27.c42
-rw-r--r--arch/arm/mach-mx3/clock.c26
-rw-r--r--arch/arm/plat-mxc/clock.c44
-rw-r--r--arch/arm/plat-mxc/include/mach/clock.h2
5 files changed, 57 insertions, 88 deletions
diff --git a/arch/arm/mach-mx1/clock.c b/arch/arm/mach-mx1/clock.c
index 4bcd1ece55f5..3c464331b870 100644
--- a/arch/arm/mach-mx1/clock.c
+++ b/arch/arm/mach-mx1/clock.c
@@ -87,33 +87,6 @@ static int _clk_parent_set_rate(struct clk *clk, unsigned long rate)
87 return clk->parent->set_rate(clk->parent, rate); 87 return clk->parent->set_rate(clk->parent, rate);
88} 88}
89 89
90/*
91 * get the system pll clock in Hz
92 *
93 * mfi + mfn / (mfd +1)
94 * f = 2 * f_ref * --------------------
95 * pd + 1
96 */
97static unsigned long mx1_decode_pll(unsigned int pll, u32 f_ref)
98{
99 unsigned long long ll;
100 unsigned long quot;
101
102 u32 mfi = (pll >> 10) & 0xf;
103 u32 mfn = pll & 0x3ff;
104 u32 mfd = (pll >> 16) & 0x3ff;
105 u32 pd = (pll >> 26) & 0xf;
106
107 mfi = mfi <= 5 ? 5 : mfi;
108
109 ll = 2 * (unsigned long long)f_ref *
110 ((mfi << 16) + (mfn << 16) / (mfd + 1));
111 quot = (pd + 1) * (1 << 16);
112 ll += quot / 2;
113 do_div(ll, quot);
114 return (unsigned long)ll;
115}
116
117static unsigned long clk16m_get_rate(struct clk *clk) 90static unsigned long clk16m_get_rate(struct clk *clk)
118{ 91{
119 return 16000000; 92 return 16000000;
@@ -188,7 +161,7 @@ static struct clk prem_clk = {
188 161
189static unsigned long system_clk_get_rate(struct clk *clk) 162static unsigned long system_clk_get_rate(struct clk *clk)
190{ 163{
191 return mx1_decode_pll(__raw_readl(CCM_SPCTL0), 164 return mxc_decode_pll(__raw_readl(CCM_SPCTL0),
192 clk_get_rate(clk->parent)); 165 clk_get_rate(clk->parent));
193} 166}
194 167
@@ -200,7 +173,7 @@ static struct clk system_clk = {
200 173
201static unsigned long mcu_clk_get_rate(struct clk *clk) 174static unsigned long mcu_clk_get_rate(struct clk *clk)
202{ 175{
203 return mx1_decode_pll(__raw_readl(CCM_MPCTL0), 176 return mxc_decode_pll(__raw_readl(CCM_MPCTL0),
204 clk_get_rate(clk->parent)); 177 clk_get_rate(clk->parent));
205} 178}
206 179
diff --git a/arch/arm/mach-mx2/clock_imx27.c b/arch/arm/mach-mx2/clock_imx27.c
index c69896d011a1..047e71e6ea9a 100644
--- a/arch/arm/mach-mx2/clock_imx27.c
+++ b/arch/arm/mach-mx2/clock_imx27.c
@@ -486,26 +486,8 @@ static struct clk ckil_clk = {
486 486
487static unsigned long get_mpll_clk(struct clk *clk) 487static unsigned long get_mpll_clk(struct clk *clk)
488{ 488{
489 uint32_t reg; 489 return mxc_decode_pll(__raw_readl(CCM_MPCTL0),
490 unsigned long ref_clk; 490 clk_get_rate(clk->parent));
491 unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
492 unsigned long long temp;
493
494 ref_clk = clk_get_rate(clk->parent);
495
496 reg = __raw_readl(CCM_MPCTL0);
497 pdf = (reg & CCM_MPCTL0_PD_MASK) >> CCM_MPCTL0_PD_OFFSET;
498 mfd = (reg & CCM_MPCTL0_MFD_MASK) >> CCM_MPCTL0_MFD_OFFSET;
499 mfi = (reg & CCM_MPCTL0_MFI_MASK) >> CCM_MPCTL0_MFI_OFFSET;
500 mfn = (reg & CCM_MPCTL0_MFN_MASK) >> CCM_MPCTL0_MFN_OFFSET;
501
502 mfi = (mfi <= 5) ? 5 : mfi;
503 temp = 2LL * ref_clk * mfn;
504 do_div(temp, mfd + 1);
505 temp = 2LL * ref_clk * mfi + temp;
506 do_div(temp, pdf + 1);
507
508 return (unsigned long)temp;
509} 491}
510 492
511static struct clk mpll_clk = { 493static struct clk mpll_clk = {
@@ -555,28 +537,18 @@ static unsigned long get_spll_clk(struct clk *clk)
555{ 537{
556 uint32_t reg; 538 uint32_t reg;
557 unsigned long ref_clk; 539 unsigned long ref_clk;
558 unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
559 unsigned long long temp;
560 540
561 ref_clk = clk_get_rate(clk->parent); 541 ref_clk = clk_get_rate(clk->parent);
562 542
563 reg = __raw_readl(CCM_SPCTL0); 543 reg = __raw_readl(CCM_SPCTL0);
564 /*TODO: This is TO2 Bug */ 544
545 /* On TO2 we have to write the value back. Otherwise we
546 * read 0 from this register the next time.
547 */
565 if (mx27_revision() >= CHIP_REV_2_0) 548 if (mx27_revision() >= CHIP_REV_2_0)
566 __raw_writel(reg, CCM_SPCTL0); 549 __raw_writel(reg, CCM_SPCTL0);
567 550
568 pdf = (reg & CCM_SPCTL0_PD_MASK) >> CCM_SPCTL0_PD_OFFSET; 551 return mxc_decode_pll(reg, ref_clk);
569 mfd = (reg & CCM_SPCTL0_MFD_MASK) >> CCM_SPCTL0_MFD_OFFSET;
570 mfi = (reg & CCM_SPCTL0_MFI_MASK) >> CCM_SPCTL0_MFI_OFFSET;
571 mfn = (reg & CCM_SPCTL0_MFN_MASK) >> CCM_SPCTL0_MFN_OFFSET;
572
573 mfi = (mfi <= 5) ? 5 : mfi;
574 temp = 2LL * ref_clk * mfn;
575 do_div(temp, mfd + 1);
576 temp = 2LL * ref_clk * mfi + temp;
577 do_div(temp, pdf + 1);
578
579 return (unsigned long)temp;
580} 552}
581 553
582static struct clk spll_clk = { 554static struct clk spll_clk = {
diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c
index b1746aae1f89..8486ea46d6c1 100644
--- a/arch/arm/mach-mx3/clock.c
+++ b/arch/arm/mach-mx3/clock.c
@@ -158,10 +158,8 @@ static int _clk_pll_set_rate(struct clk *clk, unsigned long rate)
158 158
159static unsigned long _clk_pll_get_rate(struct clk *clk) 159static unsigned long _clk_pll_get_rate(struct clk *clk)
160{ 160{
161 long mfi, mfn, mfd, pdf, ref_clk, mfn_abs;
162 unsigned long reg, ccmr; 161 unsigned long reg, ccmr;
163 s64 temp; 162 unsigned int prcs, ref_clk;
164 unsigned int prcs;
165 163
166 ccmr = __raw_readl(MXC_CCM_CCMR); 164 ccmr = __raw_readl(MXC_CCM_CCMR);
167 prcs = (ccmr & MXC_CCM_CCMR_PRCS_MASK) >> MXC_CCM_CCMR_PRCS_OFFSET; 165 prcs = (ccmr & MXC_CCM_CCMR_PRCS_MASK) >> MXC_CCM_CCMR_PRCS_OFFSET;
@@ -185,27 +183,7 @@ static unsigned long _clk_pll_get_rate(struct clk *clk)
185 return 0; 183 return 0;
186 } 184 }
187 185
188 pdf = (reg & MXC_CCM_PCTL_PD_MASK) >> MXC_CCM_PCTL_PD_OFFSET; 186 return mxc_decode_pll(reg, ref_clk);
189 mfd = (reg & MXC_CCM_PCTL_MFD_MASK) >> MXC_CCM_PCTL_MFD_OFFSET;
190 mfi = (reg & MXC_CCM_PCTL_MFI_MASK) >> MXC_CCM_PCTL_MFI_OFFSET;
191 mfi = (mfi <= 5) ? 5 : mfi;
192 mfn = mfn_abs = reg & MXC_CCM_PCTL_MFN_MASK;
193
194 if (mfn >= 0x200) {
195 mfn |= 0xFFFFFE00;
196 mfn_abs = -mfn;
197 }
198
199 ref_clk *= 2;
200 ref_clk /= pdf + 1;
201
202 temp = (u64) ref_clk * mfn_abs;
203 do_div(temp, mfd + 1);
204 if (mfn < 0)
205 temp = -temp;
206 temp = (ref_clk * mfi) + temp;
207
208 return temp;
209} 187}
210 188
211static int _clk_usb_pll_enable(struct clk *clk) 189static int _clk_usb_pll_enable(struct clk *clk)
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
index 0a38f0b396eb..888dd33abf76 100644
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -328,3 +328,47 @@ static int __init mxc_setup_proc_entry(void)
328 328
329late_initcall(mxc_setup_proc_entry); 329late_initcall(mxc_setup_proc_entry);
330#endif 330#endif
331
332/*
333 * Get the resulting clock rate from a PLL register value and the input
334 * frequency. PLLs with this register layout can at least be found on
335 * MX1, MX21, MX27 and MX31
336 *
337 * mfi + mfn / (mfd + 1)
338 * f = 2 * f_ref * --------------------
339 * pd + 1
340 */
341unsigned long mxc_decode_pll(unsigned int reg_val, u32 freq)
342{
343 long long ll;
344 int mfn_abs;
345 unsigned int mfi, mfn, mfd, pd;
346
347 mfi = (reg_val >> 10) & 0xf;
348 mfn = reg_val & 0x3ff;
349 mfd = (reg_val >> 16) & 0x3ff;
350 pd = (reg_val >> 26) & 0xf;
351
352 mfi = mfi <= 5 ? 5 : mfi;
353
354 mfn_abs = mfn;
355
356#if !defined CONFIG_ARCH_MX1 && !defined CONFIG_ARCH_MX21
357 if (mfn >= 0x200) {
358 mfn |= 0xFFFFFE00;
359 mfn_abs = -mfn;
360 }
361#endif
362
363 freq *= 2;
364 freq /= pd + 1;
365
366 ll = (unsigned long long)freq * mfn_abs;
367
368 do_div(ll, mfd + 1);
369 if (mfn < 0)
370 ll = -ll;
371 ll = (freq * mfi) + ll;
372
373 return ll;
374}
diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h
index d21f78e78819..b830655514eb 100644
--- a/arch/arm/plat-mxc/include/mach/clock.h
+++ b/arch/arm/plat-mxc/include/mach/clock.h
@@ -63,5 +63,7 @@ struct clk {
63int clk_register(struct clk *clk); 63int clk_register(struct clk *clk);
64void clk_unregister(struct clk *clk); 64void clk_unregister(struct clk *clk);
65 65
66unsigned long mxc_decode_pll(unsigned int pll, u32 f_ref);
67
66#endif /* __ASSEMBLY__ */ 68#endif /* __ASSEMBLY__ */
67#endif /* __ASM_ARCH_MXC_CLOCK_H__ */ 69#endif /* __ASM_ARCH_MXC_CLOCK_H__ */