linux/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR MIT
   2/**************************************************************************
   3 *
   4 * Copyright 2011-2015 VMware, Inc., Palo Alto, CA., USA
   5 *
   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"
  29#include <drm/drm_plane_helper.h>
  30#include <drm/drm_atomic.h>
  31#include <drm/drm_atomic_helper.h>
  32
  33
  34#define vmw_crtc_to_sou(x) \
  35        container_of(x, struct vmw_screen_object_unit, base.crtc)
  36#define vmw_encoder_to_sou(x) \
  37        container_of(x, struct vmw_screen_object_unit, base.encoder)
  38#define vmw_connector_to_sou(x) \
  39        container_of(x, struct vmw_screen_object_unit, base.connector)
  40
  41/**
  42 * struct vmw_kms_sou_surface_dirty - Closure structure for
  43 * blit surface to screen command.
  44 * @base: The base type we derive from. Used by vmw_kms_helper_dirty().
  45 * @left: Left side of bounding box.
  46 * @right: Right side of bounding box.
  47 * @top: Top side of bounding box.
  48 * @bottom: Bottom side of bounding box.
  49 * @dst_x: Difference between source clip rects and framebuffer coordinates.
  50 * @dst_y: Difference between source clip rects and framebuffer coordinates.
  51 * @sid: Surface id of surface to copy from.
  52 */
  53struct vmw_kms_sou_surface_dirty {
  54        struct vmw_kms_dirty base;
  55        s32 left, right, top, bottom;
  56        s32 dst_x, dst_y;
  57        u32 sid;
  58};
  59
  60/*
  61 * SVGA commands that are used by this code. Please see the device headers
  62 * for explanation.
  63 */
  64struct vmw_kms_sou_readback_blit {
  65        uint32 header;
  66        SVGAFifoCmdBlitScreenToGMRFB body;
  67};
  68
  69struct vmw_kms_sou_bo_blit {
  70        uint32 header;
  71        SVGAFifoCmdBlitGMRFBToScreen body;
  72};
  73
  74struct vmw_kms_sou_dirty_cmd {
  75        SVGA3dCmdHeader header;
  76        SVGA3dCmdBlitSurfaceToScreen body;
  77};
  78
  79/**
  80 * Display unit using screen objects.
  81 */
  82struct vmw_screen_object_unit {
  83        struct vmw_display_unit base;
  84
  85        unsigned long buffer_size; /**< Size of allocated buffer */
  86        struct vmw_buffer_object *buffer; /**< Backing store buffer */
  87
  88        bool defined;
  89};
  90
  91static void vmw_sou_destroy(struct vmw_screen_object_unit *sou)
  92{
  93        vmw_du_cleanup(&sou->base);
  94        kfree(sou);
  95}
  96
  97
  98/*
  99 * Screen Object Display Unit CRTC functions
 100 */
 101
 102static void vmw_sou_crtc_destroy(struct drm_crtc *crtc)
 103{
 104        vmw_sou_destroy(vmw_crtc_to_sou(crtc));
 105}
 106
 107/**
 108 * Send the fifo command to create a screen.
 109 */
 110static int vmw_sou_fifo_create(struct vmw_private *dev_priv,
 111                               struct vmw_screen_object_unit *sou,
 112                               int x, int y,
 113                               struct drm_display_mode *mode)
 114{
 115        size_t fifo_size;
 116
 117        struct {
 118                struct {
 119                        uint32_t cmdType;
 120                } header;
 121                SVGAScreenObject obj;
 122        } *cmd;
 123
 124        BUG_ON(!sou->buffer);
 125
 126        fifo_size = sizeof(*cmd);
 127        cmd = vmw_fifo_reserve(dev_priv, fifo_size);
 128        /* The hardware has hung, nothing we can do about it here. */
 129        if (unlikely(cmd == NULL)) {
 130                DRM_ERROR("Fifo reserve failed.\n");
 131                return -ENOMEM;
 132        }
 133
 134        memset(cmd, 0, fifo_size);
 135        cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN;
 136        cmd->obj.structSize = sizeof(SVGAScreenObject);
 137        cmd->obj.id = sou->base.unit;
 138        cmd->obj.flags = SVGA_SCREEN_HAS_ROOT |
 139                (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0);
 140        cmd->obj.size.width = mode->hdisplay;
 141        cmd->obj.size.height = mode->vdisplay;
 142        cmd->obj.root.x = x;
 143        cmd->obj.root.y = y;
 144        sou->base.set_gui_x = cmd->obj.root.x;
 145        sou->base.set_gui_y = cmd->obj.root.y;
 146
 147        /* Ok to assume that buffer is pinned in vram */
 148        vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr);
 149        cmd->obj.backingStore.pitch = mode->hdisplay * 4;
 150
 151        vmw_fifo_commit(dev_priv, fifo_size);
 152
 153        sou->defined = true;
 154
 155        return 0;
 156}
 157
 158/**
 159 * Send the fifo command to destroy a screen.
 160 */
 161static int vmw_sou_fifo_destroy(struct vmw_private *dev_priv,
 162                                struct vmw_screen_object_unit *sou)
 163{
 164        size_t fifo_size;
 165        int ret;
 166
 167        struct {
 168                struct {
 169                        uint32_t cmdType;
 170                } header;
 171                SVGAFifoCmdDestroyScreen body;
 172        } *cmd;
 173
 174        /* no need to do anything */
 175        if (unlikely(!sou->defined))
 176                return 0;
 177
 178        fifo_size = sizeof(*cmd);
 179        cmd = vmw_fifo_reserve(dev_priv, fifo_size);
 180        /* the hardware has hung, nothing we can do about it here */
 181        if (unlikely(cmd == NULL)) {
 182                DRM_ERROR("Fifo reserve failed.\n");
 183                return -ENOMEM;
 184        }
 185
 186        memset(cmd, 0, fifo_size);
 187        cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN;
 188        cmd->body.screenId = sou->base.unit;
 189
 190        vmw_fifo_commit(dev_priv, fifo_size);
 191
 192        /* Force sync */
 193        ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ);
 194        if (unlikely(ret != 0))
 195                DRM_ERROR("Failed to sync with HW");
 196        else
 197                sou->defined = false;
 198
 199        return ret;
 200}
 201
 202/**
 203 * vmw_sou_crtc_mode_set_nofb - Create new screen
 204 *
 205 * @crtc: CRTC associated with the new screen
 206 *
 207 * This function creates/destroys a screen.  This function cannot fail, so if
 208 * somehow we run into a failure, just do the best we can to get out.
 209 */
 210static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
 211{
 212        struct vmw_private *dev_priv;
 213        struct vmw_screen_object_unit *sou;
 214        struct vmw_framebuffer *vfb;
 215        struct drm_framebuffer *fb;
 216        struct drm_plane_state *ps;
 217        struct vmw_plane_state *vps;
 218        int ret;
 219
 220        sou = vmw_crtc_to_sou(crtc);
 221        dev_priv = vmw_priv(crtc->dev);
 222        ps = crtc->primary->state;
 223        fb = ps->fb;
 224        vps = vmw_plane_state_to_vps(ps);
 225
 226        vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
 227
 228        if (sou->defined) {
 229                ret = vmw_sou_fifo_destroy(dev_priv, sou);
 230                if (ret) {
 231                        DRM_ERROR("Failed to destroy Screen Object\n");
 232                        return;
 233                }
 234        }
 235
 236        if (vfb) {
 237                struct drm_connector_state *conn_state;
 238                struct vmw_connector_state *vmw_conn_state;
 239                int x, y;
 240
 241                sou->buffer = vps->bo;
 242                sou->buffer_size = vps->bo_size;
 243
 244                if (sou->base.is_implicit) {
 245                        x = crtc->x;
 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
 251                        x = vmw_conn_state->gui_x;
 252                        y = vmw_conn_state->gui_y;
 253                }
 254
 255                ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode);
 256                if (ret)
 257                        DRM_ERROR("Failed to define Screen Object %dx%d\n",
 258                                  crtc->x, crtc->y);
 259
 260                vmw_kms_add_active(dev_priv, &sou->base, vfb);
 261        } else {
 262                sou->buffer = NULL;
 263                sou->buffer_size = 0;
 264
 265                vmw_kms_del_active(dev_priv, &sou->base);
 266        }
 267}
 268
 269/**
 270 * vmw_sou_crtc_helper_prepare - Noop
 271 *
 272 * @crtc: CRTC associated with the new screen
 273 *
 274 * Prepares the CRTC for a mode set, but we don't need to do anything here.
 275 */
 276static void vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc)
 277{
 278}
 279
 280/**
 281 * vmw_sou_crtc_atomic_enable - Noop
 282 *
 283 * @crtc: CRTC associated with the new screen
 284 *
 285 * This is called after a mode set has been completed.
 286 */
 287static void vmw_sou_crtc_atomic_enable(struct drm_crtc *crtc,
 288                                       struct drm_crtc_state *old_state)
 289{
 290}
 291
 292/**
 293 * vmw_sou_crtc_atomic_disable - Turns off CRTC
 294 *
 295 * @crtc: CRTC to be turned off
 296 */
 297static void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc,
 298                                        struct drm_crtc_state *old_state)
 299{
 300        struct vmw_private *dev_priv;
 301        struct vmw_screen_object_unit *sou;
 302        int ret;
 303
 304
 305        if (!crtc) {
 306                DRM_ERROR("CRTC is NULL\n");
 307                return;
 308        }
 309
 310        sou = vmw_crtc_to_sou(crtc);
 311        dev_priv = vmw_priv(crtc->dev);
 312
 313        if (sou->defined) {
 314                ret = vmw_sou_fifo_destroy(dev_priv, sou);
 315                if (ret)
 316                        DRM_ERROR("Failed to destroy Screen Object\n");
 317        }
 318}
 319
 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 = {
 345        .gamma_set = vmw_du_crtc_gamma_set,
 346        .destroy = vmw_sou_crtc_destroy,
 347        .reset = vmw_du_crtc_reset,
 348        .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
 349        .atomic_destroy_state = vmw_du_crtc_destroy_state,
 350        .set_config = vmw_kms_set_config,
 351        .page_flip = vmw_sou_crtc_page_flip,
 352};
 353
 354/*
 355 * Screen Object Display Unit encoder functions
 356 */
 357
 358static void vmw_sou_encoder_destroy(struct drm_encoder *encoder)
 359{
 360        vmw_sou_destroy(vmw_encoder_to_sou(encoder));
 361}
 362
 363static const struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
 364        .destroy = vmw_sou_encoder_destroy,
 365};
 366
 367/*
 368 * Screen Object Display Unit connector functions
 369 */
 370
 371static void vmw_sou_connector_destroy(struct drm_connector *connector)
 372{
 373        vmw_sou_destroy(vmw_connector_to_sou(connector));
 374}
 375
 376static const struct drm_connector_funcs vmw_sou_connector_funcs = {
 377        .dpms = vmw_du_connector_dpms,
 378        .detect = vmw_du_connector_detect,
 379        .fill_modes = vmw_du_connector_fill_modes,
 380        .set_property = vmw_du_connector_set_property,
 381        .destroy = vmw_sou_connector_destroy,
 382        .reset = vmw_du_connector_reset,
 383        .atomic_duplicate_state = vmw_du_connector_duplicate_state,
 384        .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};
 388
 389
 390static const struct
 391drm_connector_helper_funcs vmw_sou_connector_helper_funcs = {
 392        .best_encoder = drm_atomic_helper_best_encoder,
 393};
 394
 395
 396
 397/*
 398 * Screen Object Display Plane Functions
 399 */
 400
 401/**
 402 * vmw_sou_primary_plane_cleanup_fb - Frees sou backing buffer
 403 *
 404 * @plane:  display plane
 405 * @old_state: Contains the FB to clean up
 406 *
 407 * Unpins the display surface
 408 *
 409 * Returns 0 on success
 410 */
 411static void
 412vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane,
 413                                 struct drm_plane_state *old_state)
 414{
 415        struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
 416        struct drm_crtc *crtc = plane->state->crtc ?
 417                plane->state->crtc : old_state->crtc;
 418
 419        if (vps->bo)
 420                vmw_bo_unpin(vmw_priv(crtc->dev), vps->bo, false);
 421        vmw_bo_unreference(&vps->bo);
 422        vps->bo_size = 0;
 423
 424        vmw_du_plane_cleanup_fb(plane, old_state);
 425}
 426
 427
 428/**
 429 * vmw_sou_primary_plane_prepare_fb - allocate backing buffer
 430 *
 431 * @plane:  display plane
 432 * @new_state: info on the new plane state, including the FB
 433 *
 434 * The SOU backing buffer is our equivalent of the display plane.
 435 *
 436 * Returns 0 on success
 437 */
 438static int
 439vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
 440                                 struct drm_plane_state *new_state)
 441{
 442        struct drm_framebuffer *new_fb = new_state->fb;
 443        struct drm_crtc *crtc = plane->state->crtc ?: new_state->crtc;
 444        struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
 445        struct vmw_private *dev_priv;
 446        size_t size;
 447        int ret;
 448
 449
 450        if (!new_fb) {
 451                vmw_bo_unreference(&vps->bo);
 452                vps->bo_size = 0;
 453
 454                return 0;
 455        }
 456
 457        size = new_state->crtc_w * new_state->crtc_h * 4;
 458        dev_priv = vmw_priv(crtc->dev);
 459
 460        if (vps->bo) {
 461                if (vps->bo_size == size) {
 462                        /*
 463                         * Note that this might temporarily up the pin-count
 464                         * to 2, until cleanup_fb() is called.
 465                         */
 466                        return vmw_bo_pin_in_vram(dev_priv, vps->bo,
 467                                                      true);
 468                }
 469
 470                vmw_bo_unreference(&vps->bo);
 471                vps->bo_size = 0;
 472        }
 473
 474        vps->bo = kzalloc(sizeof(*vps->bo), GFP_KERNEL);
 475        if (!vps->bo)
 476                return -ENOMEM;
 477
 478        vmw_svga_enable(dev_priv);
 479
 480        /* After we have alloced the backing store might not be able to
 481         * resume the overlays, this is preferred to failing to alloc.
 482         */
 483        vmw_overlay_pause_all(dev_priv);
 484        ret = vmw_bo_init(dev_priv, vps->bo, size,
 485                              &vmw_vram_ne_placement,
 486                              false, &vmw_bo_bo_free);
 487        vmw_overlay_resume_all(dev_priv);
 488        if (ret) {
 489                vps->bo = NULL; /* vmw_bo_init frees on error */
 490                return ret;
 491        }
 492
 493        vps->bo_size = size;
 494
 495        /*
 496         * TTM already thinks the buffer is pinned, but make sure the
 497         * pin_count is upped.
 498         */
 499        return vmw_bo_pin_in_vram(dev_priv, vps->bo, true);
 500}
 501
 502
 503static void
 504vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
 505                                    struct drm_plane_state *old_state)
 506{
 507        struct drm_crtc *crtc = plane->state->crtc;
 508        struct drm_pending_vblank_event *event = NULL;
 509        struct vmw_fence_obj *fence = NULL;
 510        int ret;
 511
 512        if (crtc && plane->state->fb) {
 513                struct vmw_private *dev_priv = vmw_priv(crtc->dev);
 514                struct vmw_framebuffer *vfb =
 515                        vmw_framebuffer_to_vfb(plane->state->fb);
 516                struct drm_vmw_rect vclips;
 517
 518                vclips.x = crtc->x;
 519                vclips.y = crtc->y;
 520                vclips.w = crtc->mode.hdisplay;
 521                vclips.h = crtc->mode.vdisplay;
 522
 523                if (vfb->bo)
 524                        ret = vmw_kms_sou_do_bo_dirty(dev_priv, vfb, NULL,
 525                                                      &vclips, 1, 1, true,
 526                                                      &fence, crtc);
 527                else
 528                        ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL,
 529                                                           &vclips, NULL, 0, 0,
 530                                                           1, 1, &fence, crtc);
 531
 532                /*
 533                 * We cannot really fail this function, so if we do, then output
 534                 * an error and maintain consistent atomic state.
 535                 */
 536                if (ret != 0)
 537                        DRM_ERROR("Failed to update screen.\n");
 538        } else {
 539                /*
 540                 * When disabling a plane, CRTC and FB should always be NULL
 541                 * together, otherwise it's an error.
 542                 * Here primary plane is being disable so should really blank
 543                 * the screen object display unit, if not already done.
 544                 */
 545                return;
 546        }
 547
 548        event = crtc->state->event;
 549        /*
 550         * In case of failure and other cases, vblank event will be sent in
 551         * vmw_du_crtc_atomic_flush.
 552         */
 553        if (event && fence) {
 554                struct drm_file *file_priv = event->base.file_priv;
 555
 556                ret = vmw_event_fence_action_queue(file_priv,
 557                                                   fence,
 558                                                   &event->base,
 559                                                   &event->event.vbl.tv_sec,
 560                                                   &event->event.vbl.tv_usec,
 561                                                   true);
 562
 563                if (unlikely(ret != 0))
 564                        DRM_ERROR("Failed to queue event on fence.\n");
 565                else
 566                        crtc->state->event = NULL;
 567        }
 568
 569        if (fence)
 570                vmw_fence_obj_unreference(&fence);
 571}
 572
 573
 574static const struct drm_plane_funcs vmw_sou_plane_funcs = {
 575        .update_plane = drm_atomic_helper_update_plane,
 576        .disable_plane = drm_atomic_helper_disable_plane,
 577        .destroy = vmw_du_primary_plane_destroy,
 578        .reset = vmw_du_plane_reset,
 579        .atomic_duplicate_state = vmw_du_plane_duplicate_state,
 580        .atomic_destroy_state = vmw_du_plane_destroy_state,
 581};
 582
 583static const struct drm_plane_funcs vmw_sou_cursor_funcs = {
 584        .update_plane = drm_atomic_helper_update_plane,
 585        .disable_plane = drm_atomic_helper_disable_plane,
 586        .destroy = vmw_du_cursor_plane_destroy,
 587        .reset = vmw_du_plane_reset,
 588        .atomic_duplicate_state = vmw_du_plane_duplicate_state,
 589        .atomic_destroy_state = vmw_du_plane_destroy_state,
 590};
 591
 592/*
 593 * Atomic Helpers
 594 */
 595static const struct
 596drm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = {
 597        .atomic_check = vmw_du_cursor_plane_atomic_check,
 598        .atomic_update = vmw_du_cursor_plane_atomic_update,
 599        .prepare_fb = vmw_du_cursor_plane_prepare_fb,
 600        .cleanup_fb = vmw_du_plane_cleanup_fb,
 601};
 602
 603static const struct
 604drm_plane_helper_funcs vmw_sou_primary_plane_helper_funcs = {
 605        .atomic_check = vmw_du_primary_plane_atomic_check,
 606        .atomic_update = vmw_sou_primary_plane_atomic_update,
 607        .prepare_fb = vmw_sou_primary_plane_prepare_fb,
 608        .cleanup_fb = vmw_sou_primary_plane_cleanup_fb,
 609};
 610
 611static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = {
 612        .prepare = vmw_sou_crtc_helper_prepare,
 613        .mode_set_nofb = vmw_sou_crtc_mode_set_nofb,
 614        .atomic_check = vmw_du_crtc_atomic_check,
 615        .atomic_begin = vmw_du_crtc_atomic_begin,
 616        .atomic_flush = vmw_du_crtc_atomic_flush,
 617        .atomic_enable = vmw_sou_crtc_atomic_enable,
 618        .atomic_disable = vmw_sou_crtc_atomic_disable,
 619};
 620
 621
 622static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
 623{
 624        struct vmw_screen_object_unit *sou;
 625        struct drm_device *dev = dev_priv->dev;
 626        struct drm_connector *connector;
 627        struct drm_encoder *encoder;
 628        struct drm_plane *primary, *cursor;
 629        struct drm_crtc *crtc;
 630        int ret;
 631
 632        sou = kzalloc(sizeof(*sou), GFP_KERNEL);
 633        if (!sou)
 634                return -ENOMEM;
 635
 636        sou->base.unit = unit;
 637        crtc = &sou->base.crtc;
 638        encoder = &sou->base.encoder;
 639        connector = &sou->base.connector;
 640        primary = &sou->base.primary;
 641        cursor = &sou->base.cursor;
 642
 643        sou->base.active_implicit = false;
 644        sou->base.pref_active = (unit == 0);
 645        sou->base.pref_width = dev_priv->initial_width;
 646        sou->base.pref_height = dev_priv->initial_height;
 647        sou->base.pref_mode = NULL;
 648
 649        /*
 650         * Remove this after enabling atomic because property values can
 651         * only exist in a state object
 652         */
 653        sou->base.is_implicit = false;
 654
 655        /* Initialize primary plane */
 656        vmw_du_plane_reset(primary);
 657
 658        ret = drm_universal_plane_init(dev, &sou->base.primary,
 659                                       0, &vmw_sou_plane_funcs,
 660                                       vmw_primary_plane_formats,
 661                                       ARRAY_SIZE(vmw_primary_plane_formats),
 662                                       NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
 663        if (ret) {
 664                DRM_ERROR("Failed to initialize primary plane");
 665                goto err_free;
 666        }
 667
 668        drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs);
 669
 670        /* Initialize cursor plane */
 671        vmw_du_plane_reset(cursor);
 672
 673        ret = drm_universal_plane_init(dev, &sou->base.cursor,
 674                        0, &vmw_sou_cursor_funcs,
 675                        vmw_cursor_plane_formats,
 676                        ARRAY_SIZE(vmw_cursor_plane_formats),
 677                        NULL, DRM_PLANE_TYPE_CURSOR, NULL);
 678        if (ret) {
 679                DRM_ERROR("Failed to initialize cursor plane");
 680                drm_plane_cleanup(&sou->base.primary);
 681                goto err_free;
 682        }
 683
 684        drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs);
 685
 686        vmw_du_connector_reset(connector);
 687        ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
 688                                 DRM_MODE_CONNECTOR_VIRTUAL);
 689        if (ret) {
 690                DRM_ERROR("Failed to initialize connector\n");
 691                goto err_free;
 692        }
 693
 694        drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs);
 695        connector->status = vmw_du_connector_detect(connector, true);
 696        vmw_connector_state_to_vcs(connector->state)->is_implicit = false;
 697
 698
 699        ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
 700                               DRM_MODE_ENCODER_VIRTUAL, NULL);
 701        if (ret) {
 702                DRM_ERROR("Failed to initialize encoder\n");
 703                goto err_free_connector;
 704        }
 705
 706        (void) drm_connector_attach_encoder(connector, encoder);
 707        encoder->possible_crtcs = (1 << unit);
 708        encoder->possible_clones = 0;
 709
 710        ret = drm_connector_register(connector);
 711        if (ret) {
 712                DRM_ERROR("Failed to register connector\n");
 713                goto err_free_encoder;
 714        }
 715
 716
 717        vmw_du_crtc_reset(crtc);
 718        ret = drm_crtc_init_with_planes(dev, crtc, &sou->base.primary,
 719                                        &sou->base.cursor,
 720                                        &vmw_screen_object_crtc_funcs, NULL);
 721        if (ret) {
 722                DRM_ERROR("Failed to initialize CRTC\n");
 723                goto err_free_unregister;
 724        }
 725
 726        drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs);
 727
 728        drm_mode_crtc_set_gamma_size(crtc, 256);
 729
 730        drm_object_attach_property(&connector->base,
 731                                   dev_priv->hotplug_mode_update_property, 1);
 732        drm_object_attach_property(&connector->base,
 733                                   dev->mode_config.suggested_x_property, 0);
 734        drm_object_attach_property(&connector->base,
 735                                   dev->mode_config.suggested_y_property, 0);
 736        if (dev_priv->implicit_placement_property)
 737                drm_object_attach_property
 738                        (&connector->base,
 739                         dev_priv->implicit_placement_property,
 740                         sou->base.is_implicit);
 741
 742        return 0;
 743
 744err_free_unregister:
 745        drm_connector_unregister(connector);
 746err_free_encoder:
 747        drm_encoder_cleanup(encoder);
 748err_free_connector:
 749        drm_connector_cleanup(connector);
 750err_free:
 751        kfree(sou);
 752        return ret;
 753}
 754
 755int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
 756{
 757        struct drm_device *dev = dev_priv->dev;
 758        int i, ret;
 759
 760        if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) {
 761                DRM_INFO("Not using screen objects,"
 762                         " missing cap SCREEN_OBJECT_2\n");
 763                return -ENOSYS;
 764        }
 765
 766        ret = -ENOMEM;
 767        dev_priv->num_implicit = 0;
 768        dev_priv->implicit_fb = NULL;
 769
 770        ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
 771        if (unlikely(ret != 0))
 772                return ret;
 773
 774        vmw_kms_create_implicit_placement_property(dev_priv, false);
 775
 776        for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
 777                vmw_sou_init(dev_priv, i);
 778
 779        dev_priv->active_display_unit = vmw_du_screen_object;
 780
 781        DRM_INFO("Screen Objects Display Unit initialized\n");
 782
 783        return 0;
 784}
 785
 786static int do_bo_define_gmrfb(struct vmw_private *dev_priv,
 787                                  struct vmw_framebuffer *framebuffer)
 788{
 789        struct vmw_buffer_object *buf =
 790                container_of(framebuffer, struct vmw_framebuffer_bo,
 791                             base)->buffer;
 792        int depth = framebuffer->base.format->depth;
 793        struct {
 794                uint32_t header;
 795                SVGAFifoCmdDefineGMRFB body;
 796        } *cmd;
 797
 798        /* Emulate RGBA support, contrary to svga_reg.h this is not
 799         * supported by hosts. This is only a problem if we are reading
 800         * this value later and expecting what we uploaded back.
 801         */
 802        if (depth == 32)
 803                depth = 24;
 804
 805        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
 806        if (!cmd) {
 807                DRM_ERROR("Out of fifo space for dirty framebuffer command.\n");
 808                return -ENOMEM;
 809        }
 810
 811        cmd->header = SVGA_CMD_DEFINE_GMRFB;
 812        cmd->body.format.bitsPerPixel = framebuffer->base.format->cpp[0] * 8;
 813        cmd->body.format.colorDepth = depth;
 814        cmd->body.format.reserved = 0;
 815        cmd->body.bytesPerLine = framebuffer->base.pitches[0];
 816        /* Buffer is reserved in vram or GMR */
 817        vmw_bo_get_guest_ptr(&buf->base, &cmd->body.ptr);
 818        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 819
 820        return 0;
 821}
 822
 823/**
 824 * vmw_sou_surface_fifo_commit - Callback to fill in and submit a
 825 * blit surface to screen command.
 826 *
 827 * @dirty: The closure structure.
 828 *
 829 * Fills in the missing fields in the command, and translates the cliprects
 830 * to match the destination bounding box encoded.
 831 */
 832static void vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty)
 833{
 834        struct vmw_kms_sou_surface_dirty *sdirty =
 835                container_of(dirty, typeof(*sdirty), base);
 836        struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd;
 837        s32 trans_x = dirty->unit->crtc.x - sdirty->dst_x;
 838        s32 trans_y = dirty->unit->crtc.y - sdirty->dst_y;
 839        size_t region_size = dirty->num_hits * sizeof(SVGASignedRect);
 840        SVGASignedRect *blit = (SVGASignedRect *) &cmd[1];
 841        int i;
 842
 843        if (!dirty->num_hits) {
 844                vmw_fifo_commit(dirty->dev_priv, 0);
 845                return;
 846        }
 847
 848        cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN;
 849        cmd->header.size = sizeof(cmd->body) + region_size;
 850
 851        /*
 852         * Use the destination bounding box to specify destination - and
 853         * source bounding regions.
 854         */
 855        cmd->body.destRect.left = sdirty->left;
 856        cmd->body.destRect.right = sdirty->right;
 857        cmd->body.destRect.top = sdirty->top;
 858        cmd->body.destRect.bottom = sdirty->bottom;
 859
 860        cmd->body.srcRect.left = sdirty->left + trans_x;
 861        cmd->body.srcRect.right = sdirty->right + trans_x;
 862        cmd->body.srcRect.top = sdirty->top + trans_y;
 863        cmd->body.srcRect.bottom = sdirty->bottom + trans_y;
 864
 865        cmd->body.srcImage.sid = sdirty->sid;
 866        cmd->body.destScreenId = dirty->unit->unit;
 867
 868        /* Blits are relative to the destination rect. Translate. */
 869        for (i = 0; i < dirty->num_hits; ++i, ++blit) {
 870                blit->left -= sdirty->left;
 871                blit->right -= sdirty->left;
 872                blit->top -= sdirty->top;
 873                blit->bottom -= sdirty->top;
 874        }
 875
 876        vmw_fifo_commit(dirty->dev_priv, region_size + sizeof(*cmd));
 877
 878        sdirty->left = sdirty->top = S32_MAX;
 879        sdirty->right = sdirty->bottom = S32_MIN;
 880}
 881
 882/**
 883 * vmw_sou_surface_clip - Callback to encode a blit surface to screen cliprect.
 884 *
 885 * @dirty: The closure structure
 886 *
 887 * Encodes a SVGASignedRect cliprect and updates the bounding box of the
 888 * BLIT_SURFACE_TO_SCREEN command.
 889 */
 890static void vmw_sou_surface_clip(struct vmw_kms_dirty *dirty)
 891{
 892        struct vmw_kms_sou_surface_dirty *sdirty =
 893                container_of(dirty, typeof(*sdirty), base);
 894        struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd;
 895        SVGASignedRect *blit = (SVGASignedRect *) &cmd[1];
 896
 897        /* Destination rect. */
 898        blit += dirty->num_hits;
 899        blit->left = dirty->unit_x1;
 900        blit->top = dirty->unit_y1;
 901        blit->right = dirty->unit_x2;
 902        blit->bottom = dirty->unit_y2;
 903
 904        /* Destination bounding box */
 905        sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1);
 906        sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1);
 907        sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2);
 908        sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2);
 909
 910        dirty->num_hits++;
 911}
 912
 913/**
 914 * vmw_kms_sou_do_surface_dirty - Dirty part of a surface backed framebuffer
 915 *
 916 * @dev_priv: Pointer to the device private structure.
 917 * @framebuffer: Pointer to the surface-buffer backed framebuffer.
 918 * @clips: Array of clip rects. Either @clips or @vclips must be NULL.
 919 * @vclips: Alternate array of clip rects. Either @clips or @vclips must
 920 * be NULL.
 921 * @srf: Pointer to surface to blit from. If NULL, the surface attached
 922 * to @framebuffer will be used.
 923 * @dest_x: X coordinate offset to align @srf with framebuffer coordinates.
 924 * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates.
 925 * @num_clips: Number of clip rects in @clips.
 926 * @inc: Increment to use when looping over @clips.
 927 * @out_fence: If non-NULL, will return a ref-counted pointer to a
 928 * struct vmw_fence_obj. The returned fence pointer may be NULL in which
 929 * case the device has already synchronized.
 930 * @crtc: If crtc is passed, perform surface dirty on that crtc only.
 931 *
 932 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
 933 * interrupted.
 934 */
 935int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
 936                                 struct vmw_framebuffer *framebuffer,
 937                                 struct drm_clip_rect *clips,
 938                                 struct drm_vmw_rect *vclips,
 939                                 struct vmw_resource *srf,
 940                                 s32 dest_x,
 941                                 s32 dest_y,
 942                                 unsigned num_clips, int inc,
 943                                 struct vmw_fence_obj **out_fence,
 944                                 struct drm_crtc *crtc)
 945{
 946        struct vmw_framebuffer_surface *vfbs =
 947                container_of(framebuffer, typeof(*vfbs), base);
 948        struct vmw_kms_sou_surface_dirty sdirty;
 949        struct vmw_validation_ctx ctx;
 950        int ret;
 951
 952        if (!srf)
 953                srf = &vfbs->surface->res;
 954
 955        ret = vmw_kms_helper_resource_prepare(srf, true, &ctx);
 956        if (ret)
 957                return ret;
 958
 959        sdirty.base.fifo_commit = vmw_sou_surface_fifo_commit;
 960        sdirty.base.clip = vmw_sou_surface_clip;
 961        sdirty.base.dev_priv = dev_priv;
 962        sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) +
 963          sizeof(SVGASignedRect) * num_clips;
 964        sdirty.base.crtc = crtc;
 965
 966        sdirty.sid = srf->id;
 967        sdirty.left = sdirty.top = S32_MAX;
 968        sdirty.right = sdirty.bottom = S32_MIN;
 969        sdirty.dst_x = dest_x;
 970        sdirty.dst_y = dest_y;
 971
 972        ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
 973                                   dest_x, dest_y, num_clips, inc,
 974                                   &sdirty.base);
 975        vmw_kms_helper_resource_finish(&ctx, out_fence);
 976
 977        return ret;
 978}
 979
 980/**
 981 * vmw_sou_bo_fifo_commit - Callback to submit a set of readback clips.
 982 *
 983 * @dirty: The closure structure.
 984 *
 985 * Commits a previously built command buffer of readback clips.
 986 */
 987static void vmw_sou_bo_fifo_commit(struct vmw_kms_dirty *dirty)
 988{
 989        if (!dirty->num_hits) {
 990                vmw_fifo_commit(dirty->dev_priv, 0);
 991                return;
 992        }
 993
 994        vmw_fifo_commit(dirty->dev_priv,
 995                        sizeof(struct vmw_kms_sou_bo_blit) *
 996                        dirty->num_hits);
 997}
 998
 999/**
1000 * vmw_sou_bo_clip - Callback to encode a readback cliprect.
1001 *
1002 * @dirty: The closure structure
1003 *
1004 * Encodes a BLIT_GMRFB_TO_SCREEN cliprect.
1005 */
1006static void vmw_sou_bo_clip(struct vmw_kms_dirty *dirty)
1007{
1008        struct vmw_kms_sou_bo_blit *blit = dirty->cmd;
1009
1010        blit += dirty->num_hits;
1011        blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
1012        blit->body.destScreenId = dirty->unit->unit;
1013        blit->body.srcOrigin.x = dirty->fb_x;
1014        blit->body.srcOrigin.y = dirty->fb_y;
1015        blit->body.destRect.left = dirty->unit_x1;
1016        blit->body.destRect.top = dirty->unit_y1;
1017        blit->body.destRect.right = dirty->unit_x2;
1018        blit->body.destRect.bottom = dirty->unit_y2;
1019        dirty->num_hits++;
1020}
1021
1022/**
1023 * vmw_kms_do_bo_dirty - Dirty part of a buffer-object backed framebuffer
1024 *
1025 * @dev_priv: Pointer to the device private structure.
1026 * @framebuffer: Pointer to the buffer-object backed framebuffer.
1027 * @clips: Array of clip rects.
1028 * @vclips: Alternate array of clip rects. Either @clips or @vclips must
1029 * be NULL.
1030 * @num_clips: Number of clip rects in @clips.
1031 * @increment: Increment to use when looping over @clips.
1032 * @interruptible: Whether to perform waits interruptible if possible.
1033 * @out_fence: If non-NULL, will return a ref-counted pointer to a
1034 * struct vmw_fence_obj. The returned fence pointer may be NULL in which
1035 * case the device has already synchronized.
1036 * @crtc: If crtc is passed, perform bo dirty on that crtc only.
1037 *
1038 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
1039 * interrupted.
1040 */
1041int vmw_kms_sou_do_bo_dirty(struct vmw_private *dev_priv,
1042                                struct vmw_framebuffer *framebuffer,
1043                                struct drm_clip_rect *clips,
1044                                struct drm_vmw_rect *vclips,
1045                                unsigned num_clips, int increment,
1046                                bool interruptible,
1047                                struct vmw_fence_obj **out_fence,
1048                                struct drm_crtc *crtc)
1049{
1050        struct vmw_buffer_object *buf =
1051                container_of(framebuffer, struct vmw_framebuffer_bo,
1052                             base)->buffer;
1053        struct vmw_kms_dirty dirty;
1054        int ret;
1055
1056        ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible,
1057                                            false, false);
1058        if (ret)
1059                return ret;
1060
1061        ret = do_bo_define_gmrfb(dev_priv, framebuffer);
1062        if (unlikely(ret != 0))
1063                goto out_revert;
1064
1065        dirty.crtc = crtc;
1066        dirty.fifo_commit = vmw_sou_bo_fifo_commit;
1067        dirty.clip = vmw_sou_bo_clip;
1068        dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_bo_blit) *
1069                num_clips;
1070        ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
1071                                   0, 0, num_clips, increment, &dirty);
1072        vmw_kms_helper_buffer_finish(dev_priv, NULL, buf, out_fence, NULL);
1073
1074        return ret;
1075
1076out_revert:
1077        vmw_kms_helper_buffer_revert(buf);
1078
1079        return ret;
1080}
1081
1082
1083/**
1084 * vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips.
1085 *
1086 * @dirty: The closure structure.
1087 *
1088 * Commits a previously built command buffer of readback clips.
1089 */
1090static void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty)
1091{
1092        if (!dirty->num_hits) {
1093                vmw_fifo_commit(dirty->dev_priv, 0);
1094                return;
1095        }
1096
1097        vmw_fifo_commit(dirty->dev_priv,
1098                        sizeof(struct vmw_kms_sou_readback_blit) *
1099                        dirty->num_hits);
1100}
1101
1102/**
1103 * vmw_sou_readback_clip - Callback to encode a readback cliprect.
1104 *
1105 * @dirty: The closure structure
1106 *
1107 * Encodes a BLIT_SCREEN_TO_GMRFB cliprect.
1108 */
1109static void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty)
1110{
1111        struct vmw_kms_sou_readback_blit *blit = dirty->cmd;
1112
1113        blit += dirty->num_hits;
1114        blit->header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB;
1115        blit->body.srcScreenId = dirty->unit->unit;
1116        blit->body.destOrigin.x = dirty->fb_x;
1117        blit->body.destOrigin.y = dirty->fb_y;
1118        blit->body.srcRect.left = dirty->unit_x1;
1119        blit->body.srcRect.top = dirty->unit_y1;
1120        blit->body.srcRect.right = dirty->unit_x2;
1121        blit->body.srcRect.bottom = dirty->unit_y2;
1122        dirty->num_hits++;
1123}
1124
1125/**
1126 * vmw_kms_sou_readback - Perform a readback from the screen object system to
1127 * a buffer-object backed framebuffer.
1128 *
1129 * @dev_priv: Pointer to the device private structure.
1130 * @file_priv: Pointer to a struct drm_file identifying the caller.
1131 * Must be set to NULL if @user_fence_rep is NULL.
1132 * @vfb: Pointer to the buffer-object backed framebuffer.
1133 * @user_fence_rep: User-space provided structure for fence information.
1134 * Must be set to non-NULL if @file_priv is non-NULL.
1135 * @vclips: Array of clip rects.
1136 * @num_clips: Number of clip rects in @vclips.
1137 * @crtc: If crtc is passed, readback on that crtc only.
1138 *
1139 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
1140 * interrupted.
1141 */
1142int vmw_kms_sou_readback(struct vmw_private *dev_priv,
1143                         struct drm_file *file_priv,
1144                         struct vmw_framebuffer *vfb,
1145                         struct drm_vmw_fence_rep __user *user_fence_rep,
1146                         struct drm_vmw_rect *vclips,
1147                         uint32_t num_clips,
1148                         struct drm_crtc *crtc)
1149{
1150        struct vmw_buffer_object *buf =
1151                container_of(vfb, struct vmw_framebuffer_bo, base)->buffer;
1152        struct vmw_kms_dirty dirty;
1153        int ret;
1154
1155        ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, true, false,
1156                                            false);
1157        if (ret)
1158                return ret;
1159
1160        ret = do_bo_define_gmrfb(dev_priv, vfb);
1161        if (unlikely(ret != 0))
1162                goto out_revert;
1163
1164        dirty.crtc = crtc;
1165        dirty.fifo_commit = vmw_sou_readback_fifo_commit;
1166        dirty.clip = vmw_sou_readback_clip;
1167        dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) *
1168                num_clips;
1169        ret = vmw_kms_helper_dirty(dev_priv, vfb, NULL, vclips,
1170                                   0, 0, num_clips, 1, &dirty);
1171        vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL,
1172                                     user_fence_rep);
1173
1174        return ret;
1175
1176out_revert:
1177        vmw_kms_helper_buffer_revert(buf);
1178
1179        return ret;
1180}
1181