diff options
author | Tomi Valkeinen | 2013-04-10 14:47:38 +0300 |
---|---|---|
committer | Tomi Valkeinen | 2013-04-11 13:07:54 +0300 |
commit | 648a55e1254117bd7500747a789f0b112c7af240 (patch) | |
tree | 3ec4f099ab6d2d20f743bc064cec928ffd2571f1 | |
parent | 77d3595b29e2289cb6f9e4cece5fca1335554d56 (diff) |
OMAPDSS: fix dss_fck clock rate rounding
DSS func clock is calculated with prate / div * m. However, the current
omapdss code calculates it with prate * m / div, which yields a slightly
different result when there's a remainder. For example, 432000000 / 14 *
2 = 61714284, but 432000000 * 2 / 14 = 61714285.
In addition to that, the clock framework wants the clock rate given with
clk_set_rate to be higher than the actual (truncated) end result. So, if
prate is 432000000, and div is 14, the real result is 30857142.8571...
We need to call clk_set_rate with 30857143, which gives us a clock of
30857142. That's why we need to use DIV_ROUND_UP() when calling
clk_set_rate.
This patch fixes the clock calculation.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
-rw-r--r-- | drivers/video/omap2/dss/dss.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index fdd32e8d9212..b9f6f245d4a1 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -480,6 +480,7 @@ bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data) unsigned long fck_hw_max; unsigned long fckd_hw_max; unsigned long prate; + unsigned m; if (dss.dpll4_m4_ck == NULL) { /* @@ -495,15 +496,16 @@ bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data) fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); fckd_hw_max = dss.feat->fck_div_max; - prate = dss_get_dpll4_rate() * dss.feat->dss_fck_multiplier; + m = dss.feat->dss_fck_multiplier; + prate = dss_get_dpll4_rate(); fck_min = fck_min ? fck_min : 1; - fckd_start = min(prate / fck_min, fckd_hw_max); - fckd_stop = max(DIV_ROUND_UP(prate, fck_hw_max), 1ul); + fckd_start = min(prate * m / fck_min, fckd_hw_max); + fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul); for (fckd = fckd_start; fckd >= fckd_stop; --fckd) { - fck = prate / fckd; + fck = prate / fckd * m; if (func(fckd, fck, data)) return true; @@ -521,7 +523,8 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); DSSDBG("dpll4_m4 = %ld\n", prate); - r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div); + r = clk_set_rate(dss.dpll4_m4_ck, + DIV_ROUND_UP(prate, cinfo->fck_div)); if (r) return r; } else { @@ -531,7 +534,9 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) dss.dss_clk_rate = clk_get_rate(dss.dss_clk); - WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch"); + WARN_ONCE(dss.dss_clk_rate != cinfo->fck, + "clk rate mismatch: %lu != %lu", dss.dss_clk_rate, + cinfo->fck); DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); |