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