aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbdev/omap2/dss/hdmi_pll.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev/omap2/dss/hdmi_pll.c')
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_pll.c95
1 files changed, 47 insertions, 48 deletions
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
index b28d41a08a8f..f04d435c4c0f 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
@@ -20,14 +20,9 @@
20#include "dss.h" 20#include "dss.h"
21#include "hdmi.h" 21#include "hdmi.h"
22 22
23#define HDMI_DEFAULT_REGN 16
24#define HDMI_DEFAULT_REGM2 1
25
26struct hdmi_pll_features { 23struct hdmi_pll_features {
27 bool has_refsel; 24 bool has_refsel;
28 bool sys_reset; 25 bool sys_reset;
29 /* this is a hack, need to replace it with a better computation of M2 */
30 bool bound_dcofreq;
31 unsigned long fint_min, fint_max; 26 unsigned long fint_min, fint_max;
32 u16 regm_max; 27 u16 regm_max;
33 unsigned long dcofreq_low_min, dcofreq_low_max; 28 unsigned long dcofreq_low_min, dcofreq_low_max;
@@ -52,55 +47,61 @@ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
52 DUMPPLL(PLLCTRL_CFG4); 47 DUMPPLL(PLLCTRL_CFG4);
53} 48}
54 49
55void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy) 50void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin,
51 unsigned long target_tmds)
56{ 52{
57 struct hdmi_pll_info *pi = &pll->info; 53 struct hdmi_pll_info *pi = &pll->info;
58 unsigned long refclk; 54 unsigned long fint, clkdco, clkout;
59 u32 mf; 55 unsigned long target_bitclk, target_clkdco;
56 unsigned long min_dco;
57 unsigned n, m, mf, m2, sd;
58
59 DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
60
61 target_bitclk = target_tmds * 10;
60 62
61 /* use our funky units */ 63 /* Fint */
62 clkin /= 10000; 64 n = DIV_ROUND_UP(clkin, pll_feat->fint_max);
65 fint = clkin / n;
63 66
64 /* 67 /* adjust m2 so that the clkdco will be high enough */
65 * Input clock is predivided by N + 1 68 min_dco = roundup(pll_feat->dcofreq_low_min, fint);
66 * out put of which is reference clk 69 m2 = DIV_ROUND_UP(min_dco, target_bitclk);
67 */ 70 if (m2 == 0)
71 m2 = 1;
68 72
69 pi->regn = HDMI_DEFAULT_REGN; 73 target_clkdco = target_bitclk * m2;
74 m = target_clkdco / fint;
70 75
71 refclk = clkin / pi->regn; 76 clkdco = fint * m;
72 77
73 /* temorary hack to make sure DCO freq isn't calculated too low */ 78 /* adjust clkdco with fractional mf */
74 if (pll_feat->bound_dcofreq && phy <= 65000) 79 if (WARN_ON(target_clkdco - clkdco > fint))
75 pi->regm2 = 3; 80 mf = 0;
76 else 81 else
77 pi->regm2 = HDMI_DEFAULT_REGM2; 82 mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
78 83
79 /* 84 if (mf > 0)
80 * multiplier is pixel_clk/ref_clk 85 clkdco += (u32)div_u64((u64)mf * fint, 262144);
81 * Multiplying by 100 to avoid fractional part removal
82 */
83 pi->regm = phy * pi->regm2 / refclk;
84
85 /*
86 * fractional multiplier is remainder of the difference between
87 * multiplier and actual phy(required pixel clock thus should be
88 * multiplied by 2^18(262144) divided by the reference clock
89 */
90 mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
91 pi->regmf = pi->regm2 * mf / refclk;
92
93 /*
94 * Dcofreq should be set to 1 if required pixel clock
95 * is greater than 1000MHz
96 */
97 pi->dcofreq = phy > 1000 * 100;
98 pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
99
100 DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
101 DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
102}
103 86
87 clkout = clkdco / m2;
88
89 /* sigma-delta */
90 sd = DIV_ROUND_UP(fint * m, 250000000);
91
92 DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
93 n, m, mf, m2, sd);
94 DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
95
96 pi->regn = n;
97 pi->regm = m;
98 pi->regmf = mf;
99 pi->regm2 = m2;
100 pi->regsd = sd;
101
102 pi->clkdco = clkdco;
103 pi->clkout = clkout;
104}
104 105
105static int hdmi_pll_config(struct hdmi_pll_data *pll) 106static int hdmi_pll_config(struct hdmi_pll_data *pll)
106{ 107{
@@ -123,7 +124,7 @@ static int hdmi_pll_config(struct hdmi_pll_data *pll)
123 if (pll_feat->has_refsel) 124 if (pll_feat->has_refsel)
124 r = FLD_MOD(r, 0x3, 22, 21); /* REFSEL = SYSCLK */ 125 r = FLD_MOD(r, 0x3, 22, 21); /* REFSEL = SYSCLK */
125 126
126 if (fmt->dcofreq) 127 if (fmt->clkdco > pll_feat->dcofreq_low_max)
127 r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ 128 r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
128 else 129 else
129 r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ 130 r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
@@ -210,7 +211,6 @@ void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
210 211
211static const struct hdmi_pll_features omap44xx_pll_feats = { 212static const struct hdmi_pll_features omap44xx_pll_feats = {
212 .sys_reset = false, 213 .sys_reset = false,
213 .bound_dcofreq = false,
214 .fint_min = 500000, 214 .fint_min = 500000,
215 .fint_max = 2500000, 215 .fint_max = 2500000,
216 .regm_max = 4095, 216 .regm_max = 4095,
@@ -223,7 +223,6 @@ static const struct hdmi_pll_features omap44xx_pll_feats = {
223static const struct hdmi_pll_features omap54xx_pll_feats = { 223static const struct hdmi_pll_features omap54xx_pll_feats = {
224 .has_refsel = true, 224 .has_refsel = true,
225 .sys_reset = true, 225 .sys_reset = true,
226 .bound_dcofreq = true,
227 .fint_min = 620000, 226 .fint_min = 620000,
228 .fint_max = 2500000, 227 .fint_max = 2500000,
229 .regm_max = 2046, 228 .regm_max = 2046,