From patchwork Tue Jan 23 10:28:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527148 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4B09EC47DDB for ; Tue, 23 Jan 2024 10:28:48 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id EEBFA10E767; Tue, 23 Jan 2024 10:28:41 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id A450310E766; Tue, 23 Jan 2024 10:28:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005718; x=1737541718; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oMNVZr1oLQvtaKFI0D5yAGpyJxKRX9F/sWObsoGIBLg=; b=Y5p51JeeOQRPiqaOItrD0tE/URwIqG76tncIjZBpPEnUlHysf2rL4d+/ ieUUBcz1D9XGGSzETpjCUod/l62ZcsUA9tWEAv7zZRgMm5domCdIjHkva Zsycxbq7lOGtMEmH/IWymoaIvxzmsnDgEx+rPdj3kechPGg3gsps49FUB UJ+K3rjvuOLwcSFJRaBC/gm0ou3JLIIlHUnL45yngSOfekhQQuPk7Rd73 FvQAiePbFYfHlwP1YfD4kbFxZVN10fBfyRUBHVvPJcobCpiDsMCCNKSg7 hIjtCEGeuqj8WtEzpexDUVM+bVludb4AvG+qQnYFX7TLiF3UZKm6YE/g/ g==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134091" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134091" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:38 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283360" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283360" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:37 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 01/19] drm/dp: Add drm_dp_max_dprx_data_rate() Date: Tue, 23 Jan 2024 12:28:32 +0200 Message-Id: <20240123102850.390126-2-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Copy intel_dp_max_data_rate() to DRM core. It will be needed by a follow-up DP tunnel patch, checking the maximum rate the DPRX (sink) supports. Accordingly use the drm_dp_max_dprx_data_rate() name for clarity. This patchset will also switch calling the new DRM function in i915 instead of intel_dp_max_data_rate(). Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/display/drm_dp_helper.c | 58 +++++++++++++++++++++++++ include/drm/display/drm_dp_helper.h | 2 + 2 files changed, 60 insertions(+) diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index b1ca3a1100dab..24911243d4d3a 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -4058,3 +4058,61 @@ int drm_dp_bw_channel_coding_efficiency(bool is_uhbr) return 800000; } EXPORT_SYMBOL(drm_dp_bw_channel_coding_efficiency); + +/* + * Given a link rate and lanes, get the data bandwidth. + * + * Data bandwidth is the actual payload rate, which depends on the data + * bandwidth efficiency and the link rate. + * + * For 8b/10b channel encoding, SST and non-FEC, the data bandwidth efficiency + * is 80%. For example, for a 1.62 Gbps link, 1.62*10^9 bps * 0.80 * (1/8) = + * 162000 kBps. With 8-bit symbols, we have 162000 kHz symbol clock. Just by + * coincidence, the port clock in kHz matches the data bandwidth in kBps, and + * they equal the link bit rate in Gbps multiplied by 100000. (Note that this no + * longer holds for data bandwidth as soon as FEC or MST is taken into account!) + * + * For 128b/132b channel encoding, the data bandwidth efficiency is 96.71%. For + * example, for a 10 Gbps link, 10*10^9 bps * 0.9671 * (1/8) = 1208875 + * kBps. With 32-bit symbols, we have 312500 kHz symbol clock. The value 1000000 + * does not match the symbol clock, the port clock (not even if you think in + * terms of a byte clock), nor the data bandwidth. It only matches the link bit + * rate in units of 10000 bps. + * + * Note that protocol layers above the DPRX link level considered here can + * further limit the maximum data rate. Such layers are the MST topology (with + * limits on the link between the source and first branch device as well as on + * the whole MST path until the DPRX link) and (Thunderbolt) DP tunnels - + * which in turn can encapsulate an MST link with its own limit - with each + * SST or MST encapsulated tunnel sharing the BW of a tunnel group. + * + * TODO: Add support for querying the max data rate with the above limits as + * well. + * + * Returns the maximum data rate in kBps units. + */ +int drm_dp_max_dprx_data_rate(int max_link_rate, int max_lanes) +{ + int ch_coding_efficiency = + drm_dp_bw_channel_coding_efficiency(drm_dp_is_uhbr_rate(max_link_rate)); + int max_link_rate_kbps = max_link_rate * 10; + + /* + * UHBR rates always use 128b/132b channel encoding, and have + * 97.71% data bandwidth efficiency. Consider max_link_rate the + * link bit rate in units of 10000 bps. + */ + /* + * Lower than UHBR rates always use 8b/10b channel encoding, and have + * 80% data bandwidth efficiency for SST non-FEC. However, this turns + * out to be a nop by coincidence: + * + * int max_link_rate_kbps = max_link_rate * 10; + * max_link_rate_kbps = DIV_ROUND_DOWN_ULL(max_link_rate_kbps * 8, 10); + * max_link_rate = max_link_rate_kbps / 8; + */ + return DIV_ROUND_DOWN_ULL(mul_u32_u32(max_link_rate_kbps * max_lanes, + ch_coding_efficiency), + 1000000 * 8); +} +EXPORT_SYMBOL(drm_dp_max_dprx_data_rate); diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 863b2e7add29e..454ae7517419a 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -813,4 +813,6 @@ int drm_dp_bw_overhead(int lane_count, int hactive, int bpp_x16, unsigned long flags); int drm_dp_bw_channel_coding_efficiency(bool is_uhbr); +int drm_dp_max_dprx_data_rate(int max_link_rate, int max_lanes); + #endif /* _DRM_DP_HELPER_H_ */ From patchwork Tue Jan 23 10:28:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527152 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 91A68C47258 for ; Tue, 23 Jan 2024 10:29:06 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 8C01B10EF8F; Tue, 23 Jan 2024 10:28:49 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9076D10E76E; Tue, 23 Jan 2024 10:28:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005720; x=1737541720; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=n4+XRlJHH5zo+uYkumOFO8e/6+ofc8haCBHkcQbZxOs=; b=hxrFT01n1B9PyBSqkihvFOmeixhxKhmn7pDjMQPYQZ4mAkSlyjOlZfzC 4ANFr8/xXIcPuFda14vUhtW+KMDYRDdzwFZK+TW2rHQdQSmW+w5yaxy+W OeUkVVnW7U6Lcf1C4+31Oqg3NQSEldayy0OdlvLrLHvt9VEYanvDr6IMb EwrPUxtG2Nrm0W2MOVQ70lFIJjMq673HvWGz6DZ7eUapxwXWo/7HiCslP egCsSkm6vz5k9XQqRek7ce082jPa8qdg8rfS9mrHAtbVTJpC58EECo1x8 UFxRISEtvZGKHWsyk5Gfp5FxadVuqJXJhwopVInQunv18ed5DJf1MMV1I g==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134110" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134110" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:40 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283365" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283365" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:38 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 02/19] drm/dp: Add support for DP tunneling Date: Tue, 23 Jan 2024 12:28:33 +0200 Message-Id: <20240123102850.390126-3-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add support for Display Port DP tunneling. For now this includes the support for Bandwidth Allocation Mode, leaving adding Panel Replay support for later. BWA allows using displays that share the same (Thunderbolt) link with their maximum resolution. Atm, this may not be possible due to the coarse granularity of partitioning the link BW among the displays on the link: the BW allocation policy is in a SW/FW/HW component on the link (on Thunderbolt it's the SW or FW Connection Manager), independent of the driver. This policy will set the DPRX maximum rate and lane count DPCD registers the GFX driver will see (0x00000, 0x00001, 0x02200, 0x02201) based on the available link BW. The granularity of the current BW allocation policy is course, based on the required link rate in the 1.62Gbs..8.1Gbps range and it may prevent using higher resolutions all together: the display connected first will get a share of the link BW which corresponds to its full DPRX capability (regardless of the actual mode it uses). A subsequent display connected will only get the remaining BW, which could be well below its full capability. BWA solves the above course granularity (reducing it to a 250Mbs..1Gps range) and first-come/first-served issues by letting the driver request the BW for each display on a link which reflects the actual modes the displays use. This patch adds the DRM core helper functions, while a follow-up change in the patchset takes them into use in the i915 driver. Signed-off-by: Imre Deak --- drivers/gpu/drm/display/Kconfig | 17 + drivers/gpu/drm/display/Makefile | 2 + drivers/gpu/drm/display/drm_dp_tunnel.c | 1715 +++++++++++++++++++++++ include/drm/display/drm_dp.h | 60 + include/drm/display/drm_dp_tunnel.h | 270 ++++ 5 files changed, 2064 insertions(+) create mode 100644 drivers/gpu/drm/display/drm_dp_tunnel.c create mode 100644 include/drm/display/drm_dp_tunnel.h diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig index 09712b88a5b83..b024a84b94c1c 100644 --- a/drivers/gpu/drm/display/Kconfig +++ b/drivers/gpu/drm/display/Kconfig @@ -17,6 +17,23 @@ config DRM_DISPLAY_DP_HELPER help DRM display helpers for DisplayPort. +config DRM_DISPLAY_DP_TUNNEL + bool + select DRM_DISPLAY_DP_HELPER + help + Enable support for DisplayPort tunnels. + +config DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE + bool "Enable debugging the DP tunnel state" + depends on REF_TRACKER + depends on DRM_DISPLAY_DP_TUNNEL + depends on DEBUG_KERNEL + depends on EXPERT + help + Enables debugging the DP tunnel manager's status. + + If in doubt, say "N". + config DRM_DISPLAY_HDCP_HELPER bool depends on DRM_DISPLAY_HELPER diff --git a/drivers/gpu/drm/display/Makefile b/drivers/gpu/drm/display/Makefile index 17ac4a1006a80..7ca61333c6696 100644 --- a/drivers/gpu/drm/display/Makefile +++ b/drivers/gpu/drm/display/Makefile @@ -8,6 +8,8 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \ drm_dp_helper.o \ drm_dp_mst_topology.o \ drm_dsc_helper.o +drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_TUNNEL) += \ + drm_dp_tunnel.o drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \ drm_hdmi_helper.o \ diff --git a/drivers/gpu/drm/display/drm_dp_tunnel.c b/drivers/gpu/drm/display/drm_dp_tunnel.c new file mode 100644 index 0000000000000..58f6330db7d9d --- /dev/null +++ b/drivers/gpu/drm/display/drm_dp_tunnel.c @@ -0,0 +1,1715 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#define to_group(__private_obj) \ + container_of(__private_obj, struct drm_dp_tunnel_group, base) + +#define to_group_state(__private_state) \ + container_of(__private_state, struct drm_dp_tunnel_group_state, base) + +#define is_dp_tunnel_private_obj(__obj) \ + ((__obj)->funcs == &tunnel_group_funcs) + +#define for_each_new_group_in_state(__state, __new_group_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->num_private_objs; \ + (__i)++) \ + for_each_if ((__state)->private_objs[__i].ptr && \ + is_dp_tunnel_private_obj((__state)->private_objs[__i].ptr) && \ + ((__new_group_state) = \ + to_group_state((__state)->private_objs[__i].new_state), 1)) + +#define for_each_old_group_in_state(__state, __old_group_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->num_private_objs; \ + (__i)++) \ + for_each_if ((__state)->private_objs[__i].ptr && \ + is_dp_tunnel_private_obj((__state)->private_objs[__i].ptr) && \ + ((__old_group_state) = \ + to_group_state((__state)->private_objs[__i].old_state), 1)) + +#define for_each_tunnel_in_group(__group, __tunnel) \ + list_for_each_entry(__tunnel, &(__group)->tunnels, node) + +#define for_each_tunnel_state(__group_state, __tunnel_state) \ + list_for_each_entry(__tunnel_state, &(__group_state)->tunnel_states, node) + +#define for_each_tunnel_state_safe(__group_state, __tunnel_state, __tunnel_state_tmp) \ + list_for_each_entry_safe(__tunnel_state, __tunnel_state_tmp, \ + &(__group_state)->tunnel_states, node) + +#define kbytes_to_mbits(__kbytes) \ + DIV_ROUND_UP((__kbytes) * 8, 1000) + +#define DPTUN_BW_ARG(__bw) ((__bw) < 0 ? (__bw) : kbytes_to_mbits(__bw)) + +#define __tun_prn(__tunnel, __level, __type, __fmt, ...) \ + drm_##__level##__type((__tunnel)->group->mgr->dev, \ + "[DPTUN %s][%s] " __fmt, \ + drm_dp_tunnel_name(__tunnel), \ + (__tunnel)->aux->name, ## \ + __VA_ARGS__) + +#define tun_dbg(__tunnel, __fmt, ...) \ + __tun_prn(__tunnel, dbg, _kms, __fmt, ## __VA_ARGS__) + +#define tun_dbg_stat(__tunnel, __err, __fmt, ...) do { \ + if (__err) \ + __tun_prn(__tunnel, dbg, _kms, __fmt " (Failed, err: %pe)\n", \ + ## __VA_ARGS__, ERR_PTR(__err)); \ + else \ + __tun_prn(__tunnel, dbg, _kms, __fmt " (Ok)\n", \ + ## __VA_ARGS__); \ +} while (0) + +#define tun_dbg_atomic(__tunnel, __fmt, ...) \ + __tun_prn(__tunnel, dbg, _atomic, __fmt, ## __VA_ARGS__) + +#define tun_grp_dbg(__group, __fmt, ...) \ + drm_dbg_kms((__group)->mgr->dev, \ + "[DPTUN %s] " __fmt, \ + drm_dp_tunnel_group_name(__group), ## \ + __VA_ARGS__) + +#define DP_TUNNELING_BASE DP_TUNNELING_OUI + +#define __DPTUN_REG_RANGE(start, size) \ + GENMASK_ULL(start + size - 1, start) + +#define DPTUN_REG_RANGE(addr, size) \ + __DPTUN_REG_RANGE((addr) - DP_TUNNELING_BASE, size) + +#define DPTUN_REG(addr) DPTUN_REG_RANGE(addr, 1) + +#define DPTUN_INFO_REG_MASK ( \ + DPTUN_REG_RANGE(DP_TUNNELING_OUI, DP_TUNNELING_OUI_BYTES) | \ + DPTUN_REG_RANGE(DP_TUNNELING_DEV_ID, DP_TUNNELING_DEV_ID_BYTES) | \ + DPTUN_REG(DP_TUNNELING_HW_REV) | \ + DPTUN_REG(DP_TUNNELING_SW_REV_MAJOR) | \ + DPTUN_REG(DP_TUNNELING_SW_REV_MINOR) | \ + DPTUN_REG(DP_TUNNELING_CAPABILITIES) | \ + DPTUN_REG(DP_IN_ADAPTER_INFO) | \ + DPTUN_REG(DP_USB4_DRIVER_ID) | \ + DPTUN_REG(DP_USB4_DRIVER_BW_CAPABILITY) | \ + DPTUN_REG(DP_IN_ADAPTER_TUNNEL_INFORMATION) | \ + DPTUN_REG(DP_BW_GRANULARITY) | \ + DPTUN_REG(DP_ESTIMATED_BW) | \ + DPTUN_REG(DP_ALLOCATED_BW) | \ + DPTUN_REG(DP_TUNNELING_MAX_LINK_RATE) | \ + DPTUN_REG(DP_TUNNELING_MAX_LANE_COUNT) | \ + DPTUN_REG(DP_DPTX_BW_ALLOCATION_MODE_CONTROL)) + +static const DECLARE_BITMAP(dptun_info_regs, 64) = { + DPTUN_INFO_REG_MASK & -1UL, +#if BITS_PER_LONG == 32 + DPTUN_INFO_REG_MASK >> 32, +#endif +}; + +struct drm_dp_tunnel_regs { + u8 buf[HWEIGHT64(DPTUN_INFO_REG_MASK)]; +}; + +struct drm_dp_tunnel_group; + +struct drm_dp_tunnel { + struct drm_dp_tunnel_group *group; + + struct list_head node; + + struct kref kref; +#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE + struct ref_tracker *tracker; +#endif + struct drm_dp_aux *aux; + char name[8]; + + int bw_granularity; + int estimated_bw; + int allocated_bw; + + int max_dprx_rate; + u8 max_dprx_lane_count; + + u8 adapter_id; + + bool bw_alloc_supported:1; + bool bw_alloc_enabled:1; + bool has_io_error:1; + bool destroyed:1; +}; + +struct drm_dp_tunnel_group_state; + +struct drm_dp_tunnel_state { + struct drm_dp_tunnel_group_state *group_state; + + struct drm_dp_tunnel_ref tunnel_ref; + + struct list_head node; + + u32 stream_mask; + int *stream_bw; +}; + +struct drm_dp_tunnel_group_state { + struct drm_private_state base; + + struct list_head tunnel_states; +}; + +struct drm_dp_tunnel_group { + struct drm_private_obj base; + struct drm_dp_tunnel_mgr *mgr; + + struct list_head tunnels; + + int available_bw; /* available BW including the allocated_bw of all tunnels */ + int drv_group_id; + + char name[8]; + + bool active:1; +}; + +struct drm_dp_tunnel_mgr { + struct drm_device *dev; + + int group_count; + struct drm_dp_tunnel_group *groups; + wait_queue_head_t bw_req_queue; + +#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE + struct ref_tracker_dir ref_tracker; +#endif +}; + +static int next_reg_area(int *offset) +{ + *offset = find_next_bit(dptun_info_regs, 64, *offset); + + return find_next_zero_bit(dptun_info_regs, 64, *offset + 1) - *offset; +} + +#define tunnel_reg_ptr(__regs, __address) ({ \ + WARN_ON(!test_bit((__address) - DP_TUNNELING_BASE, dptun_info_regs)); \ + &(__regs)->buf[bitmap_weight(dptun_info_regs, (__address) - DP_TUNNELING_BASE)]; \ +}) + +static int read_tunnel_regs(struct drm_dp_aux *aux, struct drm_dp_tunnel_regs *regs) +{ + int offset = 0; + int len; + + while ((len = next_reg_area(&offset))) { + int address = DP_TUNNELING_BASE + offset; + + if (drm_dp_dpcd_read(aux, address, tunnel_reg_ptr(regs, address), len) < 0) + return -EIO; + + offset += len; + } + + return 0; +} + +static u8 tunnel_reg(const struct drm_dp_tunnel_regs *regs, int address) +{ + return *tunnel_reg_ptr(regs, address); +} + +static int tunnel_reg_drv_group_id(const struct drm_dp_tunnel_regs *regs) +{ + int drv_id = tunnel_reg(regs, DP_USB4_DRIVER_ID) & DP_USB4_DRIVER_ID_MASK; + int group_id = tunnel_reg(regs, DP_IN_ADAPTER_TUNNEL_INFORMATION) & DP_GROUP_ID_MASK; + + if (!group_id) + return 0; + + return (drv_id << DP_GROUP_ID_BITS) | group_id; +} + +/* Return granularity in kB/s units */ +static int tunnel_reg_bw_granularity(const struct drm_dp_tunnel_regs *regs) +{ + int gr = tunnel_reg(regs, DP_BW_GRANULARITY) & DP_BW_GRANULARITY_MASK; + + WARN_ON(gr > 2); + + return (250000 << gr) / 8; +} + +static int tunnel_reg_max_dprx_rate(const struct drm_dp_tunnel_regs *regs) +{ + u8 bw_code = tunnel_reg(regs, DP_TUNNELING_MAX_LINK_RATE); + + return drm_dp_bw_code_to_link_rate(bw_code); +} + +static int tunnel_reg_max_dprx_lane_count(const struct drm_dp_tunnel_regs *regs) +{ + u8 lane_count = tunnel_reg(regs, DP_TUNNELING_MAX_LANE_COUNT) & + DP_TUNNELING_MAX_LANE_COUNT_MASK; + + return lane_count; +} + +static bool tunnel_reg_bw_alloc_supported(const struct drm_dp_tunnel_regs *regs) +{ + u8 cap_mask = DP_TUNNELING_SUPPORT | DP_IN_BW_ALLOCATION_MODE_SUPPORT; + + if ((tunnel_reg(regs, DP_TUNNELING_CAPABILITIES) & cap_mask) != cap_mask) + return false; + + return tunnel_reg(regs, DP_USB4_DRIVER_BW_CAPABILITY) & + DP_USB4_DRIVER_BW_ALLOCATION_MODE_SUPPORT; +} + +static bool tunnel_reg_bw_alloc_enabled(const struct drm_dp_tunnel_regs *regs) +{ + return tunnel_reg(regs, DP_DPTX_BW_ALLOCATION_MODE_CONTROL) & + DP_DISPLAY_DRIVER_BW_ALLOCATION_MODE_ENABLE; +} + +static int tunnel_group_drv_id(int drv_group_id) +{ + return drv_group_id >> DP_GROUP_ID_BITS; +} + +static int tunnel_group_id(int drv_group_id) +{ + return drv_group_id & DP_GROUP_ID_MASK; +} + +const char *drm_dp_tunnel_name(const struct drm_dp_tunnel *tunnel) +{ + return tunnel->name; +} +EXPORT_SYMBOL(drm_dp_tunnel_name); + +static const char *drm_dp_tunnel_group_name(const struct drm_dp_tunnel_group *group) +{ + return group->name; +} + +static struct drm_dp_tunnel_group * +lookup_or_alloc_group(struct drm_dp_tunnel_mgr *mgr, int drv_group_id) +{ + struct drm_dp_tunnel_group *group = NULL; + int i; + + for (i = 0; i < mgr->group_count; i++) { + /* + * A tunnel group with 0 group ID shouldn't have more than one + * tunnels. + */ + if (tunnel_group_id(drv_group_id) && + mgr->groups[i].drv_group_id == drv_group_id) + return &mgr->groups[i]; + + if (!group && !mgr->groups[i].active) + group = &mgr->groups[i]; + } + + if (!group) { + drm_dbg_kms(mgr->dev, + "DPTUN: Can't allocate more tunnel groups\n"); + return NULL; + } + + group->drv_group_id = drv_group_id; + group->active = true; + + snprintf(group->name, sizeof(group->name), "%d:%d:*", + tunnel_group_drv_id(drv_group_id) & ((1 << DP_GROUP_ID_BITS) - 1), + tunnel_group_id(drv_group_id) & ((1 << DP_USB4_DRIVER_ID_BITS) - 1)); + + return group; +} + +static void free_group(struct drm_dp_tunnel_group *group) +{ + struct drm_dp_tunnel_mgr *mgr = group->mgr; + + if (drm_WARN_ON(mgr->dev, !list_empty(&group->tunnels))) + return; + + group->drv_group_id = 0; + group->available_bw = -1; + group->active = false; +} + +static struct drm_dp_tunnel * +tunnel_get(struct drm_dp_tunnel *tunnel) +{ + kref_get(&tunnel->kref); + + return tunnel; +} + +static void free_tunnel(struct kref *kref) +{ + struct drm_dp_tunnel *tunnel = container_of(kref, typeof(*tunnel), kref); + struct drm_dp_tunnel_group *group = tunnel->group; + + list_del(&tunnel->node); + if (list_empty(&group->tunnels)) + free_group(group); + + kfree(tunnel); +} + +static void tunnel_put(struct drm_dp_tunnel *tunnel) +{ + kref_put(&tunnel->kref, free_tunnel); +} + +#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE +static void track_tunnel_ref(struct drm_dp_tunnel *tunnel, + struct ref_tracker **tracker) +{ + ref_tracker_alloc(&tunnel->group->mgr->ref_tracker, + tracker, GFP_KERNEL); +} + +static void untrack_tunnel_ref(struct drm_dp_tunnel *tunnel, + struct ref_tracker **tracker) +{ + ref_tracker_free(&tunnel->group->mgr->ref_tracker, + tracker); +} + +struct drm_dp_tunnel * +drm_dp_tunnel_get_untracked(struct drm_dp_tunnel *tunnel) +{ + track_tunnel_ref(tunnel, NULL); + + return tunnel_get(tunnel); +} +EXPORT_SYMBOL(drm_dp_tunnel_get_untracked); + +void drm_dp_tunnel_put_untracked(struct drm_dp_tunnel *tunnel) +{ + tunnel_put(tunnel); + untrack_tunnel_ref(tunnel, NULL); +} +EXPORT_SYMBOL(drm_dp_tunnel_put_untracked); + +struct drm_dp_tunnel * +drm_dp_tunnel_get(struct drm_dp_tunnel *tunnel, + struct ref_tracker **tracker) +{ + track_tunnel_ref(tunnel, tracker); + + return tunnel_get(tunnel); +} +EXPORT_SYMBOL(drm_dp_tunnel_get); + +void drm_dp_tunnel_put(struct drm_dp_tunnel *tunnel, + struct ref_tracker **tracker) +{ + untrack_tunnel_ref(tunnel, tracker); + tunnel_put(tunnel); +} +EXPORT_SYMBOL(drm_dp_tunnel_put); +#else +#define track_tunnel_ref(tunnel, tracker) do {} while (0) +#define untrack_tunnel_ref(tunnel, tracker) do {} while (0) + +struct drm_dp_tunnel * +drm_dp_tunnel_get_untracked(struct drm_dp_tunnel *tunnel) +{ + return tunnel_get(tunnel); +} +EXPORT_SYMBOL(drm_dp_tunnel_get_untracked); + +void drm_dp_tunnel_put_untracked(struct drm_dp_tunnel *tunnel) +{ + tunnel_put(tunnel); +} +EXPORT_SYMBOL(drm_dp_tunnel_put_untracked); +#endif + +static bool add_tunnel_to_group(struct drm_dp_tunnel_mgr *mgr, + int drv_group_id, + struct drm_dp_tunnel *tunnel) +{ + struct drm_dp_tunnel_group *group = + lookup_or_alloc_group(mgr, drv_group_id); + + if (!group) + return false; + + tunnel->group = group; + list_add(&tunnel->node, &group->tunnels); + + return true; +} + +static struct drm_dp_tunnel * +create_tunnel(struct drm_dp_tunnel_mgr *mgr, + struct drm_dp_aux *aux, + const struct drm_dp_tunnel_regs *regs) +{ + int drv_group_id = tunnel_reg_drv_group_id(regs); + struct drm_dp_tunnel *tunnel; + + tunnel = kzalloc(sizeof(*tunnel), GFP_KERNEL); + if (!tunnel) + return NULL; + + INIT_LIST_HEAD(&tunnel->node); + + kref_init(&tunnel->kref); + + tunnel->aux = aux; + + tunnel->adapter_id = tunnel_reg(regs, DP_IN_ADAPTER_INFO) & DP_IN_ADAPTER_NUMBER_MASK; + + snprintf(tunnel->name, sizeof(tunnel->name), "%d:%d:%d", + tunnel_group_drv_id(drv_group_id) & ((1 << DP_GROUP_ID_BITS) - 1), + tunnel_group_id(drv_group_id) & ((1 << DP_USB4_DRIVER_ID_BITS) - 1), + tunnel->adapter_id & ((1 << DP_IN_ADAPTER_NUMBER_BITS) - 1)); + + tunnel->bw_granularity = tunnel_reg_bw_granularity(regs); + tunnel->allocated_bw = tunnel_reg(regs, DP_ALLOCATED_BW) * + tunnel->bw_granularity; + + tunnel->bw_alloc_supported = tunnel_reg_bw_alloc_supported(regs); + tunnel->bw_alloc_enabled = tunnel_reg_bw_alloc_enabled(regs); + + if (!add_tunnel_to_group(mgr, drv_group_id, tunnel)) { + kfree(tunnel); + + return NULL; + } + + track_tunnel_ref(tunnel, &tunnel->tracker); + + return tunnel; +} + +static void destroy_tunnel(struct drm_dp_tunnel *tunnel) +{ + untrack_tunnel_ref(tunnel, &tunnel->tracker); + tunnel_put(tunnel); +} + +void drm_dp_tunnel_set_io_error(struct drm_dp_tunnel *tunnel) +{ + tunnel->has_io_error = true; +} +EXPORT_SYMBOL(drm_dp_tunnel_set_io_error); + +static char yes_no_chr(int val) +{ + return val ? 'Y' : 'N'; +} + +#define SKIP_DPRX_CAPS_CHECK BIT(0) +#define ALLOW_ALLOCATED_BW_CHANGE BIT(1) + +static bool tunnel_regs_are_valid(struct drm_dp_tunnel_mgr *mgr, + const struct drm_dp_tunnel_regs *regs, + unsigned int flags) +{ + int drv_group_id = tunnel_reg_drv_group_id(regs); + bool check_dprx = !(flags & SKIP_DPRX_CAPS_CHECK); + bool ret = true; + + if (!tunnel_reg_bw_alloc_supported(regs)) { + if (tunnel_group_id(drv_group_id)) { + drm_dbg_kms(mgr->dev, + "DPTUN: A non-zero group ID is only allowed with BWA support\n"); + ret = false; + } + + if (tunnel_reg(regs, DP_ALLOCATED_BW)) { + drm_dbg_kms(mgr->dev, + "DPTUN: BW is allocated without BWA support\n"); + ret = false; + } + + return ret; + } + + if (!tunnel_group_id(drv_group_id)) { + drm_dbg_kms(mgr->dev, + "DPTUN: BWA support requires a non-zero group ID\n"); + ret = false; + } + + if (check_dprx && hweight8(tunnel_reg_max_dprx_lane_count(regs)) != 1) { + drm_dbg_kms(mgr->dev, + "DPTUN: Invalid DPRX lane count: %d\n", + tunnel_reg_max_dprx_lane_count(regs)); + + ret = false; + } + + if (check_dprx && !tunnel_reg_max_dprx_rate(regs)) { + drm_dbg_kms(mgr->dev, + "DPTUN: DPRX rate is 0\n"); + + ret = false; + } + + if (tunnel_reg(regs, DP_ALLOCATED_BW) > tunnel_reg(regs, DP_ESTIMATED_BW)) { + drm_dbg_kms(mgr->dev, + "DPTUN: Allocated BW %d > estimated BW %d Mb/s\n", + DPTUN_BW_ARG(tunnel_reg(regs, DP_ALLOCATED_BW) * + tunnel_reg_bw_granularity(regs)), + DPTUN_BW_ARG(tunnel_reg(regs, DP_ESTIMATED_BW) * + tunnel_reg_bw_granularity(regs))); + + ret = false; + } + + return ret; +} + +static bool tunnel_info_changes_are_valid(struct drm_dp_tunnel *tunnel, + const struct drm_dp_tunnel_regs *regs, + unsigned int flags) +{ + int new_drv_group_id = tunnel_reg_drv_group_id(regs); + bool ret = true; + + if (tunnel->bw_alloc_supported != tunnel_reg_bw_alloc_supported(regs)) { + tun_dbg(tunnel, + "BW alloc support has changed %c -> %c\n", + yes_no_chr(tunnel->bw_alloc_supported), + yes_no_chr(tunnel_reg_bw_alloc_supported(regs))); + + ret = false; + } + + if (tunnel->group->drv_group_id != new_drv_group_id) { + tun_dbg(tunnel, + "Driver/group ID has changed %d:%d:* -> %d:%d:*\n", + tunnel_group_drv_id(tunnel->group->drv_group_id), + tunnel_group_id(tunnel->group->drv_group_id), + tunnel_group_drv_id(new_drv_group_id), + tunnel_group_id(new_drv_group_id)); + + ret = false; + } + + if (!tunnel->bw_alloc_supported) + return ret; + + if (tunnel->bw_granularity != tunnel_reg_bw_granularity(regs)) { + tun_dbg(tunnel, + "BW granularity has changed: %d -> %d Mb/s\n", + DPTUN_BW_ARG(tunnel->bw_granularity), + DPTUN_BW_ARG(tunnel_reg_bw_granularity(regs))); + + ret = false; + } + + /* + * On some devices at least the BW alloc mode enabled status is always + * reported as 0, so skip checking that here. + */ + + if (!(flags & ALLOW_ALLOCATED_BW_CHANGE) && + tunnel->allocated_bw != + tunnel_reg(regs, DP_ALLOCATED_BW) * tunnel->bw_granularity) { + tun_dbg(tunnel, + "Allocated BW has changed: %d -> %d Mb/s\n", + DPTUN_BW_ARG(tunnel->allocated_bw), + DPTUN_BW_ARG(tunnel_reg(regs, DP_ALLOCATED_BW) * tunnel->bw_granularity)); + + ret = false; + } + + return ret; +} + +static int +read_and_verify_tunnel_regs(struct drm_dp_tunnel *tunnel, + struct drm_dp_tunnel_regs *regs, + unsigned int flags) +{ + int err; + + err = read_tunnel_regs(tunnel->aux, regs); + if (err < 0) { + drm_dp_tunnel_set_io_error(tunnel); + + return err; + } + + if (!tunnel_regs_are_valid(tunnel->group->mgr, regs, flags)) + return -EINVAL; + + if (!tunnel_info_changes_are_valid(tunnel, regs, flags)) + return -EINVAL; + + return 0; +} + +static bool update_dprx_caps(struct drm_dp_tunnel *tunnel, const struct drm_dp_tunnel_regs *regs) +{ + bool changed = false; + + if (tunnel_reg_max_dprx_rate(regs) != tunnel->max_dprx_rate) { + tunnel->max_dprx_rate = tunnel_reg_max_dprx_rate(regs); + changed = true; + } + + if (tunnel_reg_max_dprx_lane_count(regs) != tunnel->max_dprx_lane_count) { + tunnel->max_dprx_lane_count = tunnel_reg_max_dprx_lane_count(regs); + changed = true; + } + + return changed; +} + +static int dev_id_len(const u8 *dev_id, int max_len) +{ + while (max_len && dev_id[max_len - 1] == '\0') + max_len--; + + return max_len; +} + +static int get_max_dprx_bw(const struct drm_dp_tunnel *tunnel) +{ + int bw = drm_dp_max_dprx_data_rate(tunnel->max_dprx_rate, + tunnel->max_dprx_lane_count); + + return min(roundup(bw, tunnel->bw_granularity), + MAX_DP_REQUEST_BW * tunnel->bw_granularity); +} + +static int get_max_tunnel_bw(const struct drm_dp_tunnel *tunnel) +{ + return min(get_max_dprx_bw(tunnel), tunnel->group->available_bw); +} + +/** + * drm_dp_tunnel_detect - Detect DP tunnel on the link + * @mgr: Tunnel manager + * @aux: DP AUX on which the tunnel will be detected + * + * Detect if there is any DP tunnel on the link and add it to the tunnel + * group's tunnel list. + * + * Returns 0 on success, negative error code on failure. + */ +struct drm_dp_tunnel * +drm_dp_tunnel_detect(struct drm_dp_tunnel_mgr *mgr, + struct drm_dp_aux *aux) +{ + struct drm_dp_tunnel_regs regs; + struct drm_dp_tunnel *tunnel; + int err; + + err = read_tunnel_regs(aux, ®s); + if (err) + return ERR_PTR(err); + + if (!(tunnel_reg(®s, DP_TUNNELING_CAPABILITIES) & + DP_TUNNELING_SUPPORT)) + return ERR_PTR(-ENODEV); + + /* The DPRX caps are valid only after enabling BW alloc mode. */ + if (!tunnel_regs_are_valid(mgr, ®s, SKIP_DPRX_CAPS_CHECK)) + return ERR_PTR(-EINVAL); + + tunnel = create_tunnel(mgr, aux, ®s); + if (!tunnel) + return ERR_PTR(-ENOMEM); + + tun_dbg(tunnel, + "OUI:%*phD DevID:%*pE Rev-HW:%d.%d SW:%d.%d PR-Sup:%c BWA-Sup:%c BWA-En:%c\n", + DP_TUNNELING_OUI_BYTES, + tunnel_reg_ptr(®s, DP_TUNNELING_OUI), + dev_id_len(tunnel_reg_ptr(®s, DP_TUNNELING_DEV_ID), DP_TUNNELING_DEV_ID_BYTES), + tunnel_reg_ptr(®s, DP_TUNNELING_DEV_ID), + (tunnel_reg(®s, DP_TUNNELING_HW_REV) & DP_TUNNELING_HW_REV_MAJOR_MASK) >> + DP_TUNNELING_HW_REV_MAJOR_SHIFT, + (tunnel_reg(®s, DP_TUNNELING_HW_REV) & DP_TUNNELING_HW_REV_MINOR_MASK) >> + DP_TUNNELING_HW_REV_MINOR_SHIFT, + tunnel_reg(®s, DP_TUNNELING_SW_REV_MAJOR), + tunnel_reg(®s, DP_TUNNELING_SW_REV_MINOR), + yes_no_chr(tunnel_reg(®s, DP_TUNNELING_CAPABILITIES) & + DP_PANEL_REPLAY_OPTIMIZATION_SUPPORT), + yes_no_chr(tunnel->bw_alloc_supported), + yes_no_chr(tunnel->bw_alloc_enabled)); + + return tunnel; +} +EXPORT_SYMBOL(drm_dp_tunnel_detect); + +/** + * drm_dp_tunnel_destroy - Destroy tunnel object + * @tunnel: Tunnel object + * + * Remove the tunnel from the tunnel topology and destroy it. + */ +int drm_dp_tunnel_destroy(struct drm_dp_tunnel *tunnel) +{ + if (drm_WARN_ON(tunnel->group->mgr->dev, tunnel->destroyed)) + return -ENODEV; + + tun_dbg(tunnel, "destroying\n"); + + tunnel->destroyed = true; + destroy_tunnel(tunnel); + + return 0; +} +EXPORT_SYMBOL(drm_dp_tunnel_destroy); + +static int check_tunnel(const struct drm_dp_tunnel *tunnel) +{ + if (tunnel->destroyed) + return -ENODEV; + + if (tunnel->has_io_error) + return -EIO; + + return 0; +} + +static int group_allocated_bw(struct drm_dp_tunnel_group *group) +{ + struct drm_dp_tunnel *tunnel; + int group_allocated_bw = 0; + + for_each_tunnel_in_group(group, tunnel) { + if (check_tunnel(tunnel) == 0 && + tunnel->bw_alloc_enabled) + group_allocated_bw += tunnel->allocated_bw; + } + + return group_allocated_bw; +} + +static int calc_group_available_bw(const struct drm_dp_tunnel *tunnel) +{ + return group_allocated_bw(tunnel->group) - + tunnel->allocated_bw + + tunnel->estimated_bw; +} + +static int update_group_available_bw(struct drm_dp_tunnel *tunnel, + const struct drm_dp_tunnel_regs *regs) +{ + struct drm_dp_tunnel *tunnel_iter; + int group_available_bw; + bool changed; + + tunnel->estimated_bw = tunnel_reg(regs, DP_ESTIMATED_BW) * tunnel->bw_granularity; + + if (calc_group_available_bw(tunnel) == tunnel->group->available_bw) + return 0; + + for_each_tunnel_in_group(tunnel->group, tunnel_iter) { + int err; + + if (tunnel_iter == tunnel) + continue; + + if (check_tunnel(tunnel_iter) != 0 || + !tunnel_iter->bw_alloc_enabled) + continue; + + err = drm_dp_dpcd_probe(tunnel_iter->aux, DP_DPCD_REV); + if (err) { + tun_dbg(tunnel_iter, + "Probe failed, assume disconnected (err %pe)\n", + ERR_PTR(err)); + drm_dp_tunnel_set_io_error(tunnel_iter); + } + } + + group_available_bw = calc_group_available_bw(tunnel); + + tun_dbg(tunnel, "Updated group available BW: %d->%d\n", + DPTUN_BW_ARG(tunnel->group->available_bw), + DPTUN_BW_ARG(group_available_bw)); + + changed = tunnel->group->available_bw != group_available_bw; + + tunnel->group->available_bw = group_available_bw; + + return changed ? 1 : 0; +} + +static int set_bw_alloc_mode(struct drm_dp_tunnel *tunnel, bool enable) +{ + u8 mask = DP_DISPLAY_DRIVER_BW_ALLOCATION_MODE_ENABLE | DP_UNMASK_BW_ALLOCATION_IRQ; + u8 val; + + if (drm_dp_dpcd_readb(tunnel->aux, DP_DPTX_BW_ALLOCATION_MODE_CONTROL, &val) < 0) + goto out_err; + + if (enable) + val |= mask; + else + val &= ~mask; + + if (drm_dp_dpcd_writeb(tunnel->aux, DP_DPTX_BW_ALLOCATION_MODE_CONTROL, val) < 0) + goto out_err; + + tunnel->bw_alloc_enabled = enable; + + return 0; + +out_err: + drm_dp_tunnel_set_io_error(tunnel); + + return -EIO; +} + +/** + * drm_dp_tunnel_enable_bw_alloc: Enable DP tunnel BW allocation mode + * @tunnel: Tunnel object + * + * Enable the DP tunnel BW allocation mode on @tunnel if it supports it. + * + * Returns 0 in case of success, negative error code otherwise. + */ +int drm_dp_tunnel_enable_bw_alloc(struct drm_dp_tunnel *tunnel) +{ + struct drm_dp_tunnel_regs regs; + int err = check_tunnel(tunnel); + + if (err) + return err; + + if (!tunnel->bw_alloc_supported) + return -EOPNOTSUPP; + + if (!tunnel_group_id(tunnel->group->drv_group_id)) + return -EINVAL; + + err = set_bw_alloc_mode(tunnel, true); + if (err) + goto out; + + err = read_and_verify_tunnel_regs(tunnel, ®s, 0); + if (err) { + set_bw_alloc_mode(tunnel, false); + + goto out; + } + + if (!tunnel->max_dprx_rate) + update_dprx_caps(tunnel, ®s); + + if (tunnel->group->available_bw == -1) { + err = update_group_available_bw(tunnel, ®s); + if (err > 0) + err = 0; + } +out: + tun_dbg_stat(tunnel, err, + "Enabling BW alloc mode: DPRX:%dx%d Group alloc:%d/%d Mb/s", + tunnel->max_dprx_rate / 100, tunnel->max_dprx_lane_count, + DPTUN_BW_ARG(group_allocated_bw(tunnel->group)), + DPTUN_BW_ARG(tunnel->group->available_bw)); + + return err; +} +EXPORT_SYMBOL(drm_dp_tunnel_enable_bw_alloc); + +/** + * drm_dp_tunnel_disable_bw_alloc: Disable DP tunnel BW allocation mode + * @tunnel: Tunnel object + * + * Disable the DP tunnel BW allocation mode on @tunnel. + * + * Returns 0 in case of success, negative error code otherwise. + */ +int drm_dp_tunnel_disable_bw_alloc(struct drm_dp_tunnel *tunnel) +{ + int err = check_tunnel(tunnel); + + if (err) + return err; + + err = set_bw_alloc_mode(tunnel, false); + + tun_dbg_stat(tunnel, err, "Disabling BW alloc mode"); + + return err; +} +EXPORT_SYMBOL(drm_dp_tunnel_disable_bw_alloc); + +bool drm_dp_tunnel_bw_alloc_is_enabled(const struct drm_dp_tunnel *tunnel) +{ + return tunnel->bw_alloc_enabled; +} +EXPORT_SYMBOL(drm_dp_tunnel_bw_alloc_is_enabled); + +static int bw_req_complete(struct drm_dp_aux *aux, bool *status_changed) +{ + u8 bw_req_mask = DP_BW_REQUEST_SUCCEEDED | DP_BW_REQUEST_FAILED; + u8 status_change_mask = DP_BW_ALLOCATION_CAPABILITY_CHANGED | DP_ESTIMATED_BW_CHANGED; + u8 val; + + if (drm_dp_dpcd_readb(aux, DP_TUNNELING_STATUS, &val) < 0) + return -EIO; + + *status_changed = val & status_change_mask; + + val &= bw_req_mask; + + if (!val) + return -EAGAIN; + + if (drm_dp_dpcd_writeb(aux, DP_TUNNELING_STATUS, val) < 0) + return -EIO; + + return val == DP_BW_REQUEST_SUCCEEDED ? 0 : -ENOSPC; +} + +static int allocate_tunnel_bw(struct drm_dp_tunnel *tunnel, int bw) +{ + struct drm_dp_tunnel_mgr *mgr = tunnel->group->mgr; + int request_bw = DIV_ROUND_UP(bw, tunnel->bw_granularity); + unsigned long wait_expires; + DEFINE_WAIT(wait); + int err; + + /* Atomic check should prevent the following. */ + if (drm_WARN_ON(mgr->dev, request_bw > MAX_DP_REQUEST_BW)) { + err = -EINVAL; + goto out; + } + + if (drm_dp_dpcd_writeb(tunnel->aux, DP_REQUEST_BW, request_bw) < 0) { + err = -EIO; + goto out; + } + + wait_expires = jiffies + msecs_to_jiffies(3000); + + for (;;) { + bool status_changed; + + err = bw_req_complete(tunnel->aux, &status_changed); + if (err != -EAGAIN) + break; + + if (status_changed) { + struct drm_dp_tunnel_regs regs; + + err = read_and_verify_tunnel_regs(tunnel, ®s, + ALLOW_ALLOCATED_BW_CHANGE); + if (err) + break; + } + + if (time_after(jiffies, wait_expires)) { + err = -ETIMEDOUT; + break; + } + + prepare_to_wait(&mgr->bw_req_queue, &wait, TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(200)); + }; + + finish_wait(&mgr->bw_req_queue, &wait); + + if (err) + goto out; + + tunnel->allocated_bw = request_bw * tunnel->bw_granularity; + +out: + tun_dbg_stat(tunnel, err, "Allocating %d/%d Mb/s for tunnel: Group alloc:%d/%d Mb/s", + DPTUN_BW_ARG(request_bw * tunnel->bw_granularity), + DPTUN_BW_ARG(get_max_tunnel_bw(tunnel)), + DPTUN_BW_ARG(group_allocated_bw(tunnel->group)), + DPTUN_BW_ARG(tunnel->group->available_bw)); + + if (err == -EIO) + drm_dp_tunnel_set_io_error(tunnel); + + return err; +} + +int drm_dp_tunnel_alloc_bw(struct drm_dp_tunnel *tunnel, int bw) +{ + int err = check_tunnel(tunnel); + + if (err) + return err; + + return allocate_tunnel_bw(tunnel, bw); +} +EXPORT_SYMBOL(drm_dp_tunnel_alloc_bw); + +static int check_and_clear_status_change(struct drm_dp_tunnel *tunnel) +{ + u8 mask = DP_BW_ALLOCATION_CAPABILITY_CHANGED | DP_ESTIMATED_BW_CHANGED; + u8 val; + + if (drm_dp_dpcd_readb(tunnel->aux, DP_TUNNELING_STATUS, &val) < 0) + goto out_err; + + val &= mask; + + if (val) { + if (drm_dp_dpcd_writeb(tunnel->aux, DP_TUNNELING_STATUS, val) < 0) + goto out_err; + + return 1; + } + + if (!drm_dp_tunnel_bw_alloc_is_enabled(tunnel)) + return 0; + + /* + * Check for estimated BW changes explicitly to account for lost + * BW change notifications. + */ + if (drm_dp_dpcd_readb(tunnel->aux, DP_ESTIMATED_BW, &val) < 0) + goto out_err; + + if (val * tunnel->bw_granularity != tunnel->estimated_bw) + return 1; + + return 0; + +out_err: + drm_dp_tunnel_set_io_error(tunnel); + + return -EIO; +} + +/** + * drm_dp_tunnel_update_state: Update DP tunnel SW state with the HW state + * @tunnel: Tunnel object + * + * Update the SW state of @tunnel with the HW state. + * + * Returns 0 if the state has not changed, 1 if it has changed and got updated + * successfully and a negative error code otherwise. + */ +int drm_dp_tunnel_update_state(struct drm_dp_tunnel *tunnel) +{ + struct drm_dp_tunnel_regs regs; + bool changed = false; + int ret = check_tunnel(tunnel); + + if (ret < 0) + return ret; + + ret = check_and_clear_status_change(tunnel); + if (ret < 0) + goto out; + + if (!ret) + return 0; + + ret = read_and_verify_tunnel_regs(tunnel, ®s, 0); + if (ret) + goto out; + + if (update_dprx_caps(tunnel, ®s)) + changed = true; + + ret = update_group_available_bw(tunnel, ®s); + if (ret == 1) + changed = true; + +out: + tun_dbg_stat(tunnel, ret < 0 ? ret : 0, + "State update: Changed:%c DPRX:%dx%d Tunnel alloc:%d/%d Group alloc:%d/%d Mb/s", + yes_no_chr(changed), + tunnel->max_dprx_rate / 100, tunnel->max_dprx_lane_count, + DPTUN_BW_ARG(tunnel->allocated_bw), + DPTUN_BW_ARG(get_max_tunnel_bw(tunnel)), + DPTUN_BW_ARG(group_allocated_bw(tunnel->group)), + DPTUN_BW_ARG(tunnel->group->available_bw)); + + if (ret < 0) + return ret; + + if (changed) + return 1; + + return 0; +} +EXPORT_SYMBOL(drm_dp_tunnel_update_state); + +/* + * Returns 0 if no re-probe is needed, 1 if a re-probe is needed, + * a negative error code otherwise. + */ +int drm_dp_tunnel_handle_irq(struct drm_dp_tunnel_mgr *mgr, struct drm_dp_aux *aux) +{ + u8 val; + + if (drm_dp_dpcd_readb(aux, DP_TUNNELING_STATUS, &val) < 0) + return -EIO; + + if (val & (DP_BW_REQUEST_SUCCEEDED | DP_BW_REQUEST_FAILED)) + wake_up_all(&mgr->bw_req_queue); + + if (val & (DP_BW_ALLOCATION_CAPABILITY_CHANGED | DP_ESTIMATED_BW_CHANGED)) + return 1; + + return 0; +} +EXPORT_SYMBOL(drm_dp_tunnel_handle_irq); + +/** + * drm_dp_tunnel_max_dprx_rate - Query the maximum rate of the tunnel's DPRX + * @tunnel: Tunnel object + * + * The function is used to query the maximum link rate of the DPRX connected + * to @tunnel. Note that this rate will not be limited by the BW limit of the + * tunnel, as opposed to the standard and extended DP_MAX_LINK_RATE DPCD + * registers. + * + * Returns the maximum link rate in 10 kbit/s units. + */ +int drm_dp_tunnel_max_dprx_rate(const struct drm_dp_tunnel *tunnel) +{ + return tunnel->max_dprx_rate; +} +EXPORT_SYMBOL(drm_dp_tunnel_max_dprx_rate); + +/** + * drm_dp_tunnel_max_dprx_lane_count - Query the maximum lane count of the tunnel's DPRX + * @tunnel: Tunnel object + * + * The function is used to query the maximum lane count of the DPRX connected + * to @tunnel. Note that this lane count will not be limited by the BW limit of + * the tunnel, as opposed to the standard and extended DP_MAX_LANE_COUNT DPCD + * registers. + * + * Returns the maximum lane count. + */ +int drm_dp_tunnel_max_dprx_lane_count(const struct drm_dp_tunnel *tunnel) +{ + return tunnel->max_dprx_lane_count; +} +EXPORT_SYMBOL(drm_dp_tunnel_max_dprx_lane_count); + +/** + * drm_dp_tunnel_available_bw - Query the estimated total available BW of the tunnel + * @tunnel: Tunnel object + * + * This function is used to query the estimated total available BW of the + * tunnel. This includes the currently allocated and free BW for all the + * tunnels in @tunnel's group. The available BW is valid only after the BW + * allocation mode has been enabled for the tunnel and its state got updated + * calling drm_dp_tunnel_update_state(). + * + * Returns the @tunnel group's estimated total available bandwidth in kB/s + * units, or -1 if the available BW isn't valid (the BW allocation mode is + * not enabled or the tunnel's state hasn't been updated). + */ +int drm_dp_tunnel_available_bw(const struct drm_dp_tunnel *tunnel) +{ + return tunnel->group->available_bw; +} +EXPORT_SYMBOL(drm_dp_tunnel_available_bw); + +static struct drm_dp_tunnel_group_state * +drm_dp_tunnel_atomic_get_group_state(struct drm_atomic_state *state, + const struct drm_dp_tunnel *tunnel) +{ + return (struct drm_dp_tunnel_group_state *) + drm_atomic_get_private_obj_state(state, + &tunnel->group->base); +} + +static struct drm_dp_tunnel_state * +add_tunnel_state(struct drm_dp_tunnel_group_state *group_state, + struct drm_dp_tunnel *tunnel) +{ + struct drm_dp_tunnel_state *tunnel_state; + + tun_dbg_atomic(tunnel, + "Adding state for tunnel %p to group state %p\n", + tunnel, group_state); + + tunnel_state = kzalloc(sizeof(*tunnel_state), GFP_KERNEL); + if (!tunnel_state) + return NULL; + + tunnel_state->group_state = group_state; + + drm_dp_tunnel_ref_get(tunnel, &tunnel_state->tunnel_ref); + + INIT_LIST_HEAD(&tunnel_state->node); + list_add(&tunnel_state->node, &group_state->tunnel_states); + + return tunnel_state; +} + +void drm_dp_tunnel_atomic_clear_state(struct drm_dp_tunnel_state *tunnel_state) +{ + tun_dbg_atomic(tunnel_state->tunnel_ref.tunnel, + "Clearing state for tunnel %p\n", + tunnel_state->tunnel_ref.tunnel); + + list_del(&tunnel_state->node); + + kfree(tunnel_state->stream_bw); + drm_dp_tunnel_ref_put(&tunnel_state->tunnel_ref); + + kfree(tunnel_state); +} +EXPORT_SYMBOL(drm_dp_tunnel_atomic_clear_state); + +static void clear_tunnel_group_state(struct drm_dp_tunnel_group_state *group_state) +{ + struct drm_dp_tunnel_state *tunnel_state; + struct drm_dp_tunnel_state *tunnel_state_tmp; + + for_each_tunnel_state_safe(group_state, tunnel_state, tunnel_state_tmp) + drm_dp_tunnel_atomic_clear_state(tunnel_state); +} + +static struct drm_dp_tunnel_state * +get_tunnel_state(struct drm_dp_tunnel_group_state *group_state, + const struct drm_dp_tunnel *tunnel) +{ + struct drm_dp_tunnel_state *tunnel_state; + + for_each_tunnel_state(group_state, tunnel_state) + if (tunnel_state->tunnel_ref.tunnel == tunnel) + return tunnel_state; + + return NULL; +} + +static struct drm_dp_tunnel_state * +get_or_add_tunnel_state(struct drm_dp_tunnel_group_state *group_state, + struct drm_dp_tunnel *tunnel) +{ + struct drm_dp_tunnel_state *tunnel_state; + + tunnel_state = get_tunnel_state(group_state, tunnel); + if (tunnel_state) + return tunnel_state; + + return add_tunnel_state(group_state, tunnel); +} + +static struct drm_private_state * +tunnel_group_duplicate_state(struct drm_private_obj *obj) +{ + struct drm_dp_tunnel_group_state *group_state = to_group_state(obj->state); + struct drm_dp_tunnel_state *tunnel_state; + + group_state = kzalloc(sizeof(*group_state), GFP_KERNEL); + if (!group_state) + return NULL; + + INIT_LIST_HEAD(&group_state->tunnel_states); + + __drm_atomic_helper_private_obj_duplicate_state(obj, &group_state->base); + + for_each_tunnel_state(to_group_state(obj->state), tunnel_state) { + struct drm_dp_tunnel_state *new_tunnel_state; + + new_tunnel_state = get_or_add_tunnel_state(group_state, + tunnel_state->tunnel_ref.tunnel); + if (!new_tunnel_state) + goto out_free_state; + + new_tunnel_state->stream_mask = tunnel_state->stream_mask; + new_tunnel_state->stream_bw = kmemdup(tunnel_state->stream_bw, + sizeof(*tunnel_state->stream_bw) * + hweight32(tunnel_state->stream_mask), + GFP_KERNEL); + + if (!new_tunnel_state->stream_bw) + goto out_free_state; + } + + return &group_state->base; + +out_free_state: + clear_tunnel_group_state(group_state); + kfree(group_state); + + return NULL; +} + +static void tunnel_group_destroy_state(struct drm_private_obj *obj, struct drm_private_state *state) +{ + struct drm_dp_tunnel_group_state *group_state = to_group_state(state); + + clear_tunnel_group_state(group_state); + kfree(group_state); +} + +static const struct drm_private_state_funcs tunnel_group_funcs = { + .atomic_duplicate_state = tunnel_group_duplicate_state, + .atomic_destroy_state = tunnel_group_destroy_state, +}; + +struct drm_dp_tunnel_state * +drm_dp_tunnel_atomic_get_state(struct drm_atomic_state *state, + struct drm_dp_tunnel *tunnel) +{ + struct drm_dp_tunnel_group_state *group_state = + drm_dp_tunnel_atomic_get_group_state(state, tunnel); + struct drm_dp_tunnel_state *tunnel_state; + + if (IS_ERR(group_state)) + return ERR_CAST(group_state); + + tunnel_state = get_or_add_tunnel_state(group_state, tunnel); + if (!tunnel_state) + return ERR_PTR(-ENOMEM); + + return tunnel_state; +} +EXPORT_SYMBOL(drm_dp_tunnel_atomic_get_state); + +struct drm_dp_tunnel_state * +drm_dp_tunnel_atomic_get_new_state(struct drm_atomic_state *state, + const struct drm_dp_tunnel *tunnel) +{ + struct drm_dp_tunnel_group_state *new_group_state; + int i; + + for_each_new_group_in_state(state, new_group_state, i) + if (to_group(new_group_state->base.obj) == tunnel->group) + return get_tunnel_state(new_group_state, tunnel); + + return NULL; +} +EXPORT_SYMBOL(drm_dp_tunnel_atomic_get_new_state); + +static bool init_group(struct drm_dp_tunnel_mgr *mgr, struct drm_dp_tunnel_group *group) +{ + struct drm_dp_tunnel_group_state *group_state = kzalloc(sizeof(*group_state), GFP_KERNEL); + + if (!group_state) + return false; + + INIT_LIST_HEAD(&group_state->tunnel_states); + + group->mgr = mgr; + group->available_bw = -1; + INIT_LIST_HEAD(&group->tunnels); + + drm_atomic_private_obj_init(mgr->dev, &group->base, &group_state->base, + &tunnel_group_funcs); + + return true; +} + +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 +static void check_unique_stream_ids(const struct drm_dp_tunnel_group_state *group_state) +{ + const struct drm_dp_tunnel_state *tunnel_state; + u32 stream_mask = 0; + + for_each_tunnel_state(group_state, tunnel_state) { + drm_WARN(to_group(group_state->base.obj)->mgr->dev, + tunnel_state->stream_mask & stream_mask, + "[DPTUN %s]: conflicting stream IDs %x (IDs in other tunnels %x)\n", + tunnel_state->tunnel_ref.tunnel->name, + tunnel_state->stream_mask, + stream_mask); + + stream_mask |= tunnel_state->stream_mask; + } +} +#else +static void check_unique_stream_ids(const struct drm_dp_tunnel_group_state *group_state) +{ +} +#endif + +static int stream_id_to_idx(u32 stream_mask, u8 stream_id) +{ + return hweight32(stream_mask & (BIT(stream_id) - 1)); +} + +static int resize_bw_array(struct drm_dp_tunnel_state *tunnel_state, + unsigned long old_mask, unsigned long new_mask) +{ + unsigned long move_mask = old_mask & new_mask; + int *new_bws = NULL; + int id; + + WARN_ON(!new_mask); + + if (old_mask == new_mask) + return 0; + + new_bws = kcalloc(hweight32(new_mask), sizeof(*new_bws), GFP_KERNEL); + if (!new_bws) + return -ENOMEM; + + for_each_set_bit(id, &move_mask, BITS_PER_TYPE(move_mask)) + new_bws[stream_id_to_idx(new_mask, id)] = + tunnel_state->stream_bw[stream_id_to_idx(old_mask, id)]; + + kfree(tunnel_state->stream_bw); + tunnel_state->stream_bw = new_bws; + tunnel_state->stream_mask = new_mask; + + return 0; +} + +static int set_stream_bw(struct drm_dp_tunnel_state *tunnel_state, + u8 stream_id, int bw) +{ + int err; + + err = resize_bw_array(tunnel_state, + tunnel_state->stream_mask, + tunnel_state->stream_mask | BIT(stream_id)); + if (err) + return err; + + tunnel_state->stream_bw[stream_id_to_idx(tunnel_state->stream_mask, stream_id)] = bw; + + return 0; +} + +static int clear_stream_bw(struct drm_dp_tunnel_state *tunnel_state, + u8 stream_id) +{ + if (!(tunnel_state->stream_mask & ~BIT(stream_id))) { + drm_dp_tunnel_atomic_clear_state(tunnel_state); + return 0; + } + + return resize_bw_array(tunnel_state, + tunnel_state->stream_mask, + tunnel_state->stream_mask & ~BIT(stream_id)); +} + +int drm_dp_tunnel_atomic_set_stream_bw(struct drm_atomic_state *state, + struct drm_dp_tunnel *tunnel, + u8 stream_id, int bw) +{ + struct drm_dp_tunnel_group_state *new_group_state = + drm_dp_tunnel_atomic_get_group_state(state, tunnel); + struct drm_dp_tunnel_state *tunnel_state; + int err; + + if (drm_WARN_ON(tunnel->group->mgr->dev, + stream_id > BITS_PER_TYPE(tunnel_state->stream_mask))) + return -EINVAL; + + tun_dbg(tunnel, + "Setting %d Mb/s for stream %d\n", + DPTUN_BW_ARG(bw), stream_id); + + if (bw == 0) { + tunnel_state = get_tunnel_state(new_group_state, tunnel); + if (!tunnel_state) + return 0; + + return clear_stream_bw(tunnel_state, stream_id); + } + + tunnel_state = get_or_add_tunnel_state(new_group_state, tunnel); + if (drm_WARN_ON(state->dev, !tunnel_state)) + return -EINVAL; + + err = set_stream_bw(tunnel_state, stream_id, bw); + if (err) + return err; + + check_unique_stream_ids(new_group_state); + + return 0; +} +EXPORT_SYMBOL(drm_dp_tunnel_atomic_set_stream_bw); + +int drm_dp_tunnel_atomic_get_tunnel_bw(const struct drm_dp_tunnel_state *tunnel_state) +{ + int tunnel_bw = 0; + int i; + + for (i = 0; i < hweight32(tunnel_state->stream_mask); i++) + tunnel_bw += tunnel_state->stream_bw[i]; + + return tunnel_bw; +} +EXPORT_SYMBOL(drm_dp_tunnel_atomic_get_tunnel_bw); + +int drm_dp_tunnel_atomic_get_group_streams_in_state(struct drm_atomic_state *state, + const struct drm_dp_tunnel *tunnel, + u32 *stream_mask) +{ + struct drm_dp_tunnel_group_state *group_state = + drm_dp_tunnel_atomic_get_group_state(state, tunnel); + struct drm_dp_tunnel_state *tunnel_state; + + if (IS_ERR(group_state)) + return PTR_ERR(group_state); + + *stream_mask = 0; + for_each_tunnel_state(group_state, tunnel_state) + *stream_mask |= tunnel_state->stream_mask; + + return 0; +} +EXPORT_SYMBOL(drm_dp_tunnel_atomic_get_group_streams_in_state); + +static int +drm_dp_tunnel_atomic_check_group_bw(struct drm_dp_tunnel_group_state *new_group_state, + u32 *failed_stream_mask) +{ + struct drm_dp_tunnel_group *group = to_group(new_group_state->base.obj); + struct drm_dp_tunnel_state *new_tunnel_state; + u32 group_stream_mask = 0; + int group_bw = 0; + + for_each_tunnel_state(new_group_state, new_tunnel_state) { + struct drm_dp_tunnel *tunnel = new_tunnel_state->tunnel_ref.tunnel; + int max_dprx_bw = get_max_dprx_bw(tunnel); + int tunnel_bw = drm_dp_tunnel_atomic_get_tunnel_bw(new_tunnel_state); + + tun_dbg(tunnel, + "%sRequired %d/%d Mb/s total for tunnel.\n", + tunnel_bw > max_dprx_bw ? "Not enough BW: " : "", + DPTUN_BW_ARG(tunnel_bw), + DPTUN_BW_ARG(max_dprx_bw)); + + if (tunnel_bw > max_dprx_bw) { + *failed_stream_mask = new_tunnel_state->stream_mask; + return -ENOSPC; + } + + group_bw += min(roundup(tunnel_bw, tunnel->bw_granularity), + max_dprx_bw); + group_stream_mask |= new_tunnel_state->stream_mask; + } + + tun_grp_dbg(group, + "%sRequired %d/%d Mb/s total for tunnel group.\n", + group_bw > group->available_bw ? "Not enough BW: " : "", + DPTUN_BW_ARG(group_bw), + DPTUN_BW_ARG(group->available_bw)); + + if (group_bw > group->available_bw) { + *failed_stream_mask = group_stream_mask; + return -ENOSPC; + } + + return 0; +} + +int drm_dp_tunnel_atomic_check_stream_bws(struct drm_atomic_state *state, + u32 *failed_stream_mask) +{ + struct drm_dp_tunnel_group_state *new_group_state; + int i; + + for_each_new_group_in_state(state, new_group_state, i) { + int ret; + + ret = drm_dp_tunnel_atomic_check_group_bw(new_group_state, + failed_stream_mask); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL(drm_dp_tunnel_atomic_check_stream_bws); + +static void destroy_mgr(struct drm_dp_tunnel_mgr *mgr) +{ + int i; + + for (i = 0; i < mgr->group_count; i++) { + cleanup_group(&mgr->groups[i]); + drm_WARN_ON(mgr->dev, !list_empty(&mgr->groups[i].tunnels)); + } + +#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE + ref_tracker_dir_exit(&mgr->ref_tracker); +#endif + + kfree(mgr->groups); + kfree(mgr); +} + +/** + * drm_dp_tunnel_mgr_create - Create a DP tunnel manager + * @i915: i915 driver object + * + * Creates a DP tunnel manager. + * + * Returns a pointer to the tunnel manager if created successfully or NULL in + * case of an error. + */ +struct drm_dp_tunnel_mgr * +drm_dp_tunnel_mgr_create(struct drm_device *dev, int max_group_count) +{ + struct drm_dp_tunnel_mgr *mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); + int i; + + if (!mgr) + return NULL; + + mgr->dev = dev; + init_waitqueue_head(&mgr->bw_req_queue); + + mgr->groups = kcalloc(max_group_count, sizeof(*mgr->groups), GFP_KERNEL); + if (!mgr->groups) { + kfree(mgr); + + return NULL; + } + +#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE + ref_tracker_dir_init(&mgr->ref_tracker, 16, "dptun"); +#endif + + for (i = 0; i < max_group_count; i++) { + if (!init_group(mgr, &mgr->groups[i])) { + destroy_mgr(mgr); + + return NULL; + } + + mgr->group_count++; + } + + return mgr; +} +EXPORT_SYMBOL(drm_dp_tunnel_mgr_create); + +/** + * drm_dp_tunnel_mgr_destroy - Destroy DP tunnel manager + * @mgr: Tunnel manager object + * + * Destroy the tunnel manager. + */ +void drm_dp_tunnel_mgr_destroy(struct drm_dp_tunnel_mgr *mgr) +{ + destroy_mgr(mgr); +} +EXPORT_SYMBOL(drm_dp_tunnel_mgr_destroy); diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h index 281afff6ee4e5..8bfd5d007be8d 100644 --- a/include/drm/display/drm_dp.h +++ b/include/drm/display/drm_dp.h @@ -1382,6 +1382,66 @@ #define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET 0x69494 #define DP_HDCP_2_2_REG_DBG_OFFSET 0x69518 +/* DP-tunneling */ +#define DP_TUNNELING_OUI 0xe0000 +#define DP_TUNNELING_OUI_BYTES 3 + +#define DP_TUNNELING_DEV_ID 0xe0003 +#define DP_TUNNELING_DEV_ID_BYTES 6 + +#define DP_TUNNELING_HW_REV 0xe0009 +#define DP_TUNNELING_HW_REV_MAJOR_SHIFT 4 +#define DP_TUNNELING_HW_REV_MAJOR_MASK (0xf << DP_TUNNELING_HW_REV_MAJOR_SHIFT) +#define DP_TUNNELING_HW_REV_MINOR_SHIFT 0 +#define DP_TUNNELING_HW_REV_MINOR_MASK (0xf << DP_TUNNELING_HW_REV_MINOR_SHIFT) + +#define DP_TUNNELING_SW_REV_MAJOR 0xe000a +#define DP_TUNNELING_SW_REV_MINOR 0xe000b + +#define DP_TUNNELING_CAPABILITIES 0xe000d +#define DP_IN_BW_ALLOCATION_MODE_SUPPORT (1 << 7) +#define DP_PANEL_REPLAY_OPTIMIZATION_SUPPORT (1 << 6) +#define DP_TUNNELING_SUPPORT (1 << 0) + +#define DP_IN_ADAPTER_INFO 0xe000e +#define DP_IN_ADAPTER_NUMBER_BITS 7 +#define DP_IN_ADAPTER_NUMBER_MASK ((1 << DP_IN_ADAPTER_NUMBER_BITS) - 1) + +#define DP_USB4_DRIVER_ID 0xe000f +#define DP_USB4_DRIVER_ID_BITS 4 +#define DP_USB4_DRIVER_ID_MASK ((1 << DP_USB4_DRIVER_ID_BITS) - 1) + +#define DP_USB4_DRIVER_BW_CAPABILITY 0xe0020 +#define DP_USB4_DRIVER_BW_ALLOCATION_MODE_SUPPORT (1 << 7) + +#define DP_IN_ADAPTER_TUNNEL_INFORMATION 0xe0021 +#define DP_GROUP_ID_BITS 3 +#define DP_GROUP_ID_MASK ((1 << DP_GROUP_ID_BITS) - 1) + +#define DP_BW_GRANULARITY 0xe0022 +#define DP_BW_GRANULARITY_MASK 0x3 + +#define DP_ESTIMATED_BW 0xe0023 +#define DP_ALLOCATED_BW 0xe0024 + +#define DP_TUNNELING_STATUS 0xe0025 +#define DP_BW_ALLOCATION_CAPABILITY_CHANGED (1 << 3) +#define DP_ESTIMATED_BW_CHANGED (1 << 2) +#define DP_BW_REQUEST_SUCCEEDED (1 << 1) +#define DP_BW_REQUEST_FAILED (1 << 0) + +#define DP_TUNNELING_MAX_LINK_RATE 0xe0028 + +#define DP_TUNNELING_MAX_LANE_COUNT 0xe0029 +#define DP_TUNNELING_MAX_LANE_COUNT_MASK 0x1f + +#define DP_DPTX_BW_ALLOCATION_MODE_CONTROL 0xe0030 +#define DP_DISPLAY_DRIVER_BW_ALLOCATION_MODE_ENABLE (1 << 7) +#define DP_UNMASK_BW_ALLOCATION_IRQ (1 << 6) + +#define DP_REQUEST_BW 0xe0031 +#define MAX_DP_REQUEST_BW 255 + /* LTTPR: Link Training (LT)-tunable PHY Repeaters */ #define DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV 0xf0000 /* 1.3 */ #define DP_MAX_LINK_RATE_PHY_REPEATER 0xf0001 /* 1.4a */ diff --git a/include/drm/display/drm_dp_tunnel.h b/include/drm/display/drm_dp_tunnel.h new file mode 100644 index 0000000000000..f6449b1b4e6e9 --- /dev/null +++ b/include/drm/display/drm_dp_tunnel.h @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __DRM_DP_TUNNEL_H__ +#define __DRM_DP_TUNNEL_H__ + +#include +#include +#include + +struct drm_dp_aux; + +struct drm_device; + +struct drm_atomic_state; +struct drm_dp_tunnel_mgr; +struct drm_dp_tunnel_state; + +struct ref_tracker; + +struct drm_dp_tunnel_ref { + struct drm_dp_tunnel *tunnel; +#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE + struct ref_tracker *tracker; +#endif +}; + +#ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL + +struct drm_dp_tunnel * +drm_dp_tunnel_get_untracked(struct drm_dp_tunnel *tunnel); +void drm_dp_tunnel_put_untracked(struct drm_dp_tunnel *tunnel); + +#ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE +struct drm_dp_tunnel * +drm_dp_tunnel_get(struct drm_dp_tunnel *tunnel, struct ref_tracker **tracker); + +void +drm_dp_tunnel_put(struct drm_dp_tunnel *tunnel, struct ref_tracker **tracker); +#else +#define drm_dp_tunnel_get(tunnel, tracker) \ + drm_dp_tunnel_get_untracked(tunnel) + +#define drm_dp_tunnel_put(tunnel, tracker) \ + drm_dp_tunnel_put_untracked(tunnel) + +#endif + +static inline void drm_dp_tunnel_ref_get(struct drm_dp_tunnel *tunnel, + struct drm_dp_tunnel_ref *tunnel_ref) +{ + tunnel_ref->tunnel = drm_dp_tunnel_get(tunnel, &tunnel_ref->tracker); +} + +static inline void drm_dp_tunnel_ref_put(struct drm_dp_tunnel_ref *tunnel_ref) +{ + drm_dp_tunnel_put(tunnel_ref->tunnel, &tunnel_ref->tracker); +} + +struct drm_dp_tunnel * +drm_dp_tunnel_detect(struct drm_dp_tunnel_mgr *mgr, + struct drm_dp_aux *aux); +int drm_dp_tunnel_destroy(struct drm_dp_tunnel *tunnel); + +int drm_dp_tunnel_enable_bw_alloc(struct drm_dp_tunnel *tunnel); +int drm_dp_tunnel_disable_bw_alloc(struct drm_dp_tunnel *tunnel); +bool drm_dp_tunnel_bw_alloc_is_enabled(const struct drm_dp_tunnel *tunnel); +int drm_dp_tunnel_alloc_bw(struct drm_dp_tunnel *tunnel, int bw); +int drm_dp_tunnel_check_state(struct drm_dp_tunnel *tunnel); +int drm_dp_tunnel_update_state(struct drm_dp_tunnel *tunnel); + +void drm_dp_tunnel_set_io_error(struct drm_dp_tunnel *tunnel); + +int drm_dp_tunnel_handle_irq(struct drm_dp_tunnel_mgr *mgr, + struct drm_dp_aux *aux); + +int drm_dp_tunnel_max_dprx_rate(const struct drm_dp_tunnel *tunnel); +int drm_dp_tunnel_max_dprx_lane_count(const struct drm_dp_tunnel *tunnel); +int drm_dp_tunnel_available_bw(const struct drm_dp_tunnel *tunnel); + +const char *drm_dp_tunnel_name(const struct drm_dp_tunnel *tunnel); + +struct drm_dp_tunnel_state * +drm_dp_tunnel_atomic_get_state(struct drm_atomic_state *state, + struct drm_dp_tunnel *tunnel); +struct drm_dp_tunnel_state * +drm_dp_tunnel_atomic_get_new_state(struct drm_atomic_state *state, + const struct drm_dp_tunnel *tunnel); + +void drm_dp_tunnel_atomic_clear_state(struct drm_dp_tunnel_state *tunnel_state); + +int drm_dp_tunnel_atomic_set_stream_bw(struct drm_atomic_state *state, + struct drm_dp_tunnel *tunnel, + u8 stream_id, int bw); +int drm_dp_tunnel_atomic_get_group_streams_in_state(struct drm_atomic_state *state, + const struct drm_dp_tunnel *tunnel, + u32 *stream_mask); + +int drm_dp_tunnel_atomic_check_stream_bws(struct drm_atomic_state *state, + u32 *failed_stream_mask); + +int drm_dp_tunnel_atomic_get_tunnel_bw(const struct drm_dp_tunnel_state *tunnel_state); + +struct drm_dp_tunnel_mgr * +drm_dp_tunnel_mgr_create(struct drm_device *dev, int max_group_count); +void drm_dp_tunnel_mgr_destroy(struct drm_dp_tunnel_mgr *mgr); + +#else + +static inline struct drm_dp_tunnel * +drm_dp_tunnel_get_untracked(struct drm_dp_tunnel *tunnel) +{ + return NULL; +} + +static inline void +drm_dp_tunnel_put_untracked(struct drm_dp_tunnel *tunnel) {} + +static inline struct drm_dp_tunnel * +drm_dp_tunnel_get(struct drm_dp_tunnel *tunnel, struct ref_tracker **tracker) +{ + return NULL; +} + +static inline void +drm_dp_tunnel_put(struct drm_dp_tunnel *tunnel, struct ref_tracker **tracker) {} + +static inline void drm_dp_tunnel_ref_get(struct drm_dp_tunnel *tunnel, + struct drm_dp_tunnel_ref *tunnel_ref) {} +static inline void drm_dp_tunnel_ref_put(struct drm_dp_tunnel_ref *tunnel_ref) {} + +static inline struct drm_dp_tunnel * +drm_dp_tunnel_detect(struct drm_dp_tunnel_mgr *mgr, + struct drm_dp_aux *aux) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline int +drm_dp_tunnel_destroy(struct drm_dp_tunnel *tunnel) +{ + return 0; +} + +static inline int drm_dp_tunnel_enable_bw_alloc(struct drm_dp_tunnel *tunnel) +{ + return -EOPNOTSUPP; +} + +static inline int drm_dp_tunnel_disable_bw_alloc(struct drm_dp_tunnel *tunnel) +{ + return -EOPNOTSUPP; +} + +static inline bool drm_dp_tunnel_bw_alloc_is_enabled(const struct drm_dp_tunnel *tunnel) +{ + return false; +} + +static inline int +drm_dp_tunnel_alloc_bw(struct drm_dp_tunnel *tunnel, int bw) +{ + return -EOPNOTSUPP; +} + +static inline int +drm_dp_tunnel_check_state(struct drm_dp_tunnel *tunnel) +{ + return -EOPNOTSUPP; +} + +static inline int +drm_dp_tunnel_update_state(struct drm_dp_tunnel *tunnel) +{ + return -EOPNOTSUPP; +} + +static inline void drm_dp_tunnel_set_io_error(struct drm_dp_tunnel *tunnel) {} +static inline int +drm_dp_tunnel_handle_irq(struct drm_dp_tunnel_mgr *mgr, + struct drm_dp_aux *aux) +{ + return -EOPNOTSUPP; +} + +static inline int +drm_dp_tunnel_max_dprx_rate(const struct drm_dp_tunnel *tunnel) +{ + return 0; +} + +static inline int +drm_dp_tunnel_max_dprx_lane_count(const struct drm_dp_tunnel *tunnel) +{ + return 0; +} + +static inline int +drm_dp_tunnel_available_bw(const struct drm_dp_tunnel *tunnel) +{ + return -1; +} + +static inline const char * +drm_dp_tunnel_name(const struct drm_dp_tunnel *tunnel) +{ + return NULL; +} + +static inline struct drm_dp_tunnel_state * +drm_dp_tunnel_atomic_get_state(struct drm_atomic_state *state, + struct drm_dp_tunnel *tunnel) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline struct drm_dp_tunnel_state * +drm_dp_tunnel_atomic_get_new_state(struct drm_atomic_state *state, + const struct drm_dp_tunnel *tunnel) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline void +drm_dp_tunnel_atomic_clear_state(struct drm_dp_tunnel_state *tunnel_state) {} + +static inline int +drm_dp_tunnel_atomic_set_stream_bw(struct drm_atomic_state *state, + struct drm_dp_tunnel *tunnel, + u8 stream_id, int bw) +{ + return -EOPNOTSUPP; +} + +static inline int +drm_dp_tunnel_atomic_get_group_streams_in_state(struct drm_atomic_state *state, + const struct drm_dp_tunnel *tunnel, + u32 *stream_mask) +{ + return -EOPNOTSUPP; +} + +static inline int +drm_dp_tunnel_atomic_check_stream_bws(struct drm_atomic_state *state, + u32 *failed_stream_mask) +{ + return -EOPNOTSUPP; +} + +static inline int +drm_dp_tunnel_atomic_get_tunnel_bw(const struct drm_dp_tunnel_state *tunnel_state) +{ + return 0; +} + +static inline struct drm_dp_tunnel_mgr * +drm_dp_tunnel_mgr_create(struct drm_device *dev, int max_group_count) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline +void drm_dp_tunnel_mgr_destroy(struct drm_dp_tunnel_mgr *mgr) {} + + +#endif /* CONFIG_DRM_DISPLAY_DP_TUNNEL */ + +#endif /* __DRM_DP_TUNNEL_H__ */ From patchwork Tue Jan 23 10:28:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527149 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9396BC47E49 for ; Tue, 23 Jan 2024 10:28:53 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0A37F10E7A2; Tue, 23 Jan 2024 10:28:44 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id C0C9910E76E; Tue, 23 Jan 2024 10:28:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005721; x=1737541721; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=SiGBezTlCUPjMEVgldPF8t4rrQVF88naNV3YWnQjwhs=; b=WVVzo/3fnXUQ2VA4yZfCKKZLiyGJBZ5dW4rsQUCYyLce44IWI0e0qzsQ RFFLjWExcUYCONkM59hVG2I4zZm8WV7h65aG6G6joHiJYxZdj/OYDg9zS 5Syf+4z/JGkH+o7eOf25mkFlt2fRNkh4ytGj7ZiO9fvi1KQoG1lu5Tz+t k02xPimfKYtKRKP1LOEH+whc6A76SXHYXuLZnO/KqfsZefB0U+gDumA/j aBvVEaOXHUzLOLuAw17GPD445Fm2R3dyH4A87joaX83j1yg/EhZerO+ow 0N+rirgdQ8Py3O5uIREG+du+jdW5IIoChxwYIkxlPphC4FfTFRES/lLZd Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134123" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134123" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:41 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283367" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283367" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:40 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 03/19] drm/i915/dp: Add support to notify MST connectors to retry modesets Date: Tue, 23 Jan 2024 12:28:34 +0200 Message-Id: <20240123102850.390126-4-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" On shared (Thunderbolt) links with DP tunnels, the modeset may need to be retried on all connectors on the link due to a link BW limitation arising only after the atomic check phase. To support this add a helper function queuing a work to retry the modeset on a given port's connector and at the same time any MST connector with streams through the same port. A follow-up change enabling the DP tunnel Bandwidth Allocation Mode will take this into use. Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_display.c | 5 +- drivers/gpu/drm/i915/display/intel_dp.c | 55 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_dp.h | 8 +++ .../drm/i915/display/intel_dp_link_training.c | 3 +- drivers/gpu/drm/i915/display/intel_dp_mst.c | 2 + 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index a92e959c8ac7b..0caebbb3e2dbb 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -8060,8 +8060,9 @@ void intel_hpd_poll_fini(struct drm_i915_private *i915) /* Kill all the work that may have been queued by hpd. */ drm_connector_list_iter_begin(&i915->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { - if (connector->modeset_retry_work.func) - cancel_work_sync(&connector->modeset_retry_work); + if (connector->modeset_retry_work.func && + cancel_work_sync(&connector->modeset_retry_work)) + drm_connector_put(&connector->base); if (connector->hdcp.shim) { cancel_delayed_work_sync(&connector->hdcp.check_work); cancel_work_sync(&connector->hdcp.prop_work); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index ab415f41924d7..4e36c2c39888e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2837,6 +2837,50 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder, intel_dp_is_uhbr(pipe_config); } +void intel_dp_queue_modeset_retry_work(struct intel_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + + drm_connector_get(&connector->base); + if (!queue_work(i915->unordered_wq, &connector->modeset_retry_work)) + drm_connector_put(&connector->base); +} + +void +intel_dp_queue_modeset_retry_for_link(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + struct intel_connector *connector; + struct intel_digital_connector_state *iter_conn_state; + struct intel_dp *intel_dp; + int i; + + if (conn_state) { + connector = to_intel_connector(conn_state->connector); + intel_dp_queue_modeset_retry_work(connector); + + return; + } + + if (drm_WARN_ON(&i915->drm, + !intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))) + return; + + intel_dp = enc_to_intel_dp(encoder); + + for_each_new_intel_connector_in_state(state, connector, iter_conn_state, i) { + (void)iter_conn_state; + + if (connector->mst_port != intel_dp) + continue; + + intel_dp_queue_modeset_retry_work(connector); + } +} + int intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, @@ -6436,6 +6480,14 @@ static void intel_dp_modeset_retry_work_fn(struct work_struct *work) mutex_unlock(&connector->dev->mode_config.mutex); /* Send Hotplug uevent so userspace can reprobe */ drm_kms_helper_connector_hotplug_event(connector); + + drm_connector_put(connector); +} + +void intel_dp_init_modeset_retry_work(struct intel_connector *connector) +{ + INIT_WORK(&connector->modeset_retry_work, + intel_dp_modeset_retry_work_fn); } bool @@ -6452,8 +6504,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, int type; /* Initialize the work for modeset in case of link train failure */ - INIT_WORK(&intel_connector->modeset_retry_work, - intel_dp_modeset_retry_work_fn); + intel_dp_init_modeset_retry_work(intel_connector); if (drm_WARN(dev, dig_port->max_lanes < 1, "Not enough lanes (%d) for DP on [ENCODER:%d:%s]\n", diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 530cc97bc42f4..105c2086310db 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -23,6 +23,8 @@ struct intel_digital_port; struct intel_dp; struct intel_encoder; +struct work_struct; + struct link_config_limits { int min_rate, max_rate; int min_lane_count, max_lane_count; @@ -43,6 +45,12 @@ void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); int intel_dp_min_bpp(enum intel_output_format output_format); +void intel_dp_init_modeset_retry_work(struct intel_connector *connector); +void intel_dp_queue_modeset_retry_work(struct intel_connector *connector); +void intel_dp_queue_modeset_retry_for_link(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state); bool intel_dp_init_connector(struct intel_digital_port *dig_port, struct intel_connector *intel_connector); void intel_dp_set_link_params(struct intel_dp *intel_dp, diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 1abfafbbfa757..7b140cbf8dd31 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -1075,7 +1075,6 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { struct intel_connector *intel_connector = intel_dp->attached_connector; - struct drm_i915_private *i915 = dp_to_i915(intel_dp); if (!intel_digital_port_connected(&dp_to_dig_port(intel_dp)->base)) { lt_dbg(intel_dp, DP_PHY_DPRX, "Link Training failed on disconnected sink.\n"); @@ -1093,7 +1092,7 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp, } /* Schedule a Hotplug Uevent to userspace to start modeset */ - queue_work(i915->unordered_wq, &intel_connector->modeset_retry_work); + intel_dp_queue_modeset_retry_work(intel_connector); } /* Perform the link training on all LTTPRs and the DPRX on a link. */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 5fa25a5a36b55..b15e43ebf138b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1542,6 +1542,8 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo intel_connector->port = port; drm_dp_mst_get_port_malloc(port); + intel_dp_init_modeset_retry_work(intel_connector); + intel_connector->dp.dsc_decompression_aux = drm_dp_mst_dsc_aux_for_port(port); intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector); intel_connector->dp.dsc_hblank_expansion_quirk = From patchwork Tue Jan 23 10:28:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527154 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1FC07C47DDC for ; Tue, 23 Jan 2024 10:29:16 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 68CD010F019; Tue, 23 Jan 2024 10:28:50 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 041F910E76E; Tue, 23 Jan 2024 10:28:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005723; x=1737541723; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=wBt1okxpgzJ1MnqnK6TGKPIY1KTWyrfUaTQNzxDpWlg=; b=NyWf3BVWvHvsFlYLyrFuoRcjc5OSRAkmjxbbbLqpF1sT4NV/+zGVX2dU Jh7xh1W8jOGGvAo97IDzhskw1Xyqy0g8fKv074L2VhKWPnM/XQLHco60i FzlkF6yN4rsFmY5QMcFPBWswJhs8uo8jtn//vzqkWewXIdWgqS+8LgCMt VI9B1rBsfy2BV8EOk7JO66Su/j0LeXOWMsnVrui8beDknUd5R39jg5gwN ryO9pjDHzHtWE947sXllX7P8ClmoWuN1ncYqIBvBX7A0zSsbXaxy5ksV/ oR5xCinvIBFQb1hDULVFc1XJQio23cB8FkiPEB6y7lwyYDYiWz41xq3IY Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134132" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134132" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:42 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283372" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283372" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:41 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 04/19] drm/i915/dp: Use drm_dp_max_dprx_data_rate() Date: Tue, 23 Jan 2024 12:28:35 +0200 Message-Id: <20240123102850.390126-5-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Instead of intel_dp_max_data_rate() use the equivalent drm_dp_max_dprx_data_rate() which was copied from the former one in a previous patch. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_dp.c | 62 +++----------------- drivers/gpu/drm/i915/display/intel_dp.h | 1 - drivers/gpu/drm/i915/display/intel_dp_mst.c | 2 +- 4 files changed, 10 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 0caebbb3e2dbb..b9f985a5e705b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2478,7 +2478,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes, u32 link_symbol_clock = intel_dp_link_symbol_clock(link_clock); u32 data_m = intel_dp_effective_data_rate(pixel_clock, bits_per_pixel_x16, bw_overhead); - u32 data_n = intel_dp_max_data_rate(link_clock, nlanes); + u32 data_n = drm_dp_max_dprx_data_rate(link_clock, nlanes); /* * Windows/BIOS uses fixed M/N values always. Follow suit. diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 4e36c2c39888e..c7b06a9b197cc 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -383,52 +383,6 @@ int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, 1000000 * 16 * 8); } -/* - * Given a link rate and lanes, get the data bandwidth. - * - * Data bandwidth is the actual payload rate, which depends on the data - * bandwidth efficiency and the link rate. - * - * For 8b/10b channel encoding, SST and non-FEC, the data bandwidth efficiency - * is 80%. For example, for a 1.62 Gbps link, 1.62*10^9 bps * 0.80 * (1/8) = - * 162000 kBps. With 8-bit symbols, we have 162000 kHz symbol clock. Just by - * coincidence, the port clock in kHz matches the data bandwidth in kBps, and - * they equal the link bit rate in Gbps multiplied by 100000. (Note that this no - * longer holds for data bandwidth as soon as FEC or MST is taken into account!) - * - * For 128b/132b channel encoding, the data bandwidth efficiency is 96.71%. For - * example, for a 10 Gbps link, 10*10^9 bps * 0.9671 * (1/8) = 1208875 - * kBps. With 32-bit symbols, we have 312500 kHz symbol clock. The value 1000000 - * does not match the symbol clock, the port clock (not even if you think in - * terms of a byte clock), nor the data bandwidth. It only matches the link bit - * rate in units of 10000 bps. - */ -int -intel_dp_max_data_rate(int max_link_rate, int max_lanes) -{ - int ch_coding_efficiency = - drm_dp_bw_channel_coding_efficiency(drm_dp_is_uhbr_rate(max_link_rate)); - int max_link_rate_kbps = max_link_rate * 10; - - /* - * UHBR rates always use 128b/132b channel encoding, and have - * 97.71% data bandwidth efficiency. Consider max_link_rate the - * link bit rate in units of 10000 bps. - */ - /* - * Lower than UHBR rates always use 8b/10b channel encoding, and have - * 80% data bandwidth efficiency for SST non-FEC. However, this turns - * out to be a nop by coincidence: - * - * int max_link_rate_kbps = max_link_rate * 10; - * max_link_rate_kbps = DIV_ROUND_DOWN_ULL(max_link_rate_kbps * 8, 10); - * max_link_rate = max_link_rate_kbps / 8; - */ - return DIV_ROUND_DOWN_ULL(mul_u32_u32(max_link_rate_kbps * max_lanes, - ch_coding_efficiency), - 1000000 * 8); -} - bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); @@ -658,7 +612,7 @@ static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp, int mode_rate, max_rate; mode_rate = intel_dp_link_required(fixed_mode->clock, 18); - max_rate = intel_dp_max_data_rate(link_rate, lane_count); + max_rate = drm_dp_max_dprx_data_rate(link_rate, lane_count); if (mode_rate > max_rate) return false; @@ -1260,7 +1214,7 @@ intel_dp_mode_valid(struct drm_connector *_connector, max_link_clock = intel_dp_max_link_rate(intel_dp); max_lanes = intel_dp_max_lane_count(intel_dp); - max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); + max_rate = drm_dp_max_dprx_data_rate(max_link_clock, max_lanes); mode_rate = intel_dp_link_required(target_clock, intel_dp_mode_min_output_bpp(connector, mode)); @@ -1610,8 +1564,8 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, for (lane_count = limits->min_lane_count; lane_count <= limits->max_lane_count; lane_count <<= 1) { - link_avail = intel_dp_max_data_rate(link_rate, - lane_count); + link_avail = drm_dp_max_dprx_data_rate(link_rate, + lane_count); if (mode_rate <= link_avail) { pipe_config->lane_count = lane_count; @@ -2462,8 +2416,8 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, "DP link rate required %i available %i\n", intel_dp_link_required(adjusted_mode->crtc_clock, to_bpp_int_roundup(pipe_config->dsc.compressed_bpp_x16)), - intel_dp_max_data_rate(pipe_config->port_clock, - pipe_config->lane_count)); + drm_dp_max_dprx_data_rate(pipe_config->port_clock, + pipe_config->lane_count)); } else { drm_dbg_kms(&i915->drm, "DP lane count %d clock %d bpp %d\n", pipe_config->lane_count, pipe_config->port_clock, @@ -2473,8 +2427,8 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, "DP link rate required %i available %i\n", intel_dp_link_required(adjusted_mode->crtc_clock, pipe_config->pipe_bpp), - intel_dp_max_data_rate(pipe_config->port_clock, - pipe_config->lane_count)); + drm_dp_max_dprx_data_rate(pipe_config->port_clock, + pipe_config->lane_count)); } return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 105c2086310db..46f79747f807d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -113,7 +113,6 @@ bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp); int intel_dp_link_required(int pixel_clock, int bpp); int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, int bw_overhead); -int intel_dp_max_data_rate(int max_link_rate, int max_lanes); bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp); bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index b15e43ebf138b..cfcc157b7d41d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1295,7 +1295,7 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, max_link_clock = intel_dp_max_link_rate(intel_dp); max_lanes = intel_dp_max_lane_count(intel_dp); - max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); + max_rate = drm_dp_max_dprx_data_rate(max_link_clock, max_lanes); mode_rate = intel_dp_link_required(mode->clock, min_bpp); ret = drm_modeset_lock(&mgr->base.lock, ctx); From patchwork Tue Jan 23 10:28:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527150 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3B80CC47E49 for ; Tue, 23 Jan 2024 10:29:00 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 2022C10EF3F; Tue, 23 Jan 2024 10:28:49 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4D22C10EA7F; Tue, 23 Jan 2024 10:28:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005724; x=1737541724; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=4RiBykxeZLL6+QW7mH8+ye4vpmFbVa12qTQcxTsBclE=; b=AgctgxPGyHq2kS2Ya0vKhoIzPV9iBoDVWwUzBEaLL69I7GjGRYbXkgAW LQ8A6GKAmU8jGT9hHJ1uNWPDzb2U1UdBz/LoKgE3vdF9rUfjKpkw1YNJV t6G8/6UD2HLz0NGV9fN6PfQgkZZqtiMrmaVpP8pUuy/wtaZOvEpGJBuKA 7czwPvNo7pQctWPZHVTsK8/kHoPKu5O6a2//HJImCmtx9IlBNCSgyBd3I BTWl8MaiitStqhdkoHHagqOIpNVBhs0USXfjttL+H8Son0X8y5WGwReF+ 5Jdd/L6WRynmiop759b8tJaxDK0wgUxiBpPIgN6hjkUjNWzM1eRfMBPx0 w==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134142" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134142" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:44 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283380" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283380" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:43 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 05/19] drm/i915/dp: Factor out intel_dp_config_required_rate() Date: Tue, 23 Jan 2024 12:28:36 +0200 Message-Id: <20240123102850.390126-6-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Factor out intel_dp_config_required_rate() used by a follow-up patch enabling the DP tunnel BW allocation mode. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_dp.c | 43 +++++++++++-------------- drivers/gpu/drm/i915/display/intel_dp.h | 1 + 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index c7b06a9b197cc..0a5c60428ffb7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2338,6 +2338,17 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp, limits); } +int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state) +{ + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + int bpp = crtc_state->dsc.compression_enable ? + to_bpp_int_roundup(crtc_state->dsc.compressed_bpp_x16) : + crtc_state->pipe_bpp; + + return intel_dp_link_required(adjusted_mode->crtc_clock, bpp); +} + static int intel_dp_compute_link_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, @@ -2405,31 +2416,15 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, return ret; } - if (pipe_config->dsc.compression_enable) { - drm_dbg_kms(&i915->drm, - "DP lane count %d clock %d Input bpp %d Compressed bpp " BPP_X16_FMT "\n", - pipe_config->lane_count, pipe_config->port_clock, - pipe_config->pipe_bpp, - BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16)); + drm_dbg_kms(&i915->drm, + "DP lane count %d clock %d bpp input %d compressed " BPP_X16_FMT " link rate required %d available %d\n", + pipe_config->lane_count, pipe_config->port_clock, + pipe_config->pipe_bpp, + BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16), + intel_dp_config_required_rate(pipe_config), + drm_dp_max_dprx_data_rate(pipe_config->port_clock, + pipe_config->lane_count)); - drm_dbg_kms(&i915->drm, - "DP link rate required %i available %i\n", - intel_dp_link_required(adjusted_mode->crtc_clock, - to_bpp_int_roundup(pipe_config->dsc.compressed_bpp_x16)), - drm_dp_max_dprx_data_rate(pipe_config->port_clock, - pipe_config->lane_count)); - } else { - drm_dbg_kms(&i915->drm, "DP lane count %d clock %d bpp %d\n", - pipe_config->lane_count, pipe_config->port_clock, - pipe_config->pipe_bpp); - - drm_dbg_kms(&i915->drm, - "DP link rate required %i available %i\n", - intel_dp_link_required(adjusted_mode->crtc_clock, - pipe_config->pipe_bpp), - drm_dp_max_dprx_data_rate(pipe_config->port_clock, - pipe_config->lane_count)); - } return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 46f79747f807d..37274e3c2902f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -102,6 +102,7 @@ void intel_dp_mst_suspend(struct drm_i915_private *dev_priv); void intel_dp_mst_resume(struct drm_i915_private *dev_priv); int intel_dp_max_link_rate(struct intel_dp *intel_dp); int intel_dp_max_lane_count(struct intel_dp *intel_dp); +int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state); int intel_dp_rate_select(struct intel_dp *intel_dp, int rate); void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, From patchwork Tue Jan 23 10:28:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527153 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 74A0EC47258 for ; Tue, 23 Jan 2024 10:29:11 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 23D7F10EFBA; Tue, 23 Jan 2024 10:28:50 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 737E910EB4C; Tue, 23 Jan 2024 10:28:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005725; x=1737541725; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Vip63RD/2s+1G9VzFNK9k2dQp3LIoby+R7cXniTTTpY=; b=b6qULlIGzw9f1LGR//yXsfcV6RP3p2uTdToKb6pq8rWW7HjbXRMsx3J2 LPl67vVIG4upRIv2nFzuqoSvjf1JcoaH/c472NEpbJFjGV2tEmA/0y5eB tUA+k9ZpPn3l9wZ5le2UivmKswKnNCbONewVN1+Qf+S/yIaP2v3qsCGsb 34KYsNNb/nldBdA/9OCZX0sOj3ntkQRko88RscTK0FEV5RiNVY6DmZ0gW VtRpPu1/bMEwOS/FKnzXuBm5MyhmD9w696JOkYAeMKLOSNghSAd26yTN1 4QwqKC9TVK7QgM17larNGWAtg6abiUWwUkpdP0YL5sDxF06CJdEUF9Ti1 A==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134149" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134149" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:45 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283384" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283384" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:44 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 06/19] drm/i915/dp: Export intel_dp_max_common_rate/lane_count() Date: Tue, 23 Jan 2024 12:28:37 +0200 Message-Id: <20240123102850.390126-7-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Export intel_dp_max_common_rate() and intel_dp_max_lane_count() used by a follow-up patch enabling the DP tunnel BW allocation mode. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_dp.c | 4 ++-- drivers/gpu/drm/i915/display/intel_dp.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0a5c60428ffb7..f40706c5d1aad 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -309,7 +309,7 @@ static int intel_dp_common_rate(struct intel_dp *intel_dp, int index) } /* Theoretical max between source and sink */ -static int intel_dp_max_common_rate(struct intel_dp *intel_dp) +int intel_dp_max_common_rate(struct intel_dp *intel_dp) { return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1); } @@ -326,7 +326,7 @@ static int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port) } /* Theoretical max between source and sink */ -static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) +int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); int source_max = intel_dp_max_source_lane_count(dig_port); diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 37274e3c2902f..a7906d8738c4a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -104,6 +104,8 @@ int intel_dp_max_link_rate(struct intel_dp *intel_dp); int intel_dp_max_lane_count(struct intel_dp *intel_dp); int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state); int intel_dp_rate_select(struct intel_dp *intel_dp, int rate); +int intel_dp_max_common_rate(struct intel_dp *intel_dp); +int intel_dp_max_common_lane_count(struct intel_dp *intel_dp); void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, u8 *link_bw, u8 *rate_select); From patchwork Tue Jan 23 10:28:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527158 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2D23EC47DDB for ; Tue, 23 Jan 2024 10:29:51 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6B75F10F241; Tue, 23 Jan 2024 10:29:02 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id AAC3C10EDBB; Tue, 23 Jan 2024 10:28:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005726; x=1737541726; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=r1SGjFbZ50BXnnoWbXE6ojq+34GJ7lTl9UhjNtzoJ68=; b=DHs9R85NE1yoCWHkUyvNBGNfNn4778G9zbKeQNtWdHa0F+MtT4yjG7SD nPejAL16YEWOyJBVbA7xpPHpy5KZS9o1f6UboxG354+ToluJ4T4cccy5k H5K0r3cNXEfPh+IfraaV6nDwK8lanlHzLnVv5+1PR7sTL1HsNPUaLvNRb fckFKVDqAcgb41oK6+0o1YGCyYgxAXEOw38debQasdsHN5NEop0TKT0jQ zu3kYGjE+UcaqkJ2b/4vSbnCAl5Rsa2CZiziMUobpET3kFZP8Nxh+UK4D samV1/wBBAR1GcQpuiZUIlzJVYFYq0O3E+oJt9TKlvvtr5OIF97HEsK9N w==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134152" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134152" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:46 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283387" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283387" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:45 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 07/19] drm/i915/dp: Factor out intel_dp_update_sink_caps() Date: Tue, 23 Jan 2024 12:28:38 +0200 Message-Id: <20240123102850.390126-8-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Factor out a function updating the sink's link rate and lane count capabilities, used by a follow-up patch enabling the DP tunnel BW allocation mode. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_dp.c | 11 ++++++++--- drivers/gpu/drm/i915/display/intel_dp.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index f40706c5d1aad..23434d0aba188 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3949,6 +3949,13 @@ intel_dp_has_sink_count(struct intel_dp *intel_dp) &intel_dp->desc); } +void intel_dp_update_sink_caps(struct intel_dp *intel_dp) +{ + intel_dp_set_sink_rates(intel_dp); + intel_dp_set_max_sink_lane_count(intel_dp); + intel_dp_set_common_rates(intel_dp); +} + static bool intel_dp_get_dpcd(struct intel_dp *intel_dp) { @@ -3965,9 +3972,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc, drm_dp_is_branch(intel_dp->dpcd)); - intel_dp_set_sink_rates(intel_dp); - intel_dp_set_max_sink_lane_count(intel_dp); - intel_dp_set_common_rates(intel_dp); + intel_dp_update_sink_caps(intel_dp); } if (intel_dp_has_sink_count(intel_dp)) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index a7906d8738c4a..49553e43add22 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -106,6 +106,7 @@ int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state); int intel_dp_rate_select(struct intel_dp *intel_dp, int rate); int intel_dp_max_common_rate(struct intel_dp *intel_dp); int intel_dp_max_common_lane_count(struct intel_dp *intel_dp); +void intel_dp_update_sink_caps(struct intel_dp *intel_dp); void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, u8 *link_bw, u8 *rate_select); From patchwork Tue Jan 23 10:28:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527151 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8BF45C47258 for ; Tue, 23 Jan 2024 10:29:02 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 55E8210EF9A; Tue, 23 Jan 2024 10:28:49 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id EC8AF10EDBB; Tue, 23 Jan 2024 10:28:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005727; x=1737541727; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=hVsTSJ1Z3VBG2JYY1RibLV4xyDF4tAtc+6xMPDfUUwY=; b=D0Y8R7MQWOPzXFZQeUvZPowYY5ZqYwXbNfWsGSbZOcTd0vgs1QZO7U7D ANIwjDNhs2bQfLYYtQKWKaFvfQZpGSDTqN0mwpfFQngmcrN4fSnJAOfHI iFsYY1CmhpHIj6ptsqRG6cy9sK3bkv4VfDzCMBvJp2muMrV46TJEvH2ML 1dZIsX+0tzTgHSosWvLE6q4a2sFMzXjer9R61Yovs4O0NOORhxfyzdzz+ yCdpRGb3jgnxJKnTLOi86vrDdaHnvVsjVXK/2Mu0ZaQDJOA8C6KA52vzc 0elHZsJyEHwhWettwwG8+uYwoaQNNpm4jIg4iioQQ2nQpLM3opYdJnkgC A==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134162" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134162" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:47 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283391" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283391" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:46 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 08/19] drm/i915/dp: Factor out intel_dp_read_dprx_caps() Date: Tue, 23 Jan 2024 12:28:39 +0200 Message-Id: <20240123102850.390126-9-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Factor out a function to read the sink's DPRX capabilities used by a follow-up patch enabling the DP tunnel BW allocation mode. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- .../drm/i915/display/intel_dp_link_training.c | 30 +++++++++++++++---- .../drm/i915/display/intel_dp_link_training.h | 1 + 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 7b140cbf8dd31..fb84ca98bb7ab 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -162,6 +162,28 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI return lttpr_count; } +int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + if (intel_dp_is_edp(intel_dp)) + return 0; + + /* + * Detecting LTTPRs must be avoided on platforms with an AUX timeout + * period < 3.2ms. (see DP Standard v2.0, 2.11.2, 3.6.6.1). + */ + if (DISPLAY_VER(i915) >= 10 && !IS_GEMINILAKE(i915)) + if (drm_dp_dpcd_probe(&intel_dp->aux, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV)) + return -EIO; + + if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd)) + return -EIO; + + return 0; +} + /** * intel_dp_init_lttpr_and_dprx_caps - detect LTTPR and DPRX caps, init the LTTPR link training mode * @intel_dp: Intel DP struct @@ -192,12 +214,10 @@ int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp) if (!intel_dp_is_edp(intel_dp) && (DISPLAY_VER(i915) >= 10 && !IS_GEMINILAKE(i915))) { u8 dpcd[DP_RECEIVER_CAP_SIZE]; + int err = intel_dp_read_dprx_caps(intel_dp, dpcd); - if (drm_dp_dpcd_probe(&intel_dp->aux, DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV)) - return -EIO; - - if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd)) - return -EIO; + if (err != 0) + return err; lttpr_count = intel_dp_init_lttpr(intel_dp, dpcd); } diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h index 2c8f2775891b0..19836a8a4f904 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h @@ -11,6 +11,7 @@ struct intel_crtc_state; struct intel_dp; +int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE]); int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp); void intel_dp_get_adjust_train(struct intel_dp *intel_dp, From patchwork Tue Jan 23 10:28:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527159 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DF3FBC47DDC for ; Tue, 23 Jan 2024 10:29:57 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1066210F265; Tue, 23 Jan 2024 10:29:03 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 270B010EF8F; Tue, 23 Jan 2024 10:28:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005729; x=1737541729; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zuEOrWj1+nchzky6mdNsAWGOTxOdI96as9foVp2PyPA=; b=HfvQJPijnGus3R3iiwGQSmFnMSR0x8fA8ZZMCZkeoMt0CZDudACivpeH HHkpTQ1kVOpWL1LPlRqAbQsnjNDarDG/XdFIJEdYPUwi79tTDcj1u5HtC 0gvXujO33lWkuczjeu3AYTRNmSGL0OK9gFwmsMy0UKfPMssmzS35YVXER rZndP1YZm0iRo510THr/WeJDwTddQpiUS8HNnGKiAkvKstL2Xjh+npV0/ 5hgGWFxN6MUiDCIO13pszJ9kscggeQF/UQH51YRHgAJI1TohkG3H1t7Gl Pt9i4et838AfUFiLC6XbAoT3UGmg+MdZbzCB9KN5IoudyMkm7SQM4vwQV Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134172" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134172" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:49 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283398" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283398" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:47 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 09/19] drm/i915/dp: Add intel_dp_max_link_data_rate() Date: Tue, 23 Jan 2024 12:28:40 +0200 Message-Id: <20240123102850.390126-10-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add intel_dp_max_link_data_rate() to get the link BW vs. the sink DPRX BW used by a follow-up patch enabling the DP tunnel BW allocation mode. The link BW can be below the DPRX BW due to a BW limitation on a link shared by multiple sinks. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_dp.c | 32 +++++++++++++++++---- drivers/gpu/drm/i915/display/intel_dp.h | 2 ++ drivers/gpu/drm/i915/display/intel_dp_mst.c | 3 +- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 23434d0aba188..9cd675c6d0ee8 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -383,6 +383,22 @@ int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, 1000000 * 16 * 8); } +/** + * intel_dp_max_link_data_rate: Calculate the maximum rate for the given link params + * @intel_dp: Intel DP object + * @max_dprx_rate: Maximum data rate of the DPRX + * @max_dprx_lanes: Maximum lane count of the DPRX + * + * Calculate the maximum data rate for the provided link parameters. + * + * Returns the maximum data rate in kBps units. + */ +int intel_dp_max_link_data_rate(struct intel_dp *intel_dp, + int max_dprx_rate, int max_dprx_lanes) +{ + return drm_dp_max_dprx_data_rate(max_dprx_rate, max_dprx_lanes); +} + bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); @@ -612,7 +628,7 @@ static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp, int mode_rate, max_rate; mode_rate = intel_dp_link_required(fixed_mode->clock, 18); - max_rate = drm_dp_max_dprx_data_rate(link_rate, lane_count); + max_rate = intel_dp_max_link_data_rate(intel_dp, link_rate, lane_count); if (mode_rate > max_rate) return false; @@ -1214,7 +1230,8 @@ intel_dp_mode_valid(struct drm_connector *_connector, max_link_clock = intel_dp_max_link_rate(intel_dp); max_lanes = intel_dp_max_lane_count(intel_dp); - max_rate = drm_dp_max_dprx_data_rate(max_link_clock, max_lanes); + max_rate = intel_dp_max_link_data_rate(intel_dp, max_link_clock, max_lanes); + mode_rate = intel_dp_link_required(target_clock, intel_dp_mode_min_output_bpp(connector, mode)); @@ -1564,8 +1581,10 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, for (lane_count = limits->min_lane_count; lane_count <= limits->max_lane_count; lane_count <<= 1) { - link_avail = drm_dp_max_dprx_data_rate(link_rate, - lane_count); + link_avail = intel_dp_max_link_data_rate(intel_dp, + link_rate, + lane_count); + if (mode_rate <= link_avail) { pipe_config->lane_count = lane_count; @@ -2422,8 +2441,9 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, pipe_config->pipe_bpp, BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16), intel_dp_config_required_rate(pipe_config), - drm_dp_max_dprx_data_rate(pipe_config->port_clock, - pipe_config->lane_count)); + intel_dp_max_link_data_rate(intel_dp, + pipe_config->port_clock, + pipe_config->lane_count)); return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 49553e43add22..8b0dfbf06afff 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -117,6 +117,8 @@ bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp); int intel_dp_link_required(int pixel_clock, int bpp); int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, int bw_overhead); +int intel_dp_max_link_data_rate(struct intel_dp *intel_dp, + int max_dprx_rate, int max_dprx_lanes); bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp); bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index cfcc157b7d41d..520393dc8b453 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1295,7 +1295,8 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, max_link_clock = intel_dp_max_link_rate(intel_dp); max_lanes = intel_dp_max_lane_count(intel_dp); - max_rate = drm_dp_max_dprx_data_rate(max_link_clock, max_lanes); + max_rate = intel_dp_max_link_data_rate(intel_dp, + max_link_clock, max_lanes); mode_rate = intel_dp_link_required(mode->clock, min_bpp); ret = drm_modeset_lock(&mgr->base.lock, ctx); From patchwork Tue Jan 23 10:28:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527156 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7C730C47258 for ; Tue, 23 Jan 2024 10:29:24 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 15FEE10F0B0; Tue, 23 Jan 2024 10:28:53 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0573A10F04A; Tue, 23 Jan 2024 10:28:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005732; x=1737541732; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=D9x17OGsgUMXNQtN+IT68prTo/7m5b9vdCMqdwFigXU=; b=OM5KMXYVSCtOvhI1tWvRiQ0TUxeRQlEgGHq6UIkDSxrLH04qyjkNz9WI pMDJ9nNiT+rb2twYdIcz+wWHS0MVAnEiwx03OWFlwphJkq2lIusBzqluz pe9Rvebv9doyedDgg3spCXiKQRtPbdGeLA/gHs+Z4j4oL85oaicX356/O j/04qjKJDiJpnOlaVKWfDT2psswg/mP2w7DKkzq+hjugupKcEXXmcv8xi DUPfxa0IL5o7prfVhQwQ7EeCSZ2WT6mQbCLxwNItEx2hBolRmg14PvvxH HmlJUwCy2w1ffR0MJpjUp9fivFoza8oudn7mJTv29j86THJ1GL3DpjGqQ A==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134184" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134184" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:51 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283406" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283406" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:49 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 10/19] drm/i915/dp: Add way to get active pipes with syncing commits Date: Tue, 23 Jan 2024 12:28:41 +0200 Message-Id: <20240123102850.390126-11-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add a way to get the active pipes through a given DP port by syncing against a related pending non-blocking commit. Atm intel_dp_get_active_pipes() will only try to sync a given pipe and if that would block ignore the pipe. A follow-up change enabling the DP tunnel BW allocation mode will need to ensure that all active pipes are returned. A follow-up patchset will add a no-sync mode as well, needed by the current intel_tc_port_link_reset() user of it, which atm incorrectly ignores active pipes for which the syncing would block (but otherwise doesn't require an actual syncing). Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_dp.c | 25 +++++++++++++++++++++---- drivers/gpu/drm/i915/display/intel_dp.h | 6 ++++++ drivers/gpu/drm/i915/display/intel_tc.c | 4 +++- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 9cd675c6d0ee8..323475569ee7f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5019,6 +5019,7 @@ static bool intel_dp_has_connector(struct intel_dp *intel_dp, int intel_dp_get_active_pipes(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx, + enum intel_dp_get_pipes_mode mode, u8 *pipe_mask) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); @@ -5053,9 +5054,23 @@ int intel_dp_get_active_pipes(struct intel_dp *intel_dp, if (!crtc_state->hw.active) continue; - if (conn_state->commit && - !try_wait_for_completion(&conn_state->commit->hw_done)) - continue; + if (conn_state->commit) { + bool synced; + + switch (mode) { + case INTEL_DP_GET_PIPES_TRY_SYNC: + if (!try_wait_for_completion(&conn_state->commit->hw_done)) + continue; + break; + case INTEL_DP_GET_PIPES_SYNC: + synced = wait_for_completion_timeout(&conn_state->commit->hw_done, + msecs_to_jiffies(5000)); + drm_WARN_ON(&i915->drm, !synced); + break; + default: + MISSING_CASE(mode); + } + } *pipe_mask |= BIT(crtc->pipe); } @@ -5092,7 +5107,9 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, if (!intel_dp_needs_link_retrain(intel_dp)) return 0; - ret = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask); + ret = intel_dp_get_active_pipes(intel_dp, ctx, + INTEL_DP_GET_PIPES_TRY_SYNC, + &pipe_mask); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 8b0dfbf06afff..1a7b87787dfa9 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -25,6 +25,11 @@ struct intel_encoder; struct work_struct; +enum intel_dp_get_pipes_mode { + INTEL_DP_GET_PIPES_TRY_SYNC, + INTEL_DP_GET_PIPES_SYNC, +}; + struct link_config_limits { int min_rate, max_rate; int min_lane_count, max_lane_count; @@ -59,6 +64,7 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, int link_rate, u8 lane_count); int intel_dp_get_active_pipes(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx, + enum intel_dp_get_pipes_mode mode, u8 *pipe_mask); int intel_dp_retrain_link(struct intel_encoder *encoder, struct drm_modeset_acquire_ctx *ctx); diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index f34743e6eeed2..561d6f97ff189 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -1655,7 +1655,9 @@ static int reset_link_commit(struct intel_tc_port *tc, if (ret) return ret; - ret = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask); + ret = intel_dp_get_active_pipes(intel_dp, ctx, + INTEL_DP_GET_PIPES_TRY_SYNC, + &pipe_mask); if (ret) return ret; From patchwork Tue Jan 23 10:28:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527155 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DB75AC47258 for ; Tue, 23 Jan 2024 10:29:20 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E5A8F10F04A; Tue, 23 Jan 2024 10:28:52 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 39EE410F0B0; Tue, 23 Jan 2024 10:28:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005732; x=1737541732; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HkTlAsuRGGFd1Dws5zKllDO2ad3BsbERl1F+c/M8F3A=; b=cCVULvfCZ9wF0q65AkkZqXT7tXH12NTEUZ/M88DjTuSe3bMlnrQkcjpJ 41huad0X6maCgBZm0vFuu4MlYFCPabpLuLLpJsadci2N0GaCnEvNQnqL9 lwwSVVX4cu/Gbgl5ToACzwhCl7XSDThl5uu1NTeWrK2EZmv7Kbk1NtKpX 8fUCVWvG5FwcN2nOA49+Yr8+KFQJ9hmxt0htzz8B9snOk0Ook34Ji7z3/ kdBURXc4Mb4/910wfTrKbbotLOBVQqwo9O9jtd8aLbvAEjIqyPAVD8TfY 2v9B0kTyWo5PD8kRCV7UAgVtxHwhTm14OEqTmH3KOSEbCEHvSAhH1cMCN Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134189" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134189" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:52 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283411" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283411" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:50 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 11/19] drm/i915/dp: Add support for DP tunnel BW allocation Date: Tue, 23 Jan 2024 12:28:42 +0200 Message-Id: <20240123102850.390126-12-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add support to enable the DP tunnel BW allocation mode. Follow-up patches will call the required helpers added here to prepare for a modeset on a link with DP tunnels, the last change in the patchset actually enabling BWA. With BWA enabled, the driver will expose the full mode list a display supports, regardless of any BW limitation on a shared (Thunderbolt) link. Such BW limits will be checked against only during a modeset, when the driver has the full knowledge of each display's BW requirement. If the link BW changes in a way that a connector's modelist may also change, userspace will get a hotplug notification for all the connectors sharing the same link (so it can adjust the mode used for a display). The BW limitation can change at any point, asynchronously to modesets on a given connector, so a modeset can fail even though the atomic check for it passed. In such scenarios userspace will get a bad link notification and in response is supposed to retry the modeset. Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/Kconfig | 13 + drivers/gpu/drm/i915/Kconfig.debug | 1 + drivers/gpu/drm/i915/Makefile | 3 + drivers/gpu/drm/i915/display/intel_atomic.c | 2 + .../gpu/drm/i915/display/intel_display_core.h | 1 + .../drm/i915/display/intel_display_types.h | 9 + .../gpu/drm/i915/display/intel_dp_tunnel.c | 642 ++++++++++++++++++ .../gpu/drm/i915/display/intel_dp_tunnel.h | 131 ++++ 8 files changed, 802 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_dp_tunnel.c create mode 100644 drivers/gpu/drm/i915/display/intel_dp_tunnel.h diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index b5d6e3352071f..4636913c17868 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -155,6 +155,19 @@ config DRM_I915_PXP protected session and manage the status of the alive software session, as well as its life cycle. +config DRM_I915_DP_TUNNEL + bool "Enable DP tunnel support" + depends on DRM_I915 + select DRM_DISPLAY_DP_TUNNEL + default y + help + Choose this option to detect DP tunnels and enable the Bandwidth + Allocation mode for such tunnels. This allows using the maximum + resolution allowed by the link BW on all displays sharing the + link BW, for instance on a Thunderbolt link. + + If in doubt, say "Y". + menu "drm/i915 Debugging" depends on DRM_I915 depends on EXPERT diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index 5b7162076850c..bc18e2d9ea05d 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -28,6 +28,7 @@ config DRM_I915_DEBUG select STACKDEPOT select STACKTRACE select DRM_DP_AUX_CHARDEV + select DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE if DRM_I915_DP_TUNNEL select X86_MSR # used by igt/pm_rpm select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) select DRM_DEBUG_MM if DRM=y diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index c13f14edb5088..3ef6ed41e62b4 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -369,6 +369,9 @@ i915-y += \ display/vlv_dsi.o \ display/vlv_dsi_pll.o +i915-$(CONFIG_DRM_I915_DP_TUNNEL) += \ + display/intel_dp_tunnel.o + i915-y += \ i915_perf.o diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index ec0d5168b5035..96ab37e158995 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -29,6 +29,7 @@ * See intel_atomic_plane.c for the plane-specific atomic functionality. */ +#include #include #include #include @@ -38,6 +39,7 @@ #include "intel_atomic.h" #include "intel_cdclk.h" #include "intel_display_types.h" +#include "intel_dp_tunnel.h" #include "intel_global_state.h" #include "intel_hdcp.h" #include "intel_psr.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index a90f1aa201be8..0993d25a0a686 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -522,6 +522,7 @@ struct intel_display { } wq; /* Grouping using named structs. Keep sorted. */ + struct drm_dp_tunnel_mgr *dp_tunnel_mgr; struct intel_audio audio; struct intel_dpll dpll; struct intel_fbc *fbc[I915_MAX_FBCS]; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index ae2e8cff9d691..b79db78b27728 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -677,6 +678,8 @@ struct intel_atomic_state { struct intel_shared_dpll_state shared_dpll[I915_NUM_PLLS]; + struct intel_dp_tunnel_inherited_state *dp_tunnel_state; + /* * Current watermarks can't be trusted during hardware readout, so * don't bother calculating intermediate watermarks. @@ -1372,6 +1375,9 @@ struct intel_crtc_state { struct drm_dsc_config config; } dsc; + /* DP tunnel used for BW allocation. */ + struct drm_dp_tunnel_ref dp_tunnel_ref; + /* HSW+ linetime watermarks */ u16 linetime; u16 ips_linetime; @@ -1775,6 +1781,9 @@ struct intel_dp { /* connector directly attached - won't be use for modeset in mst world */ struct intel_connector *attached_connector; + struct drm_dp_tunnel *tunnel; + bool tunnel_suspended:1; + /* mst connector list */ struct intel_dp_mst_encoder *mst_encoders[I915_MAX_PIPES]; struct drm_dp_mst_topology_mgr mst_mgr; diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c new file mode 100644 index 0000000000000..52dd0108a6c13 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c @@ -0,0 +1,642 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_drv.h" + +#include + +#include "intel_atomic.h" +#include "intel_display_limits.h" +#include "intel_display_types.h" +#include "intel_dp.h" +#include "intel_dp_link_training.h" +#include "intel_dp_mst.h" +#include "intel_dp_tunnel.h" +#include "intel_link_bw.h" + +struct intel_dp_tunnel_inherited_state { + struct { + struct drm_dp_tunnel_ref tunnel_ref; + } tunnels[I915_MAX_PIPES]; +}; + +static void destroy_tunnel(struct intel_dp *intel_dp) +{ + drm_dp_tunnel_destroy(intel_dp->tunnel); + intel_dp->tunnel = NULL; +} + +void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp) +{ + if (!intel_dp->tunnel) + return; + + destroy_tunnel(intel_dp); +} + +void intel_dp_tunnel_destroy(struct intel_dp *intel_dp) +{ + if (!intel_dp->tunnel) + return; + + if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) + drm_dp_tunnel_disable_bw_alloc(intel_dp->tunnel); + + destroy_tunnel(intel_dp); +} + +static int kbytes_to_mbits(int kbytes) +{ + return DIV_ROUND_UP(kbytes * 8, 1000); +} + +static int get_current_link_bw(struct intel_dp *intel_dp, + bool *below_dprx_bw) +{ + int rate = intel_dp_max_common_rate(intel_dp); + int lane_count = intel_dp_max_common_lane_count(intel_dp); + int bw; + + bw = intel_dp_max_link_data_rate(intel_dp, rate, lane_count); + *below_dprx_bw = bw < drm_dp_max_dprx_data_rate(rate, lane_count); + + return bw; +} + +static int update_tunnel_state(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + bool old_bw_below_dprx; + bool new_bw_below_dprx; + int old_bw; + int new_bw; + int ret; + + old_bw = get_current_link_bw(intel_dp, &old_bw_below_dprx); + + ret = drm_dp_tunnel_update_state(intel_dp->tunnel); + if (ret < 0) { + drm_dbg_kms(&i915->drm, + "[DPTUN %s][ENCODER:%d:%s] State update failed (err %pe)\n", + drm_dp_tunnel_name(intel_dp->tunnel), + encoder->base.base.id, + encoder->base.name, + ERR_PTR(ret)); + + return ret; + } + + if (ret == 0 || + !drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel)) + return 0; + + intel_dp_update_sink_caps(intel_dp); + + new_bw = get_current_link_bw(intel_dp, &new_bw_below_dprx); + + /* Suppress the notification if the mode list can't change due to bw. */ + if (old_bw_below_dprx == new_bw_below_dprx && + !new_bw_below_dprx) + return 0; + + drm_dbg_kms(&i915->drm, + "[DPTUN %s][ENCODER:%d:%s] Notify users about BW change: %d -> %d\n", + drm_dp_tunnel_name(intel_dp->tunnel), + encoder->base.base.id, + encoder->base.name, + kbytes_to_mbits(old_bw), + kbytes_to_mbits(new_bw)); + + return 1; +} + +static int allocate_initial_tunnel_bw(struct intel_dp *intel_dp, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + const struct intel_crtc *crtc; + int tunnel_bw = 0; + u8 pipe_mask; + int err; + + err = intel_dp_get_active_pipes(intel_dp, ctx, + INTEL_DP_GET_PIPES_SYNC, + &pipe_mask); + if (err) + return err; + + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) { + const struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); + int stream_bw = intel_dp_config_required_rate(crtc_state); + + drm_dbg_kms(&i915->drm, + "[DPTUN %s][ENCODER:%d:%s][CRTC:%d:%s] Initial BW for stream %d: %d/%d Mb/s\n", + drm_dp_tunnel_name(intel_dp->tunnel), + encoder->base.base.id, + encoder->base.name, + crtc->base.base.id, + crtc->base.name, + crtc->pipe, + kbytes_to_mbits(stream_bw), + kbytes_to_mbits(tunnel_bw)); + + tunnel_bw += stream_bw; + } + + err = drm_dp_tunnel_alloc_bw(intel_dp->tunnel, tunnel_bw); + if (err) { + drm_dbg_kms(&i915->drm, + "[DPTUN %s][ENCODER:%d:%s] Initial BW allocation failed (err %pe)\n", + drm_dp_tunnel_name(intel_dp->tunnel), + encoder->base.base.id, + encoder->base.name, + ERR_PTR(err)); + + return err; + } + + return update_tunnel_state(intel_dp); +} + +static int detect_new_tunnel(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_dp_tunnel *tunnel; + int ret; + + tunnel = drm_dp_tunnel_detect(i915->display.dp_tunnel_mgr, + &intel_dp->aux); + if (IS_ERR(tunnel)) + return PTR_ERR(tunnel); + + intel_dp->tunnel = tunnel; + + ret = drm_dp_tunnel_enable_bw_alloc(intel_dp->tunnel); + if (ret) { + if (ret == -EOPNOTSUPP) + return 0; + + drm_dbg_kms(&i915->drm, + "[DPTUN %s][ENCODER:%d:%s] Failed to enable BW allocation mode (ret %pe)\n", + drm_dp_tunnel_name(intel_dp->tunnel), + encoder->base.base.id, + encoder->base.name, + ERR_PTR(ret)); + + /* Keep the tunnel with BWA disabled */ + return 0; + } + + ret = allocate_initial_tunnel_bw(intel_dp, ctx); + if (ret < 0) + intel_dp_tunnel_destroy(intel_dp); + + return ret; +} + +int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx) +{ + int ret; + + if (intel_dp_is_edp(intel_dp)) + return 0; + + if (intel_dp->tunnel) { + ret = update_tunnel_state(intel_dp); + if (ret >= 0) + return ret; + + /* Try to recreate the tunnel after an update error. */ + intel_dp_tunnel_destroy(intel_dp); + } + + ret = detect_new_tunnel(intel_dp, ctx); + if (ret >= 0 || ret == -EDEADLK) + return ret; + + return ret; +} + +bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp) +{ + return intel_dp->tunnel && + drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel); +} + +void intel_dp_tunnel_suspend(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_connector *connector = intel_dp->attached_connector; + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + + if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) + return; + + drm_dbg_kms(&i915->drm, "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Suspend\n", + drm_dp_tunnel_name(intel_dp->tunnel), + connector->base.base.id, connector->base.name, + encoder->base.base.id, encoder->base.name); + + intel_dp->tunnel_suspended = true; +} + +void intel_dp_tunnel_resume(struct intel_dp *intel_dp, bool dpcd_updated) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_connector *connector = intel_dp->attached_connector; + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + int err = 0; + + if (!intel_dp->tunnel_suspended) + return; + + intel_dp->tunnel_suspended = false; + + drm_dbg_kms(&i915->drm, "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Resume\n", + drm_dp_tunnel_name(intel_dp->tunnel), + connector->base.base.id, connector->base.name, + encoder->base.base.id, encoder->base.name); + + /* DPRX caps read required by tunnel detection */ + if (!dpcd_updated) + err = intel_dp_read_dprx_caps(intel_dp, dpcd); + + if (err) + drm_dp_tunnel_set_io_error(intel_dp->tunnel); + else + err = drm_dp_tunnel_enable_bw_alloc(intel_dp->tunnel); + /* TODO: allocate initial BW */ + + if (!err) + return; + + drm_dbg_kms(&i915->drm, + "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Tunnel can't be resumed, will drop and redect it (err %pe)\n", + drm_dp_tunnel_name(intel_dp->tunnel), + connector->base.base.id, connector->base.name, + encoder->base.base.id, encoder->base.name, + ERR_PTR(err)); +} + +static struct drm_dp_tunnel * +get_inherited_tunnel_state(struct intel_atomic_state *state, + const struct intel_crtc *crtc) +{ + if (!state->dp_tunnel_state) + return NULL; + + return state->dp_tunnel_state->tunnels[crtc->pipe].tunnel_ref.tunnel; +} + +static int +add_inherited_tunnel_state(struct intel_atomic_state *state, + struct drm_dp_tunnel *tunnel, + const struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct drm_dp_tunnel *old_tunnel; + + old_tunnel = get_inherited_tunnel_state(state, crtc); + if (old_tunnel) { + drm_WARN_ON(&i915->drm, old_tunnel != tunnel); + return 0; + } + + if (!state->dp_tunnel_state) { + state->dp_tunnel_state = kzalloc(sizeof(*state->dp_tunnel_state), GFP_KERNEL); + if (!state->dp_tunnel_state) + return -ENOMEM; + } + + drm_dp_tunnel_ref_get(tunnel, + &state->dp_tunnel_state->tunnels[crtc->pipe].tunnel_ref); + + return 0; +} + +static int check_inherited_tunnel_state(struct intel_atomic_state *state, + struct intel_dp *intel_dp, + const struct intel_digital_connector_state *old_conn_state) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + const struct intel_connector *connector = + to_intel_connector(old_conn_state->base.connector); + struct intel_crtc *old_crtc; + const struct intel_crtc_state *old_crtc_state; + + /* + * If a BWA tunnel gets detected only after the corresponding + * connector got enabled already without a BWA tunnel, or a different + * BWA tunnel (which was removed meanwhile) the old CRTC state won't + * contain the state of the current tunnel. This tunnel still has a + * reserved BW, which needs to be released, add the state for such + * inherited tunnels separately only to this atomic state. + */ + if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) + return 0; + + if (!old_conn_state->base.crtc) + return 0; + + old_crtc = to_intel_crtc(old_conn_state->base.crtc); + old_crtc_state = intel_atomic_get_old_crtc_state(state, old_crtc); + + if (!old_crtc_state->hw.active || + old_crtc_state->dp_tunnel_ref.tunnel == intel_dp->tunnel) + return 0; + + drm_dbg_kms(&i915->drm, + "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Adding state for inherited tunnel %p\n", + drm_dp_tunnel_name(intel_dp->tunnel), + connector->base.base.id, + connector->base.name, + encoder->base.base.id, + encoder->base.name, + old_crtc->base.base.id, + old_crtc->base.name, + intel_dp->tunnel); + + return add_inherited_tunnel_state(state, intel_dp->tunnel, old_crtc); +} + +void intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state) +{ + enum pipe pipe; + + if (!state->dp_tunnel_state) + return; + + for_each_pipe(to_i915(state->base.dev), pipe) + if (state->dp_tunnel_state->tunnels[pipe].tunnel_ref.tunnel) + drm_dp_tunnel_ref_put(&state->dp_tunnel_state->tunnels[pipe].tunnel_ref); + + kfree(state->dp_tunnel_state); + state->dp_tunnel_state = NULL; +} + +static int intel_dp_tunnel_atomic_add_group_state(struct intel_atomic_state *state, + struct drm_dp_tunnel *tunnel) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + u32 pipe_mask; + int err; + + if (!tunnel) + return 0; + + err = drm_dp_tunnel_atomic_get_group_streams_in_state(&state->base, + tunnel, &pipe_mask); + if (err) + return err; + + drm_WARN_ON(&i915->drm, pipe_mask & ~((1 << I915_MAX_PIPES) - 1)); + + return intel_modeset_pipes_in_mask_early(state, "DPTUN", pipe_mask); +} + +int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + const struct drm_dp_tunnel_state *tunnel_state; + struct drm_dp_tunnel *tunnel = new_crtc_state->dp_tunnel_ref.tunnel; + + if (!tunnel) + return 0; + + tunnel_state = drm_dp_tunnel_atomic_get_state(&state->base, tunnel); + if (IS_ERR(tunnel_state)) + return PTR_ERR(tunnel_state); + + return 0; +} + +static int check_group_state(struct intel_atomic_state *state, + struct intel_dp *intel_dp, + const struct intel_connector *connector, + struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + const struct intel_crtc_state *crtc_state; + + crtc_state = intel_atomic_get_new_crtc_state(state, crtc); + + if (!crtc_state->dp_tunnel_ref.tunnel) + return 0; + + drm_dbg_kms(&i915->drm, + "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Adding group state for tunnel %p\n", + drm_dp_tunnel_name(intel_dp->tunnel), + connector->base.base.id, + connector->base.name, + encoder->base.base.id, + encoder->base.name, + crtc->base.base.id, + crtc->base.name, + intel_dp->tunnel); + + return intel_dp_tunnel_atomic_add_group_state(state, crtc_state->dp_tunnel_ref.tunnel); +} + +int intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state, + struct intel_dp *intel_dp, + struct intel_connector *connector) +{ + const struct intel_digital_connector_state *old_conn_state = + intel_atomic_get_new_connector_state(state, connector); + const struct intel_digital_connector_state *new_conn_state = + intel_atomic_get_new_connector_state(state, connector); + int err; + + if (old_conn_state->base.crtc) { + err = check_group_state(state, intel_dp, connector, + to_intel_crtc(old_conn_state->base.crtc)); + if (err) + return err; + } + + if (new_conn_state->base.crtc && + new_conn_state->base.crtc != old_conn_state->base.crtc) { + err = check_group_state(state, intel_dp, connector, + to_intel_crtc(new_conn_state->base.crtc)); + if (err) + return err; + } + + return check_inherited_tunnel_state(state, intel_dp, old_conn_state); +} + +void intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, + struct intel_dp *intel_dp, + const struct intel_connector *connector, + struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + int required_rate = intel_dp_config_required_rate(crtc_state); + + if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) + return; + + drm_dbg_kms(&i915->drm, + "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Stream %d required BW %d Mb/s\n", + drm_dp_tunnel_name(intel_dp->tunnel), + connector->base.base.id, + connector->base.name, + encoder->base.base.id, + encoder->base.name, + crtc->base.base.id, + crtc->base.name, + crtc->pipe, + kbytes_to_mbits(required_rate)); + + drm_dp_tunnel_atomic_set_stream_bw(&state->base, intel_dp->tunnel, + crtc->pipe, required_rate); + + drm_dp_tunnel_ref_get(intel_dp->tunnel, + &crtc_state->dp_tunnel_ref); +} + +/** + * intel_dp_tunnel_atomic_check_link - Check the DP tunnel atomic state + * @state: intel atomic state + * @limits: link BW limits + * + * Check the link configuration for all DP tunnels in @state. If the + * configuration is invalid @limits will be updated if possible to + * reduce the total BW, after which the configuration for all CRTCs in + * @state must be recomputed with the updated @limits. + * + * Returns: + * - 0 if the confugration is valid + * - %-EAGAIN, if the configuration is invalid and @limits got updated + * with fallback values with which the configuration of all CRTCs in + * @state must be recomputed + * - Other negative error, if the configuration is invalid without a + * fallback possibility, or the check failed for another reason + */ +int intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits) +{ + u32 failed_stream_mask; + int err; + + err = drm_dp_tunnel_atomic_check_stream_bws(&state->base, + &failed_stream_mask); + if (err != -ENOSPC) + return err; + + err = intel_link_bw_reduce_bpp(state, limits, + failed_stream_mask, "DP tunnel link BW"); + + return err ? : -EAGAIN; +} + +void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *new_crtc_state, + const struct drm_connector_state *new_conn_state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct drm_dp_tunnel *tunnel = new_crtc_state->dp_tunnel_ref.tunnel; + const struct drm_dp_tunnel_state *new_tunnel_state; + int err; + + if (!tunnel) + return; + + new_tunnel_state = drm_dp_tunnel_atomic_get_new_state(&state->base, tunnel); + + err = drm_dp_tunnel_alloc_bw(tunnel, + drm_dp_tunnel_atomic_get_tunnel_bw(new_tunnel_state)); + if (!err) + return; + + if (!intel_digital_port_connected(encoder)) + return; + + drm_dbg_kms(&i915->drm, + "[DPTUN %s][ENCODER:%d:%s] BW allocation failed on a connected sink (err %pe)\n", + drm_dp_tunnel_name(tunnel), + encoder->base.base.id, + encoder->base.name, + ERR_PTR(err)); + + intel_dp_queue_modeset_retry_for_link(state, encoder, new_crtc_state, new_conn_state); +} + +void intel_dp_tunnel_atomic_free_bw(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_crtc *old_crtc = to_intel_crtc(old_crtc_state->uapi.crtc); + struct drm_dp_tunnel *tunnel; + int err; + + tunnel = get_inherited_tunnel_state(state, old_crtc); + if (!tunnel) + tunnel = old_crtc_state->dp_tunnel_ref.tunnel; + + if (!tunnel) + return; + + err = drm_dp_tunnel_alloc_bw(tunnel, 0); + if (!err) + return; + + if (!intel_digital_port_connected(encoder)) + return; + + drm_dbg_kms(&i915->drm, + "[DPTUN %s][ENCODER:%d:%s] BW freeing failed on a connected sink (err %pe)\n", + drm_dp_tunnel_name(tunnel), + encoder->base.base.id, + encoder->base.name, + ERR_PTR(err)); + + intel_dp_queue_modeset_retry_for_link(state, encoder, old_crtc_state, old_conn_state); +} + +int intel_dp_tunnel_mgr_init(struct drm_i915_private *i915) +{ + struct drm_dp_tunnel_mgr *tunnel_mgr; + struct drm_connector_list_iter connector_list_iter; + struct intel_connector *connector; + int dp_connectors = 0; + + drm_connector_list_iter_begin(&i915->drm, &connector_list_iter); + for_each_intel_connector_iter(connector, &connector_list_iter) { + if (connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort) + continue; + + dp_connectors++; + } + drm_connector_list_iter_end(&connector_list_iter); + + tunnel_mgr = drm_dp_tunnel_mgr_create(&i915->drm, dp_connectors); + if (IS_ERR(tunnel_mgr)) + return PTR_ERR(tunnel_mgr); + + i915->display.dp_tunnel_mgr = tunnel_mgr; + + return 0; +} + +void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915) +{ + drm_dp_tunnel_mgr_destroy(i915->display.dp_tunnel_mgr); + i915->display.dp_tunnel_mgr = NULL; +} diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h new file mode 100644 index 0000000000000..bedba3ba9ad8d --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_DP_TUNNEL_H__ +#define __INTEL_DP_TUNNEL_H__ + +#include +#include + +struct drm_i915_private; +struct drm_connector_state; +struct drm_modeset_acquire_ctx; + +struct intel_atomic_state; +struct intel_connector; +struct intel_crtc; +struct intel_crtc_state; +struct intel_dp; +struct intel_encoder; +struct intel_link_bw_limits; + +#if defined(CONFIG_DRM_I915_DP_TUNNEL) && defined(I915) + +int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx); +void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp); +void intel_dp_tunnel_destroy(struct intel_dp *intel_dp); +void intel_dp_tunnel_resume(struct intel_dp *intel_dp, bool dpcd_updated); +void intel_dp_tunnel_suspend(struct intel_dp *intel_dp); + +bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp); + +void +intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state); + +void intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, + struct intel_dp *intel_dp, + const struct intel_connector *connector, + struct intel_crtc_state *crtc_state); + +int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc); +int intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits); +int intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state, + struct intel_dp *intel_dp, + struct intel_connector *connector); +void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *new_crtc_state, + const struct drm_connector_state *new_conn_state); +void intel_dp_tunnel_atomic_free_bw(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state); + +int intel_dp_tunnel_mgr_init(struct drm_i915_private *i915); +void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915); + +#else + +static inline int +intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx) +{ + return -EOPNOTSUPP; +} + +static inline void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp) {} +static inline void intel_dp_tunnel_destroy(struct intel_dp *intel_dp) {} +static inline void intel_dp_tunnel_resume(struct intel_dp *intel_dp, bool dpcd_updated) {} +static inline void intel_dp_tunnel_suspend(struct intel_dp *intel_dp) {} + +static inline bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp) +{ + return false; +} + +static inline void +intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state) {} + +static inline void +intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, + struct intel_dp *intel_dp, + const struct intel_connector *connector, + struct intel_crtc_state *crtc_state) {} + +static inline int +intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + return 0; +} + +static inline int +intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits) +{ + return 0; +} + +static inline int +intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state, + struct intel_dp *intel_dp, + struct intel_connector *connector) +{ + return 0; +} + +static inline void +intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *new_crtc_state, + const struct drm_connector_state *new_conn_state) {} +static inline void +intel_dp_tunnel_atomic_free_bw(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) {} + +static inline int +intel_dp_tunnel_mgr_init(struct drm_i915_private *i915) +{ + return 0; +} + +static inline void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915) {} + +#endif /* CONFIG_DRM_I915_DP_TUNNEL */ + +#endif /* __INTEL_DP_TUNNEL_H__ */ From patchwork Tue Jan 23 10:28:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527162 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F166AC47DDB for ; Tue, 23 Jan 2024 10:30:07 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7DDF810F3A0; Tue, 23 Jan 2024 10:29:03 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 755FF10F032; Tue, 23 Jan 2024 10:28:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005733; x=1737541733; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=m5Y6EeaDiHzOZKHfHQp/B8hgDQ2X70S5iRxAkneS8xk=; b=LXJZy8lmySVOq7epmNudfb7fnQO94/AgHpl+1I/J0+mrfP8pAXT1TjPE s7JusH5xhDNAs8MlVOCQWrhLpxkwSZQxsDsvevtgZOv6HhhksL5kRqaYK hPuQr9kT+VdwERK6G3+2V+th9nt150YfI2H0VL9dDkKrDfMUlMYuX0koG PsjsvZL0FPnkfkXo8Bga8LE+sw9WQ6i4XIl06JkI2vNXZJIWc34jNS15s jlOGQ9/L+Z4XBW7RBaDsk1ffBPUpQprZxgCn62tEWwTj9s7o0Si95FuXe jH+bK/zT7WajDYdpHctEFFWtVIHtzuaXE7vLpBcTTrid4KRBkPUsljk44 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134209" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134209" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:53 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283413" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283413" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:52 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 12/19] drm/i915/dp: Add DP tunnel atomic state and check BW limit Date: Tue, 23 Jan 2024 12:28:43 +0200 Message-Id: <20240123102850.390126-13-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add the atomic state during a modeset required to enable the DP tunnel BW allocation mode on links where such a tunnel was detected. Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_atomic.c | 8 ++++++++ drivers/gpu/drm/i915/display/intel_display.c | 19 +++++++++++++++++++ drivers/gpu/drm/i915/display/intel_link_bw.c | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 96ab37e158995..4236740ede9ed 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -260,6 +260,10 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) if (crtc_state->post_csc_lut) drm_property_blob_get(crtc_state->post_csc_lut); + if (crtc_state->dp_tunnel_ref.tunnel) + drm_dp_tunnel_ref_get(old_crtc_state->dp_tunnel_ref.tunnel, + &crtc_state->dp_tunnel_ref); + crtc_state->update_pipe = false; crtc_state->update_m_n = false; crtc_state->update_lrr = false; @@ -311,6 +315,8 @@ intel_crtc_destroy_state(struct drm_crtc *crtc, __drm_atomic_helper_crtc_destroy_state(&crtc_state->uapi); intel_crtc_free_hw_state(crtc_state); + if (crtc_state->dp_tunnel_ref.tunnel) + drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref); kfree(crtc_state); } @@ -346,6 +352,8 @@ void intel_atomic_state_clear(struct drm_atomic_state *s) /* state->internal not reset on purpose */ state->dpll_set = state->modeset = false; + + intel_dp_tunnel_atomic_cleanup_inherited_state(state); } struct intel_crtc_state * diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b9f985a5e705b..46b27a32c8640 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -73,6 +74,7 @@ #include "intel_dp.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" +#include "intel_dp_tunnel.h" #include "intel_dpll.h" #include "intel_dpll_mgr.h" #include "intel_dpt.h" @@ -4490,6 +4492,8 @@ copy_bigjoiner_crtc_state_modeset(struct intel_atomic_state *state, saved_state->crc_enabled = slave_crtc_state->crc_enabled; intel_crtc_free_hw_state(slave_crtc_state); + if (slave_crtc_state->dp_tunnel_ref.tunnel) + drm_dp_tunnel_ref_put(&slave_crtc_state->dp_tunnel_ref); memcpy(slave_crtc_state, saved_state, sizeof(*slave_crtc_state)); kfree(saved_state); @@ -4505,6 +4509,10 @@ copy_bigjoiner_crtc_state_modeset(struct intel_atomic_state *state, &master_crtc_state->hw.adjusted_mode); slave_crtc_state->hw.scaling_filter = master_crtc_state->hw.scaling_filter; + if (master_crtc_state->dp_tunnel_ref.tunnel) + drm_dp_tunnel_ref_get(master_crtc_state->dp_tunnel_ref.tunnel, + &slave_crtc_state->dp_tunnel_ref); + copy_bigjoiner_crtc_state_nomodeset(state, slave_crtc); slave_crtc_state->uapi.mode_changed = master_crtc_state->uapi.mode_changed; @@ -4533,6 +4541,13 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state, /* free the old crtc_state->hw members */ intel_crtc_free_hw_state(crtc_state); + if (crtc_state->dp_tunnel_ref.tunnel) { + drm_dp_tunnel_atomic_set_stream_bw(&state->base, + crtc_state->dp_tunnel_ref.tunnel, + crtc->pipe, 0); + drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref); + } + /* FIXME: before the switch to atomic started, a new pipe_config was * kzalloc'd. Code that depends on any field being zero should be * fixed, so that the crtc_state can be safely duplicated. For now, @@ -5374,6 +5389,10 @@ static int intel_modeset_pipe(struct intel_atomic_state *state, if (ret) return ret; + ret = intel_dp_tunnel_atomic_add_state_for_crtc(state, crtc); + if (ret) + return ret; + ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c index 9c6d35a405a18..5b539ba996ddf 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.c +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c @@ -8,6 +8,7 @@ #include "intel_atomic.h" #include "intel_display_types.h" #include "intel_dp_mst.h" +#include "intel_dp_tunnel.h" #include "intel_fdi.h" #include "intel_link_bw.h" @@ -149,6 +150,10 @@ static int check_all_link_config(struct intel_atomic_state *state, if (ret) return ret; + ret = intel_dp_tunnel_atomic_check_link(state, limits); + if (ret) + return ret; + ret = intel_fdi_atomic_check_link(state, limits); if (ret) return ret; From patchwork Tue Jan 23 10:28:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527163 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 21A27C48277 for ; Tue, 23 Jan 2024 10:30:11 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 8CABC10F3B5; Tue, 23 Jan 2024 10:29:03 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id A817A10F0BD; Tue, 23 Jan 2024 10:28:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005734; x=1737541734; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=y7xpb78w/2Yw3osL4wy9TVDVvfMoWyzygfmfTVp2JLA=; b=Bh1SBGqiCRHpXb8vfcMpH3SjQ5jnll3wA6zxDyMp3i8Jfpeu8pKr2WDG kH3bZMzix3bEwtwyngUGH+pmw0w2pwc88pbvI1yzaKBbEL+Dou5hzbYXi WTopG61HXMzDZoqzOgOps5cOAB9MeJdV4T00NyQufmIvaA2YXyiFZQQLQ sc9tekeqZSkYN5rWfvS5z6Lp+sqv08zZHA5zSRurpdckpAuDbTOV77mGM hnEC/BraroWXWovL+cucfp5Cfo7qsGb5oPUCuBAj7i9j4QgbXRk9JWIhA Nm/1jmG4yY+m1BNl6i1FoVjxgYvBWxsTLImMmSl6r4Eo5inG13NpxcKQ0 w==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134233" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134233" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:54 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283420" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283420" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:53 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 13/19] drm/i915/dp: Account for tunnel BW limit in intel_dp_max_link_data_rate() Date: Tue, 23 Jan 2024 12:28:44 +0200 Message-Id: <20240123102850.390126-14-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Take any link BW limitation into account in intel_dp_max_link_data_rate(). Such a limitation can be due to multiple displays on (Thunderbolt) links with DP tunnels sharing the link BW. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_dp.c | 32 +++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 323475569ee7f..78dfe8be6031d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -63,6 +63,7 @@ #include "intel_dp_hdcp.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" +#include "intel_dp_tunnel.h" #include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_fifo_underrun.h" @@ -152,6 +153,22 @@ int intel_dp_link_symbol_clock(int rate) return DIV_ROUND_CLOSEST(rate * 10, intel_dp_link_symbol_size(rate)); } +static int max_dprx_rate(struct intel_dp *intel_dp) +{ + if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) + return drm_dp_tunnel_max_dprx_rate(intel_dp->tunnel); + + return drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]); +} + +static int max_dprx_lane_count(struct intel_dp *intel_dp) +{ + if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) + return drm_dp_tunnel_max_dprx_lane_count(intel_dp->tunnel); + + return drm_dp_max_lane_count(intel_dp->dpcd); +} + static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp) { intel_dp->sink_rates[0] = 162000; @@ -180,7 +197,7 @@ static void intel_dp_set_dpcd_sink_rates(struct intel_dp *intel_dp) /* * Sink rates for 8b/10b. */ - max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]); + max_rate = max_dprx_rate(intel_dp); max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps); if (max_lttpr_rate) max_rate = min(max_rate, max_lttpr_rate); @@ -259,7 +276,7 @@ static void intel_dp_set_max_sink_lane_count(struct intel_dp *intel_dp) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &intel_dig_port->base; - intel_dp->max_sink_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); + intel_dp->max_sink_lane_count = max_dprx_lane_count(intel_dp); switch (intel_dp->max_sink_lane_count) { case 1: @@ -389,14 +406,21 @@ int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, * @max_dprx_rate: Maximum data rate of the DPRX * @max_dprx_lanes: Maximum lane count of the DPRX * - * Calculate the maximum data rate for the provided link parameters. + * Calculate the maximum data rate for the provided link parameters taking into + * account any BW limitations by a DP tunnel attached to @intel_dp. * * Returns the maximum data rate in kBps units. */ int intel_dp_max_link_data_rate(struct intel_dp *intel_dp, int max_dprx_rate, int max_dprx_lanes) { - return drm_dp_max_dprx_data_rate(max_dprx_rate, max_dprx_lanes); + int max_rate = drm_dp_max_dprx_data_rate(max_dprx_rate, max_dprx_lanes); + + if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) + max_rate = min(max_rate, + drm_dp_tunnel_available_bw(intel_dp->tunnel)); + + return max_rate; } bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp) From patchwork Tue Jan 23 10:28:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527157 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D41B8C47DDC for ; Tue, 23 Jan 2024 10:29:39 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 70EF210F1A0; Tue, 23 Jan 2024 10:29:01 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id F32F210F17B; Tue, 23 Jan 2024 10:28:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005736; x=1737541736; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=UhDECuvbrf8EjdLUYCZ42sEfMsO290cn3+KNjYPw+wI=; b=MBw/KDs2Q/bGbTqa7v+bDo7cR4UieZizs1Wf6cHaFO7z9E7qQyb1pvav UjaiDrhXc/P8eMA/5UcAblyg1R3YyREZ4Er5/tTIlzjLUEiB20Uy7kJ6X 9V9ormSlb5zKt1vj0dlz1N3MKxj5EE4o1yHHWk6GYHnbbTpyAB1guedZz 1kCPAvmcXJDGuhAtu1QL9uv2ifABhR9Yos+atF5qvLle7v1mZe+ute6ue jG2AKYHguSK1dN6BRA3//VV8XwbD84lhVgvtl9feu2NyZRBoGDJVtqEwM wvZ/HNuWtQyFc8h3d3Sdahu9kAxyujx+zcrnuZao5s1a3dDjY/yWphSv4 Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134245" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134245" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:55 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283429" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283429" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:54 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 14/19] drm/i915/dp: Compute DP tunel BW during encoder state computation Date: Tue, 23 Jan 2024 12:28:45 +0200 Message-Id: <20240123102850.390126-15-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Compute the BW required through a DP tunnel on links with such tunnels detected and add the corresponding atomic state during a modeset. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_dp.c | 16 +++++++++++++--- drivers/gpu/drm/i915/display/intel_dp_mst.c | 13 +++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 78dfe8be6031d..6968fdb7ffcdf 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2880,6 +2880,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state); struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); const struct drm_display_mode *fixed_mode; @@ -2980,6 +2981,9 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state); intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state); + intel_dp_tunnel_atomic_compute_stream_bw(state, intel_dp, connector, + pipe_config); + return 0; } @@ -6087,6 +6091,15 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn, return ret; } + if (!intel_connector_needs_modeset(state, conn)) + return 0; + + ret = intel_dp_tunnel_atomic_check_state(state, + intel_dp, + intel_conn); + if (ret) + return ret; + /* * We don't enable port sync on BDW due to missing w/as and * due to not having adjusted the modeset sequence appropriately. @@ -6094,9 +6107,6 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn, if (DISPLAY_VER(dev_priv) < 9) return 0; - if (!intel_connector_needs_modeset(state, conn)) - return 0; - if (conn->has_tile) { ret = intel_modeset_tile_group(state, conn->tile_group->id); if (ret) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 520393dc8b453..cbfab3173b9ef 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -42,6 +42,7 @@ #include "intel_dp.h" #include "intel_dp_hdcp.h" #include "intel_dp_mst.h" +#include "intel_dp_tunnel.h" #include "intel_dpio_phy.h" #include "intel_hdcp.h" #include "intel_hotplug.h" @@ -523,6 +524,7 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state); struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); struct intel_dp *intel_dp = &intel_mst->primary->dp; const struct intel_connector *connector = @@ -619,6 +621,9 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, intel_psr_compute_config(intel_dp, pipe_config, conn_state); + intel_dp_tunnel_atomic_compute_stream_bw(state, intel_dp, connector, + pipe_config); + return 0; } @@ -876,6 +881,14 @@ intel_dp_mst_atomic_check(struct drm_connector *connector, if (ret) return ret; + if (intel_connector_needs_modeset(state, connector)) { + ret = intel_dp_tunnel_atomic_check_state(state, + intel_connector->mst_port, + intel_connector); + if (ret) + return ret; + } + return drm_dp_atomic_release_time_slots(&state->base, &intel_connector->mst_port->mst_mgr, intel_connector->port); From patchwork Tue Jan 23 10:28:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527161 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F03BFC47DDB for ; Tue, 23 Jan 2024 10:30:04 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4CD9010F385; Tue, 23 Jan 2024 10:29:03 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3D31110F1A0; Tue, 23 Jan 2024 10:28:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005737; x=1737541737; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bKiIHUhiJwfYKGSAl6H8TfHiQ517TTsOb5MKB3Z9Ba4=; b=COQxUclQME4quSK3/+lqLoKpmXOxcKrokVqwf8MvHzp9U9hJHk6tjHpb vWFeccPdpcgDkzdYb4ZVIH8XwO09FxVZlm7gXHRzMtngccWCnWsLud1Zm YCKlmcpo7c5H4+ATo5ImxM7skIvt2srp638ryvomnwv2apAXDJA6mYwFQ 9AC7cK8EF+PgME9nNCUnZz5aCVdXlq7u/ZkJXJsD7WY4lGFpp4quI/Yu7 wH50OnElE//MWzdCyPomoeZzsPF+OvCJz5SkbqewaYJnBIiJeAFXGpGIB w0mVqlQpS+X0Xj+vZKVHzyXwmbmwSZPcUJI056IHnMSWIw++rPLuwlUU1 A==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134263" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134263" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:57 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283431" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283431" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:56 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 15/19] drm/i915/dp: Allocate/free DP tunnel BW in the encoder enable/disable hooks Date: Tue, 23 Jan 2024 12:28:46 +0200 Message-Id: <20240123102850.390126-16-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Allocate and free the DP tunnel BW required by a stream while enabling/disabling the stream during a modeset. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/g4x_dp.c | 28 ++++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_ddi.c | 7 ++++++ 2 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index dfe0b07a122d1..1e498e1510adf 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -19,6 +19,7 @@ #include "intel_dp.h" #include "intel_dp_aux.h" #include "intel_dp_link_training.h" +#include "intel_dp_tunnel.h" #include "intel_dpio_phy.h" #include "intel_fifo_underrun.h" #include "intel_hdmi.h" @@ -729,6 +730,24 @@ static void vlv_enable_dp(struct intel_atomic_state *state, encoder->audio_enable(encoder, pipe_config, conn_state); } +static void g4x_dp_pre_pll_enable(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *new_crtc_state, + const struct drm_connector_state *new_conn_state) +{ + intel_dp_tunnel_atomic_alloc_bw(state, encoder, + new_crtc_state, new_conn_state); +} + +static void g4x_dp_post_pll_disable(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) +{ + intel_dp_tunnel_atomic_free_bw(state, encoder, + old_crtc_state, old_conn_state); +} + static void g4x_pre_enable_dp(struct intel_atomic_state *state, struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, @@ -762,6 +781,8 @@ static void vlv_dp_pre_pll_enable(struct intel_atomic_state *state, intel_dp_prepare(encoder, pipe_config); vlv_phy_pre_pll_enable(encoder, pipe_config); + + g4x_dp_pre_pll_enable(state, encoder, pipe_config, conn_state); } static void chv_pre_enable_dp(struct intel_atomic_state *state, @@ -785,6 +806,8 @@ static void chv_dp_pre_pll_enable(struct intel_atomic_state *state, intel_dp_prepare(encoder, pipe_config); chv_phy_pre_pll_enable(encoder, pipe_config); + + g4x_dp_pre_pll_enable(state, encoder, pipe_config, conn_state); } static void chv_dp_post_pll_disable(struct intel_atomic_state *state, @@ -792,6 +815,8 @@ static void chv_dp_post_pll_disable(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { + g4x_dp_post_pll_disable(state, encoder, old_crtc_state, old_conn_state); + chv_phy_post_pll_disable(encoder, old_crtc_state); } @@ -1349,11 +1374,14 @@ bool g4x_dp_init(struct drm_i915_private *dev_priv, intel_encoder->enable = vlv_enable_dp; intel_encoder->disable = vlv_disable_dp; intel_encoder->post_disable = vlv_post_disable_dp; + intel_encoder->post_pll_disable = g4x_dp_post_pll_disable; } else { + intel_encoder->pre_pll_enable = g4x_dp_pre_pll_enable; intel_encoder->pre_enable = g4x_pre_enable_dp; intel_encoder->enable = g4x_enable_dp; intel_encoder->disable = g4x_disable_dp; intel_encoder->post_disable = g4x_post_disable_dp; + intel_encoder->post_pll_disable = g4x_dp_post_pll_disable; } intel_encoder->audio_enable = g4x_dp_audio_enable; intel_encoder->audio_disable = g4x_dp_audio_disable; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 922194b957be2..aa6e7da08fbce 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -54,6 +54,7 @@ #include "intel_dp_aux.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" +#include "intel_dp_tunnel.h" #include "intel_dpio_phy.h" #include "intel_dsi.h" #include "intel_fdi.h" @@ -3141,6 +3142,9 @@ static void intel_ddi_post_pll_disable(struct intel_atomic_state *state, main_link_aux_power_domain_put(dig_port, old_crtc_state); + intel_dp_tunnel_atomic_free_bw(state, encoder, + old_crtc_state, old_conn_state); + if (is_tc_port) intel_tc_port_put_link(dig_port); } @@ -3480,6 +3484,9 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state *state, intel_ddi_update_active_dpll(state, encoder, master_crtc); } + intel_dp_tunnel_atomic_alloc_bw(state, encoder, + crtc_state, conn_state); + main_link_aux_power_domain_get(dig_port, crtc_state); if (is_tc_port && !intel_tc_port_in_tbt_alt_mode(dig_port)) From patchwork Tue Jan 23 10:28:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527165 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1971CC47258 for ; Tue, 23 Jan 2024 10:30:20 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 41B2E10F409; Tue, 23 Jan 2024 10:29:04 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6F7C510F16D; Tue, 23 Jan 2024 10:28:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005738; x=1737541738; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=j7Q+HW1CbclKqHB1hHBsF+IV5inxkflp3LgPsMqWl3U=; b=TfLgVUr5mxkh0lWqgYy9p1mPUdlJX3sY7bVFJ56o2VCb22WZDFlYK4PA jLep+iwA07stserRPkCXFfUgwNSN4AKDNcT9VoccchuFUWIXiJ/MTz8Z9 bfSlXS//HVM9r0Nle4+Xv1SQFLE2HFJeCgIkpNj0/ySp82SaUvZ2pQ6d7 nukhBo4VrM8DIV7OrrjfJglLg213YD1yvti9wN12MKloCTiKzPxmuWiAk A1vOwq1t04VDn9uP8sYjWyqb4b/0+rTV8JnI8DXglBtOSONzEn0T6o7jN Y8KWpLAt/o3lUjbSLxmxZoyakDaSx8FUCoAnwHt5m938Qu1oo9BaBn+vX A==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134280" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134280" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:58 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283436" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283436" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:57 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 16/19] drm/i915/dp: Handle DP tunnel IRQs Date: Tue, 23 Jan 2024 12:28:47 +0200 Message-Id: <20240123102850.390126-17-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Handle DP tunnel IRQs a sink (or rather a BW management component like the Thunderbolt Connection Manager) raises to signal the completion of a BW request by the driver, or to signal any state change related to the link BW. Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_dp.c | 37 +++++++++++++++++++------ include/drm/display/drm_dp.h | 1 + 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6968fdb7ffcdf..8ebfb039000f6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4911,13 +4911,15 @@ static bool intel_dp_mst_link_status(struct intel_dp *intel_dp) * - %true if pending interrupts were serviced (or no interrupts were * pending) w/o detecting an error condition. * - %false if an error condition - like AUX failure or a loss of link - is - * detected, which needs servicing from the hotplug work. + * detected, or another condition - like a DP tunnel BW state change - needs + * servicing from the hotplug work. */ static bool intel_dp_check_mst_status(struct intel_dp *intel_dp) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); bool link_ok = true; + bool reprobe_needed = false; drm_WARN_ON_ONCE(&i915->drm, intel_dp->active_mst_links < 0); @@ -4944,6 +4946,13 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) intel_dp_mst_hpd_irq(intel_dp, esi, ack); + if (esi[3] & DP_TUNNELING_IRQ) { + if (drm_dp_tunnel_handle_irq(i915->display.dp_tunnel_mgr, + &intel_dp->aux)) + reprobe_needed = true; + ack[3] |= DP_TUNNELING_IRQ; + } + if (!memchr_inv(ack, 0, sizeof(ack))) break; @@ -4954,7 +4963,7 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) drm_dp_mst_hpd_irq_send_new_request(&intel_dp->mst_mgr); } - return link_ok; + return link_ok && !reprobe_needed; } static void @@ -5330,23 +5339,32 @@ static void intel_dp_check_device_service_irq(struct intel_dp *intel_dp) drm_dbg_kms(&i915->drm, "Sink specific irq unhandled\n"); } -static void intel_dp_check_link_service_irq(struct intel_dp *intel_dp) +static bool intel_dp_check_link_service_irq(struct intel_dp *intel_dp) { + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + bool reprobe_needed = false; u8 val; if (intel_dp->dpcd[DP_DPCD_REV] < 0x11) - return; + return false; if (drm_dp_dpcd_readb(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &val) != 1 || !val) - return; + return false; + + if ((val & DP_TUNNELING_IRQ) && + drm_dp_tunnel_handle_irq(i915->display.dp_tunnel_mgr, + &intel_dp->aux)) + reprobe_needed = true; if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0, val) != 1) - return; + return reprobe_needed; if (val & HDMI_LINK_STATUS_CHANGED) intel_dp_handle_hdmi_link_status_change(intel_dp); + + return reprobe_needed; } /* @@ -5367,6 +5385,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 old_sink_count = intel_dp->sink_count; + bool reprobe_needed = false; bool ret; /* @@ -5389,7 +5408,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) } intel_dp_check_device_service_irq(intel_dp); - intel_dp_check_link_service_irq(intel_dp); + reprobe_needed = intel_dp_check_link_service_irq(intel_dp); /* Handle CEC interrupts, if any */ drm_dp_cec_irq(&intel_dp->aux); @@ -5416,10 +5435,10 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) * FIXME get rid of the ad-hoc phy test modeset code * and properly incorporate it into the normal modeset. */ - return false; + reprobe_needed = true; } - return true; + return !reprobe_needed; } /* XXX this is probably wrong for multiple downstream ports */ diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h index 8bfd5d007be8d..4891bd916d26a 100644 --- a/include/drm/display/drm_dp.h +++ b/include/drm/display/drm_dp.h @@ -1081,6 +1081,7 @@ # define STREAM_STATUS_CHANGED (1 << 2) # define HDMI_LINK_STATUS_CHANGED (1 << 3) # define CONNECTED_OFF_ENTRY_REQUESTED (1 << 4) +# define DP_TUNNELING_IRQ (1 << 5) #define DP_PSR_ERROR_STATUS 0x2006 /* XXX 1.2? */ # define DP_PSR_LINK_CRC_ERROR (1 << 0) From patchwork Tue Jan 23 10:28:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527160 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B7400C47258 for ; Tue, 23 Jan 2024 10:30:01 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1EABC10F2FE; Tue, 23 Jan 2024 10:29:03 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id A979810F1AA; Tue, 23 Jan 2024 10:28:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005739; x=1737541739; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jFvGmC3V1panhwIGwXGi5xm79Tc6HxEYPuA/39ZJ20s=; b=a+Vqh7mL7Abq4/ukJu3MdIgG4ptn+li8aqF2MwFcxOXEEYMkVVZo3lz+ 3L/abcg02D4Yg2SRb5nbYmFupeaO8SKfKftfaUAbxCGTaEi6SJTftSKT1 p/eT4crRSkZA+yfByQRzPpBKROTUxK5dI3hF3EJYaxbtfgsuFCaexndip JE/16YXp2CVNvDKf+1kG1m6PPyVV3+tBjCPDs3G03PLSTEOlQbp1LMHKZ ckCzXFkYfDMXQTMnLEN4v4JOCcxaB0lUhLHbK3jUi0FK8kGF2ZdRNxIFd bOvOlLuATZz0UuPTfQHfTRJSEuFtp4cIErzZOvAPqmgrqYpbBdNwVsOVx Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134293" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134293" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:59 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283442" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283442" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:58 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 17/19] drm/i915/dp: Call intel_dp_sync_state() always for DDI DP encoders Date: Tue, 23 Jan 2024 12:28:48 +0200 Message-Id: <20240123102850.390126-18-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" A follow-up change will need to resume DP tunnels during system resume, so call intel_dp_sync_state() always for DDI encoders, so this function can resume the tunnels for all DP connectors. Signed-off-by: Imre Deak Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_ddi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index aa6e7da08fbce..1e26e62b82d48 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4131,7 +4131,7 @@ static void intel_ddi_sync_state(struct intel_encoder *encoder, intel_tc_port_sanitize_mode(enc_to_dig_port(encoder), crtc_state); - if (crtc_state && intel_crtc_has_dp_encoder(crtc_state)) + if (intel_encoder_is_dp(encoder)) intel_dp_sync_state(encoder, crtc_state); } From patchwork Tue Jan 23 10:28:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527164 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 796E9C47DDB for ; Tue, 23 Jan 2024 10:30:16 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 04FBF10E77D; Tue, 23 Jan 2024 10:29:04 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id E824510F1A0; Tue, 23 Jan 2024 10:29:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005740; x=1737541740; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=21gjnB6xKEvCpVp21MyAr5xCVewaEhbxYUVJyJqjbeo=; b=n+foJV8lb06krVeEgz2g7AFkpHys0Md3GUXdeQL7bryasdcfvIrT6CpB kbpEzaqNsrV13/q0xJJkAwATlMoX5DVf0dhUYU1KNT4GXXzNkvT8p6VSM XRhDw6wNemHO6VY/sm6zm3cDzyyAq/aHaSKoxJEU3o0bFkgmq47rXjHHs v0/j/GENunIFolAqDDE0+xb31RGEoMkcLAuXoIZll6cDMzmAdI8uCh3T3 daiUOF+Dk2ubbM+F5jDyNpex0zhSWekaPtti+MMlwjyaJea8HNlLrql5W v0/xXynMQf3PH3qANguT7BS7DKSV4u54P11qh0NFl/+nL8j83mx5fdgkp A==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134305" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134305" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:29:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283462" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283462" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:28:59 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 18/19] drm/i915/dp: Suspend/resume DP tunnels Date: Tue, 23 Jan 2024 12:28:49 +0200 Message-Id: <20240123102850.390126-19-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Suspend and resume DP tunnels during system suspend/resume, disabling the BW allocation mode during suspend, re-enabling it after resume. This reflects the link's BW management component (Thunderbolt CM) disabling BWA during suspend. Before any BW requests the driver must read the sink's DPRX capabilities (since the BW manager requires this information, so snoops for it on AUX), so ensure this read takes place. Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_dp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 8ebfb039000f6..bc138a54f8d7b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -3320,18 +3321,21 @@ void intel_dp_sync_state(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - - if (!crtc_state) - return; + bool dpcd_updated = false; /* * Don't clobber DPCD if it's been already read out during output * setup (eDP) or detect. */ - if (intel_dp->dpcd[DP_DPCD_REV] == 0) + if (crtc_state && intel_dp->dpcd[DP_DPCD_REV] == 0) { intel_dp_get_dpcd(intel_dp); + dpcd_updated = true; + } - intel_dp_reset_max_link_params(intel_dp); + intel_dp_tunnel_resume(intel_dp, dpcd_updated); + + if (crtc_state) + intel_dp_reset_max_link_params(intel_dp); } bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, @@ -5973,6 +5977,8 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder); intel_pps_vdd_off_sync(intel_dp); + + intel_dp_tunnel_suspend(intel_dp); } void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder) From patchwork Tue Jan 23 10:28:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Deak X-Patchwork-Id: 13527166 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 59AF7C47DDB for ; Tue, 23 Jan 2024 10:30:24 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B532A10E771; Tue, 23 Jan 2024 10:29:17 +0000 (UTC) Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 29F0610F1CC; Tue, 23 Jan 2024 10:29:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706005742; x=1737541742; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ngK8DbMOjRxFGZtNEZQQS0UanG2SGPN4yFHJBBsiczE=; b=JHfLWQ/iX+ni9sSHYeaY3sZRdRCRzINfF1AtniKuyI6dnJ0dNttUf7nI NhjyS02EcOsw8DUqpLP9A9Ot6Bj0tm2VQsi0qLJUCAriZ7QWhiYpXhnER dNUlhpmZdMkWFa6x16sxERJpRzv1AMYC2lVrdfBLyXKpspIZ8KQzl972q wXIqZ+Om5kE6UYaHF6OjfiTUCxEX42glf6yS7U73z6aeCojEYJB6/+9au OhYxNfgK/0xOnIEtns+WRqfCq6CuPzX15m2AsbCVz2y4hjDn3veEkYnWl F0tz+0hfM4l8knZbF3i1SIHfXUqeW7EWPJn2G1MnFzl9RQWxBooQo/INB A==; X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="401134314" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="401134314" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:29:02 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10961"; a="856283492" X-IronPort-AV: E=Sophos;i="6.05,214,1701158400"; d="scan'208";a="856283492" Received: from ideak-desk.fi.intel.com ([10.237.72.78]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2024 02:29:00 -0800 From: Imre Deak To: intel-gfx@lists.freedesktop.org Subject: [PATCH 19/19] drm/i915/dp: Enable DP tunnel BW allocation mode Date: Tue, 23 Jan 2024 12:28:50 +0200 Message-Id: <20240123102850.390126-20-imre.deak@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240123102850.390126-1-imre.deak@intel.com> References: <20240123102850.390126-1-imre.deak@intel.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Detect DP tunnels and enable the BW allocation mode on them. Send a hotplug notification to userspace in response to a BW change. Signed-off-by: Imre Deak --- .../drm/i915/display/intel_display_driver.c | 20 +++++++++++++++---- drivers/gpu/drm/i915/display/intel_dp.c | 14 +++++++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index ecf9cb74734b6..62987b8427f7b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -35,6 +35,7 @@ #include "intel_dkl_phy.h" #include "intel_dmc.h" #include "intel_dp.h" +#include "intel_dp_tunnel.h" #include "intel_dpll.h" #include "intel_dpll_mgr.h" #include "intel_fb.h" @@ -435,10 +436,8 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915) for_each_pipe(i915, pipe) { ret = intel_crtc_init(i915, pipe); - if (ret) { - intel_mode_config_cleanup(i915); - return ret; - } + if (ret) + goto err_mode_config; } intel_plane_possible_crtcs_init(i915); @@ -460,6 +459,10 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915) intel_vga_disable(i915); intel_setup_outputs(i915); + ret = intel_dp_tunnel_mgr_init(i915); + if (ret) + goto err_hdcp; + intel_display_driver_disable_user_access(i915); drm_modeset_lock_all(dev); @@ -482,6 +485,13 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915) ilk_wm_sanitize(i915); return 0; + +err_hdcp: + intel_hdcp_component_fini(i915); +err_mode_config: + intel_mode_config_cleanup(i915); + + return ret; } /* part #3: call after gem init */ @@ -598,6 +608,8 @@ void intel_display_driver_remove_noirq(struct drm_i915_private *i915) intel_mode_config_cleanup(i915); + intel_dp_tunnel_mgr_cleanup(i915); + intel_overlay_cleanup(i915); intel_gmbus_teardown(i915); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index bc138a54f8d7b..6133266d78276 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5752,6 +5752,7 @@ intel_dp_detect(struct drm_connector *connector, struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &dig_port->base; enum drm_connector_status status; + int ret; drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -5787,9 +5788,18 @@ intel_dp_detect(struct drm_connector *connector, intel_dp->is_mst); } + intel_dp_tunnel_disconnect(intel_dp); + goto out; } + ret = intel_dp_tunnel_detect(intel_dp, ctx); + if (ret == -EDEADLK) + return ret; + + if (ret == 1) + intel_connector->base.epoch_counter++; + intel_dp_detect_dsc_caps(intel_dp, intel_connector); intel_dp_configure_mst(intel_dp); @@ -5820,8 +5830,6 @@ intel_dp_detect(struct drm_connector *connector, * with an IRQ_HPD, so force a link status check. */ if (!intel_dp_is_edp(intel_dp)) { - int ret; - ret = intel_dp_retrain_link(encoder, ctx); if (ret) return ret; @@ -5961,6 +5969,8 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder) intel_dp_mst_encoder_cleanup(dig_port); + intel_dp_tunnel_destroy(intel_dp); + intel_pps_vdd_off_sync(intel_dp); /*