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