OSDN Git Service

drm/msm: add HPD notification and acknowledge support
authorRay Zhang <rayz@codeaurora.org>
Fri, 17 Feb 2017 09:46:34 +0000 (17:46 +0800)
committerRay Zhang <rayz@codeaurora.org>
Mon, 27 Feb 2017 04:33:31 +0000 (12:33 +0800)
In HPD case the HDMI driver communicate with external display
module by specific notification and acknowledge interfaces.
Add this support to enable the communication.

CRs-Fixed: 2010135
Change-Id: I24ac1e0f0cb1e3946e2a53e4bf72bafbd84e4395
Signed-off-by: Ray Zhang <rayz@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 dd1ec46..a030af0 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/of_platform.h>
 
 #include "sde_kms.h"
+#include "sde_connector.h"
 #include "msm_drv.h"
 #include "sde_hdmi.h"
 
@@ -404,6 +405,8 @@ static void _sde_hdmi_hotplug_work(struct work_struct *work)
 
        connector = sde_hdmi->ctrl.ctrl->connector;
        drm_helper_hpd_irq_event(connector->dev);
+
+       sde_hdmi_notify_clients(connector, connector->status);
 }
 
 static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi)
@@ -569,6 +572,41 @@ static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display)
        return rc;
 }
 
+void sde_hdmi_notify_clients(struct drm_connector *connector,
+       enum drm_connector_status status)
+{
+       struct sde_connector *c_conn = to_sde_connector(connector);
+       struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
+       int state = (status == connector_status_connected) ?
+               EXT_DISPLAY_CABLE_CONNECT : EXT_DISPLAY_CABLE_DISCONNECT;
+
+       if (display && display->ext_audio_data.intf_ops.hpd) {
+               struct hdmi *hdmi = display->ctrl.ctrl;
+               u32 flags = MSM_EXT_DISP_HPD_VIDEO;
+
+               if (hdmi->hdmi_mode)
+                       flags |= MSM_EXT_DISP_HPD_AUDIO;
+
+               display->ext_audio_data.intf_ops.hpd(display->ext_pdev,
+                               display->ext_audio_data.type, state, flags);
+       }
+}
+
+void sde_hdmi_ack_state(struct drm_connector *connector,
+       enum drm_connector_status status)
+{
+       struct sde_connector *c_conn = to_sde_connector(connector);
+       struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
+
+       if (display) {
+               struct hdmi *hdmi = display->ctrl.ctrl;
+
+               if (hdmi->hdmi_mode && display->ext_audio_data.intf_ops.notify)
+                       display->ext_audio_data.intf_ops.notify(
+                               display->ext_pdev, status);
+       }
+}
+
 void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
 {
        uint32_t ctrl = 0;
index 696752d..1004959 100644 (file)
@@ -271,6 +271,27 @@ void sde_hdmi_audio_off(struct hdmi *hdmi);
  * Return: error code.
  */
 int sde_hdmi_config_avmute(struct hdmi *hdmi, bool set);
+
+/**
+ * sde_hdmi_notify_clients() - notify hdmi clients of the connection status.
+ * @connector:     Handle to the drm_connector.
+ * @status:        connection status.
+ *
+ * Return: void.
+ */
+void sde_hdmi_notify_clients(struct drm_connector *connector,
+       enum drm_connector_status status);
+
+/**
+ * sde_hdmi_ack_state() - acknowledge the connection status.
+ * @connector:     Handle to the drm_connector.
+ * @status:        connection status.
+ *
+ * Return: void.
+ */
+void sde_hdmi_ack_state(struct drm_connector *connector,
+       enum drm_connector_status status);
+
 #else /*#ifdef CONFIG_DRM_SDE_HDMI*/
 
 static inline u32 sde_hdmi_get_num_of_displays(void)
index 7d3871c..681dca5 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "drm_edid.h"
 #include "sde_kms.h"
+#include "sde_connector.h"
 #include "sde_hdmi.h"
 #include "hdmi.h"
 
@@ -120,14 +121,42 @@ 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);
+
+       sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_CONNECT);
+}
+
+static void sde_hdmi_force_update_audio(struct drm_connector *connector,
+       enum drm_connector_status status)
+{
+       struct sde_connector *c_conn = to_sde_connector(connector);
+       struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
+
+       if (display && display->non_pluggable) {
+               display->ext_audio_data.intf_ops.hpd(display->ext_pdev,
+                               display->ext_audio_data.type,
+                               status,
+                               MSM_EXT_DISP_HPD_AUDIO);
+       }
 }
 
 static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge)
 {
+       struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
+       struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
+
+       /* force update audio ops when there's no HPD event */
+       sde_hdmi_force_update_audio(hdmi->connector,
+               EXT_DISPLAY_CABLE_CONNECT);
 }
 
 static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge)
 {
+       struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
+       struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
+
+       /* force update audio ops when there's no HPD event */
+       sde_hdmi_force_update_audio(hdmi->connector,
+               EXT_DISPLAY_CABLE_DISCONNECT);
 }
 
 static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
@@ -151,6 +180,8 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
                _sde_hdmi_bridge_power_off(bridge);
                hdmi->power_on = false;
        }
+
+       sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_DISCONNECT);
 }
 
 static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi,