blob: eb4c94fe1044f0f70a0174fb1cc0aa9739cf90a5 [file] [log] [blame]
Dirk Hohndel (VMware)dff96882018-05-07 01:16:26 +02001// SPDX-License-Identifier: GPL-2.0 OR MIT
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02002/**************************************************************************
3 *
Dirk Hohndel (VMware)dff96882018-05-07 01:16:26 +02004 * Copyright 2011-2015 VMware, Inc., Palo Alto, CA., USA
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#include "vmwgfx_kms.h"
Daniel Vetter3cb9ae42014-10-29 10:03:57 +010029#include <drm/drm_plane_helper.h>
Sinclair Yehd7721ca2017-03-23 11:48:44 -070030#include <drm/drm_atomic.h>
31#include <drm/drm_atomic_helper.h>
Deepak Rawat61c21382018-08-08 15:41:56 -070032#include <drm/drm_damage_helper.h>
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +020033
34
35#define vmw_crtc_to_sou(x) \
36 container_of(x, struct vmw_screen_object_unit, base.crtc)
37#define vmw_encoder_to_sou(x) \
38 container_of(x, struct vmw_screen_object_unit, base.encoder)
39#define vmw_connector_to_sou(x) \
40 container_of(x, struct vmw_screen_object_unit, base.connector)
41
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -070042/**
43 * struct vmw_kms_sou_surface_dirty - Closure structure for
44 * blit surface to screen command.
45 * @base: The base type we derive from. Used by vmw_kms_helper_dirty().
46 * @left: Left side of bounding box.
47 * @right: Right side of bounding box.
48 * @top: Top side of bounding box.
49 * @bottom: Bottom side of bounding box.
50 * @dst_x: Difference between source clip rects and framebuffer coordinates.
51 * @dst_y: Difference between source clip rects and framebuffer coordinates.
52 * @sid: Surface id of surface to copy from.
53 */
54struct vmw_kms_sou_surface_dirty {
55 struct vmw_kms_dirty base;
56 s32 left, right, top, bottom;
57 s32 dst_x, dst_y;
58 u32 sid;
59};
60
61/*
62 * SVGA commands that are used by this code. Please see the device headers
63 * for explanation.
64 */
65struct vmw_kms_sou_readback_blit {
66 uint32 header;
67 SVGAFifoCmdBlitScreenToGMRFB body;
68};
69
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +020070struct vmw_kms_sou_bo_blit {
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -070071 uint32 header;
72 SVGAFifoCmdBlitGMRFBToScreen body;
73};
74
75struct vmw_kms_sou_dirty_cmd {
76 SVGA3dCmdHeader header;
77 SVGA3dCmdBlitSurfaceToScreen body;
78};
79
Deepak Rawat5d35aba2018-08-08 15:02:48 -070080struct vmw_kms_sou_define_gmrfb {
81 uint32_t header;
82 SVGAFifoCmdDefineGMRFB body;
83};
84
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +020085/**
86 * Display unit using screen objects.
87 */
88struct vmw_screen_object_unit {
89 struct vmw_display_unit base;
90
91 unsigned long buffer_size; /**< Size of allocated buffer */
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +020092 struct vmw_buffer_object *buffer; /**< Backing store buffer */
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +020093
94 bool defined;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +020095};
96
97static void vmw_sou_destroy(struct vmw_screen_object_unit *sou)
98{
Sinclair Yehc8261a92015-06-26 01:23:42 -070099 vmw_du_cleanup(&sou->base);
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200100 kfree(sou);
101}
102
103
104/*
105 * Screen Object Display Unit CRTC functions
106 */
107
108static void vmw_sou_crtc_destroy(struct drm_crtc *crtc)
109{
110 vmw_sou_destroy(vmw_crtc_to_sou(crtc));
111}
112
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200113/**
114 * Send the fifo command to create a screen.
115 */
116static int vmw_sou_fifo_create(struct vmw_private *dev_priv,
117 struct vmw_screen_object_unit *sou,
Deepak Rawat3e79ecd2018-06-20 11:34:26 +0200118 int x, int y,
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200119 struct drm_display_mode *mode)
120{
121 size_t fifo_size;
122
123 struct {
124 struct {
125 uint32_t cmdType;
126 } header;
127 SVGAScreenObject obj;
128 } *cmd;
129
130 BUG_ON(!sou->buffer);
131
132 fifo_size = sizeof(*cmd);
133 cmd = vmw_fifo_reserve(dev_priv, fifo_size);
134 /* The hardware has hung, nothing we can do about it here. */
135 if (unlikely(cmd == NULL)) {
136 DRM_ERROR("Fifo reserve failed.\n");
137 return -ENOMEM;
138 }
139
140 memset(cmd, 0, fifo_size);
141 cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN;
142 cmd->obj.structSize = sizeof(SVGAScreenObject);
143 cmd->obj.id = sou->base.unit;
144 cmd->obj.flags = SVGA_SCREEN_HAS_ROOT |
145 (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0);
146 cmd->obj.size.width = mode->hdisplay;
147 cmd->obj.size.height = mode->vdisplay;
Deepak Rawat3e79ecd2018-06-20 11:34:26 +0200148 cmd->obj.root.x = x;
149 cmd->obj.root.y = y;
Thomas Hellstrom6dd687b2016-02-12 09:57:15 +0100150 sou->base.set_gui_x = cmd->obj.root.x;
151 sou->base.set_gui_y = cmd->obj.root.y;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200152
153 /* Ok to assume that buffer is pinned in vram */
Thomas Hellstromb37a6b92011-10-04 20:13:28 +0200154 vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr);
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200155 cmd->obj.backingStore.pitch = mode->hdisplay * 4;
156
157 vmw_fifo_commit(dev_priv, fifo_size);
158
159 sou->defined = true;
160
161 return 0;
162}
163
164/**
165 * Send the fifo command to destroy a screen.
166 */
167static int vmw_sou_fifo_destroy(struct vmw_private *dev_priv,
168 struct vmw_screen_object_unit *sou)
169{
170 size_t fifo_size;
171 int ret;
172
173 struct {
174 struct {
175 uint32_t cmdType;
176 } header;
177 SVGAFifoCmdDestroyScreen body;
178 } *cmd;
179
180 /* no need to do anything */
181 if (unlikely(!sou->defined))
182 return 0;
183
184 fifo_size = sizeof(*cmd);
185 cmd = vmw_fifo_reserve(dev_priv, fifo_size);
186 /* the hardware has hung, nothing we can do about it here */
187 if (unlikely(cmd == NULL)) {
188 DRM_ERROR("Fifo reserve failed.\n");
189 return -ENOMEM;
190 }
191
192 memset(cmd, 0, fifo_size);
193 cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN;
194 cmd->body.screenId = sou->base.unit;
195
196 vmw_fifo_commit(dev_priv, fifo_size);
197
198 /* Force sync */
199 ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ);
200 if (unlikely(ret != 0))
201 DRM_ERROR("Failed to sync with HW");
202 else
203 sou->defined = false;
204
205 return ret;
206}
207
208/**
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700209 * vmw_sou_crtc_mode_set_nofb - Create new screen
210 *
211 * @crtc: CRTC associated with the new screen
212 *
213 * This function creates/destroys a screen. This function cannot fail, so if
214 * somehow we run into a failure, just do the best we can to get out.
215 */
216static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
217{
218 struct vmw_private *dev_priv;
219 struct vmw_screen_object_unit *sou;
220 struct vmw_framebuffer *vfb;
221 struct drm_framebuffer *fb;
222 struct drm_plane_state *ps;
223 struct vmw_plane_state *vps;
224 int ret;
225
Deepak Rawat3e79ecd2018-06-20 11:34:26 +0200226 sou = vmw_crtc_to_sou(crtc);
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700227 dev_priv = vmw_priv(crtc->dev);
Deepak Rawat3e79ecd2018-06-20 11:34:26 +0200228 ps = crtc->primary->state;
229 fb = ps->fb;
230 vps = vmw_plane_state_to_vps(ps);
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700231
232 vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
233
234 if (sou->defined) {
235 ret = vmw_sou_fifo_destroy(dev_priv, sou);
236 if (ret) {
237 DRM_ERROR("Failed to destroy Screen Object\n");
238 return;
239 }
240 }
241
242 if (vfb) {
Deepak Rawat3e79ecd2018-06-20 11:34:26 +0200243 struct drm_connector_state *conn_state;
244 struct vmw_connector_state *vmw_conn_state;
245 int x, y;
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700246
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200247 sou->buffer = vps->bo;
248 sou->buffer_size = vps->bo_size;
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700249
Deepak Rawat3e79ecd2018-06-20 11:34:26 +0200250 if (sou->base.is_implicit) {
251 x = crtc->x;
252 y = crtc->y;
253 } else {
254 conn_state = sou->base.connector.state;
255 vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
256
257 x = vmw_conn_state->gui_x;
258 y = vmw_conn_state->gui_y;
259 }
260
261 ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode);
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700262 if (ret)
263 DRM_ERROR("Failed to define Screen Object %dx%d\n",
264 crtc->x, crtc->y);
265
266 vmw_kms_add_active(dev_priv, &sou->base, vfb);
267 } else {
268 sou->buffer = NULL;
269 sou->buffer_size = 0;
270
271 vmw_kms_del_active(dev_priv, &sou->base);
272 }
273}
274
275/**
276 * vmw_sou_crtc_helper_prepare - Noop
277 *
278 * @crtc: CRTC associated with the new screen
279 *
280 * Prepares the CRTC for a mode set, but we don't need to do anything here.
281 */
282static void vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc)
283{
284}
285
286/**
Laurent Pinchart0b20a0f2017-06-30 12:36:44 +0300287 * vmw_sou_crtc_atomic_enable - Noop
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700288 *
289 * @crtc: CRTC associated with the new screen
290 *
291 * This is called after a mode set has been completed.
292 */
Laurent Pinchart0b20a0f2017-06-30 12:36:44 +0300293static void vmw_sou_crtc_atomic_enable(struct drm_crtc *crtc,
294 struct drm_crtc_state *old_state)
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700295{
296}
297
298/**
Laurent Pinchart64581712017-06-30 12:36:45 +0300299 * vmw_sou_crtc_atomic_disable - Turns off CRTC
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700300 *
301 * @crtc: CRTC to be turned off
302 */
Laurent Pinchart64581712017-06-30 12:36:45 +0300303static void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc,
304 struct drm_crtc_state *old_state)
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700305{
306 struct vmw_private *dev_priv;
307 struct vmw_screen_object_unit *sou;
308 int ret;
309
310
311 if (!crtc) {
312 DRM_ERROR("CRTC is NULL\n");
313 return;
314 }
315
316 sou = vmw_crtc_to_sou(crtc);
317 dev_priv = vmw_priv(crtc->dev);
318
319 if (sou->defined) {
320 ret = vmw_sou_fifo_destroy(dev_priv, sou);
321 if (ret)
322 DRM_ERROR("Failed to destroy Screen Object\n");
323 }
324}
325
Sinclair Yehc8261a92015-06-26 01:23:42 -0700326static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc,
Sinclair Yehb0119cb2017-03-23 14:38:18 -0700327 struct drm_framebuffer *new_fb,
Sinclair Yehc8261a92015-06-26 01:23:42 -0700328 struct drm_pending_vblank_event *event,
Daniel Vetter41292b1f2017-03-22 22:50:50 +0100329 uint32_t flags,
330 struct drm_modeset_acquire_ctx *ctx)
Sinclair Yehc8261a92015-06-26 01:23:42 -0700331{
332 struct vmw_private *dev_priv = vmw_priv(crtc->dev);
Sinclair Yehc8261a92015-06-26 01:23:42 -0700333 int ret;
334
Thomas Hellstrom75c06852016-02-12 09:00:26 +0100335 if (!vmw_kms_crtc_flippable(dev_priv, crtc))
Sinclair Yehc8261a92015-06-26 01:23:42 -0700336 return -EINVAL;
337
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100338 ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx);
Sinclair Yehb0119cb2017-03-23 14:38:18 -0700339 if (ret) {
340 DRM_ERROR("Page flip error %d.\n", ret);
341 return ret;
342 }
Sinclair Yehc8261a92015-06-26 01:23:42 -0700343
Sinclair Yehc8261a92015-06-26 01:23:42 -0700344 if (vmw_crtc_to_du(crtc)->is_implicit)
Thomas Hellstrom75c06852016-02-12 09:00:26 +0100345 vmw_kms_update_implicit_fb(dev_priv, crtc);
Sinclair Yehc8261a92015-06-26 01:23:42 -0700346
347 return ret;
Sinclair Yehc8261a92015-06-26 01:23:42 -0700348}
349
Ville Syrjäläd7955fc2015-12-15 12:21:15 +0100350static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200351 .gamma_set = vmw_du_crtc_gamma_set,
352 .destroy = vmw_sou_crtc_destroy,
Sinclair Yeh9c2542a2017-03-23 11:33:39 -0700353 .reset = vmw_du_crtc_reset,
354 .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
355 .atomic_destroy_state = vmw_du_crtc_destroy_state,
Deepak Rawatb4fa61b2018-09-26 17:17:33 -0700356 .set_config = drm_atomic_helper_set_config,
Sinclair Yehc8261a92015-06-26 01:23:42 -0700357 .page_flip = vmw_sou_crtc_page_flip,
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200358};
359
360/*
361 * Screen Object Display Unit encoder functions
362 */
363
364static void vmw_sou_encoder_destroy(struct drm_encoder *encoder)
365{
366 vmw_sou_destroy(vmw_encoder_to_sou(encoder));
367}
368
Ville Syrjäläd7955fc2015-12-15 12:21:15 +0100369static const struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200370 .destroy = vmw_sou_encoder_destroy,
371};
372
373/*
374 * Screen Object Display Unit connector functions
375 */
376
377static void vmw_sou_connector_destroy(struct drm_connector *connector)
378{
379 vmw_sou_destroy(vmw_connector_to_sou(connector));
380}
381
Ville Syrjäläd7955fc2015-12-15 12:21:15 +0100382static const struct drm_connector_funcs vmw_sou_connector_funcs = {
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200383 .dpms = vmw_du_connector_dpms,
Thierry Redingd17e67d2016-03-07 18:06:01 +0100384 .detect = vmw_du_connector_detect,
385 .fill_modes = vmw_du_connector_fill_modes,
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200386 .set_property = vmw_du_connector_set_property,
387 .destroy = vmw_sou_connector_destroy,
Sinclair Yehd7721ca2017-03-23 11:48:44 -0700388 .reset = vmw_du_connector_reset,
Rob Clark8a510a52018-01-17 10:16:20 -0500389 .atomic_duplicate_state = vmw_du_connector_duplicate_state,
390 .atomic_destroy_state = vmw_du_connector_destroy_state,
Sinclair Yehd7721ca2017-03-23 11:48:44 -0700391 .atomic_set_property = vmw_du_connector_atomic_set_property,
392 .atomic_get_property = vmw_du_connector_atomic_get_property,
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200393};
394
Sinclair Yehd947d1b2017-03-23 14:23:20 -0700395
396static const struct
397drm_connector_helper_funcs vmw_sou_connector_helper_funcs = {
Sinclair Yehd947d1b2017-03-23 14:23:20 -0700398};
399
400
401
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700402/*
403 * Screen Object Display Plane Functions
404 */
405
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700406/**
407 * vmw_sou_primary_plane_cleanup_fb - Frees sou backing buffer
408 *
409 * @plane: display plane
410 * @old_state: Contains the FB to clean up
411 *
412 * Unpins the display surface
413 *
414 * Returns 0 on success
415 */
416static void
417vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane,
418 struct drm_plane_state *old_state)
419{
420 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
Thomas Hellstrom20fb5a62018-03-22 10:35:18 +0100421 struct drm_crtc *crtc = plane->state->crtc ?
422 plane->state->crtc : old_state->crtc;
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700423
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200424 if (vps->bo)
425 vmw_bo_unpin(vmw_priv(crtc->dev), vps->bo, false);
426 vmw_bo_unreference(&vps->bo);
427 vps->bo_size = 0;
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700428
429 vmw_du_plane_cleanup_fb(plane, old_state);
430}
431
432
433/**
434 * vmw_sou_primary_plane_prepare_fb - allocate backing buffer
435 *
436 * @plane: display plane
437 * @new_state: info on the new plane state, including the FB
438 *
439 * The SOU backing buffer is our equivalent of the display plane.
440 *
441 * Returns 0 on success
442 */
443static int
444vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
445 struct drm_plane_state *new_state)
446{
447 struct drm_framebuffer *new_fb = new_state->fb;
448 struct drm_crtc *crtc = plane->state->crtc ?: new_state->crtc;
449 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
450 struct vmw_private *dev_priv;
451 size_t size;
452 int ret;
453
454
455 if (!new_fb) {
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200456 vmw_bo_unreference(&vps->bo);
457 vps->bo_size = 0;
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700458
459 return 0;
460 }
461
462 size = new_state->crtc_w * new_state->crtc_h * 4;
Thomas Hellstrom20fb5a62018-03-22 10:35:18 +0100463 dev_priv = vmw_priv(crtc->dev);
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700464
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200465 if (vps->bo) {
466 if (vps->bo_size == size) {
Thomas Hellstrom20fb5a62018-03-22 10:35:18 +0100467 /*
468 * Note that this might temporarily up the pin-count
469 * to 2, until cleanup_fb() is called.
470 */
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200471 return vmw_bo_pin_in_vram(dev_priv, vps->bo,
Thomas Hellstrom20fb5a62018-03-22 10:35:18 +0100472 true);
473 }
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700474
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200475 vmw_bo_unreference(&vps->bo);
476 vps->bo_size = 0;
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700477 }
478
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200479 vps->bo = kzalloc(sizeof(*vps->bo), GFP_KERNEL);
480 if (!vps->bo)
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700481 return -ENOMEM;
482
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700483 vmw_svga_enable(dev_priv);
484
485 /* After we have alloced the backing store might not be able to
486 * resume the overlays, this is preferred to failing to alloc.
487 */
488 vmw_overlay_pause_all(dev_priv);
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200489 ret = vmw_bo_init(dev_priv, vps->bo, size,
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700490 &vmw_vram_ne_placement,
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200491 false, &vmw_bo_bo_free);
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700492 vmw_overlay_resume_all(dev_priv);
Thomas Hellstrom20fb5a62018-03-22 10:35:18 +0100493 if (ret) {
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200494 vps->bo = NULL; /* vmw_bo_init frees on error */
Thomas Hellstrom20fb5a62018-03-22 10:35:18 +0100495 return ret;
496 }
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700497
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200498 vps->bo_size = size;
Deepak Rawat91ba9f282018-05-15 15:39:09 +0200499
Thomas Hellstrom20fb5a62018-03-22 10:35:18 +0100500 /*
501 * TTM already thinks the buffer is pinned, but make sure the
502 * pin_count is upped.
503 */
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200504 return vmw_bo_pin_in_vram(dev_priv, vps->bo, true);
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700505}
506
Deepak Rawat5d35aba2018-08-08 15:02:48 -0700507static uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update,
508 uint32_t num_hits)
509{
510 return sizeof(struct vmw_kms_sou_define_gmrfb) +
511 sizeof(struct vmw_kms_sou_bo_blit) * num_hits;
512}
513
514static uint32_t vmw_sou_bo_define_gmrfb(struct vmw_du_update_plane *update,
515 void *cmd)
516{
517 struct vmw_framebuffer_bo *vfbbo =
518 container_of(update->vfb, typeof(*vfbbo), base);
519 struct vmw_kms_sou_define_gmrfb *gmr = cmd;
520 int depth = update->vfb->base.format->depth;
521
522 /* Emulate RGBA support, contrary to svga_reg.h this is not
523 * supported by hosts. This is only a problem if we are reading
524 * this value later and expecting what we uploaded back.
525 */
526 if (depth == 32)
527 depth = 24;
528
529 gmr->header = SVGA_CMD_DEFINE_GMRFB;
530
531 gmr->body.format.bitsPerPixel = update->vfb->base.format->cpp[0] * 8;
532 gmr->body.format.colorDepth = depth;
533 gmr->body.format.reserved = 0;
534 gmr->body.bytesPerLine = update->vfb->base.pitches[0];
535 vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &gmr->body.ptr);
536
537 return sizeof(*gmr);
538}
539
540static uint32_t vmw_sou_bo_populate_clip(struct vmw_du_update_plane *update,
541 void *cmd, struct drm_rect *clip,
542 uint32_t fb_x, uint32_t fb_y)
543{
544 struct vmw_kms_sou_bo_blit *blit = cmd;
545
546 blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
547 blit->body.destScreenId = update->du->unit;
548 blit->body.srcOrigin.x = fb_x;
549 blit->body.srcOrigin.y = fb_y;
550 blit->body.destRect.left = clip->x1;
551 blit->body.destRect.top = clip->y1;
552 blit->body.destRect.right = clip->x2;
553 blit->body.destRect.bottom = clip->y2;
554
555 return sizeof(*blit);
556}
557
558static uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane *update,
559 void *cmd, struct drm_rect *bb)
560{
561 return 0;
562}
563
564/**
565 * vmw_sou_plane_update_bo - Update display unit for bo backed fb.
566 * @dev_priv: Device private.
567 * @plane: Plane state.
568 * @old_state: Old plane state.
569 * @vfb: Framebuffer which is blitted to display unit.
570 * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
571 * The returned fence pointer may be NULL in which case the device
572 * has already synchronized.
573 *
574 * Return: 0 on success or a negative error code on failure.
575 */
576static int vmw_sou_plane_update_bo(struct vmw_private *dev_priv,
577 struct drm_plane *plane,
578 struct drm_plane_state *old_state,
579 struct vmw_framebuffer *vfb,
580 struct vmw_fence_obj **out_fence)
581{
582 struct vmw_du_update_plane_buffer bo_update;
583
584 memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
585 bo_update.base.plane = plane;
586 bo_update.base.old_state = old_state;
587 bo_update.base.dev_priv = dev_priv;
588 bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
589 bo_update.base.vfb = vfb;
590 bo_update.base.out_fence = out_fence;
591 bo_update.base.mutex = NULL;
592 bo_update.base.cpu_blit = false;
593 bo_update.base.intr = true;
594
595 bo_update.base.calc_fifo_size = vmw_sou_bo_fifo_size;
596 bo_update.base.post_prepare = vmw_sou_bo_define_gmrfb;
597 bo_update.base.clip = vmw_sou_bo_populate_clip;
598 bo_update.base.post_clip = vmw_stud_bo_post_clip;
599
600 return vmw_du_helper_plane_update(&bo_update.base);
601}
602
Deepak Rawat43d1e622018-08-08 12:39:31 -0700603static uint32_t vmw_sou_surface_fifo_size(struct vmw_du_update_plane *update,
604 uint32_t num_hits)
605{
606 return sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) *
607 num_hits;
608}
609
610static uint32_t vmw_sou_surface_post_prepare(struct vmw_du_update_plane *update,
611 void *cmd)
612{
613 struct vmw_du_update_plane_surface *srf_update;
614
615 srf_update = container_of(update, typeof(*srf_update), base);
616
617 /*
618 * SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that
619 * its bounding box is filled before iterating over all the clips. So
620 * store the FIFO start address and revisit to fill the details.
621 */
622 srf_update->cmd_start = cmd;
623
624 return 0;
625}
626
627static uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update,
628 void *cmd, uint32_t num_hits)
629{
630 struct vmw_kms_sou_dirty_cmd *blit = cmd;
631 struct vmw_framebuffer_surface *vfbs;
632
633 vfbs = container_of(update->vfb, typeof(*vfbs), base);
634
635 blit->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN;
636 blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) *
637 num_hits;
638
639 blit->body.srcImage.sid = vfbs->surface->res.id;
640 blit->body.destScreenId = update->du->unit;
641
642 /* Update the source and destination bounding box later in post_clip */
643 blit->body.srcRect.left = 0;
644 blit->body.srcRect.top = 0;
645 blit->body.srcRect.right = 0;
646 blit->body.srcRect.bottom = 0;
647
648 blit->body.destRect.left = 0;
649 blit->body.destRect.top = 0;
650 blit->body.destRect.right = 0;
651 blit->body.destRect.bottom = 0;
652
653 return sizeof(*blit);
654}
655
656static uint32_t vmw_sou_surface_clip_rect(struct vmw_du_update_plane *update,
657 void *cmd, struct drm_rect *clip,
658 uint32_t src_x, uint32_t src_y)
659{
660 SVGASignedRect *rect = cmd;
661
662 /*
663 * rects are relative to dest bounding box rect on screen object, so
664 * translate to it later in post_clip
665 */
666 rect->left = clip->x1;
667 rect->top = clip->y1;
668 rect->right = clip->x2;
669 rect->bottom = clip->y2;
670
671 return sizeof(*rect);
672}
673
674static uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update,
675 void *cmd, struct drm_rect *bb)
676{
677 struct vmw_du_update_plane_surface *srf_update;
678 struct drm_plane_state *state = update->plane->state;
679 struct drm_rect src_bb;
680 struct vmw_kms_sou_dirty_cmd *blit;
681 SVGASignedRect *rect;
682 uint32_t num_hits;
683 int translate_src_x;
684 int translate_src_y;
685 int i;
686
687 srf_update = container_of(update, typeof(*srf_update), base);
688
689 blit = srf_update->cmd_start;
690 rect = (SVGASignedRect *)&blit[1];
691
692 num_hits = (blit->header.size - sizeof(blit->body))/
693 sizeof(SVGASignedRect);
694
695 src_bb = *bb;
696
697 /* To translate bb back to fb src coord */
698 translate_src_x = (state->src_x >> 16) - state->crtc_x;
699 translate_src_y = (state->src_y >> 16) - state->crtc_y;
700
701 drm_rect_translate(&src_bb, translate_src_x, translate_src_y);
702
703 blit->body.srcRect.left = src_bb.x1;
704 blit->body.srcRect.top = src_bb.y1;
705 blit->body.srcRect.right = src_bb.x2;
706 blit->body.srcRect.bottom = src_bb.y2;
707
708 blit->body.destRect.left = bb->x1;
709 blit->body.destRect.top = bb->y1;
710 blit->body.destRect.right = bb->x2;
711 blit->body.destRect.bottom = bb->y2;
712
713 /* rects are relative to dest bb rect */
714 for (i = 0; i < num_hits; i++) {
715 rect->left -= bb->x1;
716 rect->top -= bb->y1;
717 rect->right -= bb->x1;
718 rect->bottom -= bb->y1;
719 rect++;
720 }
721
722 return 0;
723}
724
725/**
726 * vmw_sou_plane_update_surface - Update display unit for surface backed fb.
727 * @dev_priv: Device private.
728 * @plane: Plane state.
729 * @old_state: Old plane state.
730 * @vfb: Framebuffer which is blitted to display unit
731 * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
732 * The returned fence pointer may be NULL in which case the device
733 * has already synchronized.
734 *
735 * Return: 0 on success or a negative error code on failure.
736 */
737static int vmw_sou_plane_update_surface(struct vmw_private *dev_priv,
738 struct drm_plane *plane,
739 struct drm_plane_state *old_state,
740 struct vmw_framebuffer *vfb,
741 struct vmw_fence_obj **out_fence)
742{
743 struct vmw_du_update_plane_surface srf_update;
744
745 memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface));
746 srf_update.base.plane = plane;
747 srf_update.base.old_state = old_state;
748 srf_update.base.dev_priv = dev_priv;
749 srf_update.base.du = vmw_crtc_to_du(plane->state->crtc);
750 srf_update.base.vfb = vfb;
751 srf_update.base.out_fence = out_fence;
752 srf_update.base.mutex = &dev_priv->cmdbuf_mutex;
753 srf_update.base.cpu_blit = false;
754 srf_update.base.intr = true;
755
756 srf_update.base.calc_fifo_size = vmw_sou_surface_fifo_size;
757 srf_update.base.post_prepare = vmw_sou_surface_post_prepare;
758 srf_update.base.pre_clip = vmw_sou_surface_pre_clip;
759 srf_update.base.clip = vmw_sou_surface_clip_rect;
760 srf_update.base.post_clip = vmw_sou_surface_post_clip;
761
762 return vmw_du_helper_plane_update(&srf_update.base);
763}
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700764
765static void
766vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
767 struct drm_plane_state *old_state)
768{
Sinclair Yehb0119cb2017-03-23 14:38:18 -0700769 struct drm_crtc *crtc = plane->state->crtc;
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100770 struct drm_pending_vblank_event *event = NULL;
771 struct vmw_fence_obj *fence = NULL;
772 int ret;
Sinclair Yehb0119cb2017-03-23 14:38:18 -0700773
Deepak Rawat31da2df2018-09-21 14:10:35 -0700774 /* In case of device error, maintain consistent atomic state */
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100775 if (crtc && plane->state->fb) {
776 struct vmw_private *dev_priv = vmw_priv(crtc->dev);
777 struct vmw_framebuffer *vfb =
778 vmw_framebuffer_to_vfb(plane->state->fb);
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100779
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +0200780 if (vfb->bo)
Deepak Rawat67a51b32018-09-21 14:07:33 -0700781 ret = vmw_sou_plane_update_bo(dev_priv, plane,
782 old_state, vfb, &fence);
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100783 else
Deepak Rawat67a51b32018-09-21 14:07:33 -0700784 ret = vmw_sou_plane_update_surface(dev_priv, plane,
785 old_state, vfb,
786 &fence);
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100787 if (ret != 0)
788 DRM_ERROR("Failed to update screen.\n");
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100789 } else {
Deepak Rawat31da2df2018-09-21 14:10:35 -0700790 /* Do nothing when fb and crtc is NULL (blank crtc) */
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100791 return;
792 }
793
Deepak Rawat31da2df2018-09-21 14:10:35 -0700794 /* For error case vblank event is send from vmw_du_crtc_atomic_flush */
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100795 event = crtc->state->event;
Deepak Rawataa64b3f2018-01-16 08:31:04 +0100796 if (event && fence) {
797 struct drm_file *file_priv = event->base.file_priv;
798
799 ret = vmw_event_fence_action_queue(file_priv,
800 fence,
801 &event->base,
802 &event->event.vbl.tv_sec,
803 &event->event.vbl.tv_usec,
804 true);
805
806 if (unlikely(ret != 0))
807 DRM_ERROR("Failed to queue event on fence.\n");
808 else
809 crtc->state->event = NULL;
810 }
811
812 if (fence)
813 vmw_fence_obj_unreference(&fence);
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700814}
815
816
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700817static const struct drm_plane_funcs vmw_sou_plane_funcs = {
Sinclair Yehb0119cb2017-03-23 14:38:18 -0700818 .update_plane = drm_atomic_helper_update_plane,
819 .disable_plane = drm_atomic_helper_disable_plane,
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700820 .destroy = vmw_du_primary_plane_destroy,
Sinclair Yehcc5ec452017-03-23 11:36:05 -0700821 .reset = vmw_du_plane_reset,
822 .atomic_duplicate_state = vmw_du_plane_duplicate_state,
823 .atomic_destroy_state = vmw_du_plane_destroy_state,
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700824};
825
826static const struct drm_plane_funcs vmw_sou_cursor_funcs = {
Sinclair Yehb0119cb2017-03-23 14:38:18 -0700827 .update_plane = drm_atomic_helper_update_plane,
828 .disable_plane = drm_atomic_helper_disable_plane,
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700829 .destroy = vmw_du_cursor_plane_destroy,
Sinclair Yehcc5ec452017-03-23 11:36:05 -0700830 .reset = vmw_du_plane_reset,
831 .atomic_duplicate_state = vmw_du_plane_duplicate_state,
832 .atomic_destroy_state = vmw_du_plane_destroy_state,
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700833};
834
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700835/*
836 * Atomic Helpers
837 */
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700838static const struct
839drm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = {
840 .atomic_check = vmw_du_cursor_plane_atomic_check,
841 .atomic_update = vmw_du_cursor_plane_atomic_update,
842 .prepare_fb = vmw_du_cursor_plane_prepare_fb,
843 .cleanup_fb = vmw_du_plane_cleanup_fb,
844};
845
846static const struct
847drm_plane_helper_funcs vmw_sou_primary_plane_helper_funcs = {
848 .atomic_check = vmw_du_primary_plane_atomic_check,
849 .atomic_update = vmw_sou_primary_plane_atomic_update,
850 .prepare_fb = vmw_sou_primary_plane_prepare_fb,
851 .cleanup_fb = vmw_sou_primary_plane_cleanup_fb,
852};
853
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700854static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = {
855 .prepare = vmw_sou_crtc_helper_prepare,
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700856 .mode_set_nofb = vmw_sou_crtc_mode_set_nofb,
857 .atomic_check = vmw_du_crtc_atomic_check,
858 .atomic_begin = vmw_du_crtc_atomic_begin,
859 .atomic_flush = vmw_du_crtc_atomic_flush,
Laurent Pinchart0b20a0f2017-06-30 12:36:44 +0300860 .atomic_enable = vmw_sou_crtc_atomic_enable,
Laurent Pinchart64581712017-06-30 12:36:45 +0300861 .atomic_disable = vmw_sou_crtc_atomic_disable,
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700862};
863
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700864
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200865static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
866{
867 struct vmw_screen_object_unit *sou;
868 struct drm_device *dev = dev_priv->dev;
869 struct drm_connector *connector;
870 struct drm_encoder *encoder;
Sinclair Yehcc5ec452017-03-23 11:36:05 -0700871 struct drm_plane *primary, *cursor;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200872 struct drm_crtc *crtc;
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700873 int ret;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200874
875 sou = kzalloc(sizeof(*sou), GFP_KERNEL);
876 if (!sou)
877 return -ENOMEM;
878
879 sou->base.unit = unit;
880 crtc = &sou->base.crtc;
881 encoder = &sou->base.encoder;
882 connector = &sou->base.connector;
Sinclair Yehcc5ec452017-03-23 11:36:05 -0700883 primary = &sou->base.primary;
884 cursor = &sou->base.cursor;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200885
Thomas Hellstrom75c06852016-02-12 09:00:26 +0100886 sou->base.active_implicit = false;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200887 sou->base.pref_active = (unit == 0);
Jakob Bornecrantzeb4f9232012-02-09 16:56:46 +0100888 sou->base.pref_width = dev_priv->initial_width;
889 sou->base.pref_height = dev_priv->initial_height;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200890 sou->base.pref_mode = NULL;
Sinclair Yeh9c2542a2017-03-23 11:33:39 -0700891
892 /*
893 * Remove this after enabling atomic because property values can
894 * only exist in a state object
895 */
Thomas Hellstrom2e69b252016-02-12 09:59:50 +0100896 sou->base.is_implicit = false;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200897
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700898 /* Initialize primary plane */
Sinclair Yehcc5ec452017-03-23 11:36:05 -0700899 vmw_du_plane_reset(primary);
900
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700901 ret = drm_universal_plane_init(dev, &sou->base.primary,
902 0, &vmw_sou_plane_funcs,
903 vmw_primary_plane_formats,
904 ARRAY_SIZE(vmw_primary_plane_formats),
Ben Widawskye6fc3b62017-07-23 20:46:38 -0700905 NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700906 if (ret) {
907 DRM_ERROR("Failed to initialize primary plane");
908 goto err_free;
909 }
910
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700911 drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs);
Deepak Rawat61c21382018-08-08 15:41:56 -0700912 drm_plane_enable_fb_damage_clips(primary);
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700913
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700914 /* Initialize cursor plane */
Sinclair Yehcc5ec452017-03-23 11:36:05 -0700915 vmw_du_plane_reset(cursor);
916
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700917 ret = drm_universal_plane_init(dev, &sou->base.cursor,
918 0, &vmw_sou_cursor_funcs,
919 vmw_cursor_plane_formats,
920 ARRAY_SIZE(vmw_cursor_plane_formats),
Ben Widawskye6fc3b62017-07-23 20:46:38 -0700921 NULL, DRM_PLANE_TYPE_CURSOR, NULL);
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700922 if (ret) {
923 DRM_ERROR("Failed to initialize cursor plane");
924 drm_plane_cleanup(&sou->base.primary);
925 goto err_free;
926 }
927
Sinclair Yeh060e2ad2017-03-23 14:18:32 -0700928 drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs);
929
930 vmw_du_connector_reset(connector);
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700931 ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
932 DRM_MODE_CONNECTOR_VIRTUAL);
933 if (ret) {
934 DRM_ERROR("Failed to initialize connector\n");
935 goto err_free;
936 }
937
Sinclair Yehd947d1b2017-03-23 14:23:20 -0700938 drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs);
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200939 connector->status = vmw_du_connector_detect(connector, true);
Sinclair Yehd7721ca2017-03-23 11:48:44 -0700940 vmw_connector_state_to_vcs(connector->state)->is_implicit = false;
941
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200942
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700943 ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
944 DRM_MODE_ENCODER_VIRTUAL, NULL);
945 if (ret) {
946 DRM_ERROR("Failed to initialize encoder\n");
947 goto err_free_connector;
948 }
949
Daniel Vettercde4c442018-07-09 10:40:07 +0200950 (void) drm_connector_attach_encoder(connector, encoder);
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200951 encoder->possible_crtcs = (1 << unit);
952 encoder->possible_clones = 0;
953
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700954 ret = drm_connector_register(connector);
955 if (ret) {
956 DRM_ERROR("Failed to register connector\n");
957 goto err_free_encoder;
958 }
Thomas Hellstrom6a0a7a92013-12-02 06:04:38 -0800959
Sinclair Yehd7721ca2017-03-23 11:48:44 -0700960
961 vmw_du_crtc_reset(crtc);
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700962 ret = drm_crtc_init_with_planes(dev, crtc, &sou->base.primary,
963 &sou->base.cursor,
964 &vmw_screen_object_crtc_funcs, NULL);
965 if (ret) {
966 DRM_ERROR("Failed to initialize CRTC\n");
967 goto err_free_unregister;
968 }
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200969
Sinclair Yeh06ec4192017-03-23 13:14:54 -0700970 drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs);
971
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200972 drm_mode_crtc_set_gamma_size(crtc, 256);
973
Rob Clarkb8b163b2012-10-11 20:47:14 -0500974 drm_object_attach_property(&connector->base,
Thomas Hellstrom578e6092016-02-12 09:45:42 +0100975 dev_priv->hotplug_mode_update_property, 1);
976 drm_object_attach_property(&connector->base,
977 dev->mode_config.suggested_x_property, 0);
978 drm_object_attach_property(&connector->base,
979 dev->mode_config.suggested_y_property, 0);
Thomas Hellstrom76404ac2016-02-12 09:55:45 +0100980 if (dev_priv->implicit_placement_property)
981 drm_object_attach_property
982 (&connector->base,
983 dev_priv->implicit_placement_property,
984 sou->base.is_implicit);
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200985
986 return 0;
Sinclair Yeh36cc79b2017-03-23 11:28:11 -0700987
988err_free_unregister:
989 drm_connector_unregister(connector);
990err_free_encoder:
991 drm_encoder_cleanup(encoder);
992err_free_connector:
993 drm_connector_cleanup(connector);
994err_free:
995 kfree(sou);
996 return ret;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +0200997}
998
Sinclair Yehc8261a92015-06-26 01:23:42 -0700999int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02001000{
1001 struct drm_device *dev = dev_priv->dev;
Jakob Bornecrantz74b5ea32011-10-17 11:59:44 +02001002 int i, ret;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02001003
Thomas Hellstrom29a16e92012-11-09 12:26:13 +00001004 if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) {
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02001005 DRM_INFO("Not using screen objects,"
1006 " missing cap SCREEN_OBJECT_2\n");
1007 return -ENOSYS;
1008 }
1009
1010 ret = -ENOMEM;
Thomas Hellstrom75c06852016-02-12 09:00:26 +01001011 dev_priv->num_implicit = 0;
1012 dev_priv->implicit_fb = NULL;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02001013
1014 ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
1015 if (unlikely(ret != 0))
Thomas Hellstrom75c06852016-02-12 09:00:26 +01001016 return ret;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02001017
Thomas Hellstrom76404ac2016-02-12 09:55:45 +01001018 vmw_kms_create_implicit_placement_property(dev_priv, false);
1019
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02001020 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
1021 vmw_sou_init(dev_priv, i);
1022
Sinclair Yehc8261a92015-06-26 01:23:42 -07001023 dev_priv->active_display_unit = vmw_du_screen_object;
1024
1025 DRM_INFO("Screen Objects Display Unit initialized\n");
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02001026
1027 return 0;
Jakob Bornecrantz56d1c782011-10-04 20:13:22 +02001028}
1029
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001030static int do_bo_define_gmrfb(struct vmw_private *dev_priv,
Sinclair Yehc8261a92015-06-26 01:23:42 -07001031 struct vmw_framebuffer *framebuffer)
Jakob Bornecrantzb5ec4272012-02-09 16:56:45 +01001032{
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001033 struct vmw_buffer_object *buf =
1034 container_of(framebuffer, struct vmw_framebuffer_bo,
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001035 base)->buffer;
Ville Syrjäläb00c6002016-12-14 23:31:35 +02001036 int depth = framebuffer->base.format->depth;
Sinclair Yehc8261a92015-06-26 01:23:42 -07001037 struct {
1038 uint32_t header;
1039 SVGAFifoCmdDefineGMRFB body;
1040 } *cmd;
Jakob Bornecrantzb5ec4272012-02-09 16:56:45 +01001041
Sinclair Yehc8261a92015-06-26 01:23:42 -07001042 /* Emulate RGBA support, contrary to svga_reg.h this is not
1043 * supported by hosts. This is only a problem if we are reading
1044 * this value later and expecting what we uploaded back.
1045 */
1046 if (depth == 32)
1047 depth = 24;
Jakob Bornecrantzb5ec4272012-02-09 16:56:45 +01001048
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001049 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
1050 if (!cmd) {
1051 DRM_ERROR("Out of fifo space for dirty framebuffer command.\n");
Sinclair Yehc8261a92015-06-26 01:23:42 -07001052 return -ENOMEM;
1053 }
1054
Sinclair Yehc8261a92015-06-26 01:23:42 -07001055 cmd->header = SVGA_CMD_DEFINE_GMRFB;
Ville Syrjälä272725c2016-12-14 23:32:20 +02001056 cmd->body.format.bitsPerPixel = framebuffer->base.format->cpp[0] * 8;
Sinclair Yehc8261a92015-06-26 01:23:42 -07001057 cmd->body.format.colorDepth = depth;
1058 cmd->body.format.reserved = 0;
1059 cmd->body.bytesPerLine = framebuffer->base.pitches[0];
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001060 /* Buffer is reserved in vram or GMR */
1061 vmw_bo_get_guest_ptr(&buf->base, &cmd->body.ptr);
1062 vmw_fifo_commit(dev_priv, sizeof(*cmd));
Sinclair Yehc8261a92015-06-26 01:23:42 -07001063
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001064 return 0;
1065}
Sinclair Yehc8261a92015-06-26 01:23:42 -07001066
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001067/**
1068 * vmw_sou_surface_fifo_commit - Callback to fill in and submit a
1069 * blit surface to screen command.
1070 *
1071 * @dirty: The closure structure.
1072 *
1073 * Fills in the missing fields in the command, and translates the cliprects
1074 * to match the destination bounding box encoded.
1075 */
1076static void vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty)
1077{
1078 struct vmw_kms_sou_surface_dirty *sdirty =
1079 container_of(dirty, typeof(*sdirty), base);
1080 struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd;
1081 s32 trans_x = dirty->unit->crtc.x - sdirty->dst_x;
1082 s32 trans_y = dirty->unit->crtc.y - sdirty->dst_y;
1083 size_t region_size = dirty->num_hits * sizeof(SVGASignedRect);
1084 SVGASignedRect *blit = (SVGASignedRect *) &cmd[1];
1085 int i;
1086
Thomas Hellstromfea7dd542016-02-12 08:26:37 +01001087 if (!dirty->num_hits) {
1088 vmw_fifo_commit(dirty->dev_priv, 0);
1089 return;
1090 }
1091
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001092 cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN;
1093 cmd->header.size = sizeof(cmd->body) + region_size;
1094
1095 /*
1096 * Use the destination bounding box to specify destination - and
1097 * source bounding regions.
1098 */
1099 cmd->body.destRect.left = sdirty->left;
1100 cmd->body.destRect.right = sdirty->right;
1101 cmd->body.destRect.top = sdirty->top;
1102 cmd->body.destRect.bottom = sdirty->bottom;
1103
1104 cmd->body.srcRect.left = sdirty->left + trans_x;
1105 cmd->body.srcRect.right = sdirty->right + trans_x;
1106 cmd->body.srcRect.top = sdirty->top + trans_y;
1107 cmd->body.srcRect.bottom = sdirty->bottom + trans_y;
1108
1109 cmd->body.srcImage.sid = sdirty->sid;
1110 cmd->body.destScreenId = dirty->unit->unit;
1111
1112 /* Blits are relative to the destination rect. Translate. */
1113 for (i = 0; i < dirty->num_hits; ++i, ++blit) {
1114 blit->left -= sdirty->left;
1115 blit->right -= sdirty->left;
1116 blit->top -= sdirty->top;
1117 blit->bottom -= sdirty->top;
1118 }
1119
1120 vmw_fifo_commit(dirty->dev_priv, region_size + sizeof(*cmd));
1121
1122 sdirty->left = sdirty->top = S32_MAX;
1123 sdirty->right = sdirty->bottom = S32_MIN;
1124}
1125
1126/**
1127 * vmw_sou_surface_clip - Callback to encode a blit surface to screen cliprect.
1128 *
1129 * @dirty: The closure structure
1130 *
1131 * Encodes a SVGASignedRect cliprect and updates the bounding box of the
1132 * BLIT_SURFACE_TO_SCREEN command.
1133 */
1134static void vmw_sou_surface_clip(struct vmw_kms_dirty *dirty)
1135{
1136 struct vmw_kms_sou_surface_dirty *sdirty =
1137 container_of(dirty, typeof(*sdirty), base);
1138 struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd;
1139 SVGASignedRect *blit = (SVGASignedRect *) &cmd[1];
1140
1141 /* Destination rect. */
1142 blit += dirty->num_hits;
1143 blit->left = dirty->unit_x1;
1144 blit->top = dirty->unit_y1;
1145 blit->right = dirty->unit_x2;
1146 blit->bottom = dirty->unit_y2;
1147
1148 /* Destination bounding box */
1149 sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1);
1150 sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1);
1151 sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2);
1152 sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2);
1153
1154 dirty->num_hits++;
1155}
1156
1157/**
1158 * vmw_kms_sou_do_surface_dirty - Dirty part of a surface backed framebuffer
1159 *
1160 * @dev_priv: Pointer to the device private structure.
1161 * @framebuffer: Pointer to the surface-buffer backed framebuffer.
1162 * @clips: Array of clip rects. Either @clips or @vclips must be NULL.
1163 * @vclips: Alternate array of clip rects. Either @clips or @vclips must
1164 * be NULL.
1165 * @srf: Pointer to surface to blit from. If NULL, the surface attached
1166 * to @framebuffer will be used.
1167 * @dest_x: X coordinate offset to align @srf with framebuffer coordinates.
1168 * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates.
1169 * @num_clips: Number of clip rects in @clips.
1170 * @inc: Increment to use when looping over @clips.
1171 * @out_fence: If non-NULL, will return a ref-counted pointer to a
1172 * struct vmw_fence_obj. The returned fence pointer may be NULL in which
1173 * case the device has already synchronized.
Deepak Rawat91e9f352018-01-16 08:24:17 +01001174 * @crtc: If crtc is passed, perform surface dirty on that crtc only.
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001175 *
1176 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
1177 * interrupted.
1178 */
1179int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
1180 struct vmw_framebuffer *framebuffer,
1181 struct drm_clip_rect *clips,
1182 struct drm_vmw_rect *vclips,
1183 struct vmw_resource *srf,
1184 s32 dest_x,
1185 s32 dest_y,
1186 unsigned num_clips, int inc,
Deepak Rawat91e9f352018-01-16 08:24:17 +01001187 struct vmw_fence_obj **out_fence,
1188 struct drm_crtc *crtc)
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001189{
1190 struct vmw_framebuffer_surface *vfbs =
1191 container_of(framebuffer, typeof(*vfbs), base);
1192 struct vmw_kms_sou_surface_dirty sdirty;
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001193 DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001194 int ret;
1195
1196 if (!srf)
1197 srf = &vfbs->surface->res;
1198
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001199 ret = vmw_validation_add_resource(&val_ctx, srf, 0, NULL, NULL);
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001200 if (ret)
1201 return ret;
1202
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001203 ret = vmw_validation_prepare(&val_ctx, &dev_priv->cmdbuf_mutex, true);
1204 if (ret)
1205 goto out_unref;
1206
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001207 sdirty.base.fifo_commit = vmw_sou_surface_fifo_commit;
1208 sdirty.base.clip = vmw_sou_surface_clip;
1209 sdirty.base.dev_priv = dev_priv;
1210 sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) +
1211 sizeof(SVGASignedRect) * num_clips;
Deepak Rawat91e9f352018-01-16 08:24:17 +01001212 sdirty.base.crtc = crtc;
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001213
1214 sdirty.sid = srf->id;
1215 sdirty.left = sdirty.top = S32_MAX;
1216 sdirty.right = sdirty.bottom = S32_MIN;
1217 sdirty.dst_x = dest_x;
1218 sdirty.dst_y = dest_y;
1219
1220 ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
1221 dest_x, dest_y, num_clips, inc,
1222 &sdirty.base);
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001223 vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence,
1224 NULL);
Sinclair Yehc8261a92015-06-26 01:23:42 -07001225
1226 return ret;
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001227
1228out_unref:
1229 vmw_validation_unref_lists(&val_ctx);
1230 return ret;
Jakob Bornecrantzb5ec4272012-02-09 16:56:45 +01001231}
1232
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001233/**
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001234 * vmw_sou_bo_fifo_commit - Callback to submit a set of readback clips.
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001235 *
1236 * @dirty: The closure structure.
1237 *
1238 * Commits a previously built command buffer of readback clips.
1239 */
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001240static void vmw_sou_bo_fifo_commit(struct vmw_kms_dirty *dirty)
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001241{
Thomas Hellstromfea7dd542016-02-12 08:26:37 +01001242 if (!dirty->num_hits) {
1243 vmw_fifo_commit(dirty->dev_priv, 0);
1244 return;
1245 }
1246
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001247 vmw_fifo_commit(dirty->dev_priv,
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001248 sizeof(struct vmw_kms_sou_bo_blit) *
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001249 dirty->num_hits);
1250}
1251
1252/**
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001253 * vmw_sou_bo_clip - Callback to encode a readback cliprect.
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001254 *
1255 * @dirty: The closure structure
1256 *
1257 * Encodes a BLIT_GMRFB_TO_SCREEN cliprect.
1258 */
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001259static void vmw_sou_bo_clip(struct vmw_kms_dirty *dirty)
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001260{
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001261 struct vmw_kms_sou_bo_blit *blit = dirty->cmd;
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001262
1263 blit += dirty->num_hits;
1264 blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
1265 blit->body.destScreenId = dirty->unit->unit;
1266 blit->body.srcOrigin.x = dirty->fb_x;
1267 blit->body.srcOrigin.y = dirty->fb_y;
1268 blit->body.destRect.left = dirty->unit_x1;
1269 blit->body.destRect.top = dirty->unit_y1;
1270 blit->body.destRect.right = dirty->unit_x2;
1271 blit->body.destRect.bottom = dirty->unit_y2;
1272 dirty->num_hits++;
1273}
1274
1275/**
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001276 * vmw_kms_do_bo_dirty - Dirty part of a buffer-object backed framebuffer
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001277 *
1278 * @dev_priv: Pointer to the device private structure.
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001279 * @framebuffer: Pointer to the buffer-object backed framebuffer.
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001280 * @clips: Array of clip rects.
Thomas Hellstrom897b8182016-02-12 08:32:08 +01001281 * @vclips: Alternate array of clip rects. Either @clips or @vclips must
1282 * be NULL.
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001283 * @num_clips: Number of clip rects in @clips.
1284 * @increment: Increment to use when looping over @clips.
1285 * @interruptible: Whether to perform waits interruptible if possible.
1286 * @out_fence: If non-NULL, will return a ref-counted pointer to a
1287 * struct vmw_fence_obj. The returned fence pointer may be NULL in which
1288 * case the device has already synchronized.
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001289 * @crtc: If crtc is passed, perform bo dirty on that crtc only.
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001290 *
1291 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
1292 * interrupted.
1293 */
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001294int vmw_kms_sou_do_bo_dirty(struct vmw_private *dev_priv,
Sinclair Yehc8261a92015-06-26 01:23:42 -07001295 struct vmw_framebuffer *framebuffer,
Sinclair Yehc8261a92015-06-26 01:23:42 -07001296 struct drm_clip_rect *clips,
Thomas Hellstrom897b8182016-02-12 08:32:08 +01001297 struct drm_vmw_rect *vclips,
Sinclair Yehc8261a92015-06-26 01:23:42 -07001298 unsigned num_clips, int increment,
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001299 bool interruptible,
Deepak Rawat91e9f352018-01-16 08:24:17 +01001300 struct vmw_fence_obj **out_fence,
1301 struct drm_crtc *crtc)
Jakob Bornecrantzb5ec4272012-02-09 16:56:45 +01001302{
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001303 struct vmw_buffer_object *buf =
1304 container_of(framebuffer, struct vmw_framebuffer_bo,
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001305 base)->buffer;
1306 struct vmw_kms_dirty dirty;
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001307 DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001308 int ret;
Jakob Bornecrantzb5ec4272012-02-09 16:56:45 +01001309
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001310 ret = vmw_validation_add_bo(&val_ctx, buf, false, false);
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001311 if (ret)
1312 return ret;
Jakob Bornecrantzb5ec4272012-02-09 16:56:45 +01001313
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001314 ret = vmw_validation_prepare(&val_ctx, NULL, interruptible);
1315 if (ret)
1316 goto out_unref;
1317
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001318 ret = do_bo_define_gmrfb(dev_priv, framebuffer);
Sinclair Yehc8261a92015-06-26 01:23:42 -07001319 if (unlikely(ret != 0))
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001320 goto out_revert;
Sinclair Yehc8261a92015-06-26 01:23:42 -07001321
Deepak Rawat91e9f352018-01-16 08:24:17 +01001322 dirty.crtc = crtc;
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001323 dirty.fifo_commit = vmw_sou_bo_fifo_commit;
1324 dirty.clip = vmw_sou_bo_clip;
1325 dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_bo_blit) *
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001326 num_clips;
Thomas Hellstrom897b8182016-02-12 08:32:08 +01001327 ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001328 0, 0, num_clips, increment, &dirty);
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001329 vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence,
1330 NULL);
Sinclair Yehc8261a92015-06-26 01:23:42 -07001331
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001332 return ret;
Sinclair Yehc8261a92015-06-26 01:23:42 -07001333
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001334out_revert:
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001335 vmw_validation_revert(&val_ctx);
1336out_unref:
1337 vmw_validation_unref_lists(&val_ctx);
Sinclair Yehc8261a92015-06-26 01:23:42 -07001338
1339 return ret;
Jakob Bornecrantzb5ec4272012-02-09 16:56:45 +01001340}
Sinclair Yehc8261a92015-06-26 01:23:42 -07001341
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001342
1343/**
1344 * vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips.
1345 *
1346 * @dirty: The closure structure.
1347 *
1348 * Commits a previously built command buffer of readback clips.
1349 */
1350static void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty)
1351{
Thomas Hellstromfea7dd542016-02-12 08:26:37 +01001352 if (!dirty->num_hits) {
1353 vmw_fifo_commit(dirty->dev_priv, 0);
1354 return;
1355 }
1356
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001357 vmw_fifo_commit(dirty->dev_priv,
1358 sizeof(struct vmw_kms_sou_readback_blit) *
1359 dirty->num_hits);
1360}
1361
1362/**
1363 * vmw_sou_readback_clip - Callback to encode a readback cliprect.
1364 *
1365 * @dirty: The closure structure
1366 *
1367 * Encodes a BLIT_SCREEN_TO_GMRFB cliprect.
1368 */
1369static void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty)
1370{
1371 struct vmw_kms_sou_readback_blit *blit = dirty->cmd;
1372
1373 blit += dirty->num_hits;
1374 blit->header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB;
1375 blit->body.srcScreenId = dirty->unit->unit;
1376 blit->body.destOrigin.x = dirty->fb_x;
1377 blit->body.destOrigin.y = dirty->fb_y;
1378 blit->body.srcRect.left = dirty->unit_x1;
1379 blit->body.srcRect.top = dirty->unit_y1;
1380 blit->body.srcRect.right = dirty->unit_x2;
1381 blit->body.srcRect.bottom = dirty->unit_y2;
1382 dirty->num_hits++;
1383}
1384
1385/**
1386 * vmw_kms_sou_readback - Perform a readback from the screen object system to
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001387 * a buffer-object backed framebuffer.
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001388 *
1389 * @dev_priv: Pointer to the device private structure.
1390 * @file_priv: Pointer to a struct drm_file identifying the caller.
1391 * Must be set to NULL if @user_fence_rep is NULL.
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001392 * @vfb: Pointer to the buffer-object backed framebuffer.
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001393 * @user_fence_rep: User-space provided structure for fence information.
1394 * Must be set to non-NULL if @file_priv is non-NULL.
1395 * @vclips: Array of clip rects.
1396 * @num_clips: Number of clip rects in @vclips.
Deepak Rawat91e9f352018-01-16 08:24:17 +01001397 * @crtc: If crtc is passed, readback on that crtc only.
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001398 *
1399 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
1400 * interrupted.
1401 */
1402int vmw_kms_sou_readback(struct vmw_private *dev_priv,
1403 struct drm_file *file_priv,
1404 struct vmw_framebuffer *vfb,
1405 struct drm_vmw_fence_rep __user *user_fence_rep,
1406 struct drm_vmw_rect *vclips,
Deepak Rawat91e9f352018-01-16 08:24:17 +01001407 uint32_t num_clips,
1408 struct drm_crtc *crtc)
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001409{
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001410 struct vmw_buffer_object *buf =
1411 container_of(vfb, struct vmw_framebuffer_bo, base)->buffer;
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001412 struct vmw_kms_dirty dirty;
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001413 DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001414 int ret;
1415
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001416 ret = vmw_validation_add_bo(&val_ctx, buf, false, false);
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001417 if (ret)
1418 return ret;
1419
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001420 ret = vmw_validation_prepare(&val_ctx, NULL, true);
1421 if (ret)
1422 goto out_unref;
1423
Thomas Hellstromf1d34bf2018-06-19 15:02:16 +02001424 ret = do_bo_define_gmrfb(dev_priv, vfb);
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001425 if (unlikely(ret != 0))
1426 goto out_revert;
1427
Deepak Rawat91e9f352018-01-16 08:24:17 +01001428 dirty.crtc = crtc;
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001429 dirty.fifo_commit = vmw_sou_readback_fifo_commit;
1430 dirty.clip = vmw_sou_readback_clip;
1431 dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) *
1432 num_clips;
1433 ret = vmw_kms_helper_dirty(dev_priv, vfb, NULL, vclips,
1434 0, 0, num_clips, 1, &dirty);
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001435 vmw_kms_helper_validation_finish(dev_priv, file_priv, &val_ctx, NULL,
1436 user_fence_rep);
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001437
1438 return ret;
1439
1440out_revert:
Thomas Hellstrom2724b2d2018-09-26 15:34:50 +02001441 vmw_validation_revert(&val_ctx);
1442out_unref:
1443 vmw_validation_unref_lists(&val_ctx);
1444
Thomas Hellstrom10b1e0c2015-06-26 02:14:27 -07001445 return ret;
1446}