Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.14.15.
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2023 Intel Corporation
  4 */
  5
  6#include "i915_drv.h"
  7
  8#include "intel_atomic.h"
  9#include "intel_display_types.h"
 10#include "intel_dp_mst.h"
 11#include "intel_fdi.h"
 12#include "intel_link_bw.h"
 13
 14/**
 15 * intel_link_bw_init_limits - initialize BW limits
 16 * @i915: device instance
 17 * @limits: link BW limits
 18 *
 19 * Initialize @limits.
 20 */
 21void intel_link_bw_init_limits(struct drm_i915_private *i915, struct intel_link_bw_limits *limits)
 22{
 23	enum pipe pipe;
 24
 25	limits->force_fec_pipes = 0;
 26	limits->bpp_limit_reached_pipes = 0;
 27	for_each_pipe(i915, pipe)
 28		limits->max_bpp_x16[pipe] = INT_MAX;
 29}
 30
 31/**
 32 * intel_link_bw_reduce_bpp - reduce maximum link bpp for a selected pipe
 33 * @state: atomic state
 34 * @limits: link BW limits
 35 * @pipe_mask: mask of pipes to select from
 36 * @reason: explanation of why bpp reduction is needed
 37 *
 38 * Select the pipe from @pipe_mask with the biggest link bpp value and set the
 39 * maximum of link bpp in @limits below this value. Modeset the selected pipe,
 40 * so that its state will get recomputed.
 41 *
 42 * This function can be called to resolve a link's BW overallocation by reducing
 43 * the link bpp of one pipe on the link and hence reducing the total link BW.
 44 *
 45 * Returns
 46 *   - 0 in case of success
 47 *   - %-ENOSPC if no pipe can further reduce its link bpp
 48 *   - Other negative error, if modesetting the selected pipe failed
 49 */
 50int intel_link_bw_reduce_bpp(struct intel_atomic_state *state,
 51			     struct intel_link_bw_limits *limits,
 52			     u8 pipe_mask,
 53			     const char *reason)
 54{
 55	struct drm_i915_private *i915 = to_i915(state->base.dev);
 56	enum pipe max_bpp_pipe = INVALID_PIPE;
 57	struct intel_crtc *crtc;
 58	int max_bpp_x16 = 0;
 59
 60	for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) {
 61		struct intel_crtc_state *crtc_state;
 62		int link_bpp_x16;
 63
 64		if (limits->bpp_limit_reached_pipes & BIT(crtc->pipe))
 65			continue;
 66
 67		crtc_state = intel_atomic_get_crtc_state(&state->base,
 68							 crtc);
 69		if (IS_ERR(crtc_state))
 70			return PTR_ERR(crtc_state);
 71
 72		if (crtc_state->dsc.compression_enable)
 73			link_bpp_x16 = crtc_state->dsc.compressed_bpp_x16;
 74		else
 75			/*
 76			 * TODO: for YUV420 the actual link bpp is only half
 77			 * of the pipe bpp value. The MST encoder's BW allocation
 78			 * is based on the pipe bpp value, set the actual link bpp
 79			 * limit here once the MST BW allocation is fixed.
 80			 */
 81			link_bpp_x16 = to_bpp_x16(crtc_state->pipe_bpp);
 82
 83		if (link_bpp_x16 > max_bpp_x16) {
 84			max_bpp_x16 = link_bpp_x16;
 85			max_bpp_pipe = crtc->pipe;
 86		}
 87	}
 88
 89	if (max_bpp_pipe == INVALID_PIPE)
 90		return -ENOSPC;
 91
 92	limits->max_bpp_x16[max_bpp_pipe] = max_bpp_x16 - 1;
 93
 94	return intel_modeset_pipes_in_mask_early(state, reason,
 95						 BIT(max_bpp_pipe));
 96}
 97
 98/**
 99 * intel_link_bw_set_bpp_limit_for_pipe - set link bpp limit for a pipe to its minimum
100 * @state: atomic state
101 * @old_limits: link BW limits
102 * @new_limits: link BW limits
103 * @pipe: pipe
104 *
105 * Set the link bpp limit for @pipe in @new_limits to its value in
106 * @old_limits and mark this limit as the minimum. This function must be
107 * called after a pipe's compute config function failed, @old_limits
108 * containing the bpp limit with which compute config previously passed.
109 *
110 * The function will fail if setting a minimum is not possible, either
111 * because the old and new limits match (and so would lead to a pipe compute
112 * config failure) or the limit is already at the minimum.
113 *
114 * Returns %true in case of success.
115 */
116bool
117intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state,
118				     const struct intel_link_bw_limits *old_limits,
119				     struct intel_link_bw_limits *new_limits,
120				     enum pipe pipe)
121{
122	struct drm_i915_private *i915 = to_i915(state->base.dev);
123
124	if (pipe == INVALID_PIPE)
125		return false;
126
127	if (new_limits->max_bpp_x16[pipe] ==
128	    old_limits->max_bpp_x16[pipe])
129		return false;
130
131	if (drm_WARN_ON(&i915->drm,
132			new_limits->bpp_limit_reached_pipes & BIT(pipe)))
133		return false;
134
135	new_limits->max_bpp_x16[pipe] =
136		old_limits->max_bpp_x16[pipe];
137	new_limits->bpp_limit_reached_pipes |= BIT(pipe);
138
139	return true;
140}
141
142static int check_all_link_config(struct intel_atomic_state *state,
143				 struct intel_link_bw_limits *limits)
144{
145	/* TODO: Check additional shared display link configurations like MST */
146	int ret;
147
148	ret = intel_dp_mst_atomic_check_link(state, limits);
149	if (ret)
150		return ret;
151
152	ret = intel_fdi_atomic_check_link(state, limits);
153	if (ret)
154		return ret;
155
156	return 0;
157}
158
159static bool
160assert_link_limit_change_valid(struct drm_i915_private *i915,
161			       const struct intel_link_bw_limits *old_limits,
162			       const struct intel_link_bw_limits *new_limits)
163{
164	bool bpps_changed = false;
165	enum pipe pipe;
166
167	/* FEC can't be forced off after it was forced on. */
168	if (drm_WARN_ON(&i915->drm,
169			(old_limits->force_fec_pipes & new_limits->force_fec_pipes) !=
170			old_limits->force_fec_pipes))
171		return false;
172
173	for_each_pipe(i915, pipe) {
174		/* The bpp limit can only decrease. */
175		if (drm_WARN_ON(&i915->drm,
176				new_limits->max_bpp_x16[pipe] >
177				old_limits->max_bpp_x16[pipe]))
178			return false;
179
180		if (new_limits->max_bpp_x16[pipe] <
181		    old_limits->max_bpp_x16[pipe])
182			bpps_changed = true;
183	}
184
185	/* At least one limit must change. */
186	if (drm_WARN_ON(&i915->drm,
187			!bpps_changed &&
188			new_limits->force_fec_pipes ==
189			old_limits->force_fec_pipes))
190		return false;
191
192	return true;
193}
194
195/**
196 * intel_link_bw_atomic_check - check display link states and set a fallback config if needed
197 * @state: atomic state
198 * @new_limits: link BW limits
199 *
200 * Check the configuration of all shared display links in @state and set new BW
201 * limits in @new_limits if there is a BW limitation.
202 *
203 * Returns:
204 *   - 0 if the confugration is valid
205 *   - %-EAGAIN, if the configuration is invalid and @new_limits got updated
206 *     with fallback values with which the configuration of all CRTCs
207 *     in @state must be recomputed
208 *   - Other negative error, if the configuration is invalid without a
209 *     fallback possibility, or the check failed for another reason
210 */
211int intel_link_bw_atomic_check(struct intel_atomic_state *state,
212			       struct intel_link_bw_limits *new_limits)
213{
214	struct drm_i915_private *i915 = to_i915(state->base.dev);
215	struct intel_link_bw_limits old_limits = *new_limits;
216	int ret;
217
218	ret = check_all_link_config(state, new_limits);
219	if (ret != -EAGAIN)
220		return ret;
221
222	if (!assert_link_limit_change_valid(i915, &old_limits, new_limits))
223		return -EINVAL;
224
225	return -EAGAIN;
226}