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 | |
32 | #include <drm/display/drm_dp_tunnel.h> |
33 | #include <drm/drm_atomic.h> |
34 | #include <drm/drm_atomic_helper.h> |
35 | #include <drm/drm_fourcc.h> |
36 | |
37 | #include "i915_drv.h" |
38 | #include "i915_reg.h" |
39 | #include "intel_atomic.h" |
40 | #include "intel_cdclk.h" |
41 | #include "intel_display_types.h" |
42 | #include "intel_dp_tunnel.h" |
43 | #include "intel_global_state.h" |
44 | #include "intel_hdcp.h" |
45 | #include "intel_psr.h" |
46 | #include "intel_fb.h" |
47 | #include "skl_universal_plane.h" |
48 | |
49 | /** |
50 | * intel_digital_connector_atomic_get_property - hook for connector->atomic_get_property. |
51 | * @connector: Connector to get the property for. |
52 | * @state: Connector state to retrieve the property from. |
53 | * @property: Property to retrieve. |
54 | * @val: Return value for the property. |
55 | * |
56 | * Returns the atomic property value for a digital connector. |
57 | */ |
58 | int intel_digital_connector_atomic_get_property(struct drm_connector *connector, |
59 | const struct drm_connector_state *state, |
60 | struct drm_property *property, |
61 | u64 *val) |
62 | { |
63 | struct drm_device *dev = connector->dev; |
64 | struct drm_i915_private *dev_priv = to_i915(dev); |
65 | struct intel_digital_connector_state *intel_conn_state = |
66 | to_intel_digital_connector_state(state); |
67 | |
68 | if (property == dev_priv->display.properties.force_audio) |
69 | *val = intel_conn_state->force_audio; |
70 | else if (property == dev_priv->display.properties.broadcast_rgb) |
71 | *val = intel_conn_state->broadcast_rgb; |
72 | else { |
73 | drm_dbg_atomic(&dev_priv->drm, |
74 | "Unknown property [PROP:%d:%s]\n" , |
75 | property->base.id, property->name); |
76 | return -EINVAL; |
77 | } |
78 | |
79 | return 0; |
80 | } |
81 | |
82 | /** |
83 | * intel_digital_connector_atomic_set_property - hook for connector->atomic_set_property. |
84 | * @connector: Connector to set the property for. |
85 | * @state: Connector state to set the property on. |
86 | * @property: Property to set. |
87 | * @val: New value for the property. |
88 | * |
89 | * Sets the atomic property value for a digital connector. |
90 | */ |
91 | int intel_digital_connector_atomic_set_property(struct drm_connector *connector, |
92 | struct drm_connector_state *state, |
93 | struct drm_property *property, |
94 | u64 val) |
95 | { |
96 | struct drm_device *dev = connector->dev; |
97 | struct drm_i915_private *dev_priv = to_i915(dev); |
98 | struct intel_digital_connector_state *intel_conn_state = |
99 | to_intel_digital_connector_state(state); |
100 | |
101 | if (property == dev_priv->display.properties.force_audio) { |
102 | intel_conn_state->force_audio = val; |
103 | return 0; |
104 | } |
105 | |
106 | if (property == dev_priv->display.properties.broadcast_rgb) { |
107 | intel_conn_state->broadcast_rgb = val; |
108 | return 0; |
109 | } |
110 | |
111 | drm_dbg_atomic(&dev_priv->drm, "Unknown property [PROP:%d:%s]\n" , |
112 | property->base.id, property->name); |
113 | return -EINVAL; |
114 | } |
115 | |
116 | int intel_digital_connector_atomic_check(struct drm_connector *conn, |
117 | struct drm_atomic_state *state) |
118 | { |
119 | struct drm_connector_state *new_state = |
120 | drm_atomic_get_new_connector_state(state, connector: conn); |
121 | struct intel_digital_connector_state *new_conn_state = |
122 | to_intel_digital_connector_state(new_state); |
123 | struct drm_connector_state *old_state = |
124 | drm_atomic_get_old_connector_state(state, connector: conn); |
125 | struct intel_digital_connector_state *old_conn_state = |
126 | to_intel_digital_connector_state(old_state); |
127 | struct drm_crtc_state *crtc_state; |
128 | |
129 | intel_hdcp_atomic_check(connector: conn, old_state, new_state); |
130 | |
131 | if (!new_state->crtc) |
132 | return 0; |
133 | |
134 | crtc_state = drm_atomic_get_new_crtc_state(state, crtc: new_state->crtc); |
135 | |
136 | /* |
137 | * These properties are handled by fastset, and might not end |
138 | * up in a modeset. |
139 | */ |
140 | if (new_conn_state->force_audio != old_conn_state->force_audio || |
141 | new_conn_state->broadcast_rgb != old_conn_state->broadcast_rgb || |
142 | new_conn_state->base.colorspace != old_conn_state->base.colorspace || |
143 | new_conn_state->base.picture_aspect_ratio != old_conn_state->base.picture_aspect_ratio || |
144 | new_conn_state->base.content_type != old_conn_state->base.content_type || |
145 | new_conn_state->base.scaling_mode != old_conn_state->base.scaling_mode || |
146 | new_conn_state->base.privacy_screen_sw_state != old_conn_state->base.privacy_screen_sw_state || |
147 | !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) |
148 | crtc_state->mode_changed = true; |
149 | |
150 | return 0; |
151 | } |
152 | |
153 | /** |
154 | * intel_digital_connector_duplicate_state - duplicate connector state |
155 | * @connector: digital connector |
156 | * |
157 | * Allocates and returns a copy of the connector state (both common and |
158 | * digital connector specific) for the specified connector. |
159 | * |
160 | * Returns: The newly allocated connector state, or NULL on failure. |
161 | */ |
162 | struct drm_connector_state * |
163 | intel_digital_connector_duplicate_state(struct drm_connector *connector) |
164 | { |
165 | struct intel_digital_connector_state *state; |
166 | |
167 | state = kmemdup(p: connector->state, size: sizeof(*state), GFP_KERNEL); |
168 | if (!state) |
169 | return NULL; |
170 | |
171 | __drm_atomic_helper_connector_duplicate_state(connector, state: &state->base); |
172 | return &state->base; |
173 | } |
174 | |
175 | /** |
176 | * intel_connector_needs_modeset - check if connector needs a modeset |
177 | * @state: the atomic state corresponding to this modeset |
178 | * @connector: the connector |
179 | */ |
180 | bool |
181 | intel_connector_needs_modeset(struct intel_atomic_state *state, |
182 | struct drm_connector *connector) |
183 | { |
184 | const struct drm_connector_state *old_conn_state, *new_conn_state; |
185 | |
186 | old_conn_state = drm_atomic_get_old_connector_state(state: &state->base, connector); |
187 | new_conn_state = drm_atomic_get_new_connector_state(state: &state->base, connector); |
188 | |
189 | return old_conn_state->crtc != new_conn_state->crtc || |
190 | (new_conn_state->crtc && |
191 | drm_atomic_crtc_needs_modeset(state: drm_atomic_get_new_crtc_state(state: &state->base, |
192 | crtc: new_conn_state->crtc))); |
193 | } |
194 | |
195 | /** |
196 | * intel_any_crtc_needs_modeset - check if any CRTC needs a modeset |
197 | * @state: the atomic state corresponding to this modeset |
198 | * |
199 | * Returns true if any CRTC in @state needs a modeset. |
200 | */ |
201 | bool intel_any_crtc_needs_modeset(struct intel_atomic_state *state) |
202 | { |
203 | struct intel_crtc *crtc; |
204 | struct intel_crtc_state *crtc_state; |
205 | int i; |
206 | |
207 | for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { |
208 | if (intel_crtc_needs_modeset(crtc_state)) |
209 | return true; |
210 | } |
211 | |
212 | return false; |
213 | } |
214 | |
215 | struct intel_digital_connector_state * |
216 | intel_atomic_get_digital_connector_state(struct intel_atomic_state *state, |
217 | struct intel_connector *connector) |
218 | { |
219 | struct drm_connector_state *conn_state; |
220 | |
221 | conn_state = drm_atomic_get_connector_state(state: &state->base, |
222 | connector: &connector->base); |
223 | if (IS_ERR(ptr: conn_state)) |
224 | return ERR_CAST(ptr: conn_state); |
225 | |
226 | return to_intel_digital_connector_state(conn_state); |
227 | } |
228 | |
229 | /** |
230 | * intel_crtc_duplicate_state - duplicate crtc state |
231 | * @crtc: drm crtc |
232 | * |
233 | * Allocates and returns a copy of the crtc state (both common and |
234 | * Intel-specific) for the specified crtc. |
235 | * |
236 | * Returns: The newly allocated crtc state, or NULL on failure. |
237 | */ |
238 | struct drm_crtc_state * |
239 | intel_crtc_duplicate_state(struct drm_crtc *crtc) |
240 | { |
241 | const struct intel_crtc_state *old_crtc_state = to_intel_crtc_state(crtc->state); |
242 | struct intel_crtc_state *crtc_state; |
243 | |
244 | crtc_state = kmemdup(p: old_crtc_state, size: sizeof(*crtc_state), GFP_KERNEL); |
245 | if (!crtc_state) |
246 | return NULL; |
247 | |
248 | __drm_atomic_helper_crtc_duplicate_state(crtc, state: &crtc_state->uapi); |
249 | |
250 | /* copy color blobs */ |
251 | if (crtc_state->hw.degamma_lut) |
252 | drm_property_blob_get(blob: crtc_state->hw.degamma_lut); |
253 | if (crtc_state->hw.ctm) |
254 | drm_property_blob_get(blob: crtc_state->hw.ctm); |
255 | if (crtc_state->hw.gamma_lut) |
256 | drm_property_blob_get(blob: crtc_state->hw.gamma_lut); |
257 | |
258 | if (crtc_state->pre_csc_lut) |
259 | drm_property_blob_get(blob: crtc_state->pre_csc_lut); |
260 | if (crtc_state->post_csc_lut) |
261 | drm_property_blob_get(blob: crtc_state->post_csc_lut); |
262 | |
263 | if (crtc_state->dp_tunnel_ref.tunnel) |
264 | drm_dp_tunnel_ref_get(tunnel: crtc_state->dp_tunnel_ref.tunnel, |
265 | tunnel_ref: &crtc_state->dp_tunnel_ref); |
266 | |
267 | crtc_state->update_pipe = false; |
268 | crtc_state->update_m_n = false; |
269 | crtc_state->update_lrr = false; |
270 | crtc_state->disable_lp_wm = false; |
271 | crtc_state->disable_cxsr = false; |
272 | crtc_state->update_wm_pre = false; |
273 | crtc_state->update_wm_post = false; |
274 | crtc_state->fifo_changed = false; |
275 | crtc_state->preload_luts = false; |
276 | crtc_state->wm.need_postvbl_update = false; |
277 | crtc_state->do_async_flip = false; |
278 | crtc_state->fb_bits = 0; |
279 | crtc_state->update_planes = 0; |
280 | crtc_state->dsb = NULL; |
281 | |
282 | return &crtc_state->uapi; |
283 | } |
284 | |
285 | static void intel_crtc_put_color_blobs(struct intel_crtc_state *crtc_state) |
286 | { |
287 | drm_property_blob_put(blob: crtc_state->hw.degamma_lut); |
288 | drm_property_blob_put(blob: crtc_state->hw.gamma_lut); |
289 | drm_property_blob_put(blob: crtc_state->hw.ctm); |
290 | |
291 | drm_property_blob_put(blob: crtc_state->pre_csc_lut); |
292 | drm_property_blob_put(blob: crtc_state->post_csc_lut); |
293 | } |
294 | |
295 | void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state) |
296 | { |
297 | intel_crtc_put_color_blobs(crtc_state); |
298 | } |
299 | |
300 | /** |
301 | * intel_crtc_destroy_state - destroy crtc state |
302 | * @crtc: drm crtc |
303 | * @state: the state to destroy |
304 | * |
305 | * Destroys the crtc state (both common and Intel-specific) for the |
306 | * specified crtc. |
307 | */ |
308 | void |
309 | intel_crtc_destroy_state(struct drm_crtc *crtc, |
310 | struct drm_crtc_state *state) |
311 | { |
312 | struct intel_crtc_state *crtc_state = to_intel_crtc_state(state); |
313 | |
314 | drm_WARN_ON(crtc->dev, crtc_state->dsb); |
315 | |
316 | __drm_atomic_helper_crtc_destroy_state(state: &crtc_state->uapi); |
317 | intel_crtc_free_hw_state(crtc_state); |
318 | if (crtc_state->dp_tunnel_ref.tunnel) |
319 | drm_dp_tunnel_ref_put(tunnel_ref: &crtc_state->dp_tunnel_ref); |
320 | kfree(objp: crtc_state); |
321 | } |
322 | |
323 | struct drm_atomic_state * |
324 | intel_atomic_state_alloc(struct drm_device *dev) |
325 | { |
326 | struct intel_atomic_state *state = kzalloc(size: sizeof(*state), GFP_KERNEL); |
327 | |
328 | if (!state || drm_atomic_state_init(dev, state: &state->base) < 0) { |
329 | kfree(objp: state); |
330 | return NULL; |
331 | } |
332 | |
333 | return &state->base; |
334 | } |
335 | |
336 | void intel_atomic_state_free(struct drm_atomic_state *_state) |
337 | { |
338 | struct intel_atomic_state *state = to_intel_atomic_state(_state); |
339 | |
340 | drm_atomic_state_default_release(state: &state->base); |
341 | kfree(objp: state->global_objs); |
342 | kfree(objp: state); |
343 | } |
344 | |
345 | void intel_atomic_state_clear(struct drm_atomic_state *s) |
346 | { |
347 | struct intel_atomic_state *state = to_intel_atomic_state(s); |
348 | |
349 | drm_atomic_state_default_clear(state: &state->base); |
350 | intel_atomic_clear_global_state(state); |
351 | |
352 | /* state->internal not reset on purpose */ |
353 | |
354 | state->dpll_set = state->modeset = false; |
355 | |
356 | intel_dp_tunnel_atomic_cleanup_inherited_state(state); |
357 | } |
358 | |
359 | struct intel_crtc_state * |
360 | intel_atomic_get_crtc_state(struct drm_atomic_state *state, |
361 | struct intel_crtc *crtc) |
362 | { |
363 | struct drm_crtc_state *crtc_state; |
364 | crtc_state = drm_atomic_get_crtc_state(state, crtc: &crtc->base); |
365 | if (IS_ERR(ptr: crtc_state)) |
366 | return ERR_CAST(ptr: crtc_state); |
367 | |
368 | return to_intel_crtc_state(crtc_state); |
369 | } |
370 | |