From: Thierry Reding Date: Fri, 7 Aug 2015 14:04:54 +0000 (+0200) Subject: drm/tegra: sor: Implement runtime PM X-Git-Tag: v4.8-rc1~62^2~15^2~7 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=aaff8bd2e824b6256e6cc1bd4eb3714de0683996;p=linux.git drm/tegra: sor: Implement runtime PM Use runtime PM to clock-(un)gate and (de)assert reset to the SOR controller. This ties in nicely with atomic DPMS in that a runtime PM reference is taken before a pipe is enabled and dropped after it has been shut down. Signed-off-by: Thierry Reding --- diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 8c893b6c6a4c..1eb19ca9fea4 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -1331,8 +1332,7 @@ static void tegra_sor_edp_disable(struct drm_encoder *encoder) if (output->panel) drm_panel_unprepare(output->panel); - reset_control_assert(sor->rst); - clk_disable_unprepare(sor->clk); + pm_runtime_put(sor->dev); } #if 0 @@ -1393,11 +1393,7 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) state = to_sor_state(output->connector.state); - err = clk_prepare_enable(sor->clk); - if (err < 0) - dev_err(sor->dev, "failed to enable clock: %d\n", err); - - reset_control_deassert(sor->rst); + pm_runtime_get_sync(sor->dev); if (output->panel) drm_panel_prepare(output->panel); @@ -1874,9 +1870,7 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) if (err < 0) dev_err(sor->dev, "failed to power off HDMI rail: %d\n", err); - reset_control_assert(sor->rst); - usleep_range(1000, 2000); - clk_disable_unprepare(sor->clk); + pm_runtime_put(sor->dev); } static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) @@ -1895,13 +1889,7 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) state = to_sor_state(output->connector.state); mode = &encoder->crtc->state->adjusted_mode; - err = clk_prepare_enable(sor->clk); - if (err < 0) - dev_err(sor->dev, "failed to enable clock: %d\n", err); - - usleep_range(1000, 2000); - - reset_control_deassert(sor->rst); + pm_runtime_get_sync(sor->dev); /* switch to safe parent clock */ err = tegra_sor_set_parent_clock(sor, sor->clk_safe); @@ -2531,6 +2519,9 @@ static int tegra_sor_probe(struct platform_device *pdev) goto remove; } + platform_set_drvdata(pdev, sor); + pm_runtime_enable(&pdev->dev); + INIT_LIST_HEAD(&sor->client.list); sor->client.ops = &sor_client_ops; sor->client.dev = &pdev->dev; @@ -2542,8 +2533,6 @@ static int tegra_sor_probe(struct platform_device *pdev) goto remove; } - platform_set_drvdata(pdev, sor); - return 0; remove: @@ -2559,6 +2548,8 @@ static int tegra_sor_remove(struct platform_device *pdev) struct tegra_sor *sor = platform_get_drvdata(pdev); int err; + pm_runtime_disable(&pdev->dev); + err = host1x_client_unregister(&sor->client); if (err < 0) { dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", @@ -2577,10 +2568,58 @@ static int tegra_sor_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int tegra_sor_suspend(struct device *dev) +{ + struct tegra_sor *sor = dev_get_drvdata(dev); + int err; + + err = reset_control_assert(sor->rst); + if (err < 0) { + dev_err(dev, "failed to assert reset: %d\n", err); + return err; + } + + usleep_range(1000, 2000); + + clk_disable_unprepare(sor->clk); + + return 0; +} + +static int tegra_sor_resume(struct device *dev) +{ + struct tegra_sor *sor = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(sor->clk); + if (err < 0) { + dev_err(dev, "failed to enable clock: %d\n", err); + return err; + } + + usleep_range(1000, 2000); + + err = reset_control_deassert(sor->rst); + if (err < 0) { + dev_err(dev, "failed to deassert reset: %d\n", err); + clk_disable_unprepare(sor->clk); + return err; + } + + return 0; +} +#endif + +static const struct dev_pm_ops tegra_sor_pm_ops = { + SET_RUNTIME_PM_OPS(tegra_sor_suspend, tegra_sor_resume, NULL) +}; + struct platform_driver tegra_sor_driver = { .driver = { .name = "tegra-sor", .of_match_table = tegra_sor_of_match, + .pm = &tegra_sor_pm_ops, }, .probe = tegra_sor_probe, .remove = tegra_sor_remove,