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

Signed-off-by: Dmitry Baryshkov <dmitry.barysh...@linaro.org>
Signed-off-by: Dmitry Baryshkov <dmitry.barysh...@oss.qualcomm.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 83 ++++++++++++++++++++++++++
 include/drm/drm_bridge.h                       | 26 ++++++++
 2 files changed, 109 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c 
b/drivers/gpu/drm/display/drm_bridge_connector.c
index 
daf6117268d9d3bb0c0c12b5094e79ad13cf72dd..54b49be7837a174e0a25eec3395fd10d9c487c9e
 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -554,6 +554,66 @@ 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_cec;
+
+       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_cec;
+
+       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_cec;
+
+       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_cec;
+
+       if (!bridge->funcs->hdmi_cec_init)
+               return 0;
+
+       return bridge->funcs->hdmi_cec_init(connector, bridge);
+}
+
+static const struct drm_connector_hdmi_cec_funcs 
drm_bridge_connector_hdmi_cec_funcs = {
+       .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
  */
@@ -677,6 +737,18 @@ struct drm_connector *drm_bridge_connector_init(struct 
drm_device *drm,
                        bridge_connector->bridge_hdmi_cec = bridge;
                }
 
+               if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {
+                       if (bridge_connector->bridge_hdmi_cec)
+                               return ERR_PTR(-EBUSY);
+
+                       bridge_connector->bridge_hdmi_cec = bridge;
+
+                       if (!bridge->funcs->hdmi_cec_enable ||
+                           !bridge->funcs->hdmi_cec_log_addr ||
+                           !bridge->funcs->hdmi_cec_transmit)
+                               return ERR_PTR(-EINVAL);
+               }
+
                if (!drm_bridge_get_next_bridge(bridge))
                        connector_type = bridge->type;
 
@@ -748,6 +820,17 @@ struct drm_connector *drm_bridge_connector_init(struct 
drm_device *drm,
                        return ERR_PTR(ret);
        }
 
+       if (bridge_connector->bridge_hdmi_cec &&
+           bridge_connector->bridge_hdmi_cec->ops & 
DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {
+               ret = drm_connector_hdmi_cec_register(connector,
+                                                     
&drm_bridge_connector_hdmi_cec_funcs,
+                                                     
bridge->hdmi_cec_adapter_name,
+                                                     
bridge->hdmi_cec_available_las,
+                                                     bridge->hdmi_cec_dev);
+               if (ret)
+                       return ERR_PTR(ret);
+       }
+
        drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs);
 
        if (bridge_connector->bridge_hpd)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 
0e5f6a007d536215bd50e11846433290c2060b9c..cc9f7df38102e3c43913b35312f0ed5c4d8a7bd0
 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;
@@ -737,6 +738,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);
+
        /**
         * @dp_audio_startup:
         *
@@ -912,6 +923,11 @@ enum drm_bridge_ops {
         * to be present.
         */
        DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER = BIT(7),
+       /**
+        * @DRM_BRIDGE_OP_HDMI_CEC_ADAPTER: The bridge requires CEC notifier
+        * to be present.
+        */
+       DRM_BRIDGE_OP_HDMI_CEC_ADAPTER = BIT(8),
 };
 
 /**
@@ -1048,6 +1064,16 @@ struct drm_bridge {
         */
        int hdmi_audio_dai_port;
 
+       /**
+        * @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