]>
Commit | Line | Data |
---|---|---|
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 |
23 | void 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 | */ | |
65 | int 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 | */ | |
131 | bool | |
132 | intel_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 | ||
157 | static 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 | ||
178 | static bool | |
179 | assert_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 | */ | |
230 | int 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 | } |