OSDN Git Service

DRM: SDE: Update the hdmi bridge to handle HPD clock
authorCamus Wong <camusw@codeaurora.org>
Thu, 23 Nov 2017 23:03:21 +0000 (18:03 -0500)
committerGerrit - the friendly Code Review server <code-review@localhost>
Mon, 27 Nov 2017 22:37:29 +0000 (14:37 -0800)
For non-pluggable display, it should not enable HPD.  Instead, the
bridge should handle all the clocks for HDMI.  Also the scrambler
should be activated after the HDMI has power on the clock.

Change-Id: I9162a49b8f314de4d30b0d82c7867a639ddf05a6
Signed-off-by: Camus Wong <camusw@codeaurora.org>
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c

index 35ba396..f70a0ea 100644 (file)
@@ -1342,7 +1342,56 @@ fail:
        return ret;
 }
 
-static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi)
+int sde_hdmi_core_enable(struct sde_hdmi *sde_hdmi)
+{
+       struct hdmi *hdmi = sde_hdmi->ctrl.ctrl;
+       const struct hdmi_platform_config *config = hdmi->config;
+       struct device *dev = &hdmi->pdev->dev;
+       int i, ret;
+       struct drm_connector *connector;
+       struct msm_drm_private *priv;
+       struct sde_kms *sde_kms;
+
+       connector = hdmi->connector;
+       priv = connector->dev->dev_private;
+       sde_kms = to_sde_kms(priv->kms);
+
+       for (i = 0; i < config->hpd_reg_cnt; i++) {
+               ret = regulator_enable(hdmi->hpd_regs[i]);
+               if (ret) {
+                       SDE_ERROR("failed to enable hpd regulator: %s (%d)\n",
+                                       config->hpd_reg_names[i], ret);
+               }
+       }
+
+       ret = pinctrl_pm_select_default_state(dev);
+       if (ret)
+               SDE_ERROR("pinctrl state chg failed: %d\n", ret);
+
+       ret = _sde_hdmi_gpio_config(hdmi, true);
+       if (ret)
+               SDE_ERROR("failed to configure GPIOs: %d\n", ret);
+
+       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)
+                               pr_warn("failed to set clk %s (%d)\n",
+                                               config->hpd_clk_names[i], ret);
+               }
+
+               ret = clk_prepare_enable(hdmi->hpd_clks[i]);
+               if (ret) {
+                       SDE_ERROR("failed to enable hpd clk: %s (%d)\n",
+                                       config->hpd_clk_names[i], ret);
+               }
+       }
+
+       return ret;
+}
+
+static void _sde_hdmi_hpd_disable(struct sde_hdmi *sde_hdmi)
 {
        struct hdmi *hdmi = sde_hdmi->ctrl.ctrl;
        const struct hdmi_platform_config *config = hdmi->config;
@@ -1373,6 +1422,12 @@ static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi)
        }
 }
 
+void sde_hdmi_core_disable(struct sde_hdmi *sde_hdmi)
+{
+       /* HPD contains all the core clock and pwr */
+       _sde_hdmi_hpd_disable(sde_hdmi);
+}
+
 static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display)
 {
        struct edid *edid = display->edid_ctrl->edid;
@@ -2217,7 +2272,8 @@ int sde_hdmi_connector_pre_deinit(struct drm_connector *connector,
                return -EINVAL;
        }
 
-       _sde_hdmi_hdp_disable(sde_hdmi);
+       if (!sde_hdmi->non_pluggable)
+               _sde_hdmi_hpd_disable(sde_hdmi);
 
        return 0;
 }
@@ -2389,9 +2445,14 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector,
        INIT_WORK(&sde_hdmi->hpd_work, _sde_hdmi_hotplug_work);
 
        /* Enable HPD detection */
-       rc = _sde_hdmi_hpd_enable(sde_hdmi);
-       if (rc)
-               SDE_ERROR("failed to enable HPD: %d\n", rc);
+       if (!sde_hdmi->non_pluggable) {
+               rc = _sde_hdmi_hpd_enable(sde_hdmi);
+               if (rc)
+                       SDE_ERROR("failed to enable HPD: %d\n", rc);
+               } else {
+               /* Disable HPD interrupt */
+               hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
+       }
 
        _sde_hdmi_get_tx_version(sde_hdmi);
 
index 865998c..471472e 100644 (file)
@@ -302,6 +302,22 @@ sde_hdmi_connector_detect(struct drm_connector *connector,
                void *display);
 
 /**
+ * sde_hdmi_core_enable()- turn on clk and pwr for hdmi core
+ * @sde_hdmi: Pointer to sde_hdmi structure
+ *
+ * Return: error code
+ */
+int sde_hdmi_core_enable(struct sde_hdmi *sde_hdmi);
+
+/**
+ * sde_hdmi_core_disable()- turn off clk and pwr for hdmi core
+ * @sde_hdmi: Pointer to sde_hdmi structure
+ *
+ * Return: none
+ */
+void sde_hdmi_core_disable(struct sde_hdmi *sde_hdmi);
+
+/**
  * sde_hdmi_connector_get_modes - add drm modes via drm_mode_probed_add()
  * @connector: Pointer to drm connector structure
  * @display: Pointer to private display handle
index 5fbe476..01283aa 100644 (file)
@@ -106,6 +106,8 @@ struct sde_hdmi_bridge {
 #define HDMI_AVI_IFRAME_LINE_NUMBER 1
 #define HDMI_VENDOR_IFRAME_LINE_NUMBER 3
 
+static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi,
+                       struct drm_display_mode *mode);
 void _sde_hdmi_bridge_destroy(struct drm_bridge *bridge)
 {
 }
@@ -129,6 +131,8 @@ static void _sde_hdmi_bridge_power_on(struct drm_bridge *bridge)
        struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
        struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
        const struct hdmi_platform_config *config = hdmi->config;
+       struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
+       struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
        int i, ret;
 
        for (i = 0; i < config->pwr_reg_cnt; i++) {
@@ -155,6 +159,13 @@ static void _sde_hdmi_bridge_power_on(struct drm_bridge *bridge)
                                        config->pwr_clk_names[i], ret);
                }
        }
+
+       if (display->non_pluggable) {
+               ret = sde_hdmi_core_enable(display);
+               if (ret)
+                       SDE_ERROR("failed to enable hpd clks: %d\n", ret);
+       }
+       _sde_hdmi_bridge_setup_scrambler(hdmi, &display->mode);
 }
 
 static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge)
@@ -162,6 +173,8 @@ static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge)
        struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
        struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
        const struct hdmi_platform_config *config = hdmi->config;
+       struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
+       struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
        int i, ret;
 
        /* Wait for vsync */
@@ -177,6 +190,9 @@ static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge)
                                        config->pwr_reg_names[i], ret);
                }
        }
+
+       if (display->non_pluggable)
+               sde_hdmi_core_disable(display);
 }
 
 static int _sde_hdmi_bridge_ddc_clear_irq(struct hdmi *hdmi,
@@ -488,6 +504,9 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
        if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported)
                hdmi_hdcp_ctrl_on(hdmi->hdcp_ctrl);
 
+       /* turn on scrambler, scrambler was skipped if HDMI is off */
+       _sde_hdmi_bridge_setup_scrambler(hdmi, &display->mode);
+
        mutex_lock(&display->display_lock);
        if (display->codec_ready)
                sde_hdmi_notify_clients(display, display->connected);
@@ -896,7 +915,8 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
        }
 
        _sde_hdmi_save_mode(hdmi, mode);
-       _sde_hdmi_bridge_setup_scrambler(hdmi, mode);
+       if (hdmi->power_on)
+               _sde_hdmi_bridge_setup_scrambler(hdmi, mode);
        _sde_hdmi_bridge_setup_deep_color(hdmi);
 }