2 * Copyright (C) 2014 Red Hat
3 * Copyright (C) 2014 Intel Corp.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
24 * Rob Clark <robdclark@gmail.com>
25 * Daniel Vetter <daniel.vetter@ffwll.ch>
29 #include <drm/drm_atomic.h>
30 #include <drm/drm_plane_helper.h>
31 #include <drm/drm_crtc_helper.h>
34 drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
35 struct drm_plane_state *plane_state,
36 struct drm_plane *plane)
38 struct drm_crtc_state *crtc_state;
40 if (plane->state->crtc) {
41 crtc_state = state->crtc_states[drm_crtc_index(plane->crtc)];
43 if (WARN_ON(!crtc_state))
46 crtc_state->planes_changed = true;
49 if (plane_state->crtc) {
51 state->crtc_states[drm_crtc_index(plane_state->crtc)];
53 if (WARN_ON(!crtc_state))
56 crtc_state->planes_changed = true;
61 * drm_atomic_helper_check - validate state object
63 * @state: the driver state object
65 * Check the state object to see if the requested state is physically possible.
66 * Only crtcs and planes have check callbacks, so for any additional (global)
67 * checking that a driver needs it can simply wrap that around this function.
68 * Drivers without such needs can directly use this as their ->atomic_check()
72 * Zero for success or -errno
74 int drm_atomic_helper_check(struct drm_device *dev,
75 struct drm_atomic_state *state)
77 int nplanes = dev->mode_config.num_total_plane;
78 int ncrtcs = dev->mode_config.num_crtc;
81 for (i = 0; i < nplanes; i++) {
82 struct drm_plane_helper_funcs *funcs;
83 struct drm_plane *plane = state->planes[i];
84 struct drm_plane_state *plane_state = state->plane_states[i];
89 funcs = plane->helper_private;
91 drm_atomic_helper_plane_changed(state, plane_state, plane);
93 if (!funcs || !funcs->atomic_check)
96 ret = funcs->atomic_check(plane, plane_state);
98 DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n",
104 for (i = 0; i < ncrtcs; i++) {
105 struct drm_crtc_helper_funcs *funcs;
106 struct drm_crtc *crtc = state->crtcs[i];
111 funcs = crtc->helper_private;
113 if (!funcs || !funcs->atomic_check)
116 ret = funcs->atomic_check(crtc, state->crtc_states[i]);
118 DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n",
126 EXPORT_SYMBOL(drm_atomic_helper_check);
129 * drm_atomic_helper_prepare_planes - prepare plane resources after commit
131 * @state: atomic state object with old state structures
133 * This function prepares plane state, specifically framebuffers, for the new
134 * configuration. If any failure is encountered this function will call
135 * ->cleanup_fb on any already successfully prepared framebuffer.
138 * 0 on success, negative error code on failure.
140 int drm_atomic_helper_prepare_planes(struct drm_device *dev,
141 struct drm_atomic_state *state)
143 int nplanes = dev->mode_config.num_total_plane;
146 for (i = 0; i < nplanes; i++) {
147 struct drm_plane_helper_funcs *funcs;
148 struct drm_plane *plane = state->planes[i];
149 struct drm_framebuffer *fb;
154 funcs = plane->helper_private;
156 fb = state->plane_states[i]->fb;
158 if (fb && funcs->prepare_fb) {
159 ret = funcs->prepare_fb(plane, fb);
168 for (i--; i >= 0; i--) {
169 struct drm_plane_helper_funcs *funcs;
170 struct drm_plane *plane = state->planes[i];
171 struct drm_framebuffer *fb;
176 funcs = plane->helper_private;
178 fb = state->plane_states[i]->fb;
180 if (fb && funcs->cleanup_fb)
181 funcs->cleanup_fb(plane, fb);
187 EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
190 * drm_atomic_helper_commit_planes - commit plane state
192 * @state: atomic state
194 * This function commits the new plane state using the plane and atomic helper
195 * functions for planes and crtcs. It assumes that the atomic state has already
196 * been pushed into the relevant object state pointers, since this step can no
199 * It still requires the global state object @state to know which planes and
200 * crtcs need to be updated though.
202 void drm_atomic_helper_commit_planes(struct drm_device *dev,
203 struct drm_atomic_state *state)
205 int nplanes = dev->mode_config.num_total_plane;
206 int ncrtcs = dev->mode_config.num_crtc;
209 for (i = 0; i < ncrtcs; i++) {
210 struct drm_crtc_helper_funcs *funcs;
211 struct drm_crtc *crtc = state->crtcs[i];
216 funcs = crtc->helper_private;
218 if (!funcs || !funcs->atomic_begin)
221 funcs->atomic_begin(crtc);
224 for (i = 0; i < nplanes; i++) {
225 struct drm_plane_helper_funcs *funcs;
226 struct drm_plane *plane = state->planes[i];
231 funcs = plane->helper_private;
233 if (!funcs || !funcs->atomic_update)
236 funcs->atomic_update(plane);
239 for (i = 0; i < ncrtcs; i++) {
240 struct drm_crtc_helper_funcs *funcs;
241 struct drm_crtc *crtc = state->crtcs[i];
246 funcs = crtc->helper_private;
248 if (!funcs || !funcs->atomic_flush)
251 funcs->atomic_flush(crtc);
254 EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
257 * drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
259 * @old_state: atomic state object with old state structures
261 * This function cleans up plane state, specifically framebuffers, from the old
262 * configuration. Hence the old configuration must be perserved in @old_state to
263 * be able to call this function.
265 * This function must also be called on the new state when the atomic update
266 * fails at any point after calling drm_atomic_helper_prepare_planes().
268 void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
269 struct drm_atomic_state *old_state)
271 int nplanes = dev->mode_config.num_total_plane;
274 for (i = 0; i < nplanes; i++) {
275 struct drm_plane_helper_funcs *funcs;
276 struct drm_plane *plane = old_state->planes[i];
277 struct drm_framebuffer *old_fb;
282 funcs = plane->helper_private;
284 old_fb = old_state->plane_states[i]->fb;
286 if (old_fb && funcs->cleanup_fb)
287 funcs->cleanup_fb(plane, old_fb);
290 EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
293 * drm_atomic_helper_swap_state - store atomic state into current sw state
295 * @state: atomic state
297 * This function stores the atomic state into the current state pointers in all
298 * driver objects. It should be called after all failing steps have been done
299 * and succeeded, but before the actual hardware state is committed.
301 * For cleanup and error recovery the current state for all changed objects will
302 * be swaped into @state.
304 * With that sequence it fits perfectly into the plane prepare/cleanup sequence:
306 * 1. Call drm_atomic_helper_prepare_planes() with the staged atomic state.
308 * 2. Do any other steps that might fail.
310 * 3. Put the staged state into the current state pointers with this function.
312 * 4. Actually commit the hardware state.
314 * 5. Call drm_atomic_helper_cleanup_planes with @state, which since step 3
315 * contains the old state. Also do any other cleanup required with that state.
317 void drm_atomic_helper_swap_state(struct drm_device *dev,
318 struct drm_atomic_state *state)
322 for (i = 0; i < dev->mode_config.num_connector; i++) {
323 struct drm_connector *connector = state->connectors[i];
328 connector->state->state = state;
329 swap(state->connector_states[i], connector->state);
330 connector->state->state = NULL;
333 for (i = 0; i < dev->mode_config.num_crtc; i++) {
334 struct drm_crtc *crtc = state->crtcs[i];
339 crtc->state->state = state;
340 swap(state->crtc_states[i], crtc->state);
341 crtc->state->state = NULL;
344 for (i = 0; i < dev->mode_config.num_total_plane; i++) {
345 struct drm_plane *plane = state->planes[i];
350 plane->state->state = state;
351 swap(state->plane_states[i], plane->state);
352 plane->state->state = NULL;
355 EXPORT_SYMBOL(drm_atomic_helper_swap_state);