video: tegra3: dc: remove hard coded HDMI rates
Shashank Sharma [Mon, 27 Feb 2012 09:36:54 +0000 (14:36 +0530)]
Set dc clock rate dynamically to requested pixel rate.
Using modes specified in monitor's EDID data.
Return mode set errors on unsupported clock tolerances.

Bug 931908

Change-Id: I60990ecbc2fbeab542987036b8ccc30b8dababe8
Signed-off-by: Shashank Sharma <shashanks@nvidia.com>
Reviewed-on: http://git-master/r/86073
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

drivers/video/tegra/dc/dc.c

index ac024f6..3d09a13 100644 (file)
@@ -66,6 +66,8 @@
 
 static int no_vsync;
 
+static void _tegra_dc_controller_disable(struct tegra_dc *dc);
+
 module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR);
 
 static int use_dynamic_emc = 1;
@@ -1445,15 +1447,13 @@ void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
                        clk_get_sys(NULL, dc->out->parent_clk ? : "pll_d_out0");
                struct clk *base_clk = clk_get_parent(parent_clk);
 
-               /* needs to match tegra_dc_hdmi_supported_modes[]
-               and tegra_pll_d_freq_table[] */
-               if (dc->mode.pclk > 70000000)
-                       rate = 594000000;
-               else if (dc->mode.pclk > 25200000)
-                       rate = 216000000;
-               else
-                       rate = 504000000;
+               /*
+                * Providing dynamic frequency rate setting for T20/T30 HDMI.
+                * The required rate needs to be setup at 4x multiplier,
+                * as out0 is 1/2 of the actual PLL output.
+                */
 
+               rate = dc->mode.pclk * 4;
                if (rate != clk_get_rate(base_clk))
                        clk_set_rate(base_clk, rate);
 
@@ -2374,7 +2374,7 @@ static u32 get_syncpt(struct tegra_dc *dc, int idx)
        return syncpt_id;
 }
 
-static void tegra_dc_init(struct tegra_dc *dc)
+static int tegra_dc_init(struct tegra_dc *dc)
 {
        int i;
 
@@ -2440,15 +2440,20 @@ static void tegra_dc_init(struct tegra_dc *dc)
        print_mode(dc, &dc->mode, __func__);
 
        if (dc->mode.pclk)
-               tegra_dc_program_mode(dc, &dc->mode);
+               if (tegra_dc_program_mode(dc, &dc->mode))
+                       return -EINVAL;
 
        /* Initialize SD AFTER the modeset.
           nvsd_init handles the sd_settings = NULL case. */
        nvsd_init(dc, dc->out->sd_settings);
+
+       return 0;
 }
 
 static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
 {
+       int failed_init = 0;
+
        if (dc->out->enable)
                dc->out->enable();
 
@@ -2461,7 +2466,11 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
 
        enable_dc_irq(dc->irq);
 
-       tegra_dc_init(dc);
+       failed_init = tegra_dc_init(dc);
+       if (failed_init) {
+               _tegra_dc_controller_disable(dc);
+               return false;
+       }
 
        if (dc->out_ops && dc->out_ops->enable)
                dc->out_ops->enable(dc);
@@ -2480,6 +2489,8 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
 static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
 {
+       bool ret = true;
+
        if (dc->out->enable)
                dc->out->enable();
 
@@ -2512,7 +2523,10 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
 
        enable_dc_irq(dc->irq);
 
-       tegra_dc_init(dc);
+       if (tegra_dc_init(dc)) {
+               dev_err(&dc->ndev->dev, "cannot initialize\n");
+               ret = false;
+       }
 
        if (dc->out_ops && dc->out_ops->enable)
                dc->out_ops->enable(dc);
@@ -2525,7 +2539,12 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
 
        tegra_dc_ext_enable(dc->ext);
 
-       return true;
+       if (!ret) {
+               dev_err(&dc->ndev->dev, "initialization failed,disabling");
+               _tegra_dc_controller_disable(dc);
+       }
+
+       return ret;
 }
 #endif