brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · e7a9b86 Raw
249 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2023 Intel Corporation4 */5 6#include <drm/drm_fixed.h>7 8#include "i915_drv.h"9 10#include "intel_atomic.h"11#include "intel_crtc.h"12#include "intel_display_types.h"13#include "intel_dp_mst.h"14#include "intel_dp_tunnel.h"15#include "intel_fdi.h"16#include "intel_link_bw.h"17 18/**19 * intel_link_bw_init_limits - initialize BW limits20 * @state: Atomic state21 * @limits: link BW limits22 *23 * Initialize @limits.24 */25void intel_link_bw_init_limits(struct intel_atomic_state *state,26			       struct intel_link_bw_limits *limits)27{28	struct intel_display *display = to_intel_display(state);29	struct drm_i915_private *i915 = to_i915(state->base.dev);30	enum pipe pipe;31 32	limits->force_fec_pipes = 0;33	limits->bpp_limit_reached_pipes = 0;34	for_each_pipe(display, pipe) {35		const struct intel_crtc_state *crtc_state =36			intel_atomic_get_new_crtc_state(state,37							intel_crtc_for_pipe(i915, pipe));38 39		if (state->base.duplicated && crtc_state) {40			limits->max_bpp_x16[pipe] = crtc_state->max_link_bpp_x16;41			if (crtc_state->fec_enable)42				limits->force_fec_pipes |= BIT(pipe);43		} else {44			limits->max_bpp_x16[pipe] = INT_MAX;45		}46	}47}48 49/**50 * intel_link_bw_reduce_bpp - reduce maximum link bpp for a selected pipe51 * @state: atomic state52 * @limits: link BW limits53 * @pipe_mask: mask of pipes to select from54 * @reason: explanation of why bpp reduction is needed55 *56 * Select the pipe from @pipe_mask with the biggest link bpp value and set the57 * maximum of link bpp in @limits below this value. Modeset the selected pipe,58 * so that its state will get recomputed.59 *60 * This function can be called to resolve a link's BW overallocation by reducing61 * the link bpp of one pipe on the link and hence reducing the total link BW.62 *63 * Returns64 *   - 0 in case of success65 *   - %-ENOSPC if no pipe can further reduce its link bpp66 *   - Other negative error, if modesetting the selected pipe failed67 */68int intel_link_bw_reduce_bpp(struct intel_atomic_state *state,69			     struct intel_link_bw_limits *limits,70			     u8 pipe_mask,71			     const char *reason)72{73	struct intel_display *display = to_intel_display(state);74	enum pipe max_bpp_pipe = INVALID_PIPE;75	struct intel_crtc *crtc;76	int max_bpp_x16 = 0;77 78	for_each_intel_crtc_in_pipe_mask(display->drm, crtc, pipe_mask) {79		struct intel_crtc_state *crtc_state;80		int link_bpp_x16;81 82		if (limits->bpp_limit_reached_pipes & BIT(crtc->pipe))83			continue;84 85		crtc_state = intel_atomic_get_crtc_state(&state->base,86							 crtc);87		if (IS_ERR(crtc_state))88			return PTR_ERR(crtc_state);89 90		if (crtc_state->dsc.compression_enable)91			link_bpp_x16 = crtc_state->dsc.compressed_bpp_x16;92		else93			/*94			 * TODO: for YUV420 the actual link bpp is only half95			 * of the pipe bpp value. The MST encoder's BW allocation96			 * is based on the pipe bpp value, set the actual link bpp97			 * limit here once the MST BW allocation is fixed.98			 */99			link_bpp_x16 = fxp_q4_from_int(crtc_state->pipe_bpp);100 101		if (link_bpp_x16 > max_bpp_x16) {102			max_bpp_x16 = link_bpp_x16;103			max_bpp_pipe = crtc->pipe;104		}105	}106 107	if (max_bpp_pipe == INVALID_PIPE)108		return -ENOSPC;109 110	limits->max_bpp_x16[max_bpp_pipe] = max_bpp_x16 - 1;111 112	return intel_modeset_pipes_in_mask_early(state, reason,113						 BIT(max_bpp_pipe));114}115 116/**117 * intel_link_bw_set_bpp_limit_for_pipe - set link bpp limit for a pipe to its minimum118 * @state: atomic state119 * @old_limits: link BW limits120 * @new_limits: link BW limits121 * @pipe: pipe122 *123 * Set the link bpp limit for @pipe in @new_limits to its value in124 * @old_limits and mark this limit as the minimum. This function must be125 * called after a pipe's compute config function failed, @old_limits126 * containing the bpp limit with which compute config previously passed.127 *128 * The function will fail if setting a minimum is not possible, either129 * because the old and new limits match (and so would lead to a pipe compute130 * config failure) or the limit is already at the minimum.131 *132 * Returns %true in case of success.133 */134bool135intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state,136				     const struct intel_link_bw_limits *old_limits,137				     struct intel_link_bw_limits *new_limits,138				     enum pipe pipe)139{140	struct intel_display *display = to_intel_display(state);141 142	if (pipe == INVALID_PIPE)143		return false;144 145	if (new_limits->max_bpp_x16[pipe] ==146	    old_limits->max_bpp_x16[pipe])147		return false;148 149	if (drm_WARN_ON(display->drm,150			new_limits->bpp_limit_reached_pipes & BIT(pipe)))151		return false;152 153	new_limits->max_bpp_x16[pipe] =154		old_limits->max_bpp_x16[pipe];155	new_limits->bpp_limit_reached_pipes |= BIT(pipe);156 157	return true;158}159 160static int check_all_link_config(struct intel_atomic_state *state,161				 struct intel_link_bw_limits *limits)162{163	/* TODO: Check additional shared display link configurations like MST */164	int ret;165 166	ret = intel_dp_mst_atomic_check_link(state, limits);167	if (ret)168		return ret;169 170	ret = intel_dp_tunnel_atomic_check_link(state, limits);171	if (ret)172		return ret;173 174	ret = intel_fdi_atomic_check_link(state, limits);175	if (ret)176		return ret;177 178	return 0;179}180 181static bool182assert_link_limit_change_valid(struct intel_display *display,183			       const struct intel_link_bw_limits *old_limits,184			       const struct intel_link_bw_limits *new_limits)185{186	bool bpps_changed = false;187	enum pipe pipe;188 189	/* FEC can't be forced off after it was forced on. */190	if (drm_WARN_ON(display->drm,191			(old_limits->force_fec_pipes & new_limits->force_fec_pipes) !=192			old_limits->force_fec_pipes))193		return false;194 195	for_each_pipe(display, pipe) {196		/* The bpp limit can only decrease. */197		if (drm_WARN_ON(display->drm,198				new_limits->max_bpp_x16[pipe] >199				old_limits->max_bpp_x16[pipe]))200			return false;201 202		if (new_limits->max_bpp_x16[pipe] <203		    old_limits->max_bpp_x16[pipe])204			bpps_changed = true;205	}206 207	/* At least one limit must change. */208	if (drm_WARN_ON(display->drm,209			!bpps_changed &&210			new_limits->force_fec_pipes ==211			old_limits->force_fec_pipes))212		return false;213 214	return true;215}216 217/**218 * intel_link_bw_atomic_check - check display link states and set a fallback config if needed219 * @state: atomic state220 * @new_limits: link BW limits221 *222 * Check the configuration of all shared display links in @state and set new BW223 * limits in @new_limits if there is a BW limitation.224 *225 * Returns:226 *   - 0 if the confugration is valid227 *   - %-EAGAIN, if the configuration is invalid and @new_limits got updated228 *     with fallback values with which the configuration of all CRTCs229 *     in @state must be recomputed230 *   - Other negative error, if the configuration is invalid without a231 *     fallback possibility, or the check failed for another reason232 */233int intel_link_bw_atomic_check(struct intel_atomic_state *state,234			       struct intel_link_bw_limits *new_limits)235{236	struct intel_display *display = to_intel_display(state);237	struct intel_link_bw_limits old_limits = *new_limits;238	int ret;239 240	ret = check_all_link_config(state, new_limits);241	if (ret != -EAGAIN)242		return ret;243 244	if (!assert_link_limit_change_valid(display, &old_limits, new_limits))245		return -EINVAL;246 247	return -EAGAIN;248}249