diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2009-01-26 09:41:16 -0500 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2009-03-13 05:33:46 -0400 |
commit | a2865197a5dad23c619c84f44b7fdf7fdbef3f9c (patch) | |
tree | e62afa2bf72a8bad1cbfd400f79b92a13617fac6 | |
parent | 5512e88f3a1f1b498fd07181f14596ee117b3471 (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.c | 31 | ||||
-rw-r--r-- | arch/arm/mach-mx2/clock_imx27.c | 42 | ||||
-rw-r--r-- | arch/arm/mach-mx3/clock.c | 26 | ||||
-rw-r--r-- | arch/arm/plat-mxc/clock.c | 44 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/clock.h | 2 |
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 | */ | ||
97 | static 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 | |||
117 | static unsigned long clk16m_get_rate(struct clk *clk) | 90 | static 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 | ||
189 | static unsigned long system_clk_get_rate(struct clk *clk) | 162 | static 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 | ||
201 | static unsigned long mcu_clk_get_rate(struct clk *clk) | 174 | static 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 | ||
487 | static unsigned long get_mpll_clk(struct clk *clk) | 487 | static 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 | ||
511 | static struct clk mpll_clk = { | 493 | static 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 | ||
582 | static struct clk spll_clk = { | 554 | static 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 | ||
159 | static unsigned long _clk_pll_get_rate(struct clk *clk) | 159 | static 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 | ||
211 | static int _clk_usb_pll_enable(struct clk *clk) | 189 | static 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 | ||
329 | late_initcall(mxc_setup_proc_entry); | 329 | late_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 | */ | ||
341 | unsigned 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 { | |||
63 | int clk_register(struct clk *clk); | 63 | int clk_register(struct clk *clk); |
64 | void clk_unregister(struct clk *clk); | 64 | void clk_unregister(struct clk *clk); |
65 | 65 | ||
66 | unsigned 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__ */ |