]> git.ipfire.org Git - thirdparty/kernel/stable.git/blob - drivers/gpu/drm/i915/display/intel_link_bw.c
MAINTAINERS: Update drm.git URL
[thirdparty/kernel/stable.git] / drivers / gpu / drm / i915 / display / intel_link_bw.c
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 */
21 void 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 */
50 int 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 */
116 bool
117 intel_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
142 static 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
159 static bool
160 assert_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 */
211 int 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 }