diff options
Diffstat (limited to 'drivers/video/fbdev/omap2/dss/hdmi_pll.c')
-rw-r--r-- | drivers/video/fbdev/omap2/dss/hdmi_pll.c | 95 |
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 | |||
26 | struct hdmi_pll_features { | 23 | struct 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 | ||
55 | void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy) | 50 | void 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 | ||
105 | static int hdmi_pll_config(struct hdmi_pll_data *pll) | 106 | static 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 | ||
211 | static const struct hdmi_pll_features omap44xx_pll_feats = { | 212 | static 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 = { | |||
223 | static const struct hdmi_pll_features omap54xx_pll_feats = { | 223 | static 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, |