Commit | Line | Data |
---|---|---|
5ee67f1c MR |
1 | /* |
2 | * Copyright © 2015 Intel Corporation | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
21 | * DEALINGS IN THE SOFTWARE. | |
22 | */ | |
23 | ||
24 | /** | |
25 | * DOC: atomic modeset support | |
26 | * | |
27 | * The functions here implement the state management and hardware programming | |
28 | * dispatch required by the atomic modeset infrastructure. | |
29 | * See intel_atomic_plane.c for the plane-specific atomic functionality. | |
30 | */ | |
31 | ||
5ee67f1c MR |
32 | #include <drm/drm_atomic.h> |
33 | #include <drm/drm_atomic_helper.h> | |
d0e93599 | 34 | #include <drm/drm_fourcc.h> |
5ee67f1c | 35 | #include <drm/drm_plane_helper.h> |
d0e93599 | 36 | |
12392a74 | 37 | #include "intel_atomic.h" |
1d455f8d | 38 | #include "intel_display_types.h" |
408bd917 | 39 | #include "intel_hdcp.h" |
f9a79f9a | 40 | #include "intel_sprite.h" |
5ee67f1c | 41 | |
11c1a9ec ML |
42 | /** |
43 | * intel_digital_connector_atomic_get_property - hook for connector->atomic_get_property. | |
44 | * @connector: Connector to get the property for. | |
45 | * @state: Connector state to retrieve the property from. | |
46 | * @property: Property to retrieve. | |
47 | * @val: Return value for the property. | |
48 | * | |
49 | * Returns the atomic property value for a digital connector. | |
50 | */ | |
51 | int intel_digital_connector_atomic_get_property(struct drm_connector *connector, | |
52 | const struct drm_connector_state *state, | |
53 | struct drm_property *property, | |
739f3abd | 54 | u64 *val) |
11c1a9ec ML |
55 | { |
56 | struct drm_device *dev = connector->dev; | |
57 | struct drm_i915_private *dev_priv = to_i915(dev); | |
58 | struct intel_digital_connector_state *intel_conn_state = | |
59 | to_intel_digital_connector_state(state); | |
60 | ||
61 | if (property == dev_priv->force_audio_property) | |
62 | *val = intel_conn_state->force_audio; | |
63 | else if (property == dev_priv->broadcast_rgb_property) | |
64 | *val = intel_conn_state->broadcast_rgb; | |
65 | else { | |
1a4b8901 VS |
66 | DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", |
67 | property->base.id, property->name); | |
11c1a9ec ML |
68 | return -EINVAL; |
69 | } | |
70 | ||
71 | return 0; | |
72 | } | |
73 | ||
74 | /** | |
75 | * intel_digital_connector_atomic_set_property - hook for connector->atomic_set_property. | |
76 | * @connector: Connector to set the property for. | |
77 | * @state: Connector state to set the property on. | |
78 | * @property: Property to set. | |
79 | * @val: New value for the property. | |
80 | * | |
81 | * Sets the atomic property value for a digital connector. | |
82 | */ | |
83 | int intel_digital_connector_atomic_set_property(struct drm_connector *connector, | |
84 | struct drm_connector_state *state, | |
85 | struct drm_property *property, | |
739f3abd | 86 | u64 val) |
11c1a9ec ML |
87 | { |
88 | struct drm_device *dev = connector->dev; | |
89 | struct drm_i915_private *dev_priv = to_i915(dev); | |
90 | struct intel_digital_connector_state *intel_conn_state = | |
91 | to_intel_digital_connector_state(state); | |
92 | ||
93 | if (property == dev_priv->force_audio_property) { | |
94 | intel_conn_state->force_audio = val; | |
95 | return 0; | |
96 | } | |
97 | ||
98 | if (property == dev_priv->broadcast_rgb_property) { | |
99 | intel_conn_state->broadcast_rgb = val; | |
100 | return 0; | |
101 | } | |
102 | ||
1a4b8901 VS |
103 | DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", |
104 | property->base.id, property->name); | |
11c1a9ec ML |
105 | return -EINVAL; |
106 | } | |
107 | ||
86beaea1 US |
108 | static bool blob_equal(const struct drm_property_blob *a, |
109 | const struct drm_property_blob *b) | |
110 | { | |
111 | if (a && b) | |
112 | return a->length == b->length && | |
113 | !memcmp(a->data, b->data, a->length); | |
114 | ||
115 | return !a == !b; | |
116 | } | |
117 | ||
11c1a9ec | 118 | int intel_digital_connector_atomic_check(struct drm_connector *conn, |
6f3b6278 | 119 | struct drm_atomic_state *state) |
11c1a9ec | 120 | { |
6f3b6278 SP |
121 | struct drm_connector_state *new_state = |
122 | drm_atomic_get_new_connector_state(state, conn); | |
11c1a9ec ML |
123 | struct intel_digital_connector_state *new_conn_state = |
124 | to_intel_digital_connector_state(new_state); | |
125 | struct drm_connector_state *old_state = | |
6f3b6278 | 126 | drm_atomic_get_old_connector_state(state, conn); |
11c1a9ec ML |
127 | struct intel_digital_connector_state *old_conn_state = |
128 | to_intel_digital_connector_state(old_state); | |
129 | struct drm_crtc_state *crtc_state; | |
130 | ||
ee5e5e7a SP |
131 | intel_hdcp_atomic_check(conn, old_state, new_state); |
132 | ||
11c1a9ec ML |
133 | if (!new_state->crtc) |
134 | return 0; | |
135 | ||
6f3b6278 | 136 | crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); |
11c1a9ec ML |
137 | |
138 | /* | |
139 | * These properties are handled by fastset, and might not end | |
140 | * up in a modeset. | |
141 | */ | |
142 | if (new_conn_state->force_audio != old_conn_state->force_audio || | |
143 | new_conn_state->broadcast_rgb != old_conn_state->broadcast_rgb || | |
2f146b78 | 144 | new_conn_state->base.colorspace != old_conn_state->base.colorspace || |
11c1a9ec | 145 | new_conn_state->base.picture_aspect_ratio != old_conn_state->base.picture_aspect_ratio || |
6553b123 | 146 | new_conn_state->base.content_type != old_conn_state->base.content_type || |
86beaea1 US |
147 | new_conn_state->base.scaling_mode != old_conn_state->base.scaling_mode || |
148 | !blob_equal(new_conn_state->base.hdr_output_metadata, | |
149 | old_conn_state->base.hdr_output_metadata)) | |
11c1a9ec ML |
150 | crtc_state->mode_changed = true; |
151 | ||
152 | return 0; | |
153 | } | |
154 | ||
155 | /** | |
156 | * intel_digital_connector_duplicate_state - duplicate connector state | |
157 | * @connector: digital connector | |
158 | * | |
159 | * Allocates and returns a copy of the connector state (both common and | |
160 | * digital connector specific) for the specified connector. | |
161 | * | |
162 | * Returns: The newly allocated connector state, or NULL on failure. | |
163 | */ | |
164 | struct drm_connector_state * | |
165 | intel_digital_connector_duplicate_state(struct drm_connector *connector) | |
166 | { | |
167 | struct intel_digital_connector_state *state; | |
168 | ||
169 | state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL); | |
170 | if (!state) | |
171 | return NULL; | |
172 | ||
173 | __drm_atomic_helper_connector_duplicate_state(connector, &state->base); | |
174 | return &state->base; | |
175 | } | |
176 | ||
177 | /** | |
1356837e MR |
178 | * intel_crtc_duplicate_state - duplicate crtc state |
179 | * @crtc: drm crtc | |
180 | * | |
181 | * Allocates and returns a copy of the crtc state (both common and | |
182 | * Intel-specific) for the specified crtc. | |
183 | * | |
184 | * Returns: The newly allocated crtc state, or NULL on failure. | |
185 | */ | |
186 | struct drm_crtc_state * | |
187 | intel_crtc_duplicate_state(struct drm_crtc *crtc) | |
188 | { | |
a91572f3 | 189 | struct intel_crtc_state *crtc_state; |
1356837e | 190 | |
f2a066f3 | 191 | crtc_state = kmemdup(crtc->state, sizeof(*crtc_state), GFP_KERNEL); |
f0c60574 ACO |
192 | if (!crtc_state) |
193 | return NULL; | |
194 | ||
195 | __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base); | |
196 | ||
bfd16b2a | 197 | crtc_state->update_pipe = false; |
d21fbe87 | 198 | crtc_state->disable_lp_wm = false; |
ab1d3a0e | 199 | crtc_state->disable_cxsr = false; |
caed361d VS |
200 | crtc_state->update_wm_pre = false; |
201 | crtc_state->update_wm_post = false; | |
e8861675 | 202 | crtc_state->fb_changed = false; |
236c48e6 | 203 | crtc_state->fifo_changed = false; |
1aa4df7e | 204 | crtc_state->preload_luts = false; |
ed4a6a7c | 205 | crtc_state->wm.need_postvbl_update = false; |
cd202f69 | 206 | crtc_state->fb_bits = 0; |
afbd8a72 | 207 | crtc_state->update_planes = 0; |
bfd16b2a | 208 | |
a91572f3 | 209 | return &crtc_state->base; |
1356837e MR |
210 | } |
211 | ||
212 | /** | |
213 | * intel_crtc_destroy_state - destroy crtc state | |
214 | * @crtc: drm crtc | |
eac95c4e | 215 | * @state: the state to destroy |
1356837e MR |
216 | * |
217 | * Destroys the crtc state (both common and Intel-specific) for the | |
218 | * specified crtc. | |
219 | */ | |
220 | void | |
221 | intel_crtc_destroy_state(struct drm_crtc *crtc, | |
eac95c4e | 222 | struct drm_crtc_state *state) |
1356837e MR |
223 | { |
224 | drm_atomic_helper_crtc_destroy_state(crtc, state); | |
225 | } | |
d03c93d4 | 226 | |
0aaf29b3 ML |
227 | static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state, |
228 | int num_scalers_need, struct intel_crtc *intel_crtc, | |
229 | const char *name, int idx, | |
230 | struct intel_plane_state *plane_state, | |
231 | int *scaler_id) | |
232 | { | |
233 | struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); | |
234 | int j; | |
235 | u32 mode; | |
236 | ||
237 | if (*scaler_id < 0) { | |
238 | /* find a free scaler */ | |
239 | for (j = 0; j < intel_crtc->num_scalers; j++) { | |
240 | if (scaler_state->scalers[j].in_use) | |
241 | continue; | |
242 | ||
243 | *scaler_id = j; | |
244 | scaler_state->scalers[*scaler_id].in_use = 1; | |
245 | break; | |
246 | } | |
247 | } | |
248 | ||
249 | if (WARN(*scaler_id < 0, "Cannot find scaler for %s:%d\n", name, idx)) | |
250 | return; | |
251 | ||
252 | /* set scaler mode */ | |
253 | if (plane_state && plane_state->base.fb && | |
254 | plane_state->base.fb->format->is_yuv && | |
255 | plane_state->base.fb->format->num_planes > 1) { | |
42fd20ed | 256 | struct intel_plane *plane = to_intel_plane(plane_state->base.plane); |
cf819eff | 257 | if (IS_GEN(dev_priv, 9) && |
b1554e23 | 258 | !IS_GEMINILAKE(dev_priv)) { |
0aaf29b3 | 259 | mode = SKL_PS_SCALER_MODE_NV12; |
42fd20ed | 260 | } else if (icl_is_hdr_plane(dev_priv, plane->id)) { |
b1554e23 ML |
261 | /* |
262 | * On gen11+'s HDR planes we only use the scaler for | |
263 | * scaling. They have a dedicated chroma upsampler, so | |
264 | * we don't need the scaler to upsample the UV plane. | |
265 | */ | |
266 | mode = PS_SCALER_MODE_NORMAL; | |
267 | } else { | |
0aaf29b3 ML |
268 | mode = PS_SCALER_MODE_PLANAR; |
269 | ||
b1554e23 ML |
270 | if (plane_state->linked_plane) |
271 | mode |= PS_PLANE_Y_SEL(plane_state->linked_plane->id); | |
272 | } | |
0aaf29b3 | 273 | } else if (INTEL_GEN(dev_priv) > 9 || IS_GEMINILAKE(dev_priv)) { |
b1554e23 | 274 | mode = PS_SCALER_MODE_NORMAL; |
0aaf29b3 ML |
275 | } else if (num_scalers_need == 1 && intel_crtc->num_scalers > 1) { |
276 | /* | |
277 | * when only 1 scaler is in use on a pipe with 2 scalers | |
278 | * scaler 0 operates in high quality (HQ) mode. | |
279 | * In this case use scaler 0 to take advantage of HQ mode | |
280 | */ | |
281 | scaler_state->scalers[*scaler_id].in_use = 0; | |
282 | *scaler_id = 0; | |
283 | scaler_state->scalers[0].in_use = 1; | |
284 | mode = SKL_PS_SCALER_MODE_HQ; | |
285 | } else { | |
286 | mode = SKL_PS_SCALER_MODE_DYN; | |
287 | } | |
288 | ||
289 | DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n", | |
290 | intel_crtc->pipe, *scaler_id, name, idx); | |
291 | scaler_state->scalers[*scaler_id].mode = mode; | |
292 | } | |
293 | ||
d03c93d4 CK |
294 | /** |
295 | * intel_atomic_setup_scalers() - setup scalers for crtc per staged requests | |
6ebc6923 | 296 | * @dev_priv: i915 device |
eac95c4e | 297 | * @intel_crtc: intel crtc |
d03c93d4 CK |
298 | * @crtc_state: incoming crtc_state to validate and setup scalers |
299 | * | |
300 | * This function sets up scalers based on staged scaling requests for | |
301 | * a @crtc and its planes. It is called from crtc level check path. If request | |
302 | * is a supportable request, it attaches scalers to requested planes and crtc. | |
303 | * | |
304 | * This function takes into account the current scaler(s) in use by any planes | |
305 | * not being part of this atomic state | |
306 | * | |
307 | * Returns: | |
308 | * 0 - scalers were setup succesfully | |
309 | * error code - otherwise | |
310 | */ | |
6ebc6923 ACO |
311 | int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, |
312 | struct intel_crtc *intel_crtc, | |
313 | struct intel_crtc_state *crtc_state) | |
d03c93d4 CK |
314 | { |
315 | struct drm_plane *plane = NULL; | |
316 | struct intel_plane *intel_plane; | |
317 | struct intel_plane_state *plane_state = NULL; | |
e435d6e5 ML |
318 | struct intel_crtc_scaler_state *scaler_state = |
319 | &crtc_state->scaler_state; | |
320 | struct drm_atomic_state *drm_state = crtc_state->base.state; | |
cd27d88f | 321 | struct intel_atomic_state *intel_state = to_intel_atomic_state(drm_state); |
d03c93d4 | 322 | int num_scalers_need; |
0aaf29b3 | 323 | int i; |
d03c93d4 | 324 | |
d03c93d4 | 325 | num_scalers_need = hweight32(scaler_state->scaler_users); |
d03c93d4 CK |
326 | |
327 | /* | |
328 | * High level flow: | |
329 | * - staged scaler requests are already in scaler_state->scaler_users | |
330 | * - check whether staged scaling requests can be supported | |
331 | * - add planes using scalers that aren't in current transaction | |
332 | * - assign scalers to requested users | |
333 | * - as part of plane commit, scalers will be committed | |
334 | * (i.e., either attached or detached) to respective planes in hw | |
335 | * - as part of crtc_commit, scaler will be either attached or detached | |
336 | * to crtc in hw | |
337 | */ | |
338 | ||
339 | /* fail if required scalers > available scalers */ | |
340 | if (num_scalers_need > intel_crtc->num_scalers){ | |
341 | DRM_DEBUG_KMS("Too many scaling requests %d > %d\n", | |
342 | num_scalers_need, intel_crtc->num_scalers); | |
343 | return -EINVAL; | |
344 | } | |
345 | ||
346 | /* walkthrough scaler_users bits and start assigning scalers */ | |
347 | for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) { | |
348 | int *scaler_id; | |
133b0d12 ML |
349 | const char *name; |
350 | int idx; | |
d03c93d4 CK |
351 | |
352 | /* skip if scaler not required */ | |
353 | if (!(scaler_state->scaler_users & (1 << i))) | |
354 | continue; | |
355 | ||
356 | if (i == SKL_CRTC_INDEX) { | |
133b0d12 ML |
357 | name = "CRTC"; |
358 | idx = intel_crtc->base.base.id; | |
359 | ||
d03c93d4 CK |
360 | /* panel fitter case: assign as a crtc scaler */ |
361 | scaler_id = &scaler_state->scaler_id; | |
362 | } else { | |
133b0d12 | 363 | name = "PLANE"; |
133b0d12 | 364 | |
d03c93d4 CK |
365 | /* plane scaler case: assign as a plane scaler */ |
366 | /* find the plane that set the bit as scaler_user */ | |
b8b5342b | 367 | plane = drm_state->planes[i].ptr; |
d03c93d4 CK |
368 | |
369 | /* | |
370 | * to enable/disable hq mode, add planes that are using scaler | |
371 | * into this transaction | |
372 | */ | |
373 | if (!plane) { | |
374 | struct drm_plane_state *state; | |
6ebc6923 | 375 | plane = drm_plane_from_index(&dev_priv->drm, i); |
d03c93d4 CK |
376 | state = drm_atomic_get_plane_state(drm_state, plane); |
377 | if (IS_ERR(state)) { | |
378 | DRM_DEBUG_KMS("Failed to add [PLANE:%d] to drm_state\n", | |
379 | plane->base.id); | |
380 | return PTR_ERR(state); | |
381 | } | |
cf5a15be ML |
382 | |
383 | /* | |
384 | * the plane is added after plane checks are run, | |
385 | * but since this plane is unchanged just do the | |
386 | * minimum required validation. | |
387 | */ | |
cf5a15be | 388 | crtc_state->base.planes_changed = true; |
d03c93d4 CK |
389 | } |
390 | ||
391 | intel_plane = to_intel_plane(plane); | |
c07a2d11 | 392 | idx = plane->base.id; |
d03c93d4 CK |
393 | |
394 | /* plane on different crtc cannot be a scaler user of this crtc */ | |
0aaf29b3 | 395 | if (WARN_ON(intel_plane->pipe != intel_crtc->pipe)) |
d03c93d4 | 396 | continue; |
d03c93d4 | 397 | |
cd27d88f ML |
398 | plane_state = intel_atomic_get_new_plane_state(intel_state, |
399 | intel_plane); | |
d03c93d4 CK |
400 | scaler_id = &plane_state->scaler_id; |
401 | } | |
402 | ||
0aaf29b3 ML |
403 | intel_atomic_setup_scaler(scaler_state, num_scalers_need, |
404 | intel_crtc, name, idx, | |
405 | plane_state, scaler_id); | |
d03c93d4 CK |
406 | } |
407 | ||
408 | return 0; | |
409 | } | |
de419ab6 | 410 | |
de419ab6 ML |
411 | struct drm_atomic_state * |
412 | intel_atomic_state_alloc(struct drm_device *dev) | |
413 | { | |
414 | struct intel_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL); | |
415 | ||
416 | if (!state || drm_atomic_state_init(dev, &state->base) < 0) { | |
417 | kfree(state); | |
418 | return NULL; | |
419 | } | |
420 | ||
421 | return &state->base; | |
422 | } | |
423 | ||
424 | void intel_atomic_state_clear(struct drm_atomic_state *s) | |
425 | { | |
426 | struct intel_atomic_state *state = to_intel_atomic_state(s); | |
427 | drm_atomic_state_default_clear(&state->base); | |
565602d7 | 428 | state->dpll_set = state->modeset = false; |
de419ab6 | 429 | } |
12392a74 JN |
430 | |
431 | struct intel_crtc_state * | |
432 | intel_atomic_get_crtc_state(struct drm_atomic_state *state, | |
433 | struct intel_crtc *crtc) | |
434 | { | |
435 | struct drm_crtc_state *crtc_state; | |
436 | crtc_state = drm_atomic_get_crtc_state(state, &crtc->base); | |
437 | if (IS_ERR(crtc_state)) | |
438 | return ERR_CAST(crtc_state); | |
439 | ||
440 | return to_intel_crtc_state(crtc_state); | |
441 | } |