aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2018-12-05 22:43:22 -0500
committerDave Airlie <airlied@redhat.com>2018-12-05 22:43:56 -0500
commit1f9a5dce3548d54d810b23e4e0b1d8c6d73a52d4 (patch)
tree1d257e265325b04909278b52fe18cea616bf674f
parentfb878d106b7738ae7cdb513f98876b22bd6a485f (diff)
parent9a01135b98b9d5a7033c544245da7aad0d886758 (diff)
Merge tag 'vmwgfx-next-2018-12-05' of git://people.freedesktop.org/~thomash/linux into drm-next
Pull request of 2018-12-05 Page flip with damage by Deepak and others, Various vmwgfx minor fixes anc cleanups. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Hellstrom <thellstrom@vmware.com> Link: https://patchwork.freedesktop.org/patch/msgid/20181205103554.3675-1-thellstrom@vmware.com
-rw-r--r--Documentation/gpu/drm-kms.rst12
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/drm_atomic.c22
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c3
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c13
-rw-r--r--drivers/gpu/drm/drm_damage_helper.c334
-rw-r--r--drivers/gpu/drm/drm_mode_config.c6
-rw-r--r--drivers/gpu/drm/selftests/Makefile3
-rw-r--r--drivers/gpu/drm/selftests/drm_modeset_selftests.h21
-rw-r--r--drivers/gpu/drm/selftests/test-drm_damage_helper.c811
-rw-r--r--drivers/gpu/drm/selftests/test-drm_modeset_common.h21
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h11
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fence.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c569
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h150
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c11
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c359
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c561
-rw-r--r--include/drm/drm_damage_helper.h99
-rw-r--r--include/drm/drm_mode_config.h9
-rw-r--r--include/drm/drm_plane.h42
-rw-r--r--include/uapi/drm/drm_mode.h19
25 files changed, 2521 insertions, 565 deletions
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index 8da2a178cf85..75c882e09fee 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -554,6 +554,18 @@ Plane Composition Properties
554.. kernel-doc:: drivers/gpu/drm/drm_blend.c 554.. kernel-doc:: drivers/gpu/drm/drm_blend.c
555 :export: 555 :export:
556 556
557FB_DAMAGE_CLIPS
558~~~~~~~~~~~~~~~
559
560.. kernel-doc:: drivers/gpu/drm/drm_damage_helper.c
561 :doc: overview
562
563.. kernel-doc:: drivers/gpu/drm/drm_damage_helper.c
564 :export:
565
566.. kernel-doc:: include/drm/drm_damage_helper.h
567 :internal:
568
557Color Management Properties 569Color Management Properties
558--------------------------- 570---------------------------
559 571
diff --git a/MAINTAINERS b/MAINTAINERS
index 254b7b267731..e12da05e2feb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4781,10 +4781,8 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
4781 4781
4782DRM DRIVER FOR VMWARE VIRTUAL GPU 4782DRM DRIVER FOR VMWARE VIRTUAL GPU
4783M: "VMware Graphics" <linux-graphics-maintainer@vmware.com> 4783M: "VMware Graphics" <linux-graphics-maintainer@vmware.com>
4784M: Sinclair Yeh <syeh@vmware.com>
4785M: Thomas Hellstrom <thellstrom@vmware.com> 4784M: Thomas Hellstrom <thellstrom@vmware.com>
4786L: dri-devel@lists.freedesktop.org 4785L: dri-devel@lists.freedesktop.org
4787T: git git://people.freedesktop.org/~syeh/repos_linux
4788T: git git://people.freedesktop.org/~thomash/linux 4786T: git git://people.freedesktop.org/~thomash/linux
4789S: Supported 4787S: Supported
4790F: drivers/gpu/drm/vmwgfx/ 4788F: drivers/gpu/drm/vmwgfx/
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e490fe2687db..ce8d1d384319 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -37,7 +37,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
37 drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ 37 drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
38 drm_simple_kms_helper.o drm_modeset_helper.o \ 38 drm_simple_kms_helper.o drm_modeset_helper.o \
39 drm_scdc_helper.o drm_gem_framebuffer_helper.o \ 39 drm_scdc_helper.o drm_gem_framebuffer_helper.o \
40 drm_atomic_state_helper.o 40 drm_atomic_state_helper.o drm_damage_helper.o
41 41
42drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o 42drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
43drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o 43drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 9ac26437051b..48ec378fb27e 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -531,6 +531,8 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
531 struct drm_crtc *crtc = new_plane_state->crtc; 531 struct drm_crtc *crtc = new_plane_state->crtc;
532 const struct drm_framebuffer *fb = new_plane_state->fb; 532 const struct drm_framebuffer *fb = new_plane_state->fb;
533 unsigned int fb_width, fb_height; 533 unsigned int fb_width, fb_height;
534 struct drm_mode_rect *clips;
535 uint32_t num_clips;
534 int ret; 536 int ret;
535 537
536 /* either *both* CRTC and FB must be set, or neither */ 538 /* either *both* CRTC and FB must be set, or neither */
@@ -604,6 +606,26 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
604 return -ENOSPC; 606 return -ENOSPC;
605 } 607 }
606 608
609 clips = drm_plane_get_damage_clips(new_plane_state);
610 num_clips = drm_plane_get_damage_clips_count(new_plane_state);
611
612 /* Make sure damage clips are valid and inside the fb. */
613 while (num_clips > 0) {
614 if (clips->x1 >= clips->x2 ||
615 clips->y1 >= clips->y2 ||
616 clips->x1 < 0 ||
617 clips->y1 < 0 ||
618 clips->x2 > fb_width ||
619 clips->y2 > fb_height) {
620 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid damage clip %d %d %d %d\n",
621 plane->base.id, plane->name, clips->x1,
622 clips->y1, clips->x2, clips->y2);
623 return -EINVAL;
624 }
625 clips++;
626 num_clips--;
627 }
628
607 if (plane_switching_crtc(old_plane_state, new_plane_state)) { 629 if (plane_switching_crtc(old_plane_state, new_plane_state)) {
608 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n", 630 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
609 plane->base.id, plane->name); 631 plane->base.id, plane->name);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index bc9fc9665614..5ed12144ceb7 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -32,6 +32,7 @@
32#include <drm/drm_crtc_helper.h> 32#include <drm/drm_crtc_helper.h>
33#include <drm/drm_atomic_helper.h> 33#include <drm/drm_atomic_helper.h>
34#include <drm/drm_writeback.h> 34#include <drm/drm_writeback.h>
35#include <drm/drm_damage_helper.h>
35#include <linux/dma-fence.h> 36#include <linux/dma-fence.h>
36 37
37#include "drm_crtc_helper_internal.h" 38#include "drm_crtc_helper_internal.h"
@@ -862,6 +863,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
862 863
863 drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane); 864 drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane);
864 865
866 drm_atomic_helper_check_plane_damage(state, new_plane_state);
867
865 if (!funcs || !funcs->atomic_check) 868 if (!funcs || !funcs->atomic_check)
866 continue; 869 continue;
867 870
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 30a6d1edd5fe..c40889888a16 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -517,6 +517,8 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
517{ 517{
518 struct drm_device *dev = plane->dev; 518 struct drm_device *dev = plane->dev;
519 struct drm_mode_config *config = &dev->mode_config; 519 struct drm_mode_config *config = &dev->mode_config;
520 bool replaced = false;
521 int ret;
520 522
521 if (property == config->prop_fb_id) { 523 if (property == config->prop_fb_id) {
522 struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val); 524 struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val);
@@ -570,6 +572,14 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
570 state->color_encoding = val; 572 state->color_encoding = val;
571 } else if (property == plane->color_range_property) { 573 } else if (property == plane->color_range_property) {
572 state->color_range = val; 574 state->color_range = val;
575 } else if (property == config->prop_fb_damage_clips) {
576 ret = drm_atomic_replace_property_blob_from_id(dev,
577 &state->fb_damage_clips,
578 val,
579 -1,
580 sizeof(struct drm_rect),
581 &replaced);
582 return ret;
573 } else if (plane->funcs->atomic_set_property) { 583 } else if (plane->funcs->atomic_set_property) {
574 return plane->funcs->atomic_set_property(plane, state, 584 return plane->funcs->atomic_set_property(plane, state,
575 property, val); 585 property, val);
@@ -625,6 +635,9 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
625 *val = state->color_encoding; 635 *val = state->color_encoding;
626 } else if (property == plane->color_range_property) { 636 } else if (property == plane->color_range_property) {
627 *val = state->color_range; 637 *val = state->color_range;
638 } else if (property == config->prop_fb_damage_clips) {
639 *val = (state->fb_damage_clips) ?
640 state->fb_damage_clips->base.id : 0;
628 } else if (plane->funcs->atomic_get_property) { 641 } else if (plane->funcs->atomic_get_property) {
629 return plane->funcs->atomic_get_property(plane, state, property, val); 642 return plane->funcs->atomic_get_property(plane, state, property, val);
630 } else { 643 } else {
diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
new file mode 100644
index 000000000000..05c8e7267165
--- /dev/null
+++ b/drivers/gpu/drm/drm_damage_helper.c
@@ -0,0 +1,334 @@
1// SPDX-License-Identifier: GPL-2.0 OR MIT
2/**************************************************************************
3 *
4 * Copyright (c) 2018 VMware, Inc., Palo Alto, CA., USA
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Authors:
28 * Deepak Rawat <drawat@vmware.com>
29 * Rob Clark <robdclark@gmail.com>
30 *
31 **************************************************************************/
32
33#include <drm/drm_atomic.h>
34#include <drm/drm_damage_helper.h>
35
36/**
37 * DOC: overview
38 *
39 * FB_DAMAGE_CLIPS is an optional plane property which provides a means to
40 * specify a list of damage rectangles on a plane in framebuffer coordinates of
41 * the framebuffer attached to the plane. In current context damage is the area
42 * of plane framebuffer that has changed since last plane update (also called
43 * page-flip), irrespective of whether currently attached framebuffer is same as
44 * framebuffer attached during last plane update or not.
45 *
46 * FB_DAMAGE_CLIPS is a hint to kernel which could be helpful for some drivers
47 * to optimize internally especially for virtual devices where each framebuffer
48 * change needs to be transmitted over network, usb, etc.
49 *
50 * Since FB_DAMAGE_CLIPS is a hint so it is an optional property. User-space can
51 * ignore damage clips property and in that case driver will do a full plane
52 * update. In case damage clips are provided then it is guaranteed that the area
53 * inside damage clips will be updated to plane. For efficiency driver can do
54 * full update or can update more than specified in damage clips. Since driver
55 * is free to read more, user-space must always render the entire visible
56 * framebuffer. Otherwise there can be corruptions. Also, if a user-space
57 * provides damage clips which doesn't encompass the actual damage to
58 * framebuffer (since last plane update) can result in incorrect rendering.
59 *
60 * FB_DAMAGE_CLIPS is a blob property with the layout of blob data is simply an
61 * array of &drm_mode_rect. Unlike plane &drm_plane_state.src coordinates,
62 * damage clips are not in 16.16 fixed point. Similar to plane src in
63 * framebuffer, damage clips cannot be negative. In damage clip, x1/y1 are
64 * inclusive and x2/y2 are exclusive. While kernel does not error for overlapped
65 * damage clips, it is strongly discouraged.
66 *
67 * Drivers that are interested in damage interface for plane should enable
68 * FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips().
69 * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and
70 * drm_atomic_helper_damage_iter_next() helper iterator function to get damage
71 * rectangles clipped to &drm_plane_state.src.
72 */
73
74static void convert_clip_rect_to_rect(const struct drm_clip_rect *src,
75 struct drm_mode_rect *dest,
76 uint32_t num_clips, uint32_t src_inc)
77{
78 while (num_clips > 0) {
79 dest->x1 = src->x1;
80 dest->y1 = src->y1;
81 dest->x2 = src->x2;
82 dest->y2 = src->y2;
83 src += src_inc;
84 dest++;
85 num_clips--;
86 }
87}
88
89/**
90 * drm_plane_enable_fb_damage_clips - Enables plane fb damage clips property.
91 * @plane: Plane on which to enable damage clips property.
92 *
93 * This function lets driver to enable the damage clips property on a plane.
94 */
95void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)
96{
97 struct drm_device *dev = plane->dev;
98 struct drm_mode_config *config = &dev->mode_config;
99
100 drm_object_attach_property(&plane->base, config->prop_fb_damage_clips,
101 0);
102}
103EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips);
104
105/**
106 * drm_atomic_helper_check_plane_damage - Verify plane damage on atomic_check.
107 * @state: The driver state object.
108 * @plane_state: Plane state for which to verify damage.
109 *
110 * This helper function makes sure that damage from plane state is discarded
111 * for full modeset. If there are more reasons a driver would want to do a full
112 * plane update rather than processing individual damage regions, then those
113 * cases should be taken care of here.
114 *
115 * Note that &drm_plane_state.fb_damage_clips == NULL in plane state means that
116 * full plane update should happen. It also ensure helper iterator will return
117 * &drm_plane_state.src as damage.
118 */
119void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
120 struct drm_plane_state *plane_state)
121{
122 struct drm_crtc_state *crtc_state;
123
124 if (plane_state->crtc) {
125 crtc_state = drm_atomic_get_new_crtc_state(state,
126 plane_state->crtc);
127
128 if (WARN_ON(!crtc_state))
129 return;
130
131 if (drm_atomic_crtc_needs_modeset(crtc_state)) {
132 drm_property_blob_put(plane_state->fb_damage_clips);
133 plane_state->fb_damage_clips = NULL;
134 }
135 }
136}
137EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
138
139/**
140 * drm_atomic_helper_dirtyfb - Helper for dirtyfb.
141 * @fb: DRM framebuffer.
142 * @file_priv: Drm file for the ioctl call.
143 * @flags: Dirty fb annotate flags.
144 * @color: Color for annotate fill.
145 * @clips: Dirty region.
146 * @num_clips: Count of clip in clips.
147 *
148 * A helper to implement &drm_framebuffer_funcs.dirty using damage interface
149 * during plane update. If num_clips is 0 then this helper will do a full plane
150 * update. This is the same behaviour expected by DIRTFB IOCTL.
151 *
152 * Note that this helper is blocking implementation. This is what current
153 * drivers and userspace expect in their DIRTYFB IOCTL implementation, as a way
154 * to rate-limit userspace and make sure its rendering doesn't get ahead of
155 * uploading new data too much.
156 *
157 * Return: Zero on success, negative errno on failure.
158 */
159int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
160 struct drm_file *file_priv, unsigned int flags,
161 unsigned int color, struct drm_clip_rect *clips,
162 unsigned int num_clips)
163{
164 struct drm_modeset_acquire_ctx ctx;
165 struct drm_property_blob *damage = NULL;
166 struct drm_mode_rect *rects = NULL;
167 struct drm_atomic_state *state;
168 struct drm_plane *plane;
169 int ret = 0;
170
171 /*
172 * When called from ioctl, we are interruptable, but not when called
173 * internally (ie. defio worker)
174 */
175 drm_modeset_acquire_init(&ctx,
176 file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0);
177
178 state = drm_atomic_state_alloc(fb->dev);
179 if (!state) {
180 ret = -ENOMEM;
181 goto out;
182 }
183 state->acquire_ctx = &ctx;
184
185 if (clips) {
186 uint32_t inc = 1;
187
188 if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
189 inc = 2;
190 num_clips /= 2;
191 }
192
193 rects = kcalloc(num_clips, sizeof(*rects), GFP_KERNEL);
194 if (!rects) {
195 ret = -ENOMEM;
196 goto out;
197 }
198
199 convert_clip_rect_to_rect(clips, rects, num_clips, inc);
200 damage = drm_property_create_blob(fb->dev,
201 num_clips * sizeof(*rects),
202 rects);
203 if (IS_ERR(damage)) {
204 ret = PTR_ERR(damage);
205 damage = NULL;
206 goto out;
207 }
208 }
209
210retry:
211 drm_for_each_plane(plane, fb->dev) {
212 struct drm_plane_state *plane_state;
213
214 if (plane->state->fb != fb)
215 continue;
216
217 plane_state = drm_atomic_get_plane_state(state, plane);
218 if (IS_ERR(plane_state)) {
219 ret = PTR_ERR(plane_state);
220 goto out;
221 }
222
223 drm_property_replace_blob(&plane_state->fb_damage_clips,
224 damage);
225 }
226
227 ret = drm_atomic_commit(state);
228
229out:
230 if (ret == -EDEADLK) {
231 drm_atomic_state_clear(state);
232 ret = drm_modeset_backoff(&ctx);
233 if (!ret)
234 goto retry;
235 }
236
237 drm_property_blob_put(damage);
238 kfree(rects);
239 drm_atomic_state_put(state);
240
241 drm_modeset_drop_locks(&ctx);
242 drm_modeset_acquire_fini(&ctx);
243
244 return ret;
245
246}
247EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
248
249/**
250 * drm_atomic_helper_damage_iter_init - Initialize the damage iterator.
251 * @iter: The iterator to initialize.
252 * @old_state: Old plane state for validation.
253 * @new_state: Plane state from which to iterate the damage clips.
254 *
255 * Initialize an iterator, which clips plane damage
256 * &drm_plane_state.fb_damage_clips to plane &drm_plane_state.src. This iterator
257 * returns full plane src in case damage is not present because either
258 * user-space didn't sent or driver discarded it (it want to do full plane
259 * update). Currently this iterator returns full plane src in case plane src
260 * changed but that can be changed in future to return damage.
261 *
262 * For the case when plane is not visible or plane update should not happen the
263 * first call to iter_next will return false. Note that this helper use clipped
264 * &drm_plane_state.src, so driver calling this helper should have called
265 * drm_atomic_helper_check_plane_state() earlier.
266 */
267void
268drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
269 const struct drm_plane_state *old_state,
270 const struct drm_plane_state *state)
271{
272 memset(iter, 0, sizeof(*iter));
273
274 if (!state || !state->crtc || !state->fb || !state->visible)
275 return;
276
277 iter->clips = drm_helper_get_plane_damage_clips(state);
278 iter->num_clips = drm_plane_get_damage_clips_count(state);
279
280 /* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
281 iter->plane_src.x1 = state->src.x1 >> 16;
282 iter->plane_src.y1 = state->src.y1 >> 16;
283 iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
284 iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
285
286 if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
287 iter->clips = 0;
288 iter->num_clips = 0;
289 iter->full_update = true;
290 }
291}
292EXPORT_SYMBOL(drm_atomic_helper_damage_iter_init);
293
294/**
295 * drm_atomic_helper_damage_iter_next - Advance the damage iterator.
296 * @iter: The iterator to advance.
297 * @rect: Return a rectangle in fb coordinate clipped to plane src.
298 *
299 * Since plane src is in 16.16 fixed point and damage clips are whole number,
300 * this iterator round off clips that intersect with plane src. Round down for
301 * x1/y1 and round up for x2/y2 for the intersected coordinate. Similar rounding
302 * off for full plane src, in case it's returned as damage. This iterator will
303 * skip damage clips outside of plane src.
304 *
305 * Return: True if the output is valid, false if reached the end.
306 *
307 * If the first call to iterator next returns false then it means no need to
308 * update the plane.
309 */
310bool
311drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
312 struct drm_rect *rect)
313{
314 bool ret = false;
315
316 if (iter->full_update) {
317 *rect = iter->plane_src;
318 iter->full_update = false;
319 return true;
320 }
321
322 while (iter->curr_clip < iter->num_clips) {
323 *rect = iter->clips[iter->curr_clip];
324 iter->curr_clip++;
325
326 if (drm_rect_intersect(rect, &iter->plane_src)) {
327 ret = true;
328 break;
329 }
330 }
331
332 return ret;
333}
334EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 5670c67f28d4..703bfce975bb 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -297,6 +297,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
297 return -ENOMEM; 297 return -ENOMEM;
298 dev->mode_config.prop_crtc_id = prop; 298 dev->mode_config.prop_crtc_id = prop;
299 299
300 prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "FB_DAMAGE_CLIPS",
301 0);
302 if (!prop)
303 return -ENOMEM;
304 dev->mode_config.prop_fb_damage_clips = prop;
305
300 prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, 306 prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
301 "ACTIVE"); 307 "ACTIVE");
302 if (!prop) 308 if (!prop)
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 383d8d6c5847..1bb73dc4c88c 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,4 +1,5 @@
1test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \ 1test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \
2 test-drm_format.o test-drm_framebuffer.o 2 test-drm_format.o test-drm_framebuffer.o \
3 test-drm_damage_helper.o
3 4
4obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o 5obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 92601defd8f6..464753746013 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -11,3 +11,24 @@ selftest(check_drm_format_block_width, igt_check_drm_format_block_width)
11selftest(check_drm_format_block_height, igt_check_drm_format_block_height) 11selftest(check_drm_format_block_height, igt_check_drm_format_block_height)
12selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch) 12selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch)
13selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create) 13selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create)
14selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
15selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
16selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved)
17selftest(damage_iter_no_damage_fractional_src_moved, igt_damage_iter_no_damage_fractional_src_moved)
18selftest(damage_iter_no_damage_not_visible, igt_damage_iter_no_damage_not_visible)
19selftest(damage_iter_no_damage_no_crtc, igt_damage_iter_no_damage_no_crtc)
20selftest(damage_iter_no_damage_no_fb, igt_damage_iter_no_damage_no_fb)
21selftest(damage_iter_simple_damage, igt_damage_iter_simple_damage)
22selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
23selftest(damage_iter_single_damage_intersect_src, igt_damage_iter_single_damage_intersect_src)
24selftest(damage_iter_single_damage_outside_src, igt_damage_iter_single_damage_outside_src)
25selftest(damage_iter_single_damage_fractional_src, igt_damage_iter_single_damage_fractional_src)
26selftest(damage_iter_single_damage_intersect_fractional_src, igt_damage_iter_single_damage_intersect_fractional_src)
27selftest(damage_iter_single_damage_outside_fractional_src, igt_damage_iter_single_damage_outside_fractional_src)
28selftest(damage_iter_single_damage_src_moved, igt_damage_iter_single_damage_src_moved)
29selftest(damage_iter_single_damage_fractional_src_moved, igt_damage_iter_single_damage_fractional_src_moved)
30selftest(damage_iter_damage, igt_damage_iter_damage)
31selftest(damage_iter_damage_one_intersect, igt_damage_iter_damage_one_intersect)
32selftest(damage_iter_damage_one_outside, igt_damage_iter_damage_one_outside)
33selftest(damage_iter_damage_src_moved, igt_damage_iter_damage_src_moved)
34selftest(damage_iter_damage_not_visible, igt_damage_iter_damage_not_visible)
diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
new file mode 100644
index 000000000000..a2f753205a3e
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
@@ -0,0 +1,811 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Test case for drm_damage_helper functions
4 */
5
6#define pr_fmt(fmt) "drm_damage_helper: " fmt
7
8#include <drm/drm_damage_helper.h>
9
10#include "test-drm_modeset_common.h"
11
12static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
13 int y2)
14{
15 state->src.x1 = x1;
16 state->src.y1 = y1;
17 state->src.x2 = x2;
18 state->src.y2 = y2;
19}
20
21static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2,
22 int y2)
23{
24 r->x1 = x1;
25 r->y1 = y1;
26 r->x2 = x2;
27 r->y2 = y2;
28}
29
30static void set_damage_blob(struct drm_property_blob *damage_blob,
31 struct drm_mode_rect *r, uint32_t size)
32{
33 damage_blob->length = size;
34 damage_blob->data = r;
35}
36
37static void set_plane_damage(struct drm_plane_state *state,
38 struct drm_property_blob *damage_blob)
39{
40 state->fb_damage_clips = damage_blob;
41}
42
43static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
44 int x1, int y1, int x2, int y2)
45{
46 /*
47 * Round down x1/y1 and round up x2/y2. This is because damage is not in
48 * 16.16 fixed point so to catch all pixels.
49 */
50 int src_x1 = state->src.x1 >> 16;
51 int src_y1 = state->src.y1 >> 16;
52 int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
53 int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
54
55 if (x1 >= x2 || y1 >= y2) {
56 pr_err("Cannot have damage clip with no dimention.\n");
57 return false;
58 }
59
60 if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
61 pr_err("Damage cannot be outside rounded plane src.\n");
62 return false;
63 }
64
65 if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
66 pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2);
67 return false;
68 }
69
70 return true;
71}
72
73int igt_damage_iter_no_damage(void *ignored)
74{
75 struct drm_atomic_helper_damage_iter iter;
76 struct drm_plane_state old_state;
77 struct drm_rect clip;
78 uint32_t num_hits = 0;
79
80 struct drm_framebuffer fb = {
81 .width = 2048,
82 .height = 2048
83 };
84
85 struct drm_plane_state state = {
86 .crtc = ZERO_SIZE_PTR,
87 .fb = &fb,
88 .visible = true,
89 };
90
91 /* Plane src same as fb size. */
92 set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
93 set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
94 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
95 drm_atomic_for_each_plane_damage(&iter, &clip)
96 num_hits++;
97
98 FAIL(num_hits != 1, "Should return plane src as damage.");
99 FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
100
101 return 0;
102}
103
104int igt_damage_iter_no_damage_fractional_src(void *ignored)
105{
106 struct drm_atomic_helper_damage_iter iter;
107 struct drm_plane_state old_state;
108 struct drm_rect clip;
109 uint32_t num_hits = 0;
110
111 struct drm_framebuffer fb = {
112 .width = 2048,
113 .height = 2048
114 };
115
116 struct drm_plane_state state = {
117 .crtc = ZERO_SIZE_PTR,
118 .fb = &fb,
119 .visible = true,
120 };
121
122 /* Plane src has fractional part. */
123 set_plane_src(&old_state, 0x3fffe, 0x3fffe,
124 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
125 set_plane_src(&state, 0x3fffe, 0x3fffe,
126 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
127 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
128 drm_atomic_for_each_plane_damage(&iter, &clip)
129 num_hits++;
130
131 FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
132 FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
133
134 return 0;
135}
136
137int igt_damage_iter_no_damage_src_moved(void *ignored)
138{
139 struct drm_atomic_helper_damage_iter iter;
140 struct drm_plane_state old_state;
141 struct drm_rect clip;
142 uint32_t num_hits = 0;
143
144 struct drm_framebuffer fb = {
145 .width = 2048,
146 .height = 2048
147 };
148
149 struct drm_plane_state state = {
150 .crtc = ZERO_SIZE_PTR,
151 .fb = &fb,
152 .visible = true,
153 };
154
155 /* Plane src moved since old plane state. */
156 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
157 set_plane_src(&state, 10 << 16, 10 << 16,
158 (10 + 1024) << 16, (10 + 768) << 16);
159 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
160 drm_atomic_for_each_plane_damage(&iter, &clip)
161 num_hits++;
162
163 FAIL(num_hits != 1, "Should return plane src as damage.");
164 FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
165
166 return 0;
167}
168
169int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
170{
171 struct drm_atomic_helper_damage_iter iter;
172 struct drm_plane_state old_state;
173 struct drm_rect clip;
174 uint32_t num_hits = 0;
175
176 struct drm_framebuffer fb = {
177 .width = 2048,
178 .height = 2048
179 };
180
181 struct drm_plane_state state = {
182 .crtc = ZERO_SIZE_PTR,
183 .fb = &fb,
184 .visible = true,
185 };
186
187 /* Plane src has fractional part and it moved since old plane state. */
188 set_plane_src(&old_state, 0x3fffe, 0x3fffe,
189 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
190 set_plane_src(&state, 0x40002, 0x40002,
191 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
192 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
193 drm_atomic_for_each_plane_damage(&iter, &clip)
194 num_hits++;
195
196 FAIL(num_hits != 1, "Should return plane src as damage.");
197 FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
198
199 return 0;
200}
201
202int igt_damage_iter_no_damage_not_visible(void *ignored)
203{
204 struct drm_atomic_helper_damage_iter iter;
205 struct drm_plane_state old_state;
206 struct drm_rect clip;
207 uint32_t num_hits = 0;
208
209 struct drm_framebuffer fb = {
210 .width = 2048,
211 .height = 2048
212 };
213
214 struct drm_plane_state state = {
215 .crtc = ZERO_SIZE_PTR,
216 .fb = &fb,
217 .visible = false,
218 };
219
220 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
221 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
222 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
223 drm_atomic_for_each_plane_damage(&iter, &clip)
224 num_hits++;
225
226 FAIL(num_hits != 0, "Should have no damage.");
227
228 return 0;
229}
230
231int igt_damage_iter_no_damage_no_crtc(void *ignored)
232{
233 struct drm_atomic_helper_damage_iter iter;
234 struct drm_plane_state old_state;
235 struct drm_rect clip;
236 uint32_t num_hits = 0;
237
238 struct drm_framebuffer fb = {
239 .width = 2048,
240 .height = 2048
241 };
242
243 struct drm_plane_state state = {
244 .crtc = 0,
245 .fb = &fb,
246 };
247
248 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
249 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
250 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
251 drm_atomic_for_each_plane_damage(&iter, &clip)
252 num_hits++;
253
254 FAIL(num_hits != 0, "Should have no damage.");
255
256 return 0;
257}
258
259int igt_damage_iter_no_damage_no_fb(void *ignored)
260{
261 struct drm_atomic_helper_damage_iter iter;
262 struct drm_plane_state old_state;
263 struct drm_rect clip;
264 uint32_t num_hits = 0;
265
266 struct drm_plane_state state = {
267 .crtc = ZERO_SIZE_PTR,
268 .fb = 0,
269 };
270
271 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
272 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
273 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
274 drm_atomic_for_each_plane_damage(&iter, &clip)
275 num_hits++;
276
277 FAIL(num_hits != 0, "Should have no damage.");
278
279 return 0;
280}
281
282int igt_damage_iter_simple_damage(void *ignored)
283{
284 struct drm_atomic_helper_damage_iter iter;
285 struct drm_plane_state old_state;
286 struct drm_property_blob damage_blob;
287 struct drm_mode_rect damage;
288 struct drm_rect clip;
289 uint32_t num_hits = 0;
290
291 struct drm_framebuffer fb = {
292 .width = 2048,
293 .height = 2048
294 };
295
296 struct drm_plane_state state = {
297 .crtc = ZERO_SIZE_PTR,
298 .fb = &fb,
299 .visible = true,
300 };
301
302 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
303 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
304 /* Damage set to plane src */
305 set_damage_clip(&damage, 0, 0, 1024, 768);
306 set_damage_blob(&damage_blob, &damage, sizeof(damage));
307 set_plane_damage(&state, &damage_blob);
308 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
309 drm_atomic_for_each_plane_damage(&iter, &clip)
310 num_hits++;
311
312 FAIL(num_hits != 1, "Should return damage when set.");
313 FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
314
315 return 0;
316}
317
318int igt_damage_iter_single_damage(void *ignored)
319{
320 struct drm_atomic_helper_damage_iter iter;
321 struct drm_plane_state old_state;
322 struct drm_property_blob damage_blob;
323 struct drm_mode_rect damage;
324 struct drm_rect clip;
325 uint32_t num_hits = 0;
326
327 struct drm_framebuffer fb = {
328 .width = 2048,
329 .height = 2048
330 };
331
332 struct drm_plane_state state = {
333 .crtc = ZERO_SIZE_PTR,
334 .fb = &fb,
335 .visible = true,
336 };
337
338 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
339 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
340 set_damage_clip(&damage, 256, 192, 768, 576);
341 set_damage_blob(&damage_blob, &damage, sizeof(damage));
342 set_plane_damage(&state, &damage_blob);
343 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
344 drm_atomic_for_each_plane_damage(&iter, &clip)
345 num_hits++;
346
347 FAIL(num_hits != 1, "Should return damage when set.");
348 FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
349
350 return 0;
351}
352
353int igt_damage_iter_single_damage_intersect_src(void *ignored)
354{
355 struct drm_atomic_helper_damage_iter iter;
356 struct drm_plane_state old_state;
357 struct drm_property_blob damage_blob;
358 struct drm_mode_rect damage;
359 struct drm_rect clip;
360 uint32_t num_hits = 0;
361
362 struct drm_framebuffer fb = {
363 .width = 2048,
364 .height = 2048
365 };
366
367 struct drm_plane_state state = {
368 .crtc = ZERO_SIZE_PTR,
369 .fb = &fb,
370 .visible = true,
371 };
372
373 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
374 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
375 /* Damage intersect with plane src. */
376 set_damage_clip(&damage, 256, 192, 1360, 768);
377 set_damage_blob(&damage_blob, &damage, sizeof(damage));
378 set_plane_damage(&state, &damage_blob);
379 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
380 drm_atomic_for_each_plane_damage(&iter, &clip)
381 num_hits++;
382
383 FAIL(num_hits != 1, "Should return damage clipped to src.");
384 FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
385
386 return 0;
387}
388
389int igt_damage_iter_single_damage_outside_src(void *ignored)
390{
391 struct drm_atomic_helper_damage_iter iter;
392 struct drm_plane_state old_state;
393 struct drm_property_blob damage_blob;
394 struct drm_mode_rect damage;
395 struct drm_rect clip;
396 uint32_t num_hits = 0;
397
398 struct drm_framebuffer fb = {
399 .width = 2048,
400 .height = 2048
401 };
402
403 struct drm_plane_state state = {
404 .crtc = ZERO_SIZE_PTR,
405 .fb = &fb,
406 .visible = true,
407 };
408
409 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
410 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
411 /* Damage clip outside plane src */
412 set_damage_clip(&damage, 1360, 1360, 1380, 1380);
413 set_damage_blob(&damage_blob, &damage, sizeof(damage));
414 set_plane_damage(&state, &damage_blob);
415 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
416 drm_atomic_for_each_plane_damage(&iter, &clip)
417 num_hits++;
418
419 FAIL(num_hits != 0, "Should have no damage.");
420
421 return 0;
422}
423
424int igt_damage_iter_single_damage_fractional_src(void *ignored)
425{
426 struct drm_atomic_helper_damage_iter iter;
427 struct drm_plane_state old_state;
428 struct drm_property_blob damage_blob;
429 struct drm_mode_rect damage;
430 struct drm_rect clip;
431 uint32_t num_hits = 0;
432
433 struct drm_framebuffer fb = {
434 .width = 2048,
435 .height = 2048
436 };
437
438 struct drm_plane_state state = {
439 .crtc = ZERO_SIZE_PTR,
440 .fb = &fb,
441 .visible = true,
442 };
443
444 /* Plane src has fractional part. */
445 set_plane_src(&old_state, 0x40002, 0x40002,
446 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
447 set_plane_src(&state, 0x40002, 0x40002,
448 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
449 set_damage_clip(&damage, 10, 10, 256, 330);
450 set_damage_blob(&damage_blob, &damage, sizeof(damage));
451 set_plane_damage(&state, &damage_blob);
452 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
453 drm_atomic_for_each_plane_damage(&iter, &clip)
454 num_hits++;
455
456 FAIL(num_hits != 1, "Should return damage when set.");
457 FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
458
459 return 0;
460}
461
462int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
463{
464 struct drm_atomic_helper_damage_iter iter;
465 struct drm_plane_state old_state;
466 struct drm_property_blob damage_blob;
467 struct drm_mode_rect damage;
468 struct drm_rect clip;
469 uint32_t num_hits = 0;
470
471 struct drm_framebuffer fb = {
472 .width = 2048,
473 .height = 2048
474 };
475
476 struct drm_plane_state state = {
477 .crtc = ZERO_SIZE_PTR,
478 .fb = &fb,
479 .visible = true,
480 };
481
482 /* Plane src has fractional part. */
483 set_plane_src(&old_state, 0x40002, 0x40002,
484 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
485 set_plane_src(&state, 0x40002, 0x40002,
486 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
487 /* Damage intersect with plane src. */
488 set_damage_clip(&damage, 10, 1, 1360, 330);
489 set_damage_blob(&damage_blob, &damage, sizeof(damage));
490 set_plane_damage(&state, &damage_blob);
491 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
492 drm_atomic_for_each_plane_damage(&iter, &clip)
493 num_hits++;
494
495 FAIL(num_hits != 1, "Should return damage clipped to rounded off src.");
496 FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
497
498 return 0;
499}
500
501int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
502{
503 struct drm_atomic_helper_damage_iter iter;
504 struct drm_plane_state old_state;
505 struct drm_property_blob damage_blob;
506 struct drm_mode_rect damage;
507 struct drm_rect clip;
508 uint32_t num_hits = 0;
509
510 struct drm_framebuffer fb = {
511 .width = 2048,
512 .height = 2048
513 };
514
515 struct drm_plane_state state = {
516 .crtc = ZERO_SIZE_PTR,
517 .fb = &fb,
518 .visible = true,
519 };
520
521 /* Plane src has fractional part. */
522 set_plane_src(&old_state, 0x40002, 0x40002,
523 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
524 set_plane_src(&state, 0x40002, 0x40002,
525 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
526 /* Damage clip outside plane src */
527 set_damage_clip(&damage, 1360, 1360, 1380, 1380);
528 set_damage_blob(&damage_blob, &damage, sizeof(damage));
529 set_plane_damage(&state, &damage_blob);
530 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
531 drm_atomic_for_each_plane_damage(&iter, &clip)
532 num_hits++;
533
534 FAIL(num_hits != 0, "Should have no damage.");
535
536 return 0;
537}
538
539int igt_damage_iter_single_damage_src_moved(void *ignored)
540{
541 struct drm_atomic_helper_damage_iter iter;
542 struct drm_plane_state old_state;
543 struct drm_property_blob damage_blob;
544 struct drm_mode_rect damage;
545 struct drm_rect clip;
546 uint32_t num_hits = 0;
547
548 struct drm_framebuffer fb = {
549 .width = 2048,
550 .height = 2048
551 };
552
553 struct drm_plane_state state = {
554 .crtc = ZERO_SIZE_PTR,
555 .fb = &fb,
556 .visible = true,
557 };
558
559 /* Plane src moved since old plane state. */
560 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
561 set_plane_src(&state, 10 << 16, 10 << 16,
562 (10 + 1024) << 16, (10 + 768) << 16);
563 set_damage_clip(&damage, 20, 30, 256, 256);
564 set_damage_blob(&damage_blob, &damage, sizeof(damage));
565 set_plane_damage(&state, &damage_blob);
566 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
567 drm_atomic_for_each_plane_damage(&iter, &clip)
568 num_hits++;
569
570 FAIL(num_hits != 1, "Should return plane src as damage.");
571 FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
572
573 return 0;
574}
575
576int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
577{
578 struct drm_atomic_helper_damage_iter iter;
579 struct drm_plane_state old_state;
580 struct drm_property_blob damage_blob;
581 struct drm_mode_rect damage;
582 struct drm_rect clip;
583 uint32_t num_hits = 0;
584
585 struct drm_framebuffer fb = {
586 .width = 2048,
587 .height = 2048
588 };
589
590 struct drm_plane_state state = {
591 .crtc = ZERO_SIZE_PTR,
592 .fb = &fb,
593 .visible = true,
594 };
595
596 /* Plane src with fractional part moved since old plane state. */
597 set_plane_src(&old_state, 0x3fffe, 0x3fffe,
598 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
599 set_plane_src(&state, 0x40002, 0x40002,
600 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
601 /* Damage intersect with plane src. */
602 set_damage_clip(&damage, 20, 30, 1360, 256);
603 set_damage_blob(&damage_blob, &damage, sizeof(damage));
604 set_plane_damage(&state, &damage_blob);
605 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
606 drm_atomic_for_each_plane_damage(&iter, &clip)
607 num_hits++;
608
609 FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
610 FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
611
612 return 0;
613}
614
615int igt_damage_iter_damage(void *ignored)
616{
617 struct drm_atomic_helper_damage_iter iter;
618 struct drm_plane_state old_state;
619 struct drm_property_blob damage_blob;
620 struct drm_mode_rect damage[2];
621 struct drm_rect clip;
622 uint32_t num_hits = 0;
623
624 struct drm_framebuffer fb = {
625 .width = 2048,
626 .height = 2048
627 };
628
629 struct drm_plane_state state = {
630 .crtc = ZERO_SIZE_PTR,
631 .fb = &fb,
632 .visible = true,
633 };
634
635 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
636 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
637 /* 2 damage clips. */
638 set_damage_clip(&damage[0], 20, 30, 200, 180);
639 set_damage_clip(&damage[1], 240, 200, 280, 250);
640 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
641 set_plane_damage(&state, &damage_blob);
642 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
643 drm_atomic_for_each_plane_damage(&iter, &clip) {
644 if (num_hits == 0)
645 FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
646 if (num_hits == 1)
647 FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
648 num_hits++;
649 }
650
651 FAIL(num_hits != 2, "Should return damage when set.");
652
653 return 0;
654}
655
656int igt_damage_iter_damage_one_intersect(void *ignored)
657{
658 struct drm_atomic_helper_damage_iter iter;
659 struct drm_plane_state old_state;
660 struct drm_property_blob damage_blob;
661 struct drm_mode_rect damage[2];
662 struct drm_rect clip;
663 uint32_t num_hits = 0;
664
665 struct drm_framebuffer fb = {
666 .width = 2048,
667 .height = 2048
668 };
669
670 struct drm_plane_state state = {
671 .crtc = ZERO_SIZE_PTR,
672 .fb = &fb,
673 .visible = true,
674 };
675
676 set_plane_src(&old_state, 0x40002, 0x40002,
677 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
678 set_plane_src(&state, 0x40002, 0x40002,
679 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
680 /* 2 damage clips, one intersect plane src. */
681 set_damage_clip(&damage[0], 20, 30, 200, 180);
682 set_damage_clip(&damage[1], 2, 2, 1360, 1360);
683 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
684 set_plane_damage(&state, &damage_blob);
685 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
686 drm_atomic_for_each_plane_damage(&iter, &clip) {
687 if (num_hits == 0)
688 FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
689 if (num_hits == 1)
690 FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
691 num_hits++;
692 }
693
694 FAIL(num_hits != 2, "Should return damage when set.");
695
696 return 0;
697}
698
699int igt_damage_iter_damage_one_outside(void *ignored)
700{
701 struct drm_atomic_helper_damage_iter iter;
702 struct drm_plane_state old_state;
703 struct drm_property_blob damage_blob;
704 struct drm_mode_rect damage[2];
705 struct drm_rect clip;
706 uint32_t num_hits = 0;
707
708 struct drm_framebuffer fb = {
709 .width = 2048,
710 .height = 2048
711 };
712
713 struct drm_plane_state state = {
714 .crtc = ZERO_SIZE_PTR,
715 .fb = &fb,
716 .visible = true,
717 };
718
719 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
720 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
721 /* 2 damage clips, one outside plane src. */
722 set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
723 set_damage_clip(&damage[1], 240, 200, 280, 250);
724 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
725 set_plane_damage(&state, &damage_blob);
726 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
727 drm_atomic_for_each_plane_damage(&iter, &clip)
728 num_hits++;
729
730 FAIL(num_hits != 1, "Should return damage when set.");
731 FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
732
733 return 0;
734}
735
736int igt_damage_iter_damage_src_moved(void *ignored)
737{
738 struct drm_atomic_helper_damage_iter iter;
739 struct drm_plane_state old_state;
740 struct drm_property_blob damage_blob;
741 struct drm_mode_rect damage[2];
742 struct drm_rect clip;
743 uint32_t num_hits = 0;
744
745 struct drm_framebuffer fb = {
746 .width = 2048,
747 .height = 2048
748 };
749
750 struct drm_plane_state state = {
751 .crtc = ZERO_SIZE_PTR,
752 .fb = &fb,
753 .visible = true,
754 };
755
756 set_plane_src(&old_state, 0x40002, 0x40002,
757 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
758 set_plane_src(&state, 0x3fffe, 0x3fffe,
759 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
760 /* 2 damage clips, one outside plane src. */
761 set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
762 set_damage_clip(&damage[1], 240, 200, 280, 250);
763 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
764 set_plane_damage(&state, &damage_blob);
765 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
766 drm_atomic_for_each_plane_damage(&iter, &clip)
767 num_hits++;
768
769 FAIL(num_hits != 1, "Should return round off plane src as damage.");
770 FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
771
772 return 0;
773}
774
775int igt_damage_iter_damage_not_visible(void *ignored)
776{
777 struct drm_atomic_helper_damage_iter iter;
778 struct drm_plane_state old_state;
779 struct drm_property_blob damage_blob;
780 struct drm_mode_rect damage[2];
781 struct drm_rect clip;
782 uint32_t num_hits = 0;
783
784 struct drm_framebuffer fb = {
785 .width = 2048,
786 .height = 2048
787 };
788
789 struct drm_plane_state state = {
790 .crtc = ZERO_SIZE_PTR,
791 .fb = &fb,
792 .visible = false,
793 };
794
795 set_plane_src(&old_state, 0x40002, 0x40002,
796 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
797 set_plane_src(&state, 0x3fffe, 0x3fffe,
798 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
799 /* 2 damage clips, one outside plane src. */
800 set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
801 set_damage_clip(&damage[1], 240, 200, 280, 250);
802 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
803 set_plane_damage(&state, &damage_blob);
804 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
805 drm_atomic_for_each_plane_damage(&iter, &clip)
806 num_hits++;
807
808 FAIL(num_hits != 0, "Should not return any damage.");
809
810 return 0;
811}
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index d5df5bd51b05..8c76f09c12d1 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -18,5 +18,26 @@ int igt_check_drm_format_block_width(void *ignored);
18int igt_check_drm_format_block_height(void *ignored); 18int igt_check_drm_format_block_height(void *ignored);
19int igt_check_drm_format_min_pitch(void *ignored); 19int igt_check_drm_format_min_pitch(void *ignored);
20int igt_check_drm_framebuffer_create(void *ignored); 20int igt_check_drm_framebuffer_create(void *ignored);
21int igt_damage_iter_no_damage(void *ignored);
22int igt_damage_iter_no_damage_fractional_src(void *ignored);
23int igt_damage_iter_no_damage_src_moved(void *ignored);
24int igt_damage_iter_no_damage_fractional_src_moved(void *ignored);
25int igt_damage_iter_no_damage_not_visible(void *ignored);
26int igt_damage_iter_no_damage_no_crtc(void *ignored);
27int igt_damage_iter_no_damage_no_fb(void *ignored);
28int igt_damage_iter_simple_damage(void *ignored);
29int igt_damage_iter_single_damage(void *ignored);
30int igt_damage_iter_single_damage_intersect_src(void *ignored);
31int igt_damage_iter_single_damage_outside_src(void *ignored);
32int igt_damage_iter_single_damage_fractional_src(void *ignored);
33int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored);
34int igt_damage_iter_single_damage_outside_fractional_src(void *ignored);
35int igt_damage_iter_single_damage_src_moved(void *ignored);
36int igt_damage_iter_single_damage_fractional_src_moved(void *ignored);
37int igt_damage_iter_damage(void *ignored);
38int igt_damage_iter_damage_one_intersect(void *ignored);
39int igt_damage_iter_damage_one_outside(void *ignored);
40int igt_damage_iter_damage_src_moved(void *ignored);
41int igt_damage_iter_damage_not_visible(void *ignored);
21 42
22#endif 43#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index b9c078860a7c..9fd8b4e75a8c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -665,7 +665,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
665 mutex_init(&dev_priv->cmdbuf_mutex); 665 mutex_init(&dev_priv->cmdbuf_mutex);
666 mutex_init(&dev_priv->release_mutex); 666 mutex_init(&dev_priv->release_mutex);
667 mutex_init(&dev_priv->binding_mutex); 667 mutex_init(&dev_priv->binding_mutex);
668 mutex_init(&dev_priv->requested_layout_mutex);
669 mutex_init(&dev_priv->global_kms_state_mutex); 668 mutex_init(&dev_priv->global_kms_state_mutex);
670 ttm_lock_init(&dev_priv->reservation_sem); 669 ttm_lock_init(&dev_priv->reservation_sem);
671 spin_lock_init(&dev_priv->resource_lock); 670 spin_lock_init(&dev_priv->resource_lock);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 28df788da44e..d7f6cb9331de 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -466,15 +466,6 @@ struct vmw_private {
466 uint32_t num_displays; 466 uint32_t num_displays;
467 467
468 /* 468 /*
469 * Currently requested_layout_mutex is used to protect the gui
470 * positionig state in display unit. With that use case currently this
471 * mutex is only taken during layout ioctl and atomic check_modeset.
472 * Other display unit state can be protected with this mutex but that
473 * needs careful consideration.
474 */
475 struct mutex requested_layout_mutex;
476
477 /*
478 * Framebuffer info. 469 * Framebuffer info.
479 */ 470 */
480 471
@@ -484,8 +475,6 @@ struct vmw_private {
484 struct vmw_overlay *overlay_priv; 475 struct vmw_overlay *overlay_priv;
485 struct drm_property *hotplug_mode_update_property; 476 struct drm_property *hotplug_mode_update_property;
486 struct drm_property *implicit_placement_property; 477 struct drm_property *implicit_placement_property;
487 unsigned num_implicit;
488 struct vmw_framebuffer *implicit_fb;
489 struct mutex global_kms_state_mutex; 478 struct mutex global_kms_state_mutex;
490 spinlock_t cursor_lock; 479 spinlock_t cursor_lock;
491 struct drm_atomic_state *suspend_state; 480 struct drm_atomic_state *suspend_state;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 5a6b70ba137a..260650bb5560 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -1738,7 +1738,6 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,
1738 void *buf) 1738 void *buf)
1739{ 1739{
1740 struct vmw_buffer_object *vmw_bo; 1740 struct vmw_buffer_object *vmw_bo;
1741 int ret;
1742 1741
1743 struct { 1742 struct {
1744 uint32_t header; 1743 uint32_t header;
@@ -1748,7 +1747,6 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,
1748 return vmw_translate_guest_ptr(dev_priv, sw_context, 1747 return vmw_translate_guest_ptr(dev_priv, sw_context,
1749 &cmd->body.ptr, 1748 &cmd->body.ptr,
1750 &vmw_bo); 1749 &vmw_bo);
1751 return ret;
1752} 1750}
1753 1751
1754 1752
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index f87261545f2c..301260e23e52 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -906,13 +906,10 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
906 container_of(action, struct vmw_event_fence_action, action); 906 container_of(action, struct vmw_event_fence_action, action);
907 struct drm_device *dev = eaction->dev; 907 struct drm_device *dev = eaction->dev;
908 struct drm_pending_event *event = eaction->event; 908 struct drm_pending_event *event = eaction->event;
909 struct drm_file *file_priv;
910
911 909
912 if (unlikely(event == NULL)) 910 if (unlikely(event == NULL))
913 return; 911 return;
914 912
915 file_priv = event->file_priv;
916 spin_lock_irq(&dev->event_lock); 913 spin_lock_irq(&dev->event_lock);
917 914
918 if (likely(eaction->tv_sec != NULL)) { 915 if (likely(eaction->tv_sec != NULL)) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index e6b11f6ae2e4..b351fb5214d3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -30,6 +30,7 @@
30#include <drm/drm_atomic.h> 30#include <drm/drm_atomic.h>
31#include <drm/drm_atomic_helper.h> 31#include <drm/drm_atomic_helper.h>
32#include <drm/drm_rect.h> 32#include <drm/drm_rect.h>
33#include <drm/drm_damage_helper.h>
33 34
34/* Might need a hrtimer here? */ 35/* Might need a hrtimer here? */
35#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) 36#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
@@ -456,21 +457,8 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
456 struct drm_crtc *crtc = state->crtc; 457 struct drm_crtc *crtc = state->crtc;
457 struct vmw_connector_state *vcs; 458 struct vmw_connector_state *vcs;
458 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 459 struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
459 struct vmw_private *dev_priv = vmw_priv(crtc->dev);
460 struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb);
461 460
462 vcs = vmw_connector_state_to_vcs(du->connector.state); 461 vcs = vmw_connector_state_to_vcs(du->connector.state);
463
464 /* Only one active implicit framebuffer at a time. */
465 mutex_lock(&dev_priv->global_kms_state_mutex);
466 if (vcs->is_implicit && dev_priv->implicit_fb &&
467 !(dev_priv->num_implicit == 1 && du->active_implicit)
468 && dev_priv->implicit_fb != vfb) {
469 DRM_ERROR("Multiple implicit framebuffers "
470 "not supported.\n");
471 ret = -EINVAL;
472 }
473 mutex_unlock(&dev_priv->global_kms_state_mutex);
474 } 462 }
475 463
476 464
@@ -846,58 +834,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
846 kfree(vfbs); 834 kfree(vfbs);
847} 835}
848 836
849static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
850 struct drm_file *file_priv,
851 unsigned flags, unsigned color,
852 struct drm_clip_rect *clips,
853 unsigned num_clips)
854{
855 struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
856 struct vmw_framebuffer_surface *vfbs =
857 vmw_framebuffer_to_vfbs(framebuffer);
858 struct drm_clip_rect norect;
859 int ret, inc = 1;
860
861 /* Legacy Display Unit does not support 3D */
862 if (dev_priv->active_display_unit == vmw_du_legacy)
863 return -EINVAL;
864
865 drm_modeset_lock_all(dev_priv->dev);
866
867 ret = ttm_read_lock(&dev_priv->reservation_sem, true);
868 if (unlikely(ret != 0)) {
869 drm_modeset_unlock_all(dev_priv->dev);
870 return ret;
871 }
872
873 if (!num_clips) {
874 num_clips = 1;
875 clips = &norect;
876 norect.x1 = norect.y1 = 0;
877 norect.x2 = framebuffer->width;
878 norect.y2 = framebuffer->height;
879 } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
880 num_clips /= 2;
881 inc = 2; /* skip source rects */
882 }
883
884 if (dev_priv->active_display_unit == vmw_du_screen_object)
885 ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base,
886 clips, NULL, NULL, 0, 0,
887 num_clips, inc, NULL, NULL);
888 else
889 ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base,
890 clips, NULL, NULL, 0, 0,
891 num_clips, inc, NULL, NULL);
892
893 vmw_fifo_flush(dev_priv, false);
894 ttm_read_unlock(&dev_priv->reservation_sem);
895
896 drm_modeset_unlock_all(dev_priv->dev);
897
898 return 0;
899}
900
901/** 837/**
902 * vmw_kms_readback - Perform a readback from the screen system to 838 * vmw_kms_readback - Perform a readback from the screen system to
903 * a buffer-object backed framebuffer. 839 * a buffer-object backed framebuffer.
@@ -941,7 +877,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
941 877
942static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { 878static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
943 .destroy = vmw_framebuffer_surface_destroy, 879 .destroy = vmw_framebuffer_surface_destroy,
944 .dirty = vmw_framebuffer_surface_dirty, 880 .dirty = drm_atomic_helper_dirtyfb,
945}; 881};
946 882
947static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, 883static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
@@ -1084,16 +1020,6 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer,
1084 } 1020 }
1085 1021
1086 switch (dev_priv->active_display_unit) { 1022 switch (dev_priv->active_display_unit) {
1087 case vmw_du_screen_target:
1088 ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL,
1089 clips, NULL, num_clips, increment,
1090 true, true, NULL);
1091 break;
1092 case vmw_du_screen_object:
1093 ret = vmw_kms_sou_do_bo_dirty(dev_priv, &vfbd->base,
1094 clips, NULL, num_clips,
1095 increment, true, NULL, NULL);
1096 break;
1097 case vmw_du_legacy: 1023 case vmw_du_legacy:
1098 ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0, 1024 ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0,
1099 clips, num_clips, increment); 1025 clips, num_clips, increment);
@@ -1112,9 +1038,25 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer,
1112 return ret; 1038 return ret;
1113} 1039}
1114 1040
1041static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer,
1042 struct drm_file *file_priv,
1043 unsigned int flags, unsigned int color,
1044 struct drm_clip_rect *clips,
1045 unsigned int num_clips)
1046{
1047 struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
1048
1049 if (dev_priv->active_display_unit == vmw_du_legacy)
1050 return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags,
1051 color, clips, num_clips);
1052
1053 return drm_atomic_helper_dirtyfb(framebuffer, file_priv, flags, color,
1054 clips, num_clips);
1055}
1056
1115static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = { 1057static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = {
1116 .destroy = vmw_framebuffer_bo_destroy, 1058 .destroy = vmw_framebuffer_bo_destroy,
1117 .dirty = vmw_framebuffer_bo_dirty, 1059 .dirty = vmw_framebuffer_bo_dirty_ext,
1118}; 1060};
1119 1061
1120/** 1062/**
@@ -1565,6 +1507,88 @@ static int vmw_kms_check_display_memory(struct drm_device *dev,
1565} 1507}
1566 1508
1567/** 1509/**
1510 * vmw_crtc_state_and_lock - Return new or current crtc state with locked
1511 * crtc mutex
1512 * @state: The atomic state pointer containing the new atomic state
1513 * @crtc: The crtc
1514 *
1515 * This function returns the new crtc state if it's part of the state update.
1516 * Otherwise returns the current crtc state. It also makes sure that the
1517 * crtc mutex is locked.
1518 *
1519 * Returns: A valid crtc state pointer or NULL. It may also return a
1520 * pointer error, in particular -EDEADLK if locking needs to be rerun.
1521 */
1522static struct drm_crtc_state *
1523vmw_crtc_state_and_lock(struct drm_atomic_state *state, struct drm_crtc *crtc)
1524{
1525 struct drm_crtc_state *crtc_state;
1526
1527 crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
1528 if (crtc_state) {
1529 lockdep_assert_held(&crtc->mutex.mutex.base);
1530 } else {
1531 int ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
1532
1533 if (ret != 0 && ret != -EALREADY)
1534 return ERR_PTR(ret);
1535
1536 crtc_state = crtc->state;
1537 }
1538
1539 return crtc_state;
1540}
1541
1542/**
1543 * vmw_kms_check_implicit - Verify that all implicit display units scan out
1544 * from the same fb after the new state is committed.
1545 * @dev: The drm_device.
1546 * @state: The new state to be checked.
1547 *
1548 * Returns:
1549 * Zero on success,
1550 * -EINVAL on invalid state,
1551 * -EDEADLK if modeset locking needs to be rerun.
1552 */
1553static int vmw_kms_check_implicit(struct drm_device *dev,
1554 struct drm_atomic_state *state)
1555{
1556 struct drm_framebuffer *implicit_fb = NULL;
1557 struct drm_crtc *crtc;
1558 struct drm_crtc_state *crtc_state;
1559 struct drm_plane_state *plane_state;
1560
1561 drm_for_each_crtc(crtc, dev) {
1562 struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
1563
1564 if (!du->is_implicit)
1565 continue;
1566
1567 crtc_state = vmw_crtc_state_and_lock(state, crtc);
1568 if (IS_ERR(crtc_state))
1569 return PTR_ERR(crtc_state);
1570
1571 if (!crtc_state || !crtc_state->enable)
1572 continue;
1573
1574 /*
1575 * Can't move primary planes across crtcs, so this is OK.
1576 * It also means we don't need to take the plane mutex.
1577 */
1578 plane_state = du->primary.state;
1579 if (plane_state->crtc != crtc)
1580 continue;
1581
1582 if (!implicit_fb)
1583 implicit_fb = plane_state->fb;
1584 else if (implicit_fb != plane_state->fb)
1585 return -EINVAL;
1586 }
1587
1588 return 0;
1589}
1590
1591/**
1568 * vmw_kms_check_topology - Validates topology in drm_atomic_state 1592 * vmw_kms_check_topology - Validates topology in drm_atomic_state
1569 * @dev: DRM device 1593 * @dev: DRM device
1570 * @state: the driver state object 1594 * @state: the driver state object
@@ -1575,7 +1599,6 @@ static int vmw_kms_check_display_memory(struct drm_device *dev,
1575static int vmw_kms_check_topology(struct drm_device *dev, 1599static int vmw_kms_check_topology(struct drm_device *dev,
1576 struct drm_atomic_state *state) 1600 struct drm_atomic_state *state)
1577{ 1601{
1578 struct vmw_private *dev_priv = vmw_priv(dev);
1579 struct drm_crtc_state *old_crtc_state, *new_crtc_state; 1602 struct drm_crtc_state *old_crtc_state, *new_crtc_state;
1580 struct drm_rect *rects; 1603 struct drm_rect *rects;
1581 struct drm_crtc *crtc; 1604 struct drm_crtc *crtc;
@@ -1587,19 +1610,31 @@ static int vmw_kms_check_topology(struct drm_device *dev,
1587 if (!rects) 1610 if (!rects)
1588 return -ENOMEM; 1611 return -ENOMEM;
1589 1612
1590 mutex_lock(&dev_priv->requested_layout_mutex);
1591
1592 drm_for_each_crtc(crtc, dev) { 1613 drm_for_each_crtc(crtc, dev) {
1593 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 1614 struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
1594 struct drm_crtc_state *crtc_state = crtc->state; 1615 struct drm_crtc_state *crtc_state;
1595 1616
1596 i = drm_crtc_index(crtc); 1617 i = drm_crtc_index(crtc);
1597 1618
1598 if (crtc_state && crtc_state->enable) { 1619 crtc_state = vmw_crtc_state_and_lock(state, crtc);
1620 if (IS_ERR(crtc_state)) {
1621 ret = PTR_ERR(crtc_state);
1622 goto clean;
1623 }
1624
1625 if (!crtc_state)
1626 continue;
1627
1628 if (crtc_state->enable) {
1599 rects[i].x1 = du->gui_x; 1629 rects[i].x1 = du->gui_x;
1600 rects[i].y1 = du->gui_y; 1630 rects[i].y1 = du->gui_y;
1601 rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; 1631 rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay;
1602 rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay; 1632 rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay;
1633 } else {
1634 rects[i].x1 = 0;
1635 rects[i].y1 = 0;
1636 rects[i].x2 = 0;
1637 rects[i].y2 = 0;
1603 } 1638 }
1604 } 1639 }
1605 1640
@@ -1611,14 +1646,6 @@ static int vmw_kms_check_topology(struct drm_device *dev,
1611 struct drm_connector_state *conn_state; 1646 struct drm_connector_state *conn_state;
1612 struct vmw_connector_state *vmw_conn_state; 1647 struct vmw_connector_state *vmw_conn_state;
1613 1648
1614 if (!new_crtc_state->enable) {
1615 rects[i].x1 = 0;
1616 rects[i].y1 = 0;
1617 rects[i].x2 = 0;
1618 rects[i].y2 = 0;
1619 continue;
1620 }
1621
1622 if (!du->pref_active) { 1649 if (!du->pref_active) {
1623 ret = -EINVAL; 1650 ret = -EINVAL;
1624 goto clean; 1651 goto clean;
@@ -1639,18 +1666,12 @@ static int vmw_kms_check_topology(struct drm_device *dev,
1639 vmw_conn_state = vmw_connector_state_to_vcs(conn_state); 1666 vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
1640 vmw_conn_state->gui_x = du->gui_x; 1667 vmw_conn_state->gui_x = du->gui_x;
1641 vmw_conn_state->gui_y = du->gui_y; 1668 vmw_conn_state->gui_y = du->gui_y;
1642
1643 rects[i].x1 = du->gui_x;
1644 rects[i].y1 = du->gui_y;
1645 rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay;
1646 rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay;
1647 } 1669 }
1648 1670
1649 ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, 1671 ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc,
1650 rects); 1672 rects);
1651 1673
1652clean: 1674clean:
1653 mutex_unlock(&dev_priv->requested_layout_mutex);
1654 kfree(rects); 1675 kfree(rects);
1655 return ret; 1676 return ret;
1656} 1677}
@@ -1681,6 +1702,10 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev,
1681 if (ret) 1702 if (ret)
1682 return ret; 1703 return ret;
1683 1704
1705 ret = vmw_kms_check_implicit(dev, state);
1706 if (ret)
1707 return ret;
1708
1684 if (!state->allow_modeset) 1709 if (!state->allow_modeset)
1685 return ret; 1710 return ret;
1686 1711
@@ -2003,11 +2028,25 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
2003 struct vmw_display_unit *du; 2028 struct vmw_display_unit *du;
2004 struct drm_connector *con; 2029 struct drm_connector *con;
2005 struct drm_connector_list_iter conn_iter; 2030 struct drm_connector_list_iter conn_iter;
2031 struct drm_modeset_acquire_ctx ctx;
2032 struct drm_crtc *crtc;
2033 int ret;
2034
2035 /* Currently gui_x/y is protected with the crtc mutex */
2036 mutex_lock(&dev->mode_config.mutex);
2037 drm_modeset_acquire_init(&ctx, 0);
2038retry:
2039 drm_for_each_crtc(crtc, dev) {
2040 ret = drm_modeset_lock(&crtc->mutex, &ctx);
2041 if (ret < 0) {
2042 if (ret == -EDEADLK) {
2043 drm_modeset_backoff(&ctx);
2044 goto retry;
2045 }
2046 goto out_fini;
2047 }
2048 }
2006 2049
2007 /*
2008 * Currently only gui_x/y is protected with requested_layout_mutex.
2009 */
2010 mutex_lock(&dev_priv->requested_layout_mutex);
2011 drm_connector_list_iter_begin(dev, &conn_iter); 2050 drm_connector_list_iter_begin(dev, &conn_iter);
2012 drm_for_each_connector_iter(con, &conn_iter) { 2051 drm_for_each_connector_iter(con, &conn_iter) {
2013 du = vmw_connector_to_du(con); 2052 du = vmw_connector_to_du(con);
@@ -2026,9 +2065,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
2026 } 2065 }
2027 } 2066 }
2028 drm_connector_list_iter_end(&conn_iter); 2067 drm_connector_list_iter_end(&conn_iter);
2029 mutex_unlock(&dev_priv->requested_layout_mutex);
2030 2068
2031 mutex_lock(&dev->mode_config.mutex);
2032 list_for_each_entry(con, &dev->mode_config.connector_list, head) { 2069 list_for_each_entry(con, &dev->mode_config.connector_list, head) {
2033 du = vmw_connector_to_du(con); 2070 du = vmw_connector_to_du(con);
2034 if (num_rects > du->unit) { 2071 if (num_rects > du->unit) {
@@ -2048,10 +2085,13 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
2048 } 2085 }
2049 con->status = vmw_du_connector_detect(con, true); 2086 con->status = vmw_du_connector_detect(con, true);
2050 } 2087 }
2051 mutex_unlock(&dev->mode_config.mutex);
2052 2088
2053 drm_sysfs_hotplug_event(dev); 2089 drm_sysfs_hotplug_event(dev);
2054 2090out_fini:
2091 drm_modeset_drop_locks(&ctx);
2092 drm_modeset_acquire_fini(&ctx);
2093 mutex_unlock(&dev->mode_config.mutex);
2094
2055 return 0; 2095 return 0;
2056} 2096}
2057 2097
@@ -2275,84 +2315,6 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
2275 return 1; 2315 return 1;
2276} 2316}
2277 2317
2278int vmw_du_connector_set_property(struct drm_connector *connector,
2279 struct drm_property *property,
2280 uint64_t val)
2281{
2282 struct vmw_display_unit *du = vmw_connector_to_du(connector);
2283 struct vmw_private *dev_priv = vmw_priv(connector->dev);
2284
2285 if (property == dev_priv->implicit_placement_property)
2286 du->is_implicit = val;
2287
2288 return 0;
2289}
2290
2291
2292
2293/**
2294 * vmw_du_connector_atomic_set_property - Atomic version of get property
2295 *
2296 * @crtc - crtc the property is associated with
2297 *
2298 * Returns:
2299 * Zero on success, negative errno on failure.
2300 */
2301int
2302vmw_du_connector_atomic_set_property(struct drm_connector *connector,
2303 struct drm_connector_state *state,
2304 struct drm_property *property,
2305 uint64_t val)
2306{
2307 struct vmw_private *dev_priv = vmw_priv(connector->dev);
2308 struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state);
2309 struct vmw_display_unit *du = vmw_connector_to_du(connector);
2310
2311
2312 if (property == dev_priv->implicit_placement_property) {
2313 vcs->is_implicit = val;
2314
2315 /*
2316 * We should really be doing a drm_atomic_commit() to
2317 * commit the new state, but since this doesn't cause
2318 * an immedate state change, this is probably ok
2319 */
2320 du->is_implicit = vcs->is_implicit;
2321 } else {
2322 return -EINVAL;
2323 }
2324
2325 return 0;
2326}
2327
2328
2329/**
2330 * vmw_du_connector_atomic_get_property - Atomic version of get property
2331 *
2332 * @connector - connector the property is associated with
2333 *
2334 * Returns:
2335 * Zero on success, negative errno on failure.
2336 */
2337int
2338vmw_du_connector_atomic_get_property(struct drm_connector *connector,
2339 const struct drm_connector_state *state,
2340 struct drm_property *property,
2341 uint64_t *val)
2342{
2343 struct vmw_private *dev_priv = vmw_priv(connector->dev);
2344 struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state);
2345
2346 if (property == dev_priv->implicit_placement_property)
2347 *val = vcs->is_implicit;
2348 else {
2349 DRM_ERROR("Invalid Property %s\n", property->name);
2350 return -EINVAL;
2351 }
2352
2353 return 0;
2354}
2355
2356/** 2318/**
2357 * vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl 2319 * vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl
2358 * @dev: drm device for the ioctl 2320 * @dev: drm device for the ioctl
@@ -2742,143 +2704,25 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
2742} 2704}
2743 2705
2744/** 2706/**
2745 * vmw_kms_del_active - unregister a crtc binding to the implicit framebuffer
2746 *
2747 * @dev_priv: Pointer to a device private struct.
2748 * @du: The display unit of the crtc.
2749 */
2750void vmw_kms_del_active(struct vmw_private *dev_priv,
2751 struct vmw_display_unit *du)
2752{
2753 mutex_lock(&dev_priv->global_kms_state_mutex);
2754 if (du->active_implicit) {
2755 if (--(dev_priv->num_implicit) == 0)
2756 dev_priv->implicit_fb = NULL;
2757 du->active_implicit = false;
2758 }
2759 mutex_unlock(&dev_priv->global_kms_state_mutex);
2760}
2761
2762/**
2763 * vmw_kms_add_active - register a crtc binding to an implicit framebuffer
2764 *
2765 * @vmw_priv: Pointer to a device private struct.
2766 * @du: The display unit of the crtc.
2767 * @vfb: The implicit framebuffer
2768 *
2769 * Registers a binding to an implicit framebuffer.
2770 */
2771void vmw_kms_add_active(struct vmw_private *dev_priv,
2772 struct vmw_display_unit *du,
2773 struct vmw_framebuffer *vfb)
2774{
2775 mutex_lock(&dev_priv->global_kms_state_mutex);
2776 WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb);
2777
2778 if (!du->active_implicit && du->is_implicit) {
2779 dev_priv->implicit_fb = vfb;
2780 du->active_implicit = true;
2781 dev_priv->num_implicit++;
2782 }
2783 mutex_unlock(&dev_priv->global_kms_state_mutex);
2784}
2785
2786/**
2787 * vmw_kms_screen_object_flippable - Check whether we can page-flip a crtc.
2788 *
2789 * @dev_priv: Pointer to device-private struct.
2790 * @crtc: The crtc we want to flip.
2791 *
2792 * Returns true or false depending whether it's OK to flip this crtc
2793 * based on the criterion that we must not have more than one implicit
2794 * frame-buffer at any one time.
2795 */
2796bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv,
2797 struct drm_crtc *crtc)
2798{
2799 struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
2800 bool ret;
2801
2802 mutex_lock(&dev_priv->global_kms_state_mutex);
2803 ret = !du->is_implicit || dev_priv->num_implicit == 1;
2804 mutex_unlock(&dev_priv->global_kms_state_mutex);
2805
2806 return ret;
2807}
2808
2809/**
2810 * vmw_kms_update_implicit_fb - Update the implicit fb.
2811 *
2812 * @dev_priv: Pointer to device-private struct.
2813 * @crtc: The crtc the new implicit frame-buffer is bound to.
2814 */
2815void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv,
2816 struct drm_crtc *crtc)
2817{
2818 struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
2819 struct drm_plane *plane = crtc->primary;
2820 struct vmw_framebuffer *vfb;
2821
2822 mutex_lock(&dev_priv->global_kms_state_mutex);
2823
2824 if (!du->is_implicit)
2825 goto out_unlock;
2826
2827 vfb = vmw_framebuffer_to_vfb(plane->state->fb);
2828 WARN_ON_ONCE(dev_priv->num_implicit != 1 &&
2829 dev_priv->implicit_fb != vfb);
2830
2831 dev_priv->implicit_fb = vfb;
2832out_unlock:
2833 mutex_unlock(&dev_priv->global_kms_state_mutex);
2834}
2835
2836/**
2837 * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement 2707 * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement
2838 * property. 2708 * property.
2839 * 2709 *
2840 * @dev_priv: Pointer to a device private struct. 2710 * @dev_priv: Pointer to a device private struct.
2841 * @immutable: Whether the property is immutable.
2842 * 2711 *
2843 * Sets up the implicit placement property unless it's already set up. 2712 * Sets up the implicit placement property unless it's already set up.
2844 */ 2713 */
2845void 2714void
2846vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, 2715vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv)
2847 bool immutable)
2848{ 2716{
2849 if (dev_priv->implicit_placement_property) 2717 if (dev_priv->implicit_placement_property)
2850 return; 2718 return;
2851 2719
2852 dev_priv->implicit_placement_property = 2720 dev_priv->implicit_placement_property =
2853 drm_property_create_range(dev_priv->dev, 2721 drm_property_create_range(dev_priv->dev,
2854 immutable ? 2722 DRM_MODE_PROP_IMMUTABLE,
2855 DRM_MODE_PROP_IMMUTABLE : 0,
2856 "implicit_placement", 0, 1); 2723 "implicit_placement", 0, 1);
2857
2858}
2859
2860
2861/**
2862 * vmw_kms_set_config - Wrapper around drm_atomic_helper_set_config
2863 *
2864 * @set: The configuration to set.
2865 *
2866 * The vmwgfx Xorg driver doesn't assign the mode::type member, which
2867 * when drm_mode_set_crtcinfo is called as part of the configuration setting
2868 * causes it to return incorrect crtc dimensions causing severe problems in
2869 * the vmwgfx modesetting. So explicitly clear that member before calling
2870 * into drm_atomic_helper_set_config.
2871 */
2872int vmw_kms_set_config(struct drm_mode_set *set,
2873 struct drm_modeset_acquire_ctx *ctx)
2874{
2875 if (set && set->mode)
2876 set->mode->type = 0;
2877
2878 return drm_atomic_helper_set_config(set, ctx);
2879} 2724}
2880 2725
2881
2882/** 2726/**
2883 * vmw_kms_suspend - Save modesetting state and turn modesetting off. 2727 * vmw_kms_suspend - Save modesetting state and turn modesetting off.
2884 * 2728 *
@@ -2935,3 +2779,124 @@ void vmw_kms_lost_device(struct drm_device *dev)
2935{ 2779{
2936 drm_atomic_helper_shutdown(dev); 2780 drm_atomic_helper_shutdown(dev);
2937} 2781}
2782
2783/**
2784 * vmw_du_helper_plane_update - Helper to do plane update on a display unit.
2785 * @update: The closure structure.
2786 *
2787 * Call this helper after setting callbacks in &vmw_du_update_plane to do plane
2788 * update on display unit.
2789 *
2790 * Return: 0 on success or a negative error code on failure.
2791 */
2792int vmw_du_helper_plane_update(struct vmw_du_update_plane *update)
2793{
2794 struct drm_plane_state *state = update->plane->state;
2795 struct drm_plane_state *old_state = update->old_state;
2796 struct drm_atomic_helper_damage_iter iter;
2797 struct drm_rect clip;
2798 struct drm_rect bb;
2799 DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
2800 uint32_t reserved_size = 0;
2801 uint32_t submit_size = 0;
2802 uint32_t curr_size = 0;
2803 uint32_t num_hits = 0;
2804 void *cmd_start;
2805 char *cmd_next;
2806 int ret;
2807
2808 /*
2809 * Iterate in advance to check if really need plane update and find the
2810 * number of clips that actually are in plane src for fifo allocation.
2811 */
2812 drm_atomic_helper_damage_iter_init(&iter, old_state, state);
2813 drm_atomic_for_each_plane_damage(&iter, &clip)
2814 num_hits++;
2815
2816 if (num_hits == 0)
2817 return 0;
2818
2819 if (update->vfb->bo) {
2820 struct vmw_framebuffer_bo *vfbbo =
2821 container_of(update->vfb, typeof(*vfbbo), base);
2822
2823 ret = vmw_validation_add_bo(&val_ctx, vfbbo->buffer, false,
2824 update->cpu_blit);
2825 } else {
2826 struct vmw_framebuffer_surface *vfbs =
2827 container_of(update->vfb, typeof(*vfbs), base);
2828
2829 ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res,
2830 0, NULL, NULL);
2831 }
2832
2833 if (ret)
2834 return ret;
2835
2836 ret = vmw_validation_prepare(&val_ctx, update->mutex, update->intr);
2837 if (ret)
2838 goto out_unref;
2839
2840 reserved_size = update->calc_fifo_size(update, num_hits);
2841 cmd_start = vmw_fifo_reserve(update->dev_priv, reserved_size);
2842 if (!cmd_start) {
2843 ret = -ENOMEM;
2844 goto out_revert;
2845 }
2846
2847 cmd_next = cmd_start;
2848
2849 if (update->post_prepare) {
2850 curr_size = update->post_prepare(update, cmd_next);
2851 cmd_next += curr_size;
2852 submit_size += curr_size;
2853 }
2854
2855 if (update->pre_clip) {
2856 curr_size = update->pre_clip(update, cmd_next, num_hits);
2857 cmd_next += curr_size;
2858 submit_size += curr_size;
2859 }
2860
2861 bb.x1 = INT_MAX;
2862 bb.y1 = INT_MAX;
2863 bb.x2 = INT_MIN;
2864 bb.y2 = INT_MIN;
2865
2866 drm_atomic_helper_damage_iter_init(&iter, old_state, state);
2867 drm_atomic_for_each_plane_damage(&iter, &clip) {
2868 uint32_t fb_x = clip.x1;
2869 uint32_t fb_y = clip.y1;
2870
2871 vmw_du_translate_to_crtc(state, &clip);
2872 if (update->clip) {
2873 curr_size = update->clip(update, cmd_next, &clip, fb_x,
2874 fb_y);
2875 cmd_next += curr_size;
2876 submit_size += curr_size;
2877 }
2878 bb.x1 = min_t(int, bb.x1, clip.x1);
2879 bb.y1 = min_t(int, bb.y1, clip.y1);
2880 bb.x2 = max_t(int, bb.x2, clip.x2);
2881 bb.y2 = max_t(int, bb.y2, clip.y2);
2882 }
2883
2884 curr_size = update->post_clip(update, cmd_next, &bb);
2885 submit_size += curr_size;
2886
2887 if (reserved_size < submit_size)
2888 submit_size = 0;
2889
2890 vmw_fifo_commit(update->dev_priv, submit_size);
2891
2892 vmw_kms_helper_validation_finish(update->dev_priv, NULL, &val_ctx,
2893 update->out_fence, NULL);
2894 return ret;
2895
2896out_revert:
2897 vmw_validation_revert(&val_ctx);
2898
2899out_unref:
2900 vmw_validation_unref_lists(&val_ctx);
2901 return ret;
2902}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 76ec570c0684..655abbcd4058 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -33,7 +33,123 @@
33#include <drm/drm_encoder.h> 33#include <drm/drm_encoder.h>
34#include "vmwgfx_drv.h" 34#include "vmwgfx_drv.h"
35 35
36/**
37 * struct vmw_du_update_plane - Closure structure for vmw_du_helper_plane_update
38 * @plane: Plane which is being updated.
39 * @old_state: Old state of plane.
40 * @dev_priv: Device private.
41 * @du: Display unit on which to update the plane.
42 * @vfb: Framebuffer which is blitted to display unit.
43 * @out_fence: Out fence for resource finish.
44 * @mutex: The mutex used to protect resource reservation.
45 * @cpu_blit: True if need cpu blit.
46 * @intr: Whether to perform waits interruptible if possible.
47 *
48 * This structure loosely represent the set of operations needed to perform a
49 * plane update on a display unit. Implementer will define that functionality
50 * according to the function callbacks for this structure. In brief it involves
51 * surface/buffer object validation, populate FIFO commands and command
52 * submission to the device.
53 */
54struct vmw_du_update_plane {
55 /**
56 * @calc_fifo_size: Calculate fifo size.
57 *
58 * Determine fifo size for the commands needed for update. The number of
59 * damage clips on display unit @num_hits will be passed to allocate
60 * sufficient fifo space.
61 *
62 * Return: Fifo size needed
63 */
64 uint32_t (*calc_fifo_size)(struct vmw_du_update_plane *update,
65 uint32_t num_hits);
66
67 /**
68 * @post_prepare: Populate fifo for resource preparation.
69 *
70 * Some surface resource or buffer object need some extra cmd submission
71 * like update GB image for proxy surface and define a GMRFB for screen
72 * object. That should should be done here as this callback will be
73 * called after FIFO allocation with the address of command buufer.
74 *
75 * This callback is optional.
76 *
77 * Return: Size of commands populated to command buffer.
78 */
79 uint32_t (*post_prepare)(struct vmw_du_update_plane *update, void *cmd);
80
81 /**
82 * @pre_clip: Populate fifo before clip.
83 *
84 * This is where pre clip related command should be populated like
85 * surface copy/DMA, etc.
86 *
87 * This callback is optional.
88 *
89 * Return: Size of commands populated to command buffer.
90 */
91 uint32_t (*pre_clip)(struct vmw_du_update_plane *update, void *cmd,
92 uint32_t num_hits);
93
94 /**
95 * @clip: Populate fifo for clip.
96 *
97 * This is where to populate clips for surface copy/dma or blit commands
98 * if needed. This will be called times have damage in display unit,
99 * which is one if doing full update. @clip is the damage in destination
100 * coordinates which is crtc/DU and @src_x, @src_y is damage clip src in
101 * framebuffer coordinate.
102 *
103 * This callback is optional.
104 *
105 * Return: Size of commands populated to command buffer.
106 */
107 uint32_t (*clip)(struct vmw_du_update_plane *update, void *cmd,
108 struct drm_rect *clip, uint32_t src_x, uint32_t src_y);
109
110 /**
111 * @post_clip: Populate fifo after clip.
112 *
113 * This is where to populate display unit update commands or blit
114 * commands.
115 *
116 * Return: Size of commands populated to command buffer.
117 */
118 uint32_t (*post_clip)(struct vmw_du_update_plane *update, void *cmd,
119 struct drm_rect *bb);
120
121 struct drm_plane *plane;
122 struct drm_plane_state *old_state;
123 struct vmw_private *dev_priv;
124 struct vmw_display_unit *du;
125 struct vmw_framebuffer *vfb;
126 struct vmw_fence_obj **out_fence;
127 struct mutex *mutex;
128 bool cpu_blit;
129 bool intr;
130};
131
132/**
133 * struct vmw_du_update_plane_surface - closure structure for surface
134 * @base: base closure structure.
135 * @cmd_start: FIFO command start address (used by SOU only).
136 */
137struct vmw_du_update_plane_surface {
138 struct vmw_du_update_plane base;
139 /* This member is to handle special case SOU surface update */
140 void *cmd_start;
141};
36 142
143/**
144 * struct vmw_du_update_plane_buffer - Closure structure for buffer object
145 * @base: Base closure structure.
146 * @fb_left: x1 for fb damage bounding box.
147 * @fb_top: y1 for fb damage bounding box.
148 */
149struct vmw_du_update_plane_buffer {
150 struct vmw_du_update_plane base;
151 int fb_left, fb_top;
152};
37 153
38/** 154/**
39 * struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty 155 * struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty
@@ -191,8 +307,6 @@ struct vmw_plane_state {
191struct vmw_connector_state { 307struct vmw_connector_state {
192 struct drm_connector_state base; 308 struct drm_connector_state base;
193 309
194 bool is_implicit;
195
196 /** 310 /**
197 * @gui_x: 311 * @gui_x:
198 * 312 *
@@ -254,7 +368,6 @@ struct vmw_display_unit {
254 int gui_x; 368 int gui_x;
255 int gui_y; 369 int gui_y;
256 bool is_implicit; 370 bool is_implicit;
257 bool active_implicit;
258 int set_gui_x; 371 int set_gui_x;
259 int set_gui_y; 372 int set_gui_y;
260}; 373};
@@ -334,17 +447,8 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
334 struct drm_crtc **p_crtc, 447 struct drm_crtc **p_crtc,
335 struct drm_display_mode **p_mode); 448 struct drm_display_mode **p_mode);
336void vmw_guess_mode_timing(struct drm_display_mode *mode); 449void vmw_guess_mode_timing(struct drm_display_mode *mode);
337void vmw_kms_del_active(struct vmw_private *dev_priv, 450void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv);
338 struct vmw_display_unit *du); 451void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
339void vmw_kms_add_active(struct vmw_private *dev_priv,
340 struct vmw_display_unit *du,
341 struct vmw_framebuffer *vfb);
342bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv,
343 struct drm_crtc *crtc);
344void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv,
345 struct drm_crtc *crtc);
346void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv,
347 bool immutable);
348 452
349/* Universal Plane Helpers */ 453/* Universal Plane Helpers */
350void vmw_du_primary_plane_destroy(struct drm_plane *plane); 454void vmw_du_primary_plane_destroy(struct drm_plane *plane);
@@ -456,6 +560,20 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
456 bool interruptible, 560 bool interruptible,
457 struct drm_crtc *crtc); 561 struct drm_crtc *crtc);
458 562
459int vmw_kms_set_config(struct drm_mode_set *set, 563int vmw_du_helper_plane_update(struct vmw_du_update_plane *update);
460 struct drm_modeset_acquire_ctx *ctx); 564
565/**
566 * vmw_du_translate_to_crtc - Translate a rect from framebuffer to crtc
567 * @state: Plane state.
568 * @r: Rectangle to translate.
569 */
570static inline void vmw_du_translate_to_crtc(struct drm_plane_state *state,
571 struct drm_rect *r)
572{
573 int translate_crtc_x = -((state->src_x >> 16) - state->crtc_x);
574 int translate_crtc_y = -((state->src_y >> 16) - state->crtc_y);
575
576 drm_rect_translate(r, translate_crtc_x, translate_crtc_y);
577}
578
461#endif 579#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 4b5378495eea..16be515c4c0f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -233,7 +233,7 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
233 .reset = vmw_du_crtc_reset, 233 .reset = vmw_du_crtc_reset,
234 .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 234 .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
235 .atomic_destroy_state = vmw_du_crtc_destroy_state, 235 .atomic_destroy_state = vmw_du_crtc_destroy_state,
236 .set_config = vmw_kms_set_config, 236 .set_config = drm_atomic_helper_set_config,
237}; 237};
238 238
239 239
@@ -263,13 +263,10 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = {
263 .dpms = vmw_du_connector_dpms, 263 .dpms = vmw_du_connector_dpms,
264 .detect = vmw_du_connector_detect, 264 .detect = vmw_du_connector_detect,
265 .fill_modes = vmw_du_connector_fill_modes, 265 .fill_modes = vmw_du_connector_fill_modes,
266 .set_property = vmw_du_connector_set_property,
267 .destroy = vmw_ldu_connector_destroy, 266 .destroy = vmw_ldu_connector_destroy,
268 .reset = vmw_du_connector_reset, 267 .reset = vmw_du_connector_reset,
269 .atomic_duplicate_state = vmw_du_connector_duplicate_state, 268 .atomic_duplicate_state = vmw_du_connector_duplicate_state,
270 .atomic_destroy_state = vmw_du_connector_destroy_state, 269 .atomic_destroy_state = vmw_du_connector_destroy_state,
271 .atomic_set_property = vmw_du_connector_atomic_set_property,
272 .atomic_get_property = vmw_du_connector_atomic_get_property,
273}; 270};
274 271
275static const struct 272static const struct
@@ -416,7 +413,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
416 413
417 drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs); 414 drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs);
418 415
419
420 vmw_du_connector_reset(connector); 416 vmw_du_connector_reset(connector);
421 ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, 417 ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
422 DRM_MODE_CONNECTOR_VIRTUAL); 418 DRM_MODE_CONNECTOR_VIRTUAL);
@@ -427,8 +423,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
427 423
428 drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs); 424 drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs);
429 connector->status = vmw_du_connector_detect(connector, true); 425 connector->status = vmw_du_connector_detect(connector, true);
430 vmw_connector_state_to_vcs(connector->state)->is_implicit = true;
431
432 426
433 ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, 427 ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
434 DRM_MODE_ENCODER_VIRTUAL, NULL); 428 DRM_MODE_ENCODER_VIRTUAL, NULL);
@@ -447,7 +441,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
447 goto err_free_encoder; 441 goto err_free_encoder;
448 } 442 }
449 443
450
451 vmw_du_crtc_reset(crtc); 444 vmw_du_crtc_reset(crtc);
452 ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary, 445 ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary,
453 &ldu->base.cursor, 446 &ldu->base.cursor,
@@ -513,7 +506,7 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
513 if (ret != 0) 506 if (ret != 0)
514 goto err_free; 507 goto err_free;
515 508
516 vmw_kms_create_implicit_placement_property(dev_priv, true); 509 vmw_kms_create_implicit_placement_property(dev_priv);
517 510
518 if (dev_priv->capabilities & SVGA_CAP_MULTIMON) 511 if (dev_priv->capabilities & SVGA_CAP_MULTIMON)
519 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) 512 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 333418dc259f..cd586c52af7e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -29,6 +29,7 @@
29#include <drm/drm_plane_helper.h> 29#include <drm/drm_plane_helper.h>
30#include <drm/drm_atomic.h> 30#include <drm/drm_atomic.h>
31#include <drm/drm_atomic_helper.h> 31#include <drm/drm_atomic_helper.h>
32#include <drm/drm_damage_helper.h>
32 33
33 34
34#define vmw_crtc_to_sou(x) \ 35#define vmw_crtc_to_sou(x) \
@@ -76,6 +77,11 @@ struct vmw_kms_sou_dirty_cmd {
76 SVGA3dCmdBlitSurfaceToScreen body; 77 SVGA3dCmdBlitSurfaceToScreen body;
77}; 78};
78 79
80struct vmw_kms_sou_define_gmrfb {
81 uint32_t header;
82 SVGAFifoCmdDefineGMRFB body;
83};
84
79/** 85/**
80 * Display unit using screen objects. 86 * Display unit using screen objects.
81 */ 87 */
@@ -241,28 +247,20 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
241 sou->buffer = vps->bo; 247 sou->buffer = vps->bo;
242 sou->buffer_size = vps->bo_size; 248 sou->buffer_size = vps->bo_size;
243 249
244 if (sou->base.is_implicit) { 250 conn_state = sou->base.connector.state;
245 x = crtc->x; 251 vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
246 y = crtc->y;
247 } else {
248 conn_state = sou->base.connector.state;
249 vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
250 252
251 x = vmw_conn_state->gui_x; 253 x = vmw_conn_state->gui_x;
252 y = vmw_conn_state->gui_y; 254 y = vmw_conn_state->gui_y;
253 }
254 255
255 ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); 256 ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode);
256 if (ret) 257 if (ret)
257 DRM_ERROR("Failed to define Screen Object %dx%d\n", 258 DRM_ERROR("Failed to define Screen Object %dx%d\n",
258 crtc->x, crtc->y); 259 crtc->x, crtc->y);
259 260
260 vmw_kms_add_active(dev_priv, &sou->base, vfb);
261 } else { 261 } else {
262 sou->buffer = NULL; 262 sou->buffer = NULL;
263 sou->buffer_size = 0; 263 sou->buffer_size = 0;
264
265 vmw_kms_del_active(dev_priv, &sou->base);
266 } 264 }
267} 265}
268 266
@@ -317,38 +315,14 @@ static void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc,
317 } 315 }
318} 316}
319 317
320static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc,
321 struct drm_framebuffer *new_fb,
322 struct drm_pending_vblank_event *event,
323 uint32_t flags,
324 struct drm_modeset_acquire_ctx *ctx)
325{
326 struct vmw_private *dev_priv = vmw_priv(crtc->dev);
327 int ret;
328
329 if (!vmw_kms_crtc_flippable(dev_priv, crtc))
330 return -EINVAL;
331
332 ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx);
333 if (ret) {
334 DRM_ERROR("Page flip error %d.\n", ret);
335 return ret;
336 }
337
338 if (vmw_crtc_to_du(crtc)->is_implicit)
339 vmw_kms_update_implicit_fb(dev_priv, crtc);
340
341 return ret;
342}
343
344static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { 318static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
345 .gamma_set = vmw_du_crtc_gamma_set, 319 .gamma_set = vmw_du_crtc_gamma_set,
346 .destroy = vmw_sou_crtc_destroy, 320 .destroy = vmw_sou_crtc_destroy,
347 .reset = vmw_du_crtc_reset, 321 .reset = vmw_du_crtc_reset,
348 .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 322 .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
349 .atomic_destroy_state = vmw_du_crtc_destroy_state, 323 .atomic_destroy_state = vmw_du_crtc_destroy_state,
350 .set_config = vmw_kms_set_config, 324 .set_config = drm_atomic_helper_set_config,
351 .page_flip = vmw_sou_crtc_page_flip, 325 .page_flip = drm_atomic_helper_page_flip,
352}; 326};
353 327
354/* 328/*
@@ -377,13 +351,10 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = {
377 .dpms = vmw_du_connector_dpms, 351 .dpms = vmw_du_connector_dpms,
378 .detect = vmw_du_connector_detect, 352 .detect = vmw_du_connector_detect,
379 .fill_modes = vmw_du_connector_fill_modes, 353 .fill_modes = vmw_du_connector_fill_modes,
380 .set_property = vmw_du_connector_set_property,
381 .destroy = vmw_sou_connector_destroy, 354 .destroy = vmw_sou_connector_destroy,
382 .reset = vmw_du_connector_reset, 355 .reset = vmw_du_connector_reset,
383 .atomic_duplicate_state = vmw_du_connector_duplicate_state, 356 .atomic_duplicate_state = vmw_du_connector_duplicate_state,
384 .atomic_destroy_state = vmw_du_connector_destroy_state, 357 .atomic_destroy_state = vmw_du_connector_destroy_state,
385 .atomic_set_property = vmw_du_connector_atomic_set_property,
386 .atomic_get_property = vmw_du_connector_atomic_get_property,
387}; 358};
388 359
389 360
@@ -498,6 +469,263 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
498 return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); 469 return vmw_bo_pin_in_vram(dev_priv, vps->bo, true);
499} 470}
500 471
472static uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update,
473 uint32_t num_hits)
474{
475 return sizeof(struct vmw_kms_sou_define_gmrfb) +
476 sizeof(struct vmw_kms_sou_bo_blit) * num_hits;
477}
478
479static uint32_t vmw_sou_bo_define_gmrfb(struct vmw_du_update_plane *update,
480 void *cmd)
481{
482 struct vmw_framebuffer_bo *vfbbo =
483 container_of(update->vfb, typeof(*vfbbo), base);
484 struct vmw_kms_sou_define_gmrfb *gmr = cmd;
485 int depth = update->vfb->base.format->depth;
486
487 /* Emulate RGBA support, contrary to svga_reg.h this is not
488 * supported by hosts. This is only a problem if we are reading
489 * this value later and expecting what we uploaded back.
490 */
491 if (depth == 32)
492 depth = 24;
493
494 gmr->header = SVGA_CMD_DEFINE_GMRFB;
495
496 gmr->body.format.bitsPerPixel = update->vfb->base.format->cpp[0] * 8;
497 gmr->body.format.colorDepth = depth;
498 gmr->body.format.reserved = 0;
499 gmr->body.bytesPerLine = update->vfb->base.pitches[0];
500 vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &gmr->body.ptr);
501
502 return sizeof(*gmr);
503}
504
505static uint32_t vmw_sou_bo_populate_clip(struct vmw_du_update_plane *update,
506 void *cmd, struct drm_rect *clip,
507 uint32_t fb_x, uint32_t fb_y)
508{
509 struct vmw_kms_sou_bo_blit *blit = cmd;
510
511 blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
512 blit->body.destScreenId = update->du->unit;
513 blit->body.srcOrigin.x = fb_x;
514 blit->body.srcOrigin.y = fb_y;
515 blit->body.destRect.left = clip->x1;
516 blit->body.destRect.top = clip->y1;
517 blit->body.destRect.right = clip->x2;
518 blit->body.destRect.bottom = clip->y2;
519
520 return sizeof(*blit);
521}
522
523static uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane *update,
524 void *cmd, struct drm_rect *bb)
525{
526 return 0;
527}
528
529/**
530 * vmw_sou_plane_update_bo - Update display unit for bo backed fb.
531 * @dev_priv: Device private.
532 * @plane: Plane state.
533 * @old_state: Old plane state.
534 * @vfb: Framebuffer which is blitted to display unit.
535 * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
536 * The returned fence pointer may be NULL in which case the device
537 * has already synchronized.
538 *
539 * Return: 0 on success or a negative error code on failure.
540 */
541static int vmw_sou_plane_update_bo(struct vmw_private *dev_priv,
542 struct drm_plane *plane,
543 struct drm_plane_state *old_state,
544 struct vmw_framebuffer *vfb,
545 struct vmw_fence_obj **out_fence)
546{
547 struct vmw_du_update_plane_buffer bo_update;
548
549 memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
550 bo_update.base.plane = plane;
551 bo_update.base.old_state = old_state;
552 bo_update.base.dev_priv = dev_priv;
553 bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
554 bo_update.base.vfb = vfb;
555 bo_update.base.out_fence = out_fence;
556 bo_update.base.mutex = NULL;
557 bo_update.base.cpu_blit = false;
558 bo_update.base.intr = true;
559
560 bo_update.base.calc_fifo_size = vmw_sou_bo_fifo_size;
561 bo_update.base.post_prepare = vmw_sou_bo_define_gmrfb;
562 bo_update.base.clip = vmw_sou_bo_populate_clip;
563 bo_update.base.post_clip = vmw_stud_bo_post_clip;
564
565 return vmw_du_helper_plane_update(&bo_update.base);
566}
567
568static uint32_t vmw_sou_surface_fifo_size(struct vmw_du_update_plane *update,
569 uint32_t num_hits)
570{
571 return sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) *
572 num_hits;
573}
574
575static uint32_t vmw_sou_surface_post_prepare(struct vmw_du_update_plane *update,
576 void *cmd)
577{
578 struct vmw_du_update_plane_surface *srf_update;
579
580 srf_update = container_of(update, typeof(*srf_update), base);
581
582 /*
583 * SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that
584 * its bounding box is filled before iterating over all the clips. So
585 * store the FIFO start address and revisit to fill the details.
586 */
587 srf_update->cmd_start = cmd;
588
589 return 0;
590}
591
592static uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update,
593 void *cmd, uint32_t num_hits)
594{
595 struct vmw_kms_sou_dirty_cmd *blit = cmd;
596 struct vmw_framebuffer_surface *vfbs;
597
598 vfbs = container_of(update->vfb, typeof(*vfbs), base);
599
600 blit->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN;
601 blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) *
602 num_hits;
603
604 blit->body.srcImage.sid = vfbs->surface->res.id;
605 blit->body.destScreenId = update->du->unit;
606
607 /* Update the source and destination bounding box later in post_clip */
608 blit->body.srcRect.left = 0;
609 blit->body.srcRect.top = 0;
610 blit->body.srcRect.right = 0;
611 blit->body.srcRect.bottom = 0;
612
613 blit->body.destRect.left = 0;
614 blit->body.destRect.top = 0;
615 blit->body.destRect.right = 0;
616 blit->body.destRect.bottom = 0;
617
618 return sizeof(*blit);
619}
620
621static uint32_t vmw_sou_surface_clip_rect(struct vmw_du_update_plane *update,
622 void *cmd, struct drm_rect *clip,
623 uint32_t src_x, uint32_t src_y)
624{
625 SVGASignedRect *rect = cmd;
626
627 /*
628 * rects are relative to dest bounding box rect on screen object, so
629 * translate to it later in post_clip
630 */
631 rect->left = clip->x1;
632 rect->top = clip->y1;
633 rect->right = clip->x2;
634 rect->bottom = clip->y2;
635
636 return sizeof(*rect);
637}
638
639static uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update,
640 void *cmd, struct drm_rect *bb)
641{
642 struct vmw_du_update_plane_surface *srf_update;
643 struct drm_plane_state *state = update->plane->state;
644 struct drm_rect src_bb;
645 struct vmw_kms_sou_dirty_cmd *blit;
646 SVGASignedRect *rect;
647 uint32_t num_hits;
648 int translate_src_x;
649 int translate_src_y;
650 int i;
651
652 srf_update = container_of(update, typeof(*srf_update), base);
653
654 blit = srf_update->cmd_start;
655 rect = (SVGASignedRect *)&blit[1];
656
657 num_hits = (blit->header.size - sizeof(blit->body))/
658 sizeof(SVGASignedRect);
659
660 src_bb = *bb;
661
662 /* To translate bb back to fb src coord */
663 translate_src_x = (state->src_x >> 16) - state->crtc_x;
664 translate_src_y = (state->src_y >> 16) - state->crtc_y;
665
666 drm_rect_translate(&src_bb, translate_src_x, translate_src_y);
667
668 blit->body.srcRect.left = src_bb.x1;
669 blit->body.srcRect.top = src_bb.y1;
670 blit->body.srcRect.right = src_bb.x2;
671 blit->body.srcRect.bottom = src_bb.y2;
672
673 blit->body.destRect.left = bb->x1;
674 blit->body.destRect.top = bb->y1;
675 blit->body.destRect.right = bb->x2;
676 blit->body.destRect.bottom = bb->y2;
677
678 /* rects are relative to dest bb rect */
679 for (i = 0; i < num_hits; i++) {
680 rect->left -= bb->x1;
681 rect->top -= bb->y1;
682 rect->right -= bb->x1;
683 rect->bottom -= bb->y1;
684 rect++;
685 }
686
687 return 0;
688}
689
690/**
691 * vmw_sou_plane_update_surface - Update display unit for surface backed fb.
692 * @dev_priv: Device private.
693 * @plane: Plane state.
694 * @old_state: Old plane state.
695 * @vfb: Framebuffer which is blitted to display unit
696 * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
697 * The returned fence pointer may be NULL in which case the device
698 * has already synchronized.
699 *
700 * Return: 0 on success or a negative error code on failure.
701 */
702static int vmw_sou_plane_update_surface(struct vmw_private *dev_priv,
703 struct drm_plane *plane,
704 struct drm_plane_state *old_state,
705 struct vmw_framebuffer *vfb,
706 struct vmw_fence_obj **out_fence)
707{
708 struct vmw_du_update_plane_surface srf_update;
709
710 memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface));
711 srf_update.base.plane = plane;
712 srf_update.base.old_state = old_state;
713 srf_update.base.dev_priv = dev_priv;
714 srf_update.base.du = vmw_crtc_to_du(plane->state->crtc);
715 srf_update.base.vfb = vfb;
716 srf_update.base.out_fence = out_fence;
717 srf_update.base.mutex = &dev_priv->cmdbuf_mutex;
718 srf_update.base.cpu_blit = false;
719 srf_update.base.intr = true;
720
721 srf_update.base.calc_fifo_size = vmw_sou_surface_fifo_size;
722 srf_update.base.post_prepare = vmw_sou_surface_post_prepare;
723 srf_update.base.pre_clip = vmw_sou_surface_pre_clip;
724 srf_update.base.clip = vmw_sou_surface_clip_rect;
725 srf_update.base.post_clip = vmw_sou_surface_post_clip;
726
727 return vmw_du_helper_plane_update(&srf_update.base);
728}
501 729
502static void 730static void
503vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, 731vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
@@ -508,47 +736,28 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
508 struct vmw_fence_obj *fence = NULL; 736 struct vmw_fence_obj *fence = NULL;
509 int ret; 737 int ret;
510 738
739 /* In case of device error, maintain consistent atomic state */
511 if (crtc && plane->state->fb) { 740 if (crtc && plane->state->fb) {
512 struct vmw_private *dev_priv = vmw_priv(crtc->dev); 741 struct vmw_private *dev_priv = vmw_priv(crtc->dev);
513 struct vmw_framebuffer *vfb = 742 struct vmw_framebuffer *vfb =
514 vmw_framebuffer_to_vfb(plane->state->fb); 743 vmw_framebuffer_to_vfb(plane->state->fb);
515 struct drm_vmw_rect vclips;
516
517 vclips.x = crtc->x;
518 vclips.y = crtc->y;
519 vclips.w = crtc->mode.hdisplay;
520 vclips.h = crtc->mode.vdisplay;
521 744
522 if (vfb->bo) 745 if (vfb->bo)
523 ret = vmw_kms_sou_do_bo_dirty(dev_priv, vfb, NULL, 746 ret = vmw_sou_plane_update_bo(dev_priv, plane,
524 &vclips, 1, 1, true, 747 old_state, vfb, &fence);
525 &fence, crtc);
526 else 748 else
527 ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, 749 ret = vmw_sou_plane_update_surface(dev_priv, plane,
528 &vclips, NULL, 0, 0, 750 old_state, vfb,
529 1, 1, &fence, crtc); 751 &fence);
530
531 /*
532 * We cannot really fail this function, so if we do, then output
533 * an error and maintain consistent atomic state.
534 */
535 if (ret != 0) 752 if (ret != 0)
536 DRM_ERROR("Failed to update screen.\n"); 753 DRM_ERROR("Failed to update screen.\n");
537 } else { 754 } else {
538 /* 755 /* Do nothing when fb and crtc is NULL (blank crtc) */
539 * When disabling a plane, CRTC and FB should always be NULL
540 * together, otherwise it's an error.
541 * Here primary plane is being disable so should really blank
542 * the screen object display unit, if not already done.
543 */
544 return; 756 return;
545 } 757 }
546 758
759 /* For error case vblank event is send from vmw_du_crtc_atomic_flush */
547 event = crtc->state->event; 760 event = crtc->state->event;
548 /*
549 * In case of failure and other cases, vblank event will be sent in
550 * vmw_du_crtc_atomic_flush.
551 */
552 if (event && fence) { 761 if (event && fence) {
553 struct drm_file *file_priv = event->base.file_priv; 762 struct drm_file *file_priv = event->base.file_priv;
554 763
@@ -639,7 +848,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
639 primary = &sou->base.primary; 848 primary = &sou->base.primary;
640 cursor = &sou->base.cursor; 849 cursor = &sou->base.cursor;
641 850
642 sou->base.active_implicit = false;
643 sou->base.pref_active = (unit == 0); 851 sou->base.pref_active = (unit == 0);
644 sou->base.pref_width = dev_priv->initial_width; 852 sou->base.pref_width = dev_priv->initial_width;
645 sou->base.pref_height = dev_priv->initial_height; 853 sou->base.pref_height = dev_priv->initial_height;
@@ -665,6 +873,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
665 } 873 }
666 874
667 drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs); 875 drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs);
876 drm_plane_enable_fb_damage_clips(primary);
668 877
669 /* Initialize cursor plane */ 878 /* Initialize cursor plane */
670 vmw_du_plane_reset(cursor); 879 vmw_du_plane_reset(cursor);
@@ -692,8 +901,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
692 901
693 drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs); 902 drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs);
694 connector->status = vmw_du_connector_detect(connector, true); 903 connector->status = vmw_du_connector_detect(connector, true);
695 vmw_connector_state_to_vcs(connector->state)->is_implicit = false;
696
697 904
698 ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, 905 ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
699 DRM_MODE_ENCODER_VIRTUAL, NULL); 906 DRM_MODE_ENCODER_VIRTUAL, NULL);
@@ -732,12 +939,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
732 dev->mode_config.suggested_x_property, 0); 939 dev->mode_config.suggested_x_property, 0);
733 drm_object_attach_property(&connector->base, 940 drm_object_attach_property(&connector->base,
734 dev->mode_config.suggested_y_property, 0); 941 dev->mode_config.suggested_y_property, 0);
735 if (dev_priv->implicit_placement_property)
736 drm_object_attach_property
737 (&connector->base,
738 dev_priv->implicit_placement_property,
739 sou->base.is_implicit);
740
741 return 0; 942 return 0;
742 943
743err_free_unregister: 944err_free_unregister:
@@ -763,15 +964,11 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
763 } 964 }
764 965
765 ret = -ENOMEM; 966 ret = -ENOMEM;
766 dev_priv->num_implicit = 0;
767 dev_priv->implicit_fb = NULL;
768 967
769 ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); 968 ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
770 if (unlikely(ret != 0)) 969 if (unlikely(ret != 0))
771 return ret; 970 return ret;
772 971
773 vmw_kms_create_implicit_placement_property(dev_priv, false);
774
775 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) 972 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
776 vmw_sou_init(dev_priv, i); 973 vmw_sou_init(dev_priv, i);
777 974
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index c3e435f444c1..096c2941a8e4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -30,7 +30,7 @@
30#include <drm/drm_plane_helper.h> 30#include <drm/drm_plane_helper.h>
31#include <drm/drm_atomic.h> 31#include <drm/drm_atomic.h>
32#include <drm/drm_atomic_helper.h> 32#include <drm/drm_atomic_helper.h>
33 33#include <drm/drm_damage_helper.h>
34 34
35#define vmw_crtc_to_stdu(x) \ 35#define vmw_crtc_to_stdu(x) \
36 container_of(x, struct vmw_screen_target_display_unit, base.crtc) 36 container_of(x, struct vmw_screen_target_display_unit, base.crtc)
@@ -92,6 +92,10 @@ struct vmw_stdu_surface_copy {
92 SVGA3dCmdSurfaceCopy body; 92 SVGA3dCmdSurfaceCopy body;
93}; 93};
94 94
95struct vmw_stdu_update_gb_image {
96 SVGA3dCmdHeader header;
97 SVGA3dCmdUpdateGBImage body;
98};
95 99
96/** 100/**
97 * struct vmw_screen_target_display_unit 101 * struct vmw_screen_target_display_unit
@@ -396,13 +400,8 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc)
396 if (!crtc->state->enable) 400 if (!crtc->state->enable)
397 return; 401 return;
398 402
399 if (stdu->base.is_implicit) { 403 x = vmw_conn_state->gui_x;
400 x = crtc->x; 404 y = vmw_conn_state->gui_y;
401 y = crtc->y;
402 } else {
403 x = vmw_conn_state->gui_x;
404 y = vmw_conn_state->gui_y;
405 }
406 405
407 vmw_svga_enable(dev_priv); 406 vmw_svga_enable(dev_priv);
408 ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y); 407 ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y);
@@ -417,27 +416,9 @@ static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc)
417{ 416{
418} 417}
419 418
420
421static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc, 419static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc,
422 struct drm_crtc_state *old_state) 420 struct drm_crtc_state *old_state)
423{ 421{
424 struct drm_plane_state *plane_state = crtc->primary->state;
425 struct vmw_private *dev_priv;
426 struct vmw_screen_target_display_unit *stdu;
427 struct vmw_framebuffer *vfb;
428 struct drm_framebuffer *fb;
429
430
431 stdu = vmw_crtc_to_stdu(crtc);
432 dev_priv = vmw_priv(crtc->dev);
433 fb = plane_state->fb;
434
435 vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
436
437 if (vfb)
438 vmw_kms_add_active(dev_priv, &stdu->base, vfb);
439 else
440 vmw_kms_del_active(dev_priv, &stdu->base);
441} 422}
442 423
443static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, 424static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc,
@@ -472,49 +453,6 @@ static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc,
472} 453}
473 454
474/** 455/**
475 * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target
476 *
477 * @crtc: CRTC to attach FB to
478 * @fb: FB to attach
479 * @event: Event to be posted. This event should've been alloced
480 * using k[mz]alloc, and should've been completely initialized.
481 * @page_flip_flags: Input flags.
482 *
483 * If the STDU uses the same display and content buffers, i.e. a true flip,
484 * this function will replace the existing display buffer with the new content
485 * buffer.
486 *
487 * If the STDU uses different display and content buffers, i.e. a blit, then
488 * only the content buffer will be updated.
489 *
490 * RETURNS:
491 * 0 on success, error code on failure
492 */
493static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc,
494 struct drm_framebuffer *new_fb,
495 struct drm_pending_vblank_event *event,
496 uint32_t flags,
497 struct drm_modeset_acquire_ctx *ctx)
498
499{
500 struct vmw_private *dev_priv = vmw_priv(crtc->dev);
501 struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc);
502 int ret;
503
504 if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc))
505 return -EINVAL;
506
507 ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx);
508 if (ret) {
509 DRM_ERROR("Page flip error %d.\n", ret);
510 return ret;
511 }
512
513 return 0;
514}
515
516
517/**
518 * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect 456 * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect
519 * 457 *
520 * @dirty: The closure structure. 458 * @dirty: The closure structure.
@@ -986,8 +924,8 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
986 .reset = vmw_du_crtc_reset, 924 .reset = vmw_du_crtc_reset,
987 .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 925 .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
988 .atomic_destroy_state = vmw_du_crtc_destroy_state, 926 .atomic_destroy_state = vmw_du_crtc_destroy_state,
989 .set_config = vmw_kms_set_config, 927 .set_config = drm_atomic_helper_set_config,
990 .page_flip = vmw_stdu_crtc_page_flip, 928 .page_flip = drm_atomic_helper_page_flip,
991}; 929};
992 930
993 931
@@ -1042,13 +980,10 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
1042 .dpms = vmw_du_connector_dpms, 980 .dpms = vmw_du_connector_dpms,
1043 .detect = vmw_du_connector_detect, 981 .detect = vmw_du_connector_detect,
1044 .fill_modes = vmw_du_connector_fill_modes, 982 .fill_modes = vmw_du_connector_fill_modes,
1045 .set_property = vmw_du_connector_set_property,
1046 .destroy = vmw_stdu_connector_destroy, 983 .destroy = vmw_stdu_connector_destroy,
1047 .reset = vmw_du_connector_reset, 984 .reset = vmw_du_connector_reset,
1048 .atomic_duplicate_state = vmw_du_connector_duplicate_state, 985 .atomic_duplicate_state = vmw_du_connector_duplicate_state,
1049 .atomic_destroy_state = vmw_du_connector_destroy_state, 986 .atomic_destroy_state = vmw_du_connector_destroy_state,
1050 .atomic_set_property = vmw_du_connector_atomic_set_property,
1051 .atomic_get_property = vmw_du_connector_atomic_get_property,
1052}; 987};
1053 988
1054 989
@@ -1256,11 +1191,402 @@ out_srf_unref:
1256 return ret; 1191 return ret;
1257} 1192}
1258 1193
1194static uint32_t vmw_stdu_bo_fifo_size(struct vmw_du_update_plane *update,
1195 uint32_t num_hits)
1196{
1197 return sizeof(struct vmw_stdu_dma) + sizeof(SVGA3dCopyBox) * num_hits +
1198 sizeof(SVGA3dCmdSurfaceDMASuffix) +
1199 sizeof(struct vmw_stdu_update);
1200}
1201
1202static uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update,
1203 uint32_t num_hits)
1204{
1205 return sizeof(struct vmw_stdu_update_gb_image) +
1206 sizeof(struct vmw_stdu_update);
1207}
1208
1209static uint32_t vmw_stdu_bo_populate_dma(struct vmw_du_update_plane *update,
1210 void *cmd, uint32_t num_hits)
1211{
1212 struct vmw_screen_target_display_unit *stdu;
1213 struct vmw_framebuffer_bo *vfbbo;
1214 struct vmw_stdu_dma *cmd_dma = cmd;
1215
1216 stdu = container_of(update->du, typeof(*stdu), base);
1217 vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
1218
1219 cmd_dma->header.id = SVGA_3D_CMD_SURFACE_DMA;
1220 cmd_dma->header.size = sizeof(cmd_dma->body) +
1221 sizeof(struct SVGA3dCopyBox) * num_hits +
1222 sizeof(SVGA3dCmdSurfaceDMASuffix);
1223 vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &cmd_dma->body.guest.ptr);
1224 cmd_dma->body.guest.pitch = update->vfb->base.pitches[0];
1225 cmd_dma->body.host.sid = stdu->display_srf->res.id;
1226 cmd_dma->body.host.face = 0;
1227 cmd_dma->body.host.mipmap = 0;
1228 cmd_dma->body.transfer = SVGA3D_WRITE_HOST_VRAM;
1229
1230 return sizeof(*cmd_dma);
1231}
1232
1233static uint32_t vmw_stdu_bo_populate_clip(struct vmw_du_update_plane *update,
1234 void *cmd, struct drm_rect *clip,
1235 uint32_t fb_x, uint32_t fb_y)
1236{
1237 struct SVGA3dCopyBox *box = cmd;
1238
1239 box->srcx = fb_x;
1240 box->srcy = fb_y;
1241 box->srcz = 0;
1242 box->x = clip->x1;
1243 box->y = clip->y1;
1244 box->z = 0;
1245 box->w = drm_rect_width(clip);
1246 box->h = drm_rect_height(clip);
1247 box->d = 1;
1248
1249 return sizeof(*box);
1250}
1251
1252static uint32_t vmw_stdu_bo_populate_update(struct vmw_du_update_plane *update,
1253 void *cmd, struct drm_rect *bb)
1254{
1255 struct vmw_screen_target_display_unit *stdu;
1256 struct vmw_framebuffer_bo *vfbbo;
1257 SVGA3dCmdSurfaceDMASuffix *suffix = cmd;
1258
1259 stdu = container_of(update->du, typeof(*stdu), base);
1260 vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
1261
1262 suffix->suffixSize = sizeof(*suffix);
1263 suffix->maximumOffset = vfbbo->buffer->base.num_pages * PAGE_SIZE;
1264
1265 vmw_stdu_populate_update(&suffix[1], stdu->base.unit, bb->x1, bb->x2,
1266 bb->y1, bb->y2);
1267
1268 return sizeof(*suffix) + sizeof(struct vmw_stdu_update);
1269}
1270
1271static uint32_t vmw_stdu_bo_pre_clip_cpu(struct vmw_du_update_plane *update,
1272 void *cmd, uint32_t num_hits)
1273{
1274 struct vmw_du_update_plane_buffer *bo_update =
1275 container_of(update, typeof(*bo_update), base);
1276
1277 bo_update->fb_left = INT_MAX;
1278 bo_update->fb_top = INT_MAX;
1279
1280 return 0;
1281}
1282
1283static uint32_t vmw_stdu_bo_clip_cpu(struct vmw_du_update_plane *update,
1284 void *cmd, struct drm_rect *clip,
1285 uint32_t fb_x, uint32_t fb_y)
1286{
1287 struct vmw_du_update_plane_buffer *bo_update =
1288 container_of(update, typeof(*bo_update), base);
1289
1290 bo_update->fb_left = min_t(int, bo_update->fb_left, fb_x);
1291 bo_update->fb_top = min_t(int, bo_update->fb_top, fb_y);
1292
1293 return 0;
1294}
1295
1296static uint32_t
1297vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane *update, void *cmd,
1298 struct drm_rect *bb)
1299{
1300 struct vmw_du_update_plane_buffer *bo_update;
1301 struct vmw_screen_target_display_unit *stdu;
1302 struct vmw_framebuffer_bo *vfbbo;
1303 struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(0);
1304 struct vmw_stdu_update_gb_image *cmd_img = cmd;
1305 struct vmw_stdu_update *cmd_update;
1306 struct ttm_buffer_object *src_bo, *dst_bo;
1307 u32 src_offset, dst_offset;
1308 s32 src_pitch, dst_pitch;
1309 s32 width, height;
1310
1311 bo_update = container_of(update, typeof(*bo_update), base);
1312 stdu = container_of(update->du, typeof(*stdu), base);
1313 vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
1314
1315 width = bb->x2 - bb->x1;
1316 height = bb->y2 - bb->y1;
1317
1318 diff.cpp = stdu->cpp;
1319
1320 dst_bo = &stdu->display_srf->res.backup->base;
1321 dst_pitch = stdu->display_srf->base_size.width * stdu->cpp;
1322 dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp;
1323
1324 src_bo = &vfbbo->buffer->base;
1325 src_pitch = update->vfb->base.pitches[0];
1326 src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left *
1327 stdu->cpp;
1328
1329 (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, src_bo,
1330 src_offset, src_pitch, width * stdu->cpp, height,
1331 &diff);
1332
1333 if (drm_rect_visible(&diff.rect)) {
1334 SVGA3dBox *box = &cmd_img->body.box;
1335
1336 cmd_img->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
1337 cmd_img->header.size = sizeof(cmd_img->body);
1338 cmd_img->body.image.sid = stdu->display_srf->res.id;
1339 cmd_img->body.image.face = 0;
1340 cmd_img->body.image.mipmap = 0;
1341
1342 box->x = diff.rect.x1;
1343 box->y = diff.rect.y1;
1344 box->z = 0;
1345 box->w = drm_rect_width(&diff.rect);
1346 box->h = drm_rect_height(&diff.rect);
1347 box->d = 1;
1348
1349 cmd_update = (struct vmw_stdu_update *)&cmd_img[1];
1350 vmw_stdu_populate_update(cmd_update, stdu->base.unit,
1351 diff.rect.x1, diff.rect.x2,
1352 diff.rect.y1, diff.rect.y2);
1353
1354 return sizeof(*cmd_img) + sizeof(*cmd_update);
1355 }
1356
1357 return 0;
1358}
1359
1360/**
1361 * vmw_stdu_plane_update_bo - Update display unit for bo backed fb.
1362 * @dev_priv: device private.
1363 * @plane: plane state.
1364 * @old_state: old plane state.
1365 * @vfb: framebuffer which is blitted to display unit.
1366 * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
1367 * The returned fence pointer may be NULL in which case the device
1368 * has already synchronized.
1369 *
1370 * Return: 0 on success or a negative error code on failure.
1371 */
1372static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv,
1373 struct drm_plane *plane,
1374 struct drm_plane_state *old_state,
1375 struct vmw_framebuffer *vfb,
1376 struct vmw_fence_obj **out_fence)
1377{
1378 struct vmw_du_update_plane_buffer bo_update;
1379
1380 memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
1381 bo_update.base.plane = plane;
1382 bo_update.base.old_state = old_state;
1383 bo_update.base.dev_priv = dev_priv;
1384 bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
1385 bo_update.base.vfb = vfb;
1386 bo_update.base.out_fence = out_fence;
1387 bo_update.base.mutex = NULL;
1388 bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D);
1389 bo_update.base.intr = false;
1390
1391 /*
1392 * VM without 3D support don't have surface DMA command and framebuffer
1393 * should be moved out of VRAM.
1394 */
1395 if (bo_update.base.cpu_blit) {
1396 bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size_cpu;
1397 bo_update.base.pre_clip = vmw_stdu_bo_pre_clip_cpu;
1398 bo_update.base.clip = vmw_stdu_bo_clip_cpu;
1399 bo_update.base.post_clip = vmw_stdu_bo_populate_update_cpu;
1400 } else {
1401 bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size;
1402 bo_update.base.pre_clip = vmw_stdu_bo_populate_dma;
1403 bo_update.base.clip = vmw_stdu_bo_populate_clip;
1404 bo_update.base.post_clip = vmw_stdu_bo_populate_update;
1405 }
1406
1407 return vmw_du_helper_plane_update(&bo_update.base);
1408}
1409
1410static uint32_t
1411vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update,
1412 uint32_t num_hits)
1413{
1414 struct vmw_framebuffer_surface *vfbs;
1415 uint32_t size = 0;
1416
1417 vfbs = container_of(update->vfb, typeof(*vfbs), base);
1418
1419 if (vfbs->is_bo_proxy)
1420 size += sizeof(struct vmw_stdu_update_gb_image) * num_hits;
1421
1422 size += sizeof(struct vmw_stdu_update);
1423
1424 return size;
1425}
1426
1427static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update,
1428 uint32_t num_hits)
1429{
1430 struct vmw_framebuffer_surface *vfbs;
1431 uint32_t size = 0;
1432
1433 vfbs = container_of(update->vfb, typeof(*vfbs), base);
1434
1435 if (vfbs->is_bo_proxy)
1436 size += sizeof(struct vmw_stdu_update_gb_image) * num_hits;
1437
1438 size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) *
1439 num_hits + sizeof(struct vmw_stdu_update);
1440
1441 return size;
1442}
1443
1444static uint32_t
1445vmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd)
1446{
1447 struct vmw_framebuffer_surface *vfbs;
1448 struct drm_plane_state *state = update->plane->state;
1449 struct drm_plane_state *old_state = update->old_state;
1450 struct vmw_stdu_update_gb_image *cmd_update = cmd;
1451 struct drm_atomic_helper_damage_iter iter;
1452 struct drm_rect clip;
1453 uint32_t copy_size = 0;
1454
1455 vfbs = container_of(update->vfb, typeof(*vfbs), base);
1456
1457 /*
1458 * proxy surface is special where a buffer object type fb is wrapped
1459 * in a surface and need an update gb image command to sync with device.
1460 */
1461 drm_atomic_helper_damage_iter_init(&iter, old_state, state);
1462 drm_atomic_for_each_plane_damage(&iter, &clip) {
1463 SVGA3dBox *box = &cmd_update->body.box;
1464
1465 cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
1466 cmd_update->header.size = sizeof(cmd_update->body);
1467 cmd_update->body.image.sid = vfbs->surface->res.id;
1468 cmd_update->body.image.face = 0;
1469 cmd_update->body.image.mipmap = 0;
1470
1471 box->x = clip.x1;
1472 box->y = clip.y1;
1473 box->z = 0;
1474 box->w = drm_rect_width(&clip);
1475 box->h = drm_rect_height(&clip);
1476 box->d = 1;
1477
1478 copy_size += sizeof(*cmd_update);
1479 cmd_update++;
1480 }
1481
1482 return copy_size;
1483}
1484
1485static uint32_t
1486vmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd,
1487 uint32_t num_hits)
1488{
1489 struct vmw_screen_target_display_unit *stdu;
1490 struct vmw_framebuffer_surface *vfbs;
1491 struct vmw_stdu_surface_copy *cmd_copy = cmd;
1492
1493 stdu = container_of(update->du, typeof(*stdu), base);
1494 vfbs = container_of(update->vfb, typeof(*vfbs), base);
1495
1496 cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY;
1497 cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) *
1498 num_hits;
1499 cmd_copy->body.src.sid = vfbs->surface->res.id;
1500 cmd_copy->body.dest.sid = stdu->display_srf->res.id;
1501
1502 return sizeof(*cmd_copy);
1503}
1504
1505static uint32_t
1506vmw_stdu_surface_populate_clip(struct vmw_du_update_plane *update, void *cmd,
1507 struct drm_rect *clip, uint32_t fb_x,
1508 uint32_t fb_y)
1509{
1510 struct SVGA3dCopyBox *box = cmd;
1511
1512 box->srcx = fb_x;
1513 box->srcy = fb_y;
1514 box->srcz = 0;
1515 box->x = clip->x1;
1516 box->y = clip->y1;
1517 box->z = 0;
1518 box->w = drm_rect_width(clip);
1519 box->h = drm_rect_height(clip);
1520 box->d = 1;
1521
1522 return sizeof(*box);
1523}
1524
1525static uint32_t
1526vmw_stdu_surface_populate_update(struct vmw_du_update_plane *update, void *cmd,
1527 struct drm_rect *bb)
1528{
1529 vmw_stdu_populate_update(cmd, update->du->unit, bb->x1, bb->x2, bb->y1,
1530 bb->y2);
1259 1531
1532 return sizeof(struct vmw_stdu_update);
1533}
1260 1534
1261/** 1535/**
1262 * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane 1536 * vmw_stdu_plane_update_surface - Update display unit for surface backed fb
1537 * @dev_priv: Device private
1538 * @plane: Plane state
1539 * @old_state: Old plane state
1540 * @vfb: Framebuffer which is blitted to display unit
1541 * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
1542 * The returned fence pointer may be NULL in which case the device
1543 * has already synchronized.
1263 * 1544 *
1545 * Return: 0 on success or a negative error code on failure.
1546 */
1547static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv,
1548 struct drm_plane *plane,
1549 struct drm_plane_state *old_state,
1550 struct vmw_framebuffer *vfb,
1551 struct vmw_fence_obj **out_fence)
1552{
1553 struct vmw_du_update_plane srf_update;
1554 struct vmw_screen_target_display_unit *stdu;
1555 struct vmw_framebuffer_surface *vfbs;
1556
1557 stdu = vmw_crtc_to_stdu(plane->state->crtc);
1558 vfbs = container_of(vfb, typeof(*vfbs), base);
1559
1560 memset(&srf_update, 0, sizeof(struct vmw_du_update_plane));
1561 srf_update.plane = plane;
1562 srf_update.old_state = old_state;
1563 srf_update.dev_priv = dev_priv;
1564 srf_update.du = vmw_crtc_to_du(plane->state->crtc);
1565 srf_update.vfb = vfb;
1566 srf_update.out_fence = out_fence;
1567 srf_update.mutex = &dev_priv->cmdbuf_mutex;
1568 srf_update.cpu_blit = false;
1569 srf_update.intr = true;
1570
1571 if (vfbs->is_bo_proxy)
1572 srf_update.post_prepare = vmw_stdu_surface_update_proxy;
1573
1574 if (vfbs->surface->res.id != stdu->display_srf->res.id) {
1575 srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size;
1576 srf_update.pre_clip = vmw_stdu_surface_populate_copy;
1577 srf_update.clip = vmw_stdu_surface_populate_clip;
1578 } else {
1579 srf_update.calc_fifo_size =
1580 vmw_stdu_surface_fifo_size_same_display;
1581 }
1582
1583 srf_update.post_clip = vmw_stdu_surface_populate_update;
1584
1585 return vmw_du_helper_plane_update(&srf_update);
1586}
1587
1588/**
1589 * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane
1264 * @plane: display plane 1590 * @plane: display plane
1265 * @old_state: Only used to get crtc info 1591 * @old_state: Only used to get crtc info
1266 * 1592 *
@@ -1277,17 +1603,14 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
1277 struct drm_crtc *crtc = plane->state->crtc; 1603 struct drm_crtc *crtc = plane->state->crtc;
1278 struct vmw_screen_target_display_unit *stdu; 1604 struct vmw_screen_target_display_unit *stdu;
1279 struct drm_pending_vblank_event *event; 1605 struct drm_pending_vblank_event *event;
1606 struct vmw_fence_obj *fence = NULL;
1280 struct vmw_private *dev_priv; 1607 struct vmw_private *dev_priv;
1281 int ret; 1608 int ret;
1282 1609
1283 /* 1610 /* If case of device error, maintain consistent atomic state */
1284 * We cannot really fail this function, so if we do, then output an
1285 * error and maintain consistent atomic state.
1286 */
1287 if (crtc && plane->state->fb) { 1611 if (crtc && plane->state->fb) {
1288 struct vmw_framebuffer *vfb = 1612 struct vmw_framebuffer *vfb =
1289 vmw_framebuffer_to_vfb(plane->state->fb); 1613 vmw_framebuffer_to_vfb(plane->state->fb);
1290 struct drm_vmw_rect vclips;
1291 stdu = vmw_crtc_to_stdu(crtc); 1614 stdu = vmw_crtc_to_stdu(crtc);
1292 dev_priv = vmw_priv(crtc->dev); 1615 dev_priv = vmw_priv(crtc->dev);
1293 1616
@@ -1295,23 +1618,17 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
1295 stdu->content_fb_type = vps->content_fb_type; 1618 stdu->content_fb_type = vps->content_fb_type;
1296 stdu->cpp = vps->cpp; 1619 stdu->cpp = vps->cpp;
1297 1620
1298 vclips.x = crtc->x;
1299 vclips.y = crtc->y;
1300 vclips.w = crtc->mode.hdisplay;
1301 vclips.h = crtc->mode.vdisplay;
1302
1303 ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); 1621 ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res);
1304 if (ret) 1622 if (ret)
1305 DRM_ERROR("Failed to bind surface to STDU.\n"); 1623 DRM_ERROR("Failed to bind surface to STDU.\n");
1306 1624
1307 if (vfb->bo) 1625 if (vfb->bo)
1308 ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, 1626 ret = vmw_stdu_plane_update_bo(dev_priv, plane,
1309 &vclips, 1, 1, true, false, 1627 old_state, vfb, &fence);
1310 crtc);
1311 else 1628 else
1312 ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, 1629 ret = vmw_stdu_plane_update_surface(dev_priv, plane,
1313 &vclips, NULL, 0, 0, 1630 old_state, vfb,
1314 1, 1, NULL, crtc); 1631 &fence);
1315 if (ret) 1632 if (ret)
1316 DRM_ERROR("Failed to update STDU.\n"); 1633 DRM_ERROR("Failed to update STDU.\n");
1317 } else { 1634 } else {
@@ -1319,12 +1636,7 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
1319 stdu = vmw_crtc_to_stdu(crtc); 1636 stdu = vmw_crtc_to_stdu(crtc);
1320 dev_priv = vmw_priv(crtc->dev); 1637 dev_priv = vmw_priv(crtc->dev);
1321 1638
1322 /* 1639 /* Blank STDU when fb and crtc are NULL */
1323 * When disabling a plane, CRTC and FB should always be NULL
1324 * together, otherwise it's an error.
1325 * Here primary plane is being disable so blank the screen
1326 * target display unit, if not already done.
1327 */
1328 if (!stdu->defined) 1640 if (!stdu->defined)
1329 return; 1641 return;
1330 1642
@@ -1339,36 +1651,25 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
1339 return; 1651 return;
1340 } 1652 }
1341 1653
1654 /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */
1342 event = crtc->state->event; 1655 event = crtc->state->event;
1343 /* 1656 if (event && fence) {
1344 * In case of failure and other cases, vblank event will be sent in
1345 * vmw_du_crtc_atomic_flush.
1346 */
1347 if (event && (ret == 0)) {
1348 struct vmw_fence_obj *fence = NULL;
1349 struct drm_file *file_priv = event->base.file_priv; 1657 struct drm_file *file_priv = event->base.file_priv;
1350 1658
1351 vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); 1659 ret = vmw_event_fence_action_queue(file_priv,
1352 1660 fence,
1353 /* 1661 &event->base,
1354 * If fence is NULL, then already sync. 1662 &event->event.vbl.tv_sec,
1355 */ 1663 &event->event.vbl.tv_usec,
1356 if (fence) { 1664 true);
1357 ret = vmw_event_fence_action_queue( 1665 if (ret)
1358 file_priv, fence, &event->base, 1666 DRM_ERROR("Failed to queue event on fence.\n");
1359 &event->event.vbl.tv_sec, 1667 else
1360 &event->event.vbl.tv_usec, 1668 crtc->state->event = NULL;
1361 true);
1362 if (ret)
1363 DRM_ERROR("Failed to queue event on fence.\n");
1364 else
1365 crtc->state->event = NULL;
1366
1367 vmw_fence_obj_unreference(&fence);
1368 }
1369 } else {
1370 (void) vmw_fifo_flush(dev_priv, false);
1371 } 1669 }
1670
1671 if (fence)
1672 vmw_fence_obj_unreference(&fence);
1372} 1673}
1373 1674
1374 1675
@@ -1456,11 +1757,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
1456 stdu->base.pref_active = (unit == 0); 1757 stdu->base.pref_active = (unit == 0);
1457 stdu->base.pref_width = dev_priv->initial_width; 1758 stdu->base.pref_width = dev_priv->initial_width;
1458 stdu->base.pref_height = dev_priv->initial_height; 1759 stdu->base.pref_height = dev_priv->initial_height;
1459
1460 /*
1461 * Remove this after enabling atomic because property values can
1462 * only exist in a state object
1463 */
1464 stdu->base.is_implicit = false; 1760 stdu->base.is_implicit = false;
1465 1761
1466 /* Initialize primary plane */ 1762 /* Initialize primary plane */
@@ -1477,6 +1773,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
1477 } 1773 }
1478 1774
1479 drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs); 1775 drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs);
1776 drm_plane_enable_fb_damage_clips(primary);
1480 1777
1481 /* Initialize cursor plane */ 1778 /* Initialize cursor plane */
1482 vmw_du_plane_reset(cursor); 1779 vmw_du_plane_reset(cursor);
@@ -1505,7 +1802,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
1505 1802
1506 drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs); 1803 drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs);
1507 connector->status = vmw_du_connector_detect(connector, false); 1804 connector->status = vmw_du_connector_detect(connector, false);
1508 vmw_connector_state_to_vcs(connector->state)->is_implicit = false;
1509 1805
1510 ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs, 1806 ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs,
1511 DRM_MODE_ENCODER_VIRTUAL, NULL); 1807 DRM_MODE_ENCODER_VIRTUAL, NULL);
@@ -1543,11 +1839,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
1543 dev->mode_config.suggested_x_property, 0); 1839 dev->mode_config.suggested_x_property, 0);
1544 drm_object_attach_property(&connector->base, 1840 drm_object_attach_property(&connector->base,
1545 dev->mode_config.suggested_y_property, 0); 1841 dev->mode_config.suggested_y_property, 0);
1546 if (dev_priv->implicit_placement_property)
1547 drm_object_attach_property
1548 (&connector->base,
1549 dev_priv->implicit_placement_property,
1550 stdu->base.is_implicit);
1551 return 0; 1842 return 0;
1552 1843
1553err_free_unregister: 1844err_free_unregister:
@@ -1616,8 +1907,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
1616 1907
1617 dev_priv->active_display_unit = vmw_du_screen_target; 1908 dev_priv->active_display_unit = vmw_du_screen_target;
1618 1909
1619 vmw_kms_create_implicit_placement_property(dev_priv, false);
1620
1621 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { 1910 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) {
1622 ret = vmw_stdu_init(dev_priv, i); 1911 ret = vmw_stdu_init(dev_priv, i);
1623 1912
diff --git a/include/drm/drm_damage_helper.h b/include/drm/drm_damage_helper.h
new file mode 100644
index 000000000000..4487660b26b8
--- /dev/null
+++ b/include/drm/drm_damage_helper.h
@@ -0,0 +1,99 @@
1/* SPDX-License-Identifier: GPL-2.0 OR MIT */
2/**************************************************************************
3 *
4 * Copyright (c) 2018 VMware, Inc., Palo Alto, CA., USA
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Authors:
28 * Deepak Rawat <drawat@vmware.com>
29 *
30 **************************************************************************/
31
32#ifndef DRM_DAMAGE_HELPER_H_
33#define DRM_DAMAGE_HELPER_H_
34
35#include <drm/drm_atomic_helper.h>
36
37/**
38 * drm_atomic_for_each_plane_damage - Iterator macro for plane damage.
39 * @iter: The iterator to advance.
40 * @rect: Return a rectangle in fb coordinate clipped to plane src.
41 *
42 * Note that if the first call to iterator macro return false then no need to do
43 * plane update. Iterator will return full plane src when damage is not passed
44 * by user-space.
45 */
46#define drm_atomic_for_each_plane_damage(iter, rect) \
47 while (drm_atomic_helper_damage_iter_next(iter, rect))
48
49/**
50 * struct drm_atomic_helper_damage_iter - Closure structure for damage iterator.
51 *
52 * This structure tracks state needed to walk the list of plane damage clips.
53 */
54struct drm_atomic_helper_damage_iter {
55 /* private: Plane src in whole number. */
56 struct drm_rect plane_src;
57 /* private: Rectangles in plane damage blob. */
58 const struct drm_rect *clips;
59 /* private: Number of rectangles in plane damage blob. */
60 uint32_t num_clips;
61 /* private: Current clip iterator is advancing on. */
62 uint32_t curr_clip;
63 /* private: Whether need full plane update. */
64 bool full_update;
65};
66
67void drm_plane_enable_fb_damage_clips(struct drm_plane *plane);
68void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
69 struct drm_plane_state *plane_state);
70int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
71 struct drm_file *file_priv, unsigned int flags,
72 unsigned int color, struct drm_clip_rect *clips,
73 unsigned int num_clips);
74void
75drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
76 const struct drm_plane_state *old_state,
77 const struct drm_plane_state *new_state);
78bool
79drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
80 struct drm_rect *rect);
81
82/**
83 * drm_helper_get_plane_damage_clips - Returns damage clips in &drm_rect.
84 * @state: Plane state.
85 *
86 * Returns plane damage rectangles in internal &drm_rect. Currently &drm_rect
87 * can be obtained by simply typecasting &drm_mode_rect. This is because both
88 * are signed 32 and during drm_atomic_check_only() it is verified that damage
89 * clips are inside fb.
90 *
91 * Return: Clips in plane fb_damage_clips blob property.
92 */
93static inline struct drm_rect *
94drm_helper_get_plane_damage_clips(const struct drm_plane_state *state)
95{
96 return (struct drm_rect *)drm_plane_get_damage_clips(state);
97}
98
99#endif
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 9db59a1caf5b..572274ccbec7 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -634,6 +634,15 @@ struct drm_mode_config {
634 */ 634 */
635 struct drm_property *prop_crtc_id; 635 struct drm_property *prop_crtc_id;
636 /** 636 /**
637 * @prop_fb_damage_clips: Optional plane property to mark damaged
638 * regions on the plane in framebuffer coordinates of the framebuffer
639 * attached to the plane.
640 *
641 * The layout of blob data is simply an array of &drm_mode_rect. Unlike
642 * plane src coordinates, damage clips are not in 16.16 fixed point.
643 */
644 struct drm_property *prop_fb_damage_clips;
645 /**
637 * @prop_active: Default atomic CRTC property to control the active 646 * @prop_active: Default atomic CRTC property to control the active
638 * state, which is the simplified implementation for DPMS in atomic 647 * state, which is the simplified implementation for DPMS in atomic
639 * drivers. 648 * drivers.
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 3701f56c3362..6078c700d9ba 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -173,6 +173,16 @@ struct drm_plane_state {
173 */ 173 */
174 enum drm_color_range color_range; 174 enum drm_color_range color_range;
175 175
176 /**
177 * @fb_damage_clips:
178 *
179 * Blob representing damage (area in plane framebuffer that changed
180 * since last plane update) as an array of &drm_mode_rect in framebuffer
181 * coodinates of the attached framebuffer. Note that unlike plane src,
182 * damage clips are not in 16.16 fixed point.
183 */
184 struct drm_property_blob *fb_damage_clips;
185
176 /** @src: clipped source coordinates of the plane (in 16.16) */ 186 /** @src: clipped source coordinates of the plane (in 16.16) */
177 /** @dst: clipped destination coordinates of the plane */ 187 /** @dst: clipped destination coordinates of the plane */
178 struct drm_rect src, dst; 188 struct drm_rect src, dst;
@@ -800,5 +810,37 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
800 810
801bool drm_any_plane_has_format(struct drm_device *dev, 811bool drm_any_plane_has_format(struct drm_device *dev,
802 u32 format, u64 modifier); 812 u32 format, u64 modifier);
813/**
814 * drm_plane_get_damage_clips_count - Returns damage clips count.
815 * @state: Plane state.
816 *
817 * Simple helper to get the number of &drm_mode_rect clips set by user-space
818 * during plane update.
819 *
820 * Return: Number of clips in plane fb_damage_clips blob property.
821 */
822static inline unsigned int
823drm_plane_get_damage_clips_count(const struct drm_plane_state *state)
824{
825 return (state && state->fb_damage_clips) ?
826 state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0;
827}
828
829/**
830 * drm_plane_get_damage_clips - Returns damage clips.
831 * @state: Plane state.
832 *
833 * Note that this function returns uapi type &drm_mode_rect. Drivers might
834 * instead be interested in internal &drm_rect which can be obtained by calling
835 * drm_helper_get_plane_damage_clips().
836 *
837 * Return: Damage clips in plane fb_damage_clips blob property.
838 */
839static inline struct drm_mode_rect *
840drm_plane_get_damage_clips(const struct drm_plane_state *state)
841{
842 return (struct drm_mode_rect *)((state && state->fb_damage_clips) ?
843 state->fb_damage_clips->data : NULL);
844}
803 845
804#endif 846#endif
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index d3e0fe31efc5..a439c2e67896 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -888,6 +888,25 @@ struct drm_mode_revoke_lease {
888 __u32 lessee_id; 888 __u32 lessee_id;
889}; 889};
890 890
891/**
892 * struct drm_mode_rect - Two dimensional rectangle.
893 * @x1: Horizontal starting coordinate (inclusive).
894 * @y1: Vertical starting coordinate (inclusive).
895 * @x2: Horizontal ending coordinate (exclusive).
896 * @y2: Vertical ending coordinate (exclusive).
897 *
898 * With drm subsystem using struct drm_rect to manage rectangular area this
899 * export it to user-space.
900 *
901 * Currently used by drm_mode_atomic blob property FB_DAMAGE_CLIPS.
902 */
903struct drm_mode_rect {
904 __s32 x1;
905 __s32 y1;
906 __s32 x2;
907 __s32 y2;
908};
909
891#if defined(__cplusplus) 910#if defined(__cplusplus)
892} 911}
893#endif 912#endif