diff options
author | Thierry Reding <treding@nvidia.com> | 2015-08-03 08:23:29 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2016-07-01 08:42:01 -0400 |
commit | 25bb2cec88401a512c01adc8b815f8a579da2558 (patch) | |
tree | f8d68ae61a35be1c4af1d2308a0e257c4573efbf | |
parent | 0751bb5c44fe1aa9494ce259d974c3d249b73a84 (diff) |
drm/tegra: sor: Factor out tegra_sor_set_parent_clock()
Switching the SOR parent clock can glitch if done while the clock is
enabled. Extract a common function that can be used to disable the
module clock, switch the parent and reenable the module clock.
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/gpu/drm/tegra/sor.c | 35 |
1 files changed, 28 insertions, 7 deletions
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 757c6e8603af..ed03a1f5b692 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c | |||
@@ -225,6 +225,23 @@ static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value, | |||
225 | writel(value, sor->regs + (offset << 2)); | 225 | writel(value, sor->regs + (offset << 2)); |
226 | } | 226 | } |
227 | 227 | ||
228 | static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent) | ||
229 | { | ||
230 | int err; | ||
231 | |||
232 | clk_disable_unprepare(sor->clk); | ||
233 | |||
234 | err = clk_set_parent(sor->clk, parent); | ||
235 | if (err < 0) | ||
236 | return err; | ||
237 | |||
238 | err = clk_prepare_enable(sor->clk); | ||
239 | if (err < 0) | ||
240 | return err; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
228 | static int tegra_sor_dp_train_fast(struct tegra_sor *sor, | 245 | static int tegra_sor_dp_train_fast(struct tegra_sor *sor, |
229 | struct drm_dp_link *link) | 246 | struct drm_dp_link *link) |
230 | { | 247 | { |
@@ -733,7 +750,8 @@ static int tegra_sor_power_down(struct tegra_sor *sor) | |||
733 | if ((value & SOR_PWR_TRIGGER) != 0) | 750 | if ((value & SOR_PWR_TRIGGER) != 0) |
734 | return -ETIMEDOUT; | 751 | return -ETIMEDOUT; |
735 | 752 | ||
736 | err = clk_set_parent(sor->clk, sor->clk_safe); | 753 | /* switch to safe parent clock */ |
754 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | ||
737 | if (err < 0) | 755 | if (err < 0) |
738 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); | 756 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); |
739 | 757 | ||
@@ -1219,7 +1237,8 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1219 | return; | 1237 | return; |
1220 | } | 1238 | } |
1221 | 1239 | ||
1222 | err = clk_set_parent(sor->clk, sor->clk_safe); | 1240 | /* switch to safe parent clock */ |
1241 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | ||
1223 | if (err < 0) | 1242 | if (err < 0) |
1224 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); | 1243 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); |
1225 | 1244 | ||
@@ -1326,10 +1345,10 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1326 | value &= ~SOR_PLL2_PORT_POWERDOWN; | 1345 | value &= ~SOR_PLL2_PORT_POWERDOWN; |
1327 | tegra_sor_writel(sor, value, SOR_PLL2); | 1346 | tegra_sor_writel(sor, value, SOR_PLL2); |
1328 | 1347 | ||
1329 | /* switch to DP clock */ | 1348 | /* switch to DP parent clock */ |
1330 | err = clk_set_parent(sor->clk, sor->clk_dp); | 1349 | err = tegra_sor_set_parent_clock(sor, sor->clk_dp); |
1331 | if (err < 0) | 1350 | if (err < 0) |
1332 | dev_err(sor->dev, "failed to set DP parent clock: %d\n", err); | 1351 | dev_err(sor->dev, "failed to set parent clock: %d\n", err); |
1333 | 1352 | ||
1334 | /* power DP lanes */ | 1353 | /* power DP lanes */ |
1335 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); | 1354 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); |
@@ -1781,7 +1800,8 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
1781 | 1800 | ||
1782 | reset_control_deassert(sor->rst); | 1801 | reset_control_deassert(sor->rst); |
1783 | 1802 | ||
1784 | err = clk_set_parent(sor->clk, sor->clk_safe); | 1803 | /* switch to safe parent clock */ |
1804 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | ||
1785 | if (err < 0) | 1805 | if (err < 0) |
1786 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); | 1806 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); |
1787 | 1807 | ||
@@ -1892,7 +1912,8 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
1892 | 1912 | ||
1893 | tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); | 1913 | tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); |
1894 | 1914 | ||
1895 | err = clk_set_parent(sor->clk, sor->clk_parent); | 1915 | /* switch to parent clock */ |
1916 | err = tegra_sor_set_parent_clock(sor, sor->clk_parent); | ||
1896 | if (err < 0) | 1917 | if (err < 0) |
1897 | dev_err(sor->dev, "failed to set parent clock: %d\n", err); | 1918 | dev_err(sor->dev, "failed to set parent clock: %d\n", err); |
1898 | 1919 | ||