Implement necessary glue code to let DRM bridge drivers to implement CEC
adapters support.

Signed-off-by: Dmitry Baryshkov <dmitry.barysh...@linaro.org>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 93 ++++++++++++++++++++++++++
 include/drm/drm_bridge.h                       | 21 ++++++
 2 files changed, 114 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c 
b/drivers/gpu/drm/display/drm_bridge_connector.c
index 
9f234bc647d5c0880d4c42aea130074b7fa54573..5b77fd59d79abddd419e611a7868b001857ccb37
 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -9,6 +9,8 @@
 #include <linux/property.h>
 #include <linux/slab.h>
 
+#include <media/cec.h>
+
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_bridge_connector.h>
@@ -497,6 +499,82 @@ static const struct drm_connector_hdmi_audio_funcs 
drm_bridge_connector_hdmi_aud
        .mute_stream = drm_bridge_connector_audio_mute_stream,
 };
 
+static int drm_bridge_connector_hdmi_cec_enable(struct drm_connector 
*connector, bool enable)
+{
+       struct drm_bridge_connector *bridge_connector =
+               to_drm_bridge_connector(connector);
+       struct drm_bridge *bridge;
+
+       bridge = bridge_connector->bridge_hdmi;
+
+       return bridge->funcs->hdmi_cec_enable(bridge, enable);
+}
+
+static int drm_bridge_connector_hdmi_cec_log_addr(struct drm_connector 
*connector, u8 logical_addr)
+{
+       struct drm_bridge_connector *bridge_connector =
+               to_drm_bridge_connector(connector);
+       struct drm_bridge *bridge;
+
+       bridge = bridge_connector->bridge_hdmi;
+
+       return bridge->funcs->hdmi_cec_log_addr(bridge, logical_addr);
+}
+
+static int drm_bridge_connector_hdmi_cec_transmit(struct drm_connector 
*connector,
+                                                 u8 attempts,
+                                                 u32 signal_free_time,
+                                                 struct cec_msg *msg)
+{
+       struct drm_bridge_connector *bridge_connector =
+               to_drm_bridge_connector(connector);
+       struct drm_bridge *bridge;
+
+       bridge = bridge_connector->bridge_hdmi;
+
+       return bridge->funcs->hdmi_cec_transmit(bridge, attempts,
+                                               signal_free_time,
+                                               msg);
+}
+
+static int drm_bridge_connector_hdmi_cec_init(struct drm_connector *connector)
+{
+       struct drm_bridge_connector *bridge_connector =
+               to_drm_bridge_connector(connector);
+       struct drm_bridge *bridge;
+
+       bridge = bridge_connector->bridge_hdmi;
+
+       drm_bridge_cec_data_set(bridge, connector);
+
+       if (!bridge->funcs->hdmi_cec_init)
+               return 0;
+
+       return bridge->funcs->hdmi_cec_init(connector, bridge);
+}
+
+static void drm_bridge_connector_hdmi_cec_unregister(struct drm_connector 
*connector)
+{
+       struct drm_bridge_connector *bridge_connector =
+               to_drm_bridge_connector(connector);
+       struct drm_bridge *bridge;
+
+       bridge = bridge_connector->bridge_hdmi;
+
+       drm_bridge_cec_data_set(bridge, NULL);
+
+       drm_connector_hdmi_cec_unregister(connector);
+}
+
+static const struct drm_connector_hdmi_cec_adapter_ops 
drm_bridge_connector_hdmi_cec_ops = {
+       .base.unregister = drm_bridge_connector_hdmi_cec_unregister,
+       .init = drm_bridge_connector_hdmi_cec_init,
+       .enable = drm_bridge_connector_hdmi_cec_enable,
+       .log_addr = drm_bridge_connector_hdmi_cec_log_addr,
+       .transmit = drm_bridge_connector_hdmi_cec_transmit,
+};
+
+
 /* 
-----------------------------------------------------------------------------
  * Bridge Connector Initialisation
  */
@@ -633,6 +711,21 @@ struct drm_connector *drm_bridge_connector_init(struct 
drm_device *drm,
                        if (ret)
                                return ERR_PTR(ret);
                }
+
+               if (bridge->hdmi_cec_adapter_name) {
+                       if (!bridge->funcs->hdmi_cec_enable ||
+                           !bridge->funcs->hdmi_cec_log_addr ||
+                           !bridge->funcs->hdmi_cec_transmit)
+                               return ERR_PTR(-EINVAL);
+
+                       ret = drm_connector_hdmi_cec_register(connector,
+                                                             
&drm_bridge_connector_hdmi_cec_ops,
+                                                             
bridge->hdmi_cec_adapter_name,
+                                                             
bridge->hdmi_cec_available_las,
+                                                             bridge->hdmi_dev);
+                       if (ret)
+                               return ERR_PTR(ret);
+               }
        } else {
                ret = drmm_connector_init(drm, connector,
                                          &drm_bridge_connector_funcs,
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 
df1d72c7e176c75585283684acc2ef2ffb2f8bff..b55e80a57758e8b652eac0cd01cb245a04e221f5
 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -32,6 +32,7 @@
 #include <drm/drm_mode_object.h>
 #include <drm/drm_modes.h>
 
+struct cec_msg;
 struct device_node;
 
 struct drm_bridge;
@@ -729,6 +730,16 @@ struct drm_bridge_funcs {
                                      struct drm_bridge *bridge,
                                      bool enable, int direction);
 
+       int (*hdmi_cec_init)(struct drm_connector *connector,
+                            struct drm_bridge *bridge);
+
+       int (*hdmi_cec_enable)(struct drm_bridge *bridge, bool enable);
+
+       int (*hdmi_cec_log_addr)(struct drm_bridge *bridge, u8 logical_addr);
+
+       int (*hdmi_cec_transmit)(struct drm_bridge *bridge, u8 attempts,
+                                u32 signal_free_time, struct cec_msg *msg);
+
        /**
         * @debugfs_init:
         *
@@ -924,6 +935,16 @@ struct drm_bridge {
         */
        bool hdmi_cec_notifier;
 
+       /**
+        * @hdmi_cec_adapter_name: the name of the adapter to register
+        */
+       const char *hdmi_cec_adapter_name;
+
+       /**
+        * @hdmi_cec_available_las: number of logical addresses, 
CEC_MAX_LOG_ADDRS if unset
+        */
+       u8 hdmi_cec_available_las;
+
        /** private: */
        /**
         * @hpd_mutex: Protects the @hpd_cb and @hpd_data fields.

-- 
2.39.5

Reply via email to