]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/commitdiff
OMAPDSS:HDMI: Change PLL calculations
authorAndy Gross <andy.gross@ti.com>
Wed, 29 May 2013 07:38:06 +0000 (13:08 +0530)
committerArchit Taneja <archit@ti.com>
Thu, 30 May 2013 23:03:38 +0000 (04:33 +0530)
This patch modifies the algorithms used to determine the correct PLL
settings for the HDMI TMDS output.  Instead of using fixed REGM2 values
we search for a valid combination of REGN, REGM, REGM2 that satisfy the
constraints for the requested frequency.

The computation involves looping through the values of REGN and trying to
find an adequate REGM and REGM2 (if applicable).  This results in the lowest
value for REGN that will satisfy the frequency request.

This patch also modifies the API used for the hdmi_compute_pll function.
If a valid PLL combination cannot be found, we return an error back to the
caller.

Signed-off-by: Andy Gross <andy.gross@ti.com>
Signed-off-by: Archit Taneja <archit@ti.com>
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/ti_hdmi.h
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c

index 11392f8ecd5e7f02cfaca3d721630aad1960934d..8ae30bd19cb9e1be3cabd81d1fbb003668a7d219 100644 (file)
@@ -34,7 +34,7 @@ struct dss_reg_field {
 };
 
 struct dss_param_range {
-       int min, max;
+       unsigned long min, max;
 };
 
 struct omap_dss_features {
@@ -459,6 +459,10 @@ static const struct dss_param_range omap2_dss_param_range[] = {
         */
        [FEAT_PARAM_LINEWIDTH]                  = { 1, 768 },
        [FEAT_PARAM_HDMI_PCLK]                  = { 0, 0 },
+       [FEAT_PARAM_HDMIPLL_FINT]               = { 0, 0 },
+       [FEAT_PARAM_HDMIPLL_REGM]               = { 0, 0 },
+       [FEAT_PARAM_DCOFREQ_LOW]                = { 0, 0 },
+       [FEAT_PARAM_DCOFREQ_HIGH]               = { 0, 0 },
 };
 
 static const struct dss_param_range omap3_dss_param_range[] = {
@@ -474,6 +478,10 @@ static const struct dss_param_range omap3_dss_param_range[] = {
        [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
        [FEAT_PARAM_LINEWIDTH]                  = { 1, 1024 },
        [FEAT_PARAM_HDMI_PCLK]                  = { 0, 0 },
+       [FEAT_PARAM_HDMIPLL_FINT]               = { 0, 0 },
+       [FEAT_PARAM_HDMIPLL_REGM]               = { 0, 0 },
+       [FEAT_PARAM_DCOFREQ_LOW]                = { 0, 0 },
+       [FEAT_PARAM_DCOFREQ_HIGH]               = { 0, 0 },
 };
 
 static const struct dss_param_range omap4_dss_param_range[] = {
@@ -489,6 +497,10 @@ static const struct dss_param_range omap4_dss_param_range[] = {
        [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
        [FEAT_PARAM_LINEWIDTH]                  = { 1, 2048 },
        [FEAT_PARAM_HDMI_PCLK]                  = { 1, 185675000 },
+       [FEAT_PARAM_HDMIPLL_FINT]               = { 500000, 2500000 },
+       [FEAT_PARAM_HDMIPLL_REGM]               = { 0, (1 << 12) - 1 },
+       [FEAT_PARAM_DCOFREQ_LOW]                = { 500000000, 1000000000 },
+       [FEAT_PARAM_DCOFREQ_HIGH]               = { 1000000000, 2000000000 },
 };
 
 static const struct dss_param_range omap5_dss_param_range[] = {
@@ -504,6 +516,10 @@ static const struct dss_param_range omap5_dss_param_range[] = {
        [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
        [FEAT_PARAM_LINEWIDTH]                  = { 1, 2048 },
        [FEAT_PARAM_HDMI_PCLK]                  = { 1, 186000000 },
+       [FEAT_PARAM_HDMIPLL_FINT]               = { 500000, 2500000 },
+       [FEAT_PARAM_HDMIPLL_REGM]               = { 20, 2046 },
+       [FEAT_PARAM_DCOFREQ_LOW]                = { 750000000, 1500000000 },
+       [FEAT_PARAM_DCOFREQ_HIGH]               = { 1250000000, 2500000000UL },
 };
 
 static const enum dss_feat_id omap2_dss_feat_list[] = {
index 0e8fccf79ddede31cdc68bb36fcd2707d0972d79..2dc25fb89d4ea28f19a1774e1d12a19a60f48e02 100644 (file)
@@ -99,6 +99,10 @@ enum dss_range_param {
        FEAT_PARAM_DOWNSCALE,
        FEAT_PARAM_LINEWIDTH,
        FEAT_PARAM_HDMI_PCLK,
+       FEAT_PARAM_HDMIPLL_FINT,
+       FEAT_PARAM_HDMIPLL_REGM,
+       FEAT_PARAM_DCOFREQ_LOW,
+       FEAT_PARAM_DCOFREQ_HIGH,
 };
 
 /* DSS Feature Functions */
index 147c0a32671ab3a6037c3d1a07271aaeb62d0036..133da16ef8633f9af75d99606adfefd3a822208d 100644 (file)
@@ -53,9 +53,6 @@
 #define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR     4
 #define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR     4
 
-#define HDMI_DEFAULT_REGN 16
-#define HDMI_DEFAULT_REGM2 1
-
 static struct {
        struct mutex lock;
        struct platform_device *pdev;
@@ -549,75 +546,116 @@ unsigned long hdmi_get_pixel_clock(void)
        return hdmi.ip_data.cfg.timings.pixel_clock * 1000;
 }
 
-static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
+static int hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
                struct hdmi_pll_info *pi)
 {
        unsigned long clkin, refclk;
-       enum omapdss_version version = omapdss_get_version();
+       int phy_calc;
+       unsigned long regn_max, regn_min, regm_min, regm_max;
+       unsigned long fint_min, fint_max;
+       unsigned long dco_low_min, dco_high_min;
+       bool found = false;
        u32 mf;
 
        clkin = clk_get_rate(hdmi.sys_clk) / 10000;
-       /*
-        * Input clock is predivided by N + 1
-        * out put of which is reference clk
-        */
-       if (dssdev->clocks.hdmi.regn == 0)
-               pi->regn = HDMI_DEFAULT_REGN;
-       else
-               pi->regn = dssdev->clocks.hdmi.regn;
 
-       refclk = clkin / pi->regn;
+       fint_min = dss_feat_get_param_min(FEAT_PARAM_HDMIPLL_FINT) / 10000;
+       fint_max = dss_feat_get_param_max(FEAT_PARAM_HDMIPLL_FINT) / 10000;
 
-       if (dssdev->clocks.hdmi.regm2 == 0) {
-               switch (version)
-               {
-               case OMAPDSS_VER_OMAP4430_ES1:
-               case OMAPDSS_VER_OMAP4430_ES2:
-               case OMAPDSS_VER_OMAP4:
-                       pi->regm2 = HDMI_DEFAULT_REGM2;
-                       break;
-               case OMAPDSS_VER_OMAP5:
-               case OMAPDSS_VER_DRA7xx:
-                       if (phy <= 50000)
-                               pi->regm2 = 5;
-                       else
-                               pi->regm2 = 1;
-                       break;
-               default:
-                       DSSWARN("invalid omapdss version");
-                       break;
+       /* clkin limits */
+       /* .62 MHz < CLKIN/REGN < 2.5MHz */
+       regn_min = clkin / fint_max + 1;
+       regn_max = clkin / fint_min;
+
+       /* Fractional limits on REGM */
+       regm_min = dss_feat_get_param_min(FEAT_PARAM_HDMIPLL_REGM);
+       regm_max = dss_feat_get_param_max(FEAT_PARAM_HDMIPLL_REGM);
+
+       /* DCO frequency ranges */
+
+       /* DCO lowest frequency supported */
+       dco_low_min = dss_feat_get_param_min(FEAT_PARAM_DCOFREQ_LOW) / 10000;
+
+       /* Starting frequency of high frequency range(in Mhz) */
+       dco_high_min = dss_feat_get_param_min(FEAT_PARAM_DCOFREQ_HIGH);
+
+       /* set dcofreq to 1 if required clock is > 1.25GHz */
+       pi->dcofreq = phy > (dco_high_min / 10000);
+
+       if (phy < dco_low_min) {
+               /* Calculate CLKOUTLDO - low frequency */
+               for (pi->regn = regn_min; pi->regn < regn_max; pi->regn++) {
+                       refclk = clkin / pi->regn;
+
+                       regm_min = ((dco_low_min / refclk) < regm_min) ?
+                                       regm_min : (dco_low_min / refclk);
+
+                       for (pi->regm2 = 3; pi->regm2 <= 127; pi->regm2++) {
+                               pi->regm = phy * pi->regm2 / refclk;
+                               if (pi->regm < regm_min || pi->regm > regm_max)
+                                       continue;
 
+                               pi->regsd = DIV_ROUND_UP((pi->regm * clkin / 100),
+                                                       pi->regn * 250);
+                               phy_calc = clkin * pi->regm / pi->regn /
+                                               pi->regm2;
+
+                               if (pi->regsd && pi->regsd < 255 &&
+                                       phy_calc <= phy) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+
+                       if (found)
+                               break;
                }
        } else {
-               pi->regm2 = dssdev->clocks.hdmi.regm2;
+               pi->regm2 = 1;
+
+               /* CLKDCOLDO - high frequency */
+               for (pi->regn = regn_min; pi->regn < regn_max; pi->regn++) {
+                       refclk = clkin / pi->regn;
+                       pi->regm = phy / refclk;
+
+                       if (pi->regm < regm_min || pi->regm > regm_max)
+                               continue;
+
+                       pi->regsd = DIV_ROUND_UP((pi->regm * clkin / 100),
+                                               pi->regn * 250);
+
+                       phy_calc = clkin * pi->regm / pi->regn;
+
+                       if (pi->regsd < 255 && phy_calc <= phy) {
+                               found = true;
+                               break;
+                       }
+               }
        }
 
-       /*
-        * multiplier is pixel_clk/ref_clk
-        * Multiplying by 100 to avoid fractional part removal
-        */
-       pi->regm = phy * pi->regm2 / refclk;
+       if (!found) {
+               DSSERR("Failed to find pll settings\n");
+               return 1;
+       }
 
        /*
         * fractional multiplier is remainder of the difference between
         * multiplier and actual phy(required pixel clock thus should be
         * multiplied by 2^18(262144) divided by the reference clock
         */
-       mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
+       mf = (phy - refclk * pi->regm / pi->regm2) * 262144;
        pi->regmf = pi->regm2 * mf / refclk;
 
-       /*
-        * Dcofreq should be set to 1 if required pixel clock
-        * is greater than 1000MHz
-        */
-       pi->dcofreq = phy > 1000 * 100;
-       pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
+       if (pi->regmf > 262144)
+               pi->regmf = 0;
 
        /* Set the reference clock to sysclk reference */
        pi->refsel = HDMI_REFSEL_SYSCLK;
 
-       DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
-       DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
+       DSSERR("M = %d Mf = %d\n", pi->regm, pi->regmf);
+       DSSERR("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
+
+       return 0;
 }
 
 static int hdmi_power_on_core(struct omap_dss_device *dssdev)
@@ -690,7 +728,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
                break;
        }
 
-       hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
+       if (hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data))
+               goto err_pll_compute;
 
        hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
 
@@ -739,6 +778,7 @@ err_vid_enable:
 err_phy_enable:
        hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
 err_pll_enable:
+err_pll_compute:
 err_deep_color:
        hdmi_power_off_core(dssdev);
        return -EIO;
index eab2ab8385fdd8a064ebcb3e5e26884ff170a94e..2966a3af5884053afe3a31e603c5c2b1cfddb038 100644 (file)
@@ -117,6 +117,11 @@ struct hdmi_pll_info {
        u16 regsd;
        u16 dcofreq;
        enum hdmi_clk_refsel refsel;
+
+       /* pll constraints */
+       u32 dco_limit;
+       u32 refclk_min;
+       u32 refclk_max;
 };
 
 struct hdmi_irq_vector {
index d7f19376181579ff3db03d4d040b090fda1ac001..2b79e861a837a6ff027248b76cc342765fbb9de8 100644 (file)
@@ -309,6 +309,7 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
        void __iomem *phy_base = hdmi_phy_base(ip_data);
        enum omapdss_version version = omapdss_get_version();
        unsigned long pclk = ip_data->cfg.timings.pixel_clock;
+       unsigned long dcofreq_min = dss_feat_get_param_max(FEAT_PARAM_DCOFREQ_LOW) / 1000;
        u16 freqout = 1;
 
        /*
@@ -340,9 +341,9 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
                break;
        case OMAPDSS_VER_OMAP5:
        case OMAPDSS_VER_DRA7xx:
-               if (pclk < 62500) {
+               if (pclk < dcofreq_min) {
                        freqout = 0;
-               } else if ((pclk >= 62500) && (pclk < 185000)) {
+               } else if ((pclk >= dcofreq_min) && (pclk < 185000)) {
                        freqout = 1;
                } else {
                        /* clock frequency > 185MHz */