diff options
Diffstat (limited to '')
-rw-r--r-- | drivers/gpu/drm/display/Kconfig | 52 | ||||
-rw-r--r-- | drivers/gpu/drm/display/Makefile | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/display/drm_dp_helper.c | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/display/drm_dp_helper_internal.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/display/drm_dp_mst_topology.c | 46 | ||||
-rw-r--r-- | drivers/gpu/drm/display/drm_dp_mst_topology_internal.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/display/drm_dp_tunnel.c | 17 |
7 files changed, 116 insertions, 52 deletions
diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig index c0f56888c3..864a6488bf 100644 --- a/drivers/gpu/drm/display/Kconfig +++ b/drivers/gpu/drm/display/Kconfig @@ -1,15 +1,36 @@ # SPDX-License-Identifier: MIT -config DRM_DP_AUX_BUS +config DRM_DISPLAY_HELPER tristate depends on DRM - depends on OF || COMPILE_TEST + help + DRM helpers for display adapters. -config DRM_DISPLAY_HELPER +config DRM_DISPLAY_DP_AUX_BUS tristate depends on DRM + depends on OF || COMPILE_TEST + +config DRM_DISPLAY_DP_AUX_CEC + bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support" + depends on DRM && DRM_DISPLAY_HELPER + select DRM_DISPLAY_DP_HELPER + select CEC_CORE help - DRM helpers for display adapters. + Choose this option if you want to enable HDMI CEC support for + DisplayPort/USB-C to HDMI adapters. + + Note: not all adapters support this feature, and even for those + that do support this they often do not hook up the CEC pin. + +config DRM_DISPLAY_DP_AUX_CHARDEV + bool "DRM DP AUX Interface" + depends on DRM && DRM_DISPLAY_HELPER + select DRM_DISPLAY_DP_HELPER + help + Choose this option to enable a /dev/drm_dp_auxN node that allows to + read and write values to arbitrary DPCD registers on the DP aux + channel. config DRM_DISPLAY_DP_HELPER bool @@ -25,7 +46,7 @@ config DRM_DISPLAY_DP_TUNNEL DP tunnel features like the Bandwidth Allocation mode to maximize the BW utilization for display streams on Thunderbolt links. -config DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE +config DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG bool "Enable debugging the DP tunnel state" depends on REF_TRACKER depends on DRM_DISPLAY_DP_TUNNEL @@ -49,24 +70,3 @@ config DRM_DISPLAY_HDMI_HELPER depends on DRM_DISPLAY_HELPER help DRM display helpers for HDMI. - -config DRM_DP_AUX_CHARDEV - bool "DRM DP AUX Interface" - depends on DRM && DRM_DISPLAY_HELPER - select DRM_DISPLAY_DP_HELPER - help - Choose this option to enable a /dev/drm_dp_auxN node that allows to - read and write values to arbitrary DPCD registers on the DP aux - channel. - -config DRM_DP_CEC - bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support" - depends on DRM && DRM_DISPLAY_HELPER - select DRM_DISPLAY_DP_HELPER - select CEC_CORE - help - Choose this option if you want to enable HDMI CEC support for - DisplayPort/USB-C to HDMI adapters. - - Note: not all adapters support this feature, and even for those - that do support this they often do not hook up the CEC pin. diff --git a/drivers/gpu/drm/display/Makefile b/drivers/gpu/drm/display/Makefile index 7ca61333c6..17d2cc73ff 100644 --- a/drivers/gpu/drm/display/Makefile +++ b/drivers/gpu/drm/display/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: MIT -obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o +obj-$(CONFIG_DRM_DISPLAY_DP_AUX_BUS) += drm_dp_aux_bus.o drm_display_helper-y := drm_display_helper_mod.o drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \ @@ -14,7 +14,7 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \ drm_hdmi_helper.o \ drm_scdc_helper.o -drm_display_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o -drm_display_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o +drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV) += drm_dp_aux_dev.o +drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_AUX_CEC) += drm_dp_cec.o obj-$(CONFIG_DRM_DISPLAY_HELPER) += drm_display_helper.o diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index f5d4be8978..79a615667a 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2113,7 +2113,7 @@ EXPORT_SYMBOL(drm_dp_aux_init); * drm_dp_aux_register() in &drm_connector_funcs.late_register, and likewise to * call drm_dp_aux_unregister() in &drm_connector_funcs.early_unregister. * Functions which don't follow this will likely Oops when - * %CONFIG_DRM_DP_AUX_CHARDEV is enabled. + * %CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV is enabled. * * For devices where the AUX channel is a device that exists independently of * the &drm_device that uses it, such as SoCs and bridge devices, it is @@ -2281,6 +2281,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = { { OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) }, /* Synaptics DP1.4 MST hubs require DSC for some modes on which it applies HBLANK expansion. */ { OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC) }, + /* MediaTek panels (at least in U3224KBA) require DSC for modes with a short HBLANK on UHBR links. */ + { OUI(0x00, 0x0C, 0xE7), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC) }, /* Apple MacBookPro 2017 15 inch eDP Retina panel reports too low DP_MAX_LINK_RATE */ { OUI(0x00, 0x10, 0xfa), DEVICE_ID(101, 68, 21, 101, 98, 97), false, BIT(DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS) }, }; @@ -2948,6 +2950,43 @@ void drm_dp_vsc_sdp_log(struct drm_printer *p, const struct drm_dp_vsc_sdp *vsc) } EXPORT_SYMBOL(drm_dp_vsc_sdp_log); +void drm_dp_as_sdp_log(struct drm_printer *p, const struct drm_dp_as_sdp *as_sdp) +{ + drm_printf(p, "DP SDP: AS_SDP, revision %u, length %u\n", + as_sdp->revision, as_sdp->length); + drm_printf(p, " vtotal: %d\n", as_sdp->vtotal); + drm_printf(p, " target_rr: %d\n", as_sdp->target_rr); + drm_printf(p, " duration_incr_ms: %d\n", as_sdp->duration_incr_ms); + drm_printf(p, " duration_decr_ms: %d\n", as_sdp->duration_decr_ms); + drm_printf(p, " operation_mode: %d\n", as_sdp->mode); +} +EXPORT_SYMBOL(drm_dp_as_sdp_log); + +/** + * drm_dp_as_sdp_supported() - check if adaptive sync sdp is supported + * @aux: DisplayPort AUX channel + * @dpcd: DisplayPort configuration data + * + * Returns true if adaptive sync sdp is supported, else returns false + */ +bool drm_dp_as_sdp_supported(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + u8 rx_feature; + + if (dpcd[DP_DPCD_REV] < DP_DPCD_REV_13) + return false; + + if (drm_dp_dpcd_readb(aux, DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1, + &rx_feature) != 1) { + drm_dbg_dp(aux->drm_dev, + "Failed to read DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1\n"); + return false; + } + + return (rx_feature & DP_ADAPTIVE_SYNC_SDP_SUPPORTED); +} +EXPORT_SYMBOL(drm_dp_as_sdp_supported); + /** * drm_dp_vsc_sdp_supported() - check if vsc sdp is supported * @aux: DisplayPort AUX channel diff --git a/drivers/gpu/drm/display/drm_dp_helper_internal.h b/drivers/gpu/drm/display/drm_dp_helper_internal.h index 8917fc3af9..737949a282 100644 --- a/drivers/gpu/drm/display/drm_dp_helper_internal.h +++ b/drivers/gpu/drm/display/drm_dp_helper_internal.h @@ -5,7 +5,7 @@ struct drm_dp_aux; -#ifdef CONFIG_DRM_DP_AUX_CHARDEV +#ifdef CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV int drm_dp_aux_dev_init(void); void drm_dp_aux_dev_exit(void); int drm_dp_aux_register_devnode(struct drm_dp_aux *aux); diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 95fd18f24e..68831f4e50 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -2274,7 +2274,7 @@ drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb, if (port->pdt != DP_PEER_DEVICE_NONE && drm_dp_mst_is_end_device(port->pdt, port->mcs) && - port->port_num >= DP_MST_LOGICAL_PORT_0) + drm_dp_mst_port_is_logical(port)) port->cached_edid = drm_edid_read_ddc(port->connector, &port->aux.ddc); @@ -2929,7 +2929,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, /* FIXME: Actually do some real error handling here */ ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); - if (ret <= 0) { + if (ret < 0) { drm_err(mgr->dev, "Sending link address failed with %d\n", ret); goto out; } @@ -2981,7 +2981,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, mutex_unlock(&mgr->lock); out: - if (ret <= 0) + if (ret < 0) mstb->link_address_sent = false; kfree(txmsg); return ret < 0 ? ret : changed; @@ -3606,24 +3606,30 @@ fixed20_12 drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, EXPORT_SYMBOL(drm_dp_get_vc_payload_bw); /** - * drm_dp_read_mst_cap() - check whether or not a sink supports MST + * drm_dp_read_mst_cap() - Read the sink's MST mode capability * @aux: The DP AUX channel to use * @dpcd: A cached copy of the DPCD capabilities for this sink * - * Returns: %True if the sink supports MST, %false otherwise + * Returns: enum drm_dp_mst_mode to indicate MST mode capability */ -bool drm_dp_read_mst_cap(struct drm_dp_aux *aux, - const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +enum drm_dp_mst_mode drm_dp_read_mst_cap(struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { u8 mstm_cap; if (dpcd[DP_DPCD_REV] < DP_DPCD_REV_12) - return false; + return DRM_DP_SST; if (drm_dp_dpcd_readb(aux, DP_MSTM_CAP, &mstm_cap) != 1) - return false; + return DRM_DP_SST; - return mstm_cap & DP_MST_CAP; + if (mstm_cap & DP_MST_CAP) + return DRM_DP_MST; + + if (mstm_cap & DP_SINGLE_STREAM_SIDEBAND_MSG) + return DRM_DP_SST_SIDEBAND_MSG; + + return DRM_DP_SST; } EXPORT_SYMBOL(drm_dp_read_mst_cap); @@ -4211,7 +4217,7 @@ drm_dp_mst_detect_port(struct drm_connector *connector, case DP_PEER_DEVICE_SST_SINK: ret = connector_status_connected; /* for logical ports - cache the EDID */ - if (port->port_num >= DP_MST_LOGICAL_PORT_0 && !port->cached_edid) + if (drm_dp_mst_port_is_logical(port) && !port->cached_edid) port->cached_edid = drm_edid_read_ddc(connector, &port->aux.ddc); break; case DP_PEER_DEVICE_DP_LEGACY_CONV: @@ -5975,7 +5981,7 @@ static bool drm_dp_mst_is_virtual_dpcd(struct drm_dp_mst_port *port) return false; /* Virtual DP Sink (Internal Display Panel) */ - if (port->port_num >= 8) + if (drm_dp_mst_port_is_logical(port)) return true; /* DP-to-HDMI Protocol Converter */ @@ -6003,6 +6009,22 @@ static bool drm_dp_mst_is_virtual_dpcd(struct drm_dp_mst_port *port) } /** + * drm_dp_mst_aux_for_parent() - Get the AUX device for an MST port's parent + * @port: MST port whose parent's AUX device is returned + * + * Return the AUX device for @port's parent or NULL if port's parent is the + * root port. + */ +struct drm_dp_aux *drm_dp_mst_aux_for_parent(struct drm_dp_mst_port *port) +{ + if (!port->parent || !port->parent->port_parent) + return NULL; + + return &port->parent->port_parent->aux; +} +EXPORT_SYMBOL(drm_dp_mst_aux_for_parent); + +/** * drm_dp_mst_dsc_aux_for_port() - Find the correct aux for DSC * @port: The port to check. A leaf of the MST tree with an attached display. * diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology_internal.h b/drivers/gpu/drm/display/drm_dp_mst_topology_internal.h index a785ccbfdd..f41c34e26b 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology_internal.h +++ b/drivers/gpu/drm/display/drm_dp_mst_topology_internal.h @@ -10,7 +10,9 @@ #ifndef _DRM_DP_MST_HELPER_INTERNAL_H_ #define _DRM_DP_MST_HELPER_INTERNAL_H_ -#include <drm/display/drm_dp_mst_helper.h> +struct drm_dp_sideband_msg_req_body; +struct drm_dp_sideband_msg_tx; +struct drm_printer; void drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req, diff --git a/drivers/gpu/drm/display/drm_dp_tunnel.c b/drivers/gpu/drm/display/drm_dp_tunnel.c index 120e0de674..48b2df1200 100644 --- a/drivers/gpu/drm/display/drm_dp_tunnel.c +++ b/drivers/gpu/drm/display/drm_dp_tunnel.c @@ -191,7 +191,7 @@ struct drm_dp_tunnel_mgr { struct drm_dp_tunnel_group *groups; wait_queue_head_t bw_req_queue; -#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE +#ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG struct ref_tracker_dir ref_tracker; #endif }; @@ -385,7 +385,7 @@ static void tunnel_put(struct drm_dp_tunnel *tunnel) kref_put(&tunnel->kref, free_tunnel); } -#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE +#ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG static void track_tunnel_ref(struct drm_dp_tunnel *tunnel, struct ref_tracker **tracker) { @@ -436,8 +436,8 @@ EXPORT_SYMBOL(drm_dp_tunnel_get); /** * drm_dp_tunnel_put - Put a reference for a DP tunnel - * @tunnel - Tunnel object - * @tracker - Debug tracker for the reference + * @tunnel: Tunnel object + * @tracker: Debug tracker for the reference * * Put a reference for @tunnel along with its debug *@tracker, which * was obtained with drm_dp_tunnel_get(). @@ -1170,7 +1170,7 @@ int drm_dp_tunnel_alloc_bw(struct drm_dp_tunnel *tunnel, int bw) EXPORT_SYMBOL(drm_dp_tunnel_alloc_bw); /** - * drm_dp_tunnel_atomic_get_allocated_bw - Get the BW allocated for a DP tunnel + * drm_dp_tunnel_get_allocated_bw - Get the BW allocated for a DP tunnel * @tunnel: Tunnel object * * Get the current BW allocated for @tunnel. After the tunnel is created / @@ -1603,7 +1603,7 @@ static void cleanup_group(struct drm_dp_tunnel_group *group) drm_atomic_private_obj_fini(&group->base); } -#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE +#ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG static void check_unique_stream_ids(const struct drm_dp_tunnel_group_state *group_state) { const struct drm_dp_tunnel_state *tunnel_state; @@ -1881,7 +1881,7 @@ static void destroy_mgr(struct drm_dp_tunnel_mgr *mgr) drm_WARN_ON(mgr->dev, !list_empty(&mgr->groups[i].tunnels)); } -#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE +#ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG ref_tracker_dir_exit(&mgr->ref_tracker); #endif @@ -1892,6 +1892,7 @@ static void destroy_mgr(struct drm_dp_tunnel_mgr *mgr) /** * drm_dp_tunnel_mgr_create - Create a DP tunnel manager * @dev: DRM device object + * @max_group_count: Maximum number of tunnel groups * * Creates a DP tunnel manager for @dev. * @@ -1918,7 +1919,7 @@ drm_dp_tunnel_mgr_create(struct drm_device *dev, int max_group_count) return NULL; } -#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE +#ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG ref_tracker_dir_init(&mgr->ref_tracker, 16, "dptun"); #endif |