summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h1
-rw-r--r--drivers/video/tegra/dc/dc.c26
2 files changed, 27 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index caca9d84c1be..4137a8f11017 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -324,6 +324,7 @@ struct tegra_dc_out {
int dcc_bus;
int hotplug_gpio;
const char *parent_clk;
+ const char *parent_clk_backup;
unsigned max_pixclock;
unsigned order;
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 951e8caaff2e..45962baa9fce 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -1362,6 +1362,21 @@ static unsigned long tegra_dc_pclk_round_rate(struct tegra_dc *dc, int pclk)
return rate * 2 / div;
}
+static unsigned long tegra_dc_pclk_predict_rate(struct clk *parent, int pclk)
+{
+ unsigned long rate;
+ unsigned long div;
+
+ rate = clk_get_rate(parent);
+
+ div = DIV_ROUND_CLOSEST(rate * 2, pclk);
+
+ if (div < 2)
+ return 0;
+
+ return rate * 2 / div;
+}
+
void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
{
int pclk;
@@ -1371,6 +1386,17 @@ void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
struct clk *parent_clk =
clk_get_sys(NULL, dc->out->parent_clk ? : "pll_p");
+ if (dc->out->parent_clk_backup &&
+ (parent_clk == clk_get_sys(NULL, "pll_p"))) {
+ rate = tegra_dc_pclk_predict_rate(
+ parent_clk, dc->mode.pclk);
+ /* use pll_d as last resort */
+ if (rate < (dc->mode.pclk / 100 * 99) ||
+ rate > (dc->mode.pclk / 100 * 109))
+ parent_clk = clk_get_sys(
+ NULL, dc->out->parent_clk_backup);
+ }
+
if (clk_get_parent(clk) != parent_clk)
clk_set_parent(clk, parent_clk);