OMAPDSS: DSS: add new clock calculation code
authorTomi Valkeinen <tomi.valkeinen@ti.com>
Tue, 5 Mar 2013 14:34:05 +0000 (16:34 +0200)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Wed, 3 Apr 2013 12:19:17 +0000 (15:19 +0300)
Add new way to iterate over DSS clock divisors. dss_div_calc() provides
a generic way to go over all the divisors, within given clock range.
dss_div_calc() will call a callback function for each divider set,
making the function reusable for all use cases.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h

index 054c2a22b3f1c650aca01037bd6d125d3a55235f..eba4127b61a6756b31c31b6d44912a142dff3619 100644 (file)
@@ -473,6 +473,45 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
        return 0;
 }
 
+bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data)
+{
+       int fckd, fckd_start, fckd_stop;
+       unsigned long fck;
+       unsigned long fck_hw_max;
+       unsigned long fckd_hw_max;
+       unsigned long prate;
+
+       if (dss.dpll4_m4_ck == NULL) {
+               /*
+                * TODO: dss1_fclk can be changed on OMAP2, but the available
+                * dividers are not continuous. We just use the pre-set rate for
+                * now.
+                */
+               fck = clk_get_rate(dss.dss_clk);
+               fckd = 1;
+               return func(fckd, fck, 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;
+
+       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);
+
+       for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
+               fck = prate / fckd;
+
+               if (func(fckd, fck, data))
+                       return true;
+       }
+
+       return false;
+}
+
 int dss_set_clock_div(struct dss_clock_info *cinfo)
 {
        if (dss.dpll4_m4_ck) {
index 0ff41dd8f3c5d86f6dc29a7bd55eee3e19b96f94..4180302a7fb35b1b8609ea262fba619d5c8a6ade 100644 (file)
@@ -271,6 +271,9 @@ int dss_set_clock_div(struct dss_clock_info *cinfo);
 int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
                struct dispc_clock_info *dispc_cinfo);
 
+typedef bool (*dss_div_calc_func)(int fckd, unsigned long fck, void *data);
+bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data);
+
 /* SDI */
 int sdi_init_platform_driver(void) __init;
 void sdi_uninit_platform_driver(void) __exit;