Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/display: bridge-connector: handle CEC adapters

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

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Link: https://lore.kernel.org/r/20250517-drm-hdmi-connector-cec-v6-9-35651db6f19b@oss.qualcomm.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>

+109
+1
drivers/gpu/drm/display/Kconfig
··· 17 17 config DRM_BRIDGE_CONNECTOR 18 18 bool 19 19 select DRM_DISPLAY_HDMI_AUDIO_HELPER 20 + select DRM_DISPLAY_HDMI_CEC_HELPER 20 21 select DRM_DISPLAY_HDMI_STATE_HELPER 21 22 help 22 23 DRM connector implementation terminating DRM bridge chains.
+82
drivers/gpu/drm/display/drm_bridge_connector.c
··· 554 554 .mute_stream = drm_bridge_connector_audio_mute_stream, 555 555 }; 556 556 557 + static int drm_bridge_connector_hdmi_cec_enable(struct drm_connector *connector, bool enable) 558 + { 559 + struct drm_bridge_connector *bridge_connector = 560 + to_drm_bridge_connector(connector); 561 + struct drm_bridge *bridge; 562 + 563 + bridge = bridge_connector->bridge_hdmi_cec; 564 + 565 + return bridge->funcs->hdmi_cec_enable(bridge, enable); 566 + } 567 + 568 + static int drm_bridge_connector_hdmi_cec_log_addr(struct drm_connector *connector, u8 logical_addr) 569 + { 570 + struct drm_bridge_connector *bridge_connector = 571 + to_drm_bridge_connector(connector); 572 + struct drm_bridge *bridge; 573 + 574 + bridge = bridge_connector->bridge_hdmi_cec; 575 + 576 + return bridge->funcs->hdmi_cec_log_addr(bridge, logical_addr); 577 + } 578 + 579 + static int drm_bridge_connector_hdmi_cec_transmit(struct drm_connector *connector, 580 + u8 attempts, 581 + u32 signal_free_time, 582 + struct cec_msg *msg) 583 + { 584 + struct drm_bridge_connector *bridge_connector = 585 + to_drm_bridge_connector(connector); 586 + struct drm_bridge *bridge; 587 + 588 + bridge = bridge_connector->bridge_hdmi_cec; 589 + 590 + return bridge->funcs->hdmi_cec_transmit(bridge, attempts, 591 + signal_free_time, 592 + msg); 593 + } 594 + 595 + static int drm_bridge_connector_hdmi_cec_init(struct drm_connector *connector) 596 + { 597 + struct drm_bridge_connector *bridge_connector = 598 + to_drm_bridge_connector(connector); 599 + struct drm_bridge *bridge; 600 + 601 + bridge = bridge_connector->bridge_hdmi_cec; 602 + 603 + if (!bridge->funcs->hdmi_cec_init) 604 + return 0; 605 + 606 + return bridge->funcs->hdmi_cec_init(connector, bridge); 607 + } 608 + 609 + static const struct drm_connector_hdmi_cec_funcs drm_bridge_connector_hdmi_cec_funcs = { 610 + .init = drm_bridge_connector_hdmi_cec_init, 611 + .enable = drm_bridge_connector_hdmi_cec_enable, 612 + .log_addr = drm_bridge_connector_hdmi_cec_log_addr, 613 + .transmit = drm_bridge_connector_hdmi_cec_transmit, 614 + }; 615 + 557 616 /* ----------------------------------------------------------------------------- 558 617 * Bridge Connector Initialisation 559 618 */ ··· 736 677 bridge_connector->bridge_hdmi_cec = bridge; 737 678 } 738 679 680 + if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) { 681 + if (bridge_connector->bridge_hdmi_cec) 682 + return ERR_PTR(-EBUSY); 683 + 684 + bridge_connector->bridge_hdmi_cec = bridge; 685 + 686 + if (!bridge->funcs->hdmi_cec_enable || 687 + !bridge->funcs->hdmi_cec_log_addr || 688 + !bridge->funcs->hdmi_cec_transmit) 689 + return ERR_PTR(-EINVAL); 690 + } 691 + 739 692 if (!drm_bridge_get_next_bridge(bridge)) 740 693 connector_type = bridge->type; 741 694 ··· 815 744 ret = drmm_connector_hdmi_cec_notifier_register(connector, 816 745 NULL, 817 746 bridge->hdmi_cec_dev); 747 + if (ret) 748 + return ERR_PTR(ret); 749 + } 750 + 751 + if (bridge_connector->bridge_hdmi_cec && 752 + bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) { 753 + ret = drmm_connector_hdmi_cec_register(connector, 754 + &drm_bridge_connector_hdmi_cec_funcs, 755 + bridge->hdmi_cec_adapter_name, 756 + bridge->hdmi_cec_available_las, 757 + bridge->hdmi_cec_dev); 818 758 if (ret) 819 759 return ERR_PTR(ret); 820 760 }
+26
include/drm/drm_bridge.h
··· 32 32 #include <drm/drm_mode_object.h> 33 33 #include <drm/drm_modes.h> 34 34 35 + struct cec_msg; 35 36 struct device_node; 36 37 37 38 struct drm_bridge; ··· 738 737 struct drm_bridge *bridge, 739 738 bool enable, int direction); 740 739 740 + int (*hdmi_cec_init)(struct drm_connector *connector, 741 + struct drm_bridge *bridge); 742 + 743 + int (*hdmi_cec_enable)(struct drm_bridge *bridge, bool enable); 744 + 745 + int (*hdmi_cec_log_addr)(struct drm_bridge *bridge, u8 logical_addr); 746 + 747 + int (*hdmi_cec_transmit)(struct drm_bridge *bridge, u8 attempts, 748 + u32 signal_free_time, struct cec_msg *msg); 749 + 741 750 /** 742 751 * @dp_audio_startup: 743 752 * ··· 923 912 * to be present. 924 913 */ 925 914 DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER = BIT(7), 915 + /** 916 + * @DRM_BRIDGE_OP_HDMI_CEC_ADAPTER: The bridge requires CEC notifier 917 + * to be present. 918 + */ 919 + DRM_BRIDGE_OP_HDMI_CEC_ADAPTER = BIT(8), 926 920 }; 927 921 928 922 /** ··· 1063 1047 * not used. 1064 1048 */ 1065 1049 int hdmi_audio_dai_port; 1050 + 1051 + /** 1052 + * @hdmi_cec_adapter_name: the name of the adapter to register 1053 + */ 1054 + const char *hdmi_cec_adapter_name; 1055 + 1056 + /** 1057 + * @hdmi_cec_available_las: number of logical addresses, CEC_MAX_LOG_ADDRS if unset 1058 + */ 1059 + u8 hdmi_cec_available_las; 1066 1060 1067 1061 /** private: */ 1068 1062 /**