@@ -82,6 +82,11 @@ config DRM_DISPLAY_HDMI_AUDIO_HELPER
DRM display helpers for HDMI Audio functionality (generic HDMI Codec
implementation).
+config DRM_DISPLAY_HDMI_CEC_HELPER
+ bool
+ help
+ DRM display helpers for HDMI CEC implementation.
+
config DRM_DISPLAY_HDMI_HELPER
bool
help
@@ -16,6 +16,8 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_DSC_HELPER) += \
drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o
drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_AUDIO_HELPER) += \
drm_hdmi_audio_helper.o
+drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_CEC_HELPER) += \
+ drm_hdmi_cec_helper.o
drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \
drm_hdmi_helper.o \
drm_scdc_helper.o
new file mode 100644
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2024 Linaro Ltd
+ */
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
+#include <drm/display/drm_hdmi_cec_helper.h>
+
+#include <linux/mutex.h>
+
+#include <media/cec.h>
+#include <media/cec-notifier.h>
+
+static void drm_connector_hdmi_cec_adapter_unregister(struct drm_connector *connector)
+{
+ cec_unregister_adapter(connector->cec.adapter);
+ connector->cec.adapter = NULL;
+ connector->cec.unregister = NULL;
+}
+
+int drm_connector_hdmi_cec_adapter_register(struct drm_connector *connector,
+ const struct cec_adap_ops *ops,
+ const char *name,
+ u8 available_las,
+ int (*init_cec)(struct drm_connector *connector),
+ void (*uninit_cec)(struct drm_connector *connector),
+ struct device *dev)
+{
+ struct cec_connector_info conn_info;
+ struct cec_adapter *cec_adap;
+ int ret;
+
+ mutex_lock(&connector->cec.mutex);
+
+ if (connector->cec.unregister) {
+ ret = -EBUSY;
+ goto err_unlock;
+ }
+
+ cec_adap = cec_allocate_adapter(ops, connector, name,
+ CEC_CAP_DEFAULTS | CEC_CAP_CONNECTOR_INFO,
+ available_las);
+ ret = PTR_ERR_OR_ZERO(cec_adap);
+ if (ret < 0)
+ goto err_unlock;
+
+ cec_fill_conn_info_from_drm(&conn_info, connector);
+ cec_s_conn_info(cec_adap, &conn_info);
+
+ connector->cec.adapter = cec_adap;
+
+ ret = init_cec(connector);
+ if (ret < 0)
+ goto err_delete_adapter;
+
+ ret = cec_register_adapter(cec_adap, dev);
+ if (ret < 0)
+ goto err_delete_adapter;
+
+ connector->cec.unregister = drm_connector_hdmi_cec_adapter_unregister;
+ connector->cec.uninit_cec = uninit_cec;
+ mutex_unlock(&connector->cec.mutex);
+
+ return 0;
+
+err_delete_adapter:
+ cec_delete_adapter(cec_adap);
+
+ connector->cec.adapter = NULL;
+
+err_unlock:
+ mutex_unlock(&connector->cec.mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_connector_hdmi_cec_adapter_register);
+
+static void drm_connector_hdmi_cec_notifier_unregister(struct drm_connector *connector)
+{
+ cec_notifier_conn_unregister(connector->cec.notifier);
+ connector->cec.notifier = NULL;
+ connector->cec.unregister = NULL;
+}
+
+int drm_connector_hdmi_cec_notifier_register(struct drm_connector *connector,
+ const char *port_name,
+ struct device *dev)
+{
+ struct cec_connector_info conn_info;
+ struct cec_notifier *notifier;
+ int ret;
+
+ mutex_lock(&connector->cec.mutex);
+
+ if (connector->cec.unregister) {
+ ret = -EBUSY;
+ goto err_unlock;
+ }
+
+ cec_fill_conn_info_from_drm(&conn_info, connector);
+
+ notifier = cec_notifier_conn_register(dev, port_name, &conn_info);
+ if (!notifier) {
+ ret = -ENOMEM;
+ goto err_unlock;
+ }
+
+ connector->cec.notifier = notifier;
+ connector->cec.unregister = drm_connector_hdmi_cec_notifier_unregister;
+
+ mutex_unlock(&connector->cec.mutex);
+
+ return 0;
+
+err_unlock:
+ mutex_unlock(&connector->cec.mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_connector_hdmi_cec_notifier_register);
+
+void drm_connector_hdmi_cec_phys_addr_invalidate(struct drm_connector *connector)
+{
+ mutex_lock(&connector->cec.mutex);
+
+ cec_phys_addr_invalidate(connector->cec.adapter);
+ cec_notifier_phys_addr_invalidate(connector->cec.notifier);
+
+ mutex_unlock(&connector->cec.mutex);
+}
+EXPORT_SYMBOL(drm_connector_hdmi_cec_phys_addr_invalidate);
+
+void drm_connector_hdmi_cec_phys_addr_set(struct drm_connector *connector)
+{
+ mutex_lock(&connector->cec.mutex);
+
+ cec_s_phys_addr(connector->cec.adapter,
+ connector->display_info.source_physical_address, false);
+ cec_notifier_set_phys_addr(connector->cec.notifier,
+ connector->display_info.source_physical_address);
+
+ mutex_unlock(&connector->cec.mutex);
+}
+EXPORT_SYMBOL(drm_connector_hdmi_cec_phys_addr_set);
new file mode 100644
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef DRM_DISPLAY_HDMI_CEC_HELPER
+#define DRM_DISPLAY_HDMI_CEC_HELPER
+
+#include <linux/types.h>
+
+struct drm_connector;
+
+struct cec_adap_ops;
+struct cec_adapter;
+struct device;
+
+int drm_connector_hdmi_cec_adapter_register(struct drm_connector *connector,
+ const struct cec_adap_ops *ops,
+ const char *name,
+ u8 available_las,
+ int (*init_cec)(struct drm_connector *connector),
+ void (*uninit_cec)(struct drm_connector *connector),
+ struct device *dev);
+
+int drm_connector_hdmi_cec_notifier_register(struct drm_connector *connector,
+ const char *port_name,
+ struct device *dev);
+
+/*
+ * These functions are used by the state helper, so we end up linking to the
+ * same module. Define stubs to simplify the code.
+ */
+#ifdef CONFIG_DRM_DISPLAY_HDMI_CEC_HELPER
+void drm_connector_hdmi_cec_phys_addr_invalidate(struct drm_connector *connector);
+void drm_connector_hdmi_cec_phys_addr_set(struct drm_connector *connector);
+#else
+static inline void drm_connector_hdmi_cec_phys_addr_invalidate(struct drm_connector *connector) {}
+static inline void drm_connector_hdmi_cec_phys_addr_set(struct drm_connector *connector) {}
+#endif
+
+#endif
Add generic CEC helpers to be used by HDMI drivers. Both notifier and and adapter are supported for registration. Once registered, the driver can call common set of functions to update physical address, to invalidate it or to unregister CEC data. Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> --- drivers/gpu/drm/display/Kconfig | 5 + drivers/gpu/drm/display/Makefile | 2 + drivers/gpu/drm/display/drm_hdmi_cec_helper.c | 145 ++++++++++++++++++++++++++ include/drm/display/drm_hdmi_cec_helper.h | 38 +++++++ 4 files changed, 190 insertions(+)