diff options
Diffstat (limited to 'drivers/gpu/drm/display')
| -rw-r--r-- | drivers/gpu/drm/display/Kconfig | 72 | ||||
| -rw-r--r-- | drivers/gpu/drm/display/Makefile | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/display/drm_dp_dual_mode_helper.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/display/drm_dp_helper.c | 48 | ||||
| -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 | 42 | ||||
| -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 |
8 files changed, 137 insertions, 58 deletions
diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig index c0f56888c328..a38962a556c2 100644 --- a/drivers/gpu/drm/display/Kconfig +++ b/drivers/gpu/drm/display/Kconfig @@ -1,31 +1,58 @@ # SPDX-License-Identifier: MIT -config DRM_DP_AUX_BUS - tristate +config DRM_DISPLAY_HELPER + tristate "DRM Display Helpers" + depends on DRM + default y + help + DRM helpers for display adapters. + +config DRM_DISPLAY_DP_AUX_BUS + tristate "DRM DisplayPort AUX bus support" depends on DRM depends on OF || COMPILE_TEST + default y -config DRM_DISPLAY_HELPER - tristate +config DRM_DISPLAY_DP_AUX_CEC + bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support" depends on DRM + depends on DRM_DISPLAY_HELPER + depends on 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 DisplayPort AUX Interface" + depends on DRM + depends on DRM_DISPLAY_HELPER + depends on 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 + bool "DRM DisplayPort Helpers" depends on DRM_DISPLAY_HELPER + select DRM_KMS_HELPER + default y help DRM display helpers for DisplayPort. config DRM_DISPLAY_DP_TUNNEL - bool - select DRM_DISPLAY_DP_HELPER + bool "DRM DisplayPort tunnels support" + depends on DRM_DISPLAY_DP_HELPER help Enable support for DisplayPort tunnels. This allows drivers to use 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 @@ -39,34 +66,15 @@ config DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE If in doubt, say "N". config DRM_DISPLAY_HDCP_HELPER - bool + bool "DRM HDCD Helpers" depends on DRM_DISPLAY_HELPER + default y help DRM display helpers for HDCP. config DRM_DISPLAY_HDMI_HELPER - bool + bool "DRM HDMI Helpers" depends on DRM_DISPLAY_HELPER + default y 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 7ca61333c669..17d2cc73ff56 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_dual_mode_helper.c b/drivers/gpu/drm/display/drm_dp_dual_mode_helper.c index bd61e20770a5..14a2a8473682 100644 --- a/drivers/gpu/drm/display/drm_dp_dual_mode_helper.c +++ b/drivers/gpu/drm/display/drm_dp_dual_mode_helper.c @@ -52,7 +52,7 @@ * @adapter: I2C adapter for the DDC bus * @offset: register offset * @buffer: buffer for return data - * @size: sizo of the buffer + * @size: size of the buffer * * Reads @size bytes from the DP dual mode adaptor registers * starting at @offset. @@ -116,7 +116,7 @@ EXPORT_SYMBOL(drm_dp_dual_mode_read); * @adapter: I2C adapter for the DDC bus * @offset: register offset * @buffer: buffer for write data - * @size: sizo of the buffer + * @size: size of the buffer * * Writes @size bytes to the DP dual mode adaptor registers * starting at @offset. diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 266826eac4a7..79a615667aab 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 @@ -4111,6 +4150,13 @@ int drm_dp_bw_overhead(int lane_count, int hactive, u32 overhead = 1000000; int symbol_cycles; + if (lane_count == 0 || hactive == 0 || bpp_x16 == 0) { + DRM_DEBUG_KMS("Invalid BW overhead params: lane_count %d, hactive %d, bpp_x16 %d.%04d\n", + lane_count, hactive, + bpp_x16 >> 4, (bpp_x16 & 0xf) * 625); + return 0; + } + /* * DP Standard v2.1 2.6.4.1 * SSC downspread and ref clock variation margin: diff --git a/drivers/gpu/drm/display/drm_dp_helper_internal.h b/drivers/gpu/drm/display/drm_dp_helper_internal.h index 8917fc3af9ec..737949a2820f 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 03d528209426..3577786b5db2 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); @@ -3608,24 +3608,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; + + if (mstm_cap & DP_MST_CAP) + return DRM_DP_MST; - return mstm_cap & DP_MST_CAP; + 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); @@ -4213,7 +4219,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: @@ -5977,7 +5983,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 */ @@ -6005,6 +6011,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 a785ccbfdd73..f41c34e26be2 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 120e0de674c1..48b2df120086 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 |