aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi.h10
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4.c9
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5.c9
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_phy.c31
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_pll.c95
5 files changed, 71 insertions, 83 deletions
diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h
index 4bbc9d206f4a..4b9bf0804a48 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi.h
+++ b/drivers/video/fbdev/omap2/dss/hdmi.h
@@ -191,7 +191,9 @@ struct hdmi_pll_info {
191 u32 regmf; 191 u32 regmf;
192 u16 regm2; 192 u16 regm2;
193 u16 regsd; 193 u16 regsd;
194 u16 dcofreq; 194
195 unsigned long clkdco;
196 unsigned long clkout;
195}; 197};
196 198
197struct hdmi_audio_format { 199struct hdmi_audio_format {
@@ -313,11 +315,13 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp);
313int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp); 315int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
314void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp); 316void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
315void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s); 317void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
316void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy); 318void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin,
319 unsigned long target_tmds);
317int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll); 320int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll);
318 321
319/* HDMI PHY funcs */ 322/* HDMI PHY funcs */
320int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg); 323int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
324 unsigned long lfbitclk);
321void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s); 325void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
322int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy); 326int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy);
323int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes); 327int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c
index 9a8713ca090c..1f2fbccaff1f 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi4.c
@@ -180,7 +180,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
180 int r; 180 int r;
181 struct omap_video_timings *p; 181 struct omap_video_timings *p;
182 struct omap_overlay_manager *mgr = hdmi.output.manager; 182 struct omap_overlay_manager *mgr = hdmi.output.manager;
183 unsigned long phy;
184 struct hdmi_wp_data *wp = &hdmi.wp; 183 struct hdmi_wp_data *wp = &hdmi.wp;
185 184
186 r = hdmi_power_on_core(dssdev); 185 r = hdmi_power_on_core(dssdev);
@@ -195,10 +194,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
195 194
196 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); 195 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
197 196
198 /* the functions below use kHz pixel clock. TODO: change to Hz */ 197 hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), p->pixelclock);
199 phy = p->pixelclock / 1000;
200
201 hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
202 198
203 /* config the PLL and PHY hdmi_set_pll_pwrfirst */ 199 /* config the PLL and PHY hdmi_set_pll_pwrfirst */
204 r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp); 200 r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
@@ -207,7 +203,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
207 goto err_pll_enable; 203 goto err_pll_enable;
208 } 204 }
209 205
210 r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg); 206 r = hdmi_phy_configure(&hdmi.phy, hdmi.pll.info.clkdco,
207 hdmi.pll.info.clkout);
211 if (r) { 208 if (r) {
212 DSSDBG("Failed to configure PHY\n"); 209 DSSDBG("Failed to configure PHY\n");
213 goto err_phy_cfg; 210 goto err_phy_cfg;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c
index c053d692ec16..e8ca9106c8af 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi5.c
@@ -198,7 +198,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
198 int r; 198 int r;
199 struct omap_video_timings *p; 199 struct omap_video_timings *p;
200 struct omap_overlay_manager *mgr = hdmi.output.manager; 200 struct omap_overlay_manager *mgr = hdmi.output.manager;
201 unsigned long phy;
202 201
203 r = hdmi_power_on_core(dssdev); 202 r = hdmi_power_on_core(dssdev);
204 if (r) 203 if (r)
@@ -208,10 +207,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
208 207
209 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); 208 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
210 209
211 /* the functions below use kHz pixel clock. TODO: change to Hz */ 210 hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), p->pixelclock);
212 phy = p->pixelclock / 1000;
213
214 hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
215 211
216 /* disable and clear irqs */ 212 /* disable and clear irqs */
217 hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); 213 hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
@@ -225,7 +221,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
225 goto err_pll_enable; 221 goto err_pll_enable;
226 } 222 }
227 223
228 r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg); 224 r = hdmi_phy_configure(&hdmi.phy, hdmi.pll.info.clkdco,
225 hdmi.pll.info.clkout);
229 if (r) { 226 if (r) {
230 DSSDBG("Failed to start PHY\n"); 227 DSSDBG("Failed to start PHY\n");
231 goto err_phy_cfg; 228 goto err_phy_cfg;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
index e007ac892d79..bc9e07d2afbe 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_phy.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
@@ -20,9 +20,7 @@
20 20
21struct hdmi_phy_features { 21struct hdmi_phy_features {
22 bool bist_ctrl; 22 bool bist_ctrl;
23 bool calc_freqout;
24 bool ldo_voltage; 23 bool ldo_voltage;
25 unsigned long dcofreq_min;
26 unsigned long max_phy; 24 unsigned long max_phy;
27}; 25};
28 26
@@ -132,7 +130,8 @@ static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
132 REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27); 130 REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
133} 131}
134 132
135int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg) 133int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
134 unsigned long lfbitclk)
136{ 135{
137 u8 freqout; 136 u8 freqout;
138 137
@@ -149,20 +148,16 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
149 if (phy_feat->bist_ctrl) 148 if (phy_feat->bist_ctrl)
150 REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11); 149 REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
151 150
152 if (phy_feat->calc_freqout) { 151 /*
153 /* DCOCLK/10 is pixel clock, compare pclk with DCOCLK_MIN/10 */ 152 * If the hfbitclk != lfbitclk, it means the lfbitclk was configured
154 u32 dco_min = phy_feat->dcofreq_min / 10; 153 * to be used for TMDS.
155 u32 pclk = cfg->timings.pixelclock; 154 */
156 155 if (hfbitclk != lfbitclk)
157 if (pclk < dco_min) 156 freqout = 0;
158 freqout = 0; 157 else if (hfbitclk / 10 < phy_feat->max_phy)
159 else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy))
160 freqout = 1;
161 else
162 freqout = 2;
163 } else {
164 freqout = 1; 158 freqout = 1;
165 } 159 else
160 freqout = 2;
166 161
167 /* 162 /*
168 * Write to phy address 0 to configure the clock 163 * Write to phy address 0 to configure the clock
@@ -184,17 +179,13 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
184 179
185static const struct hdmi_phy_features omap44xx_phy_feats = { 180static const struct hdmi_phy_features omap44xx_phy_feats = {
186 .bist_ctrl = false, 181 .bist_ctrl = false,
187 .calc_freqout = false,
188 .ldo_voltage = true, 182 .ldo_voltage = true,
189 .dcofreq_min = 500000000,
190 .max_phy = 185675000, 183 .max_phy = 185675000,
191}; 184};
192 185
193static const struct hdmi_phy_features omap54xx_phy_feats = { 186static const struct hdmi_phy_features omap54xx_phy_feats = {
194 .bist_ctrl = true, 187 .bist_ctrl = true,
195 .calc_freqout = true,
196 .ldo_voltage = false, 188 .ldo_voltage = false,
197 .dcofreq_min = 750000000,
198 .max_phy = 186000000, 189 .max_phy = 186000000,
199}; 190};
200 191
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,