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