From 7c284e6ee3710e96bf246e6b52032f3d766fa094 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 5 Mar 2013 16:32:08 +0200 Subject: OMAPDSS: DISPC: add new clock calculation code Add new way to iterate over DISPC clock divisors. dispc_div_calc() provides a generic way to go over all the divisors, within given pixel clock range. dispc_div_calc() will call a callback function for each divider set, making the function reusable for all use cases. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 60 +++++++++++++++++++++++++++++++++++++++++ drivers/video/omap2/dss/dss.h | 6 +++++ 2 files changed, 66 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index f564955ddd9e..cd54e8fe2d58 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -3374,6 +3374,66 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, return 0; } +bool dispc_div_calc(unsigned long dispc, + unsigned long pck_min, unsigned long pck_max, + dispc_div_calc_func func, void *data) +{ + int lckd, lckd_start, lckd_stop; + int pckd, pckd_start, pckd_stop; + unsigned long pck, lck; + unsigned long lck_max; + unsigned long pckd_hw_min, pckd_hw_max; + unsigned min_fck_per_pck; + unsigned long fck; + +#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; +#else + min_fck_per_pck = 0; +#endif + + pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); + pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); + + lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + + pck_min = pck_min ? pck_min : 1; + pck_max = pck_max ? pck_max : ULONG_MAX; + + lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul); + lckd_stop = min(dispc / pck_min, 255ul); + + for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) { + lck = dispc / lckd; + + pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min); + pckd_stop = min(lck / pck_min, pckd_hw_max); + + for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) { + pck = lck / pckd; + + /* + * For OMAP2/3 the DISPC fclk is the same as LCD's logic + * clock, which means we're configuring DISPC fclk here + * also. Thus we need to use the calculated lck. For + * OMAP4+ the DISPC fclk is a separate clock. + */ + if (dss_has_feature(FEAT_CORE_CLK_DIV)) + fck = dispc_core_clk_rate(); + else + fck = lck; + + if (fck < pck * min_fck_per_pck) + continue; + + if (func(lckd, pckd, lck, pck, data)) + return true; + } + } + + return false; +} + void dispc_mgr_set_clock_div(enum omap_channel channel, const struct dispc_clock_info *cinfo) { diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 610c8e563daa..0ff41dd8f3c5 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -376,6 +376,12 @@ void dispc_enable_fifomerge(bool enable); void dispc_enable_gamma_table(bool enable); void dispc_set_loadmode(enum omap_dss_load_mode mode); +typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck, + unsigned long pck, void *data); +bool dispc_div_calc(unsigned long dispc, + unsigned long pck_min, unsigned long pck_max, + dispc_div_calc_func func, void *data); + bool dispc_mgr_timings_ok(enum omap_channel channel, const struct omap_video_timings *timings); unsigned long dispc_fclk_rate(void); -- cgit v1.2.1