drm/msm/hdmi: Set up runtime PM for HDMI
authorArchit Taneja <architt@codeaurora.org>
Fri, 28 Jul 2017 10:47:02 +0000 (16:17 +0530)
committerRob Clark <robdclark@gmail.com>
Wed, 2 Aug 2017 11:53:46 +0000 (07:53 -0400)
Enable rudimentary runtime PM in the HDMI driver. We can't really do
agressive PM toggling at the moment because we need to leave the hpd
clocks enabled all the time. There isn't much benefit of creating
suspend/resume ops to toggle clocks either.

We just make sure that we configure the power domain in the HDMI bridge's
enable/disable paths, and the HDMI connector's detect() op.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
drivers/gpu/drm/msm/hdmi/hdmi_connector.c

index a968cad509c2368b0699b184d1af1e58516dc84e..17e069a133a49bf714081e9eeee6c00154e10fda 100644 (file)
@@ -239,6 +239,8 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
                hdmi->pwr_clks[i] = clk;
        }
 
+       pm_runtime_enable(&pdev->dev);
+
        hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
 
        hdmi->i2c = msm_hdmi_i2c_init(hdmi);
index ae40e7179d4f5f21cbdef9401d68b2e09d954a7f..e9b5e886e7476bebff43a87b31c4faf421b70adc 100644 (file)
@@ -35,6 +35,8 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge)
        const struct hdmi_platform_config *config = hdmi->config;
        int i, ret;
 
+       pm_runtime_get_sync(&hdmi->pdev->dev);
+
        for (i = 0; i < config->pwr_reg_cnt; i++) {
                ret = regulator_enable(hdmi->pwr_regs[i]);
                if (ret) {
@@ -84,6 +86,8 @@ static void power_off(struct drm_bridge *bridge)
                                        config->pwr_reg_names[i], ret);
                }
        }
+
+       pm_runtime_put_autosuspend(&hdmi->pdev->dev);
 }
 
 #define AVI_IFRAME_LINE_NUMBER 1
index a2515b466ce51d771f7966e9e574deecd0bcdf19..c0e117179ecb3b9970bc0d6b2084c0d1e98bb07c 100644 (file)
@@ -137,6 +137,36 @@ err:
        return ret;
 }
 
+static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
+{
+       const struct hdmi_platform_config *config = hdmi->config;
+       struct device *dev = &hdmi->pdev->dev;
+       int i, ret;
+
+       if (enable) {
+               for (i = 0; i < config->hpd_clk_cnt; i++) {
+                       if (config->hpd_freq && config->hpd_freq[i]) {
+                               ret = clk_set_rate(hdmi->hpd_clks[i],
+                                                  config->hpd_freq[i]);
+                               if (ret)
+                                       dev_warn(dev,
+                                                "failed to set clk %s (%d)\n",
+                                                config->hpd_clk_names[i], ret);
+                       }
+
+                       ret = clk_prepare_enable(hdmi->hpd_clks[i]);
+                       if (ret) {
+                               dev_err(dev,
+                                       "failed to enable hpd clk: %s (%d)\n",
+                                       config->hpd_clk_names[i], ret);
+                       }
+               }
+       } else {
+               for (i = config->hpd_clk_cnt - 1; i >= 0; i--)
+                       clk_disable_unprepare(hdmi->hpd_clks[i]);
+       }
+}
+
 static int hpd_enable(struct hdmi_connector *hdmi_connector)
 {
        struct hdmi *hdmi = hdmi_connector->hdmi;
@@ -167,22 +197,8 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
                goto fail;
        }
 
-       for (i = 0; i < config->hpd_clk_cnt; i++) {
-               if (config->hpd_freq && config->hpd_freq[i]) {
-                       ret = clk_set_rate(hdmi->hpd_clks[i],
-                                       config->hpd_freq[i]);
-                       if (ret)
-                               dev_warn(dev, "failed to set clk %s (%d)\n",
-                                               config->hpd_clk_names[i], ret);
-               }
-
-               ret = clk_prepare_enable(hdmi->hpd_clks[i]);
-               if (ret) {
-                       dev_err(dev, "failed to enable hpd clk: %s (%d)\n",
-                                       config->hpd_clk_names[i], ret);
-                       goto fail;
-               }
-       }
+       pm_runtime_get_sync(dev);
+       enable_hpd_clocks(hdmi, true);
 
        msm_hdmi_set_mode(hdmi, false);
        msm_hdmi_phy_reset(hdmi);
@@ -225,8 +241,8 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector)
 
        msm_hdmi_set_mode(hdmi, false);
 
-       for (i = 0; i < config->hpd_clk_cnt; i++)
-               clk_disable_unprepare(hdmi->hpd_clks[i]);
+       enable_hpd_clocks(hdmi, false);
+       pm_runtime_put_autosuspend(dev);
 
        ret = gpio_config(hdmi, false);
        if (ret)
@@ -285,7 +301,16 @@ void msm_hdmi_connector_irq(struct drm_connector *connector)
 
 static enum drm_connector_status detect_reg(struct hdmi *hdmi)
 {
-       uint32_t hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
+       uint32_t hpd_int_status;
+
+       pm_runtime_get_sync(&hdmi->pdev->dev);
+       enable_hpd_clocks(hdmi, true);
+
+       hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
+
+       enable_hpd_clocks(hdmi, false);
+       pm_runtime_put_autosuspend(&hdmi->pdev->dev);
+
        return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
                        connector_status_connected : connector_status_disconnected;
 }