Subversion Repositories Kolibri OS

Rev

Rev 5078 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright © 2011-2015 VMware, Inc., Palo Alto, CA., USA
  4.  * All Rights Reserved.
  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.  
  31.  
  32. #define vmw_crtc_to_sou(x) \
  33.         container_of(x, struct vmw_screen_object_unit, base.crtc)
  34. #define vmw_encoder_to_sou(x) \
  35.         container_of(x, struct vmw_screen_object_unit, base.encoder)
  36. #define vmw_connector_to_sou(x) \
  37.         container_of(x, struct vmw_screen_object_unit, base.connector)
  38.  
  39. /**
  40.  * struct vmw_kms_sou_surface_dirty - Closure structure for
  41.  * blit surface to screen command.
  42.  * @base: The base type we derive from. Used by vmw_kms_helper_dirty().
  43.  * @left: Left side of bounding box.
  44.  * @right: Right side of bounding box.
  45.  * @top: Top side of bounding box.
  46.  * @bottom: Bottom side of bounding box.
  47.  * @dst_x: Difference between source clip rects and framebuffer coordinates.
  48.  * @dst_y: Difference between source clip rects and framebuffer coordinates.
  49.  * @sid: Surface id of surface to copy from.
  50.  */
  51. struct vmw_kms_sou_surface_dirty {
  52.         struct vmw_kms_dirty base;
  53.         s32 left, right, top, bottom;
  54.         s32 dst_x, dst_y;
  55.         u32 sid;
  56. };
  57.  
  58. /*
  59.  * SVGA commands that are used by this code. Please see the device headers
  60.  * for explanation.
  61.  */
  62. struct vmw_kms_sou_readback_blit {
  63.         uint32 header;
  64.         SVGAFifoCmdBlitScreenToGMRFB body;
  65. };
  66.  
  67. struct vmw_kms_sou_dmabuf_blit {
  68.         uint32 header;
  69.         SVGAFifoCmdBlitGMRFBToScreen body;
  70. };
  71.  
  72. struct vmw_kms_sou_dirty_cmd {
  73.         SVGA3dCmdHeader header;
  74.         SVGA3dCmdBlitSurfaceToScreen body;
  75. };
  76.  
  77.  
  78. /*
  79.  * Other structs.
  80.  */
  81.  
  82. struct vmw_screen_object_display {
  83.         unsigned num_implicit;
  84.  
  85.         struct vmw_framebuffer *implicit_fb;
  86.         SVGAFifoCmdDefineGMRFB cur;
  87.         struct vmw_dma_buffer *pinned_gmrfb;
  88. };
  89.  
  90. /**
  91.  * Display unit using screen objects.
  92.  */
  93. struct vmw_screen_object_unit {
  94.         struct vmw_display_unit base;
  95.  
  96.         unsigned long buffer_size; /**< Size of allocated buffer */
  97.         struct vmw_dma_buffer *buffer; /**< Backing store buffer */
  98.  
  99.         bool defined;
  100.         bool active_implicit;
  101. };
  102.  
  103. static void vmw_sou_destroy(struct vmw_screen_object_unit *sou)
  104. {
  105.         vmw_du_cleanup(&sou->base);
  106.         kfree(sou);
  107. }
  108.  
  109.  
  110. /*
  111.  * Screen Object Display Unit CRTC functions
  112.  */
  113.  
  114. static void vmw_sou_crtc_destroy(struct drm_crtc *crtc)
  115. {
  116.         vmw_sou_destroy(vmw_crtc_to_sou(crtc));
  117. }
  118.  
  119. static void vmw_sou_del_active(struct vmw_private *vmw_priv,
  120.                                struct vmw_screen_object_unit *sou)
  121. {
  122.         struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
  123.  
  124.         if (sou->active_implicit) {
  125.                 if (--(ld->num_implicit) == 0)
  126.                         ld->implicit_fb = NULL;
  127.                 sou->active_implicit = false;
  128.         }
  129. }
  130.  
  131. static void vmw_sou_add_active(struct vmw_private *vmw_priv,
  132.                                struct vmw_screen_object_unit *sou,
  133.                                struct vmw_framebuffer *vfb)
  134. {
  135.         struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
  136.  
  137.         BUG_ON(!ld->num_implicit && ld->implicit_fb);
  138.  
  139.         if (!sou->active_implicit && sou->base.is_implicit) {
  140.                 ld->implicit_fb = vfb;
  141.                 sou->active_implicit = true;
  142.                 ld->num_implicit++;
  143.         }
  144. }
  145.  
  146. /**
  147.  * Send the fifo command to create a screen.
  148.  */
  149. static int vmw_sou_fifo_create(struct vmw_private *dev_priv,
  150.                                struct vmw_screen_object_unit *sou,
  151.                                uint32_t x, uint32_t y,
  152.                                struct drm_display_mode *mode)
  153. {
  154.         size_t fifo_size;
  155.  
  156.         struct {
  157.                 struct {
  158.                         uint32_t cmdType;
  159.                 } header;
  160.                 SVGAScreenObject obj;
  161.         } *cmd;
  162.  
  163.         BUG_ON(!sou->buffer);
  164.  
  165.         fifo_size = sizeof(*cmd);
  166.         cmd = vmw_fifo_reserve(dev_priv, fifo_size);
  167.         /* The hardware has hung, nothing we can do about it here. */
  168.         if (unlikely(cmd == NULL)) {
  169.                 DRM_ERROR("Fifo reserve failed.\n");
  170.                 return -ENOMEM;
  171.         }
  172.  
  173.         memset(cmd, 0, fifo_size);
  174.         cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN;
  175.         cmd->obj.structSize = sizeof(SVGAScreenObject);
  176.         cmd->obj.id = sou->base.unit;
  177.         cmd->obj.flags = SVGA_SCREEN_HAS_ROOT |
  178.                 (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0);
  179.         cmd->obj.size.width = mode->hdisplay;
  180.         cmd->obj.size.height = mode->vdisplay;
  181.         if (sou->base.is_implicit) {
  182.                 cmd->obj.root.x = x;
  183.                 cmd->obj.root.y = y;
  184.         } else {
  185.                 cmd->obj.root.x = sou->base.gui_x;
  186.                 cmd->obj.root.y = sou->base.gui_y;
  187.         }
  188.  
  189.         /* Ok to assume that buffer is pinned in vram */
  190.         vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr);
  191.         cmd->obj.backingStore.pitch = mode->hdisplay * 4;
  192.  
  193.         vmw_fifo_commit(dev_priv, fifo_size);
  194.  
  195.         sou->defined = true;
  196.  
  197.         return 0;
  198. }
  199.  
  200. /**
  201.  * Send the fifo command to destroy a screen.
  202.  */
  203. static int vmw_sou_fifo_destroy(struct vmw_private *dev_priv,
  204.                                 struct vmw_screen_object_unit *sou)
  205. {
  206.         size_t fifo_size;
  207.         int ret;
  208.  
  209.         struct {
  210.                 struct {
  211.                         uint32_t cmdType;
  212.                 } header;
  213.                 SVGAFifoCmdDestroyScreen body;
  214.         } *cmd;
  215.  
  216.         /* no need to do anything */
  217.         if (unlikely(!sou->defined))
  218.                 return 0;
  219.  
  220.         fifo_size = sizeof(*cmd);
  221.         cmd = vmw_fifo_reserve(dev_priv, fifo_size);
  222.         /* the hardware has hung, nothing we can do about it here */
  223.         if (unlikely(cmd == NULL)) {
  224.                 DRM_ERROR("Fifo reserve failed.\n");
  225.                 return -ENOMEM;
  226.         }
  227.  
  228.         memset(cmd, 0, fifo_size);
  229.         cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN;
  230.         cmd->body.screenId = sou->base.unit;
  231.  
  232.         vmw_fifo_commit(dev_priv, fifo_size);
  233.  
  234.         /* Force sync */
  235.         ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ);
  236.         if (unlikely(ret != 0))
  237.                 DRM_ERROR("Failed to sync with HW");
  238.         else
  239.                 sou->defined = false;
  240.  
  241.         return ret;
  242. }
  243.  
  244. /**
  245.  * Free the backing store.
  246.  */
  247. static void vmw_sou_backing_free(struct vmw_private *dev_priv,
  248.                                  struct vmw_screen_object_unit *sou)
  249. {
  250.         vmw_dmabuf_unreference(&sou->buffer);
  251.         sou->buffer_size = 0;
  252. }
  253.  
  254. /**
  255.  * Allocate the backing store for the buffer.
  256.  */
  257. static int vmw_sou_backing_alloc(struct vmw_private *dev_priv,
  258.                                  struct vmw_screen_object_unit *sou,
  259.                                  unsigned long size)
  260. {
  261.         int ret;
  262.  
  263.         if (sou->buffer_size == size)
  264.                 return 0;
  265.  
  266.         if (sou->buffer)
  267.                 vmw_sou_backing_free(dev_priv, sou);
  268.  
  269.         sou->buffer = kzalloc(sizeof(*sou->buffer), GFP_KERNEL);
  270.         if (unlikely(sou->buffer == NULL))
  271.                 return -ENOMEM;
  272.  
  273.         /* After we have alloced the backing store might not be able to
  274.          * resume the overlays, this is preferred to failing to alloc.
  275.          */
  276.         vmw_overlay_pause_all(dev_priv);
  277.         ret = vmw_dmabuf_init(dev_priv, sou->buffer, size,
  278.                               &vmw_vram_ne_placement,
  279.                               false, &vmw_dmabuf_bo_free);
  280.         vmw_overlay_resume_all(dev_priv);
  281.  
  282.         if (unlikely(ret != 0))
  283.                 sou->buffer = NULL; /* vmw_dmabuf_init frees on error */
  284.         else
  285.                 sou->buffer_size = size;
  286.  
  287.         return ret;
  288. }
  289.  
  290. static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
  291. {
  292.         struct vmw_private *dev_priv;
  293.         struct vmw_screen_object_unit *sou;
  294.         struct drm_connector *connector;
  295.         struct drm_display_mode *mode;
  296.         struct drm_encoder *encoder;
  297.         struct vmw_framebuffer *vfb;
  298.         struct drm_framebuffer *fb;
  299.         struct drm_crtc *crtc;
  300.         int ret = 0;
  301.  
  302.         if (!set)
  303.                 return -EINVAL;
  304.  
  305.         if (!set->crtc)
  306.                 return -EINVAL;
  307.  
  308.         /* get the sou */
  309.         crtc = set->crtc;
  310.         sou = vmw_crtc_to_sou(crtc);
  311.         vfb = set->fb ? vmw_framebuffer_to_vfb(set->fb) : NULL;
  312.         dev_priv = vmw_priv(crtc->dev);
  313.  
  314.         if (set->num_connectors > 1) {
  315.                 DRM_ERROR("Too many connectors\n");
  316.                 return -EINVAL;
  317.         }
  318.  
  319.         if (set->num_connectors == 1 &&
  320.             set->connectors[0] != &sou->base.connector) {
  321.                 DRM_ERROR("Connector doesn't match %p %p\n",
  322.                         set->connectors[0], &sou->base.connector);
  323.                 return -EINVAL;
  324.         }
  325.  
  326.         /* sou only supports one fb active at the time */
  327.         if (sou->base.is_implicit &&
  328.             dev_priv->sou_priv->implicit_fb && vfb &&
  329.             !(dev_priv->sou_priv->num_implicit == 1 &&
  330.               sou->active_implicit) &&
  331.             dev_priv->sou_priv->implicit_fb != vfb) {
  332.                 DRM_ERROR("Multiple framebuffers not supported\n");
  333.                 return -EINVAL;
  334.         }
  335.  
  336.         /* since they always map one to one these are safe */
  337.         connector = &sou->base.connector;
  338.         encoder = &sou->base.encoder;
  339.  
  340.         /* should we turn the crtc off */
  341.         if (set->num_connectors == 0 || !set->mode || !set->fb) {
  342.                 ret = vmw_sou_fifo_destroy(dev_priv, sou);
  343.                 /* the hardware has hung don't do anything more */
  344.                 if (unlikely(ret != 0))
  345.                         return ret;
  346.  
  347.                 connector->encoder = NULL;
  348.                 encoder->crtc = NULL;
  349.                 crtc->primary->fb = NULL;
  350.                 crtc->x = 0;
  351.                 crtc->y = 0;
  352.                 crtc->enabled = false;
  353.  
  354.                 vmw_sou_del_active(dev_priv, sou);
  355.  
  356.                 vmw_sou_backing_free(dev_priv, sou);
  357.  
  358.                 return 0;
  359.         }
  360.  
  361.  
  362.         /* we now know we want to set a mode */
  363.         mode = set->mode;
  364.         fb = set->fb;
  365.  
  366.         if (set->x + mode->hdisplay > fb->width ||
  367.             set->y + mode->vdisplay > fb->height) {
  368.                 DRM_ERROR("set outside of framebuffer\n");
  369.                 return -EINVAL;
  370.         }
  371.  
  372.         vmw_svga_enable(dev_priv);
  373.  
  374.         if (mode->hdisplay != crtc->mode.hdisplay ||
  375.             mode->vdisplay != crtc->mode.vdisplay) {
  376.                 /* no need to check if depth is different, because backing
  377.                  * store depth is forced to 4 by the device.
  378.                  */
  379.  
  380.                 ret = vmw_sou_fifo_destroy(dev_priv, sou);
  381.                 /* the hardware has hung don't do anything more */
  382.                 if (unlikely(ret != 0))
  383.                         return ret;
  384.  
  385.                 vmw_sou_backing_free(dev_priv, sou);
  386.         }
  387.  
  388.         if (!sou->buffer) {
  389.                 /* forced to depth 4 by the device */
  390.                 size_t size = mode->hdisplay * mode->vdisplay * 4;
  391.                 ret = vmw_sou_backing_alloc(dev_priv, sou, size);
  392.                 if (unlikely(ret != 0))
  393.                         return ret;
  394.         }
  395.  
  396.         ret = vmw_sou_fifo_create(dev_priv, sou, set->x, set->y, mode);
  397.         if (unlikely(ret != 0)) {
  398.                 /*
  399.                  * We are in a bit of a situation here, the hardware has
  400.                  * hung and we may or may not have a buffer hanging of
  401.                  * the screen object, best thing to do is not do anything
  402.                  * if we where defined, if not just turn the crtc of.
  403.                  * Not what userspace wants but it needs to htfu.
  404.                  */
  405.                 if (sou->defined)
  406.                         return ret;
  407.  
  408.                 connector->encoder = NULL;
  409.                 encoder->crtc = NULL;
  410.                 crtc->primary->fb = NULL;
  411.                 crtc->x = 0;
  412.                 crtc->y = 0;
  413.                 crtc->enabled = false;
  414.  
  415.                 return ret;
  416.         }
  417.  
  418.         vmw_sou_add_active(dev_priv, sou, vfb);
  419.  
  420.         connector->encoder = encoder;
  421.         encoder->crtc = crtc;
  422.         crtc->mode = *mode;
  423.         crtc->primary->fb = fb;
  424.         crtc->x = set->x;
  425.         crtc->y = set->y;
  426.         crtc->enabled = true;
  427.  
  428.         return 0;
  429. }
  430.  
  431. /**
  432.  * Returns if this unit can be page flipped.
  433.  * Must be called with the mode_config mutex held.
  434.  */
  435. static bool vmw_sou_screen_object_flippable(struct vmw_private *dev_priv,
  436.                                             struct drm_crtc *crtc)
  437. {
  438.         struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
  439.  
  440.         if (!sou->base.is_implicit)
  441.                 return true;
  442.  
  443.         if (dev_priv->sou_priv->num_implicit != 1)
  444.                 return false;
  445.  
  446.         return true;
  447. }
  448.  
  449. /**
  450.  * Update the implicit fb to the current fb of this crtc.
  451.  * Must be called with the mode_config mutex held.
  452.  */
  453. static void vmw_sou_update_implicit_fb(struct vmw_private *dev_priv,
  454.                                        struct drm_crtc *crtc)
  455. {
  456.         struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
  457.  
  458.         BUG_ON(!sou->base.is_implicit);
  459.  
  460.         dev_priv->sou_priv->implicit_fb =
  461.                 vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
  462. }
  463. static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
  464.         .save = vmw_du_crtc_save,
  465.         .restore = vmw_du_crtc_restore,
  466. //   .cursor_set = vmw_du_crtc_cursor_set,
  467. //   .cursor_move = vmw_du_crtc_cursor_move,
  468.         .gamma_set = vmw_du_crtc_gamma_set,
  469.         .destroy = vmw_sou_crtc_destroy,
  470.         .set_config = vmw_sou_crtc_set_config,
  471. //   .page_flip = vmw_du_page_flip,
  472. };
  473.  
  474. /*
  475.  * Screen Object Display Unit encoder functions
  476.  */
  477.  
  478. static void vmw_sou_encoder_destroy(struct drm_encoder *encoder)
  479. {
  480.         vmw_sou_destroy(vmw_encoder_to_sou(encoder));
  481. }
  482.  
  483. static struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
  484.         .destroy = vmw_sou_encoder_destroy,
  485. };
  486.  
  487. /*
  488.  * Screen Object Display Unit connector functions
  489.  */
  490.  
  491. static void vmw_sou_connector_destroy(struct drm_connector *connector)
  492. {
  493.         vmw_sou_destroy(vmw_connector_to_sou(connector));
  494. }
  495.  
  496. static struct drm_connector_funcs vmw_sou_connector_funcs = {
  497.         .dpms = vmw_du_connector_dpms,
  498.         .save = vmw_du_connector_save,
  499.         .restore = vmw_du_connector_restore,
  500.         .detect = vmw_du_connector_detect,
  501.         .fill_modes = vmw_du_connector_fill_modes,
  502.         .set_property = vmw_du_connector_set_property,
  503.         .destroy = vmw_sou_connector_destroy,
  504. };
  505.  
  506. static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
  507. {
  508.         struct vmw_screen_object_unit *sou;
  509.         struct drm_device *dev = dev_priv->dev;
  510.         struct drm_connector *connector;
  511.         struct drm_encoder *encoder;
  512.         struct drm_crtc *crtc;
  513.  
  514.         sou = kzalloc(sizeof(*sou), GFP_KERNEL);
  515.         if (!sou)
  516.                 return -ENOMEM;
  517.  
  518.         sou->base.unit = unit;
  519.         crtc = &sou->base.crtc;
  520.         encoder = &sou->base.encoder;
  521.         connector = &sou->base.connector;
  522.  
  523.         sou->active_implicit = false;
  524.  
  525.         sou->base.pref_active = (unit == 0);
  526.         sou->base.pref_width = dev_priv->initial_width;
  527.         sou->base.pref_height = dev_priv->initial_height;
  528.         sou->base.pref_mode = NULL;
  529.         sou->base.is_implicit = true;
  530.  
  531.         drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
  532.                            DRM_MODE_CONNECTOR_VIRTUAL);
  533.         connector->status = vmw_du_connector_detect(connector, true);
  534.  
  535.         drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
  536.                          DRM_MODE_ENCODER_VIRTUAL);
  537.         drm_mode_connector_attach_encoder(connector, encoder);
  538.         encoder->possible_crtcs = (1 << unit);
  539.         encoder->possible_clones = 0;
  540.  
  541.         (void) drm_connector_register(connector);
  542.  
  543.         drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs);
  544.  
  545.         drm_mode_crtc_set_gamma_size(crtc, 256);
  546.  
  547.         drm_object_attach_property(&connector->base,
  548.                                       dev->mode_config.dirty_info_property,
  549.                                       1);
  550.  
  551.         return 0;
  552. }
  553.  
  554. int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
  555. {
  556.         struct drm_device *dev = dev_priv->dev;
  557.         int i, ret;
  558.  
  559.         if (dev_priv->sou_priv) {
  560.                 DRM_INFO("sou system already on\n");
  561.                 return -EINVAL;
  562.         }
  563.  
  564.         if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) {
  565.                 DRM_INFO("Not using screen objects,"
  566.                          " missing cap SCREEN_OBJECT_2\n");
  567.                 return -ENOSYS;
  568.         }
  569.  
  570.         ret = -ENOMEM;
  571.         dev_priv->sou_priv = kmalloc(sizeof(*dev_priv->sou_priv), GFP_KERNEL);
  572.         if (unlikely(!dev_priv->sou_priv))
  573.                 goto err_no_mem;
  574.  
  575.         dev_priv->sou_priv->num_implicit = 0;
  576.         dev_priv->sou_priv->implicit_fb = NULL;
  577.  
  578.         ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
  579.         if (unlikely(ret != 0))
  580.                 goto err_free;
  581.  
  582.         ret = drm_mode_create_dirty_info_property(dev);
  583.         if (unlikely(ret != 0))
  584.                 goto err_vblank_cleanup;
  585.  
  586.         for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
  587.                 vmw_sou_init(dev_priv, i);
  588.  
  589.         dev_priv->active_display_unit = vmw_du_screen_object;
  590.  
  591.         DRM_INFO("Screen Objects Display Unit initialized\n");
  592.  
  593.         return 0;
  594.  
  595. err_vblank_cleanup:
  596.         drm_vblank_cleanup(dev);
  597. err_free:
  598.         kfree(dev_priv->sou_priv);
  599.         dev_priv->sou_priv = NULL;
  600. err_no_mem:
  601.         return ret;
  602. }
  603.  
  604. int vmw_kms_sou_close_display(struct vmw_private *dev_priv)
  605. {
  606.         struct drm_device *dev = dev_priv->dev;
  607.  
  608.         if (!dev_priv->sou_priv)
  609.                 return -ENOSYS;
  610.  
  611.         drm_vblank_cleanup(dev);
  612.  
  613.         kfree(dev_priv->sou_priv);
  614.  
  615.         return 0;
  616. }
  617.  
  618. static int do_dmabuf_define_gmrfb(struct vmw_private *dev_priv,
  619.                                   struct vmw_framebuffer *framebuffer)
  620. {
  621.         struct vmw_dma_buffer *buf =
  622.                 container_of(framebuffer, struct vmw_framebuffer_dmabuf,
  623.                              base)->buffer;
  624.         int depth = framebuffer->base.depth;
  625.         struct {
  626.                 uint32_t header;
  627.                 SVGAFifoCmdDefineGMRFB body;
  628.         } *cmd;
  629.  
  630.         /* Emulate RGBA support, contrary to svga_reg.h this is not
  631.          * supported by hosts. This is only a problem if we are reading
  632.          * this value later and expecting what we uploaded back.
  633.          */
  634.         if (depth == 32)
  635.                 depth = 24;
  636.  
  637.         cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
  638.         if (!cmd) {
  639.                 DRM_ERROR("Out of fifo space for dirty framebuffer command.\n");
  640.                 return -ENOMEM;
  641.         }
  642.  
  643.         cmd->header = SVGA_CMD_DEFINE_GMRFB;
  644.         cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel;
  645.         cmd->body.format.colorDepth = depth;
  646.         cmd->body.format.reserved = 0;
  647.         cmd->body.bytesPerLine = framebuffer->base.pitches[0];
  648.         /* Buffer is reserved in vram or GMR */
  649.         vmw_bo_get_guest_ptr(&buf->base, &cmd->body.ptr);
  650.         vmw_fifo_commit(dev_priv, sizeof(*cmd));
  651.  
  652.         return 0;
  653. }
  654.  
  655. /**
  656.  * vmw_sou_surface_fifo_commit - Callback to fill in and submit a
  657.  * blit surface to screen command.
  658.  *
  659.  * @dirty: The closure structure.
  660.  *
  661.  * Fills in the missing fields in the command, and translates the cliprects
  662.  * to match the destination bounding box encoded.
  663.  */
  664. static void vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty)
  665. {
  666.         struct vmw_kms_sou_surface_dirty *sdirty =
  667.                 container_of(dirty, typeof(*sdirty), base);
  668.         struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd;
  669.         s32 trans_x = dirty->unit->crtc.x - sdirty->dst_x;
  670.         s32 trans_y = dirty->unit->crtc.y - sdirty->dst_y;
  671.         size_t region_size = dirty->num_hits * sizeof(SVGASignedRect);
  672.         SVGASignedRect *blit = (SVGASignedRect *) &cmd[1];
  673.         int i;
  674.  
  675.         cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN;
  676.         cmd->header.size = sizeof(cmd->body) + region_size;
  677.  
  678.         /*
  679.          * Use the destination bounding box to specify destination - and
  680.          * source bounding regions.
  681.          */
  682.         cmd->body.destRect.left = sdirty->left;
  683.         cmd->body.destRect.right = sdirty->right;
  684.         cmd->body.destRect.top = sdirty->top;
  685.         cmd->body.destRect.bottom = sdirty->bottom;
  686.  
  687.         cmd->body.srcRect.left = sdirty->left + trans_x;
  688.         cmd->body.srcRect.right = sdirty->right + trans_x;
  689.         cmd->body.srcRect.top = sdirty->top + trans_y;
  690.         cmd->body.srcRect.bottom = sdirty->bottom + trans_y;
  691.  
  692.         cmd->body.srcImage.sid = sdirty->sid;
  693.         cmd->body.destScreenId = dirty->unit->unit;
  694.  
  695.         /* Blits are relative to the destination rect. Translate. */
  696.         for (i = 0; i < dirty->num_hits; ++i, ++blit) {
  697.                 blit->left -= sdirty->left;
  698.                 blit->right -= sdirty->left;
  699.                 blit->top -= sdirty->top;
  700.                 blit->bottom -= sdirty->top;
  701.         }
  702.  
  703.         vmw_fifo_commit(dirty->dev_priv, region_size + sizeof(*cmd));
  704.  
  705.         sdirty->left = sdirty->top = S32_MAX;
  706.         sdirty->right = sdirty->bottom = S32_MIN;
  707. }
  708.  
  709. /**
  710.  * vmw_sou_surface_clip - Callback to encode a blit surface to screen cliprect.
  711.  *
  712.  * @dirty: The closure structure
  713.  *
  714.  * Encodes a SVGASignedRect cliprect and updates the bounding box of the
  715.  * BLIT_SURFACE_TO_SCREEN command.
  716.  */
  717. static void vmw_sou_surface_clip(struct vmw_kms_dirty *dirty)
  718. {
  719.         struct vmw_kms_sou_surface_dirty *sdirty =
  720.                 container_of(dirty, typeof(*sdirty), base);
  721.         struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd;
  722.         SVGASignedRect *blit = (SVGASignedRect *) &cmd[1];
  723.  
  724.         /* Destination rect. */
  725.         blit += dirty->num_hits;
  726.         blit->left = dirty->unit_x1;
  727.         blit->top = dirty->unit_y1;
  728.         blit->right = dirty->unit_x2;
  729.         blit->bottom = dirty->unit_y2;
  730.  
  731.         /* Destination bounding box */
  732.         sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1);
  733.         sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1);
  734.         sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2);
  735.         sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2);
  736.  
  737.         dirty->num_hits++;
  738. }
  739.  
  740. /**
  741.  * vmw_kms_sou_do_surface_dirty - Dirty part of a surface backed framebuffer
  742.  *
  743.  * @dev_priv: Pointer to the device private structure.
  744.  * @framebuffer: Pointer to the surface-buffer backed framebuffer.
  745.  * @clips: Array of clip rects. Either @clips or @vclips must be NULL.
  746.  * @vclips: Alternate array of clip rects. Either @clips or @vclips must
  747.  * be NULL.
  748.  * @srf: Pointer to surface to blit from. If NULL, the surface attached
  749.  * to @framebuffer will be used.
  750.  * @dest_x: X coordinate offset to align @srf with framebuffer coordinates.
  751.  * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates.
  752.  * @num_clips: Number of clip rects in @clips.
  753.  * @inc: Increment to use when looping over @clips.
  754.  * @out_fence: If non-NULL, will return a ref-counted pointer to a
  755.  * struct vmw_fence_obj. The returned fence pointer may be NULL in which
  756.  * case the device has already synchronized.
  757.  *
  758.  * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
  759.  * interrupted.
  760.  */
  761. int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
  762.                                  struct vmw_framebuffer *framebuffer,
  763.                                  struct drm_clip_rect *clips,
  764.                                  struct drm_vmw_rect *vclips,
  765.                                  struct vmw_resource *srf,
  766.                                  s32 dest_x,
  767.                                  s32 dest_y,
  768.                                  unsigned num_clips, int inc,
  769.                                  struct vmw_fence_obj **out_fence)
  770. {
  771.         struct vmw_framebuffer_surface *vfbs =
  772.                 container_of(framebuffer, typeof(*vfbs), base);
  773.         struct vmw_kms_sou_surface_dirty sdirty;
  774.         int ret;
  775.  
  776.         if (!srf)
  777.                 srf = &vfbs->surface->res;
  778.  
  779.         ret = vmw_kms_helper_resource_prepare(srf, true);
  780.         if (ret)
  781.                 return ret;
  782.  
  783.         sdirty.base.fifo_commit = vmw_sou_surface_fifo_commit;
  784.         sdirty.base.clip = vmw_sou_surface_clip;
  785.         sdirty.base.dev_priv = dev_priv;
  786.         sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) +
  787.           sizeof(SVGASignedRect) * num_clips;
  788.  
  789.         sdirty.sid = srf->id;
  790.         sdirty.left = sdirty.top = S32_MAX;
  791.         sdirty.right = sdirty.bottom = S32_MIN;
  792.         sdirty.dst_x = dest_x;
  793.         sdirty.dst_y = dest_y;
  794.  
  795.         ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
  796.                                    dest_x, dest_y, num_clips, inc,
  797.                                    &sdirty.base);
  798.         vmw_kms_helper_resource_finish(srf, out_fence);
  799.  
  800.         return ret;
  801. }
  802.  
  803. /**
  804.  * vmw_sou_dmabuf_fifo_commit - Callback to submit a set of readback clips.
  805.  *
  806.  * @dirty: The closure structure.
  807.  *
  808.  * Commits a previously built command buffer of readback clips.
  809.  */
  810. static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty)
  811. {
  812.         vmw_fifo_commit(dirty->dev_priv,
  813.                         sizeof(struct vmw_kms_sou_dmabuf_blit) *
  814.                         dirty->num_hits);
  815. }
  816.  
  817. /**
  818.  * vmw_sou_dmabuf_clip - Callback to encode a readback cliprect.
  819.  *
  820.  * @dirty: The closure structure
  821.  *
  822.  * Encodes a BLIT_GMRFB_TO_SCREEN cliprect.
  823.  */
  824. static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty)
  825. {
  826.         struct vmw_kms_sou_dmabuf_blit *blit = dirty->cmd;
  827.  
  828.         blit += dirty->num_hits;
  829.         blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
  830.         blit->body.destScreenId = dirty->unit->unit;
  831.         blit->body.srcOrigin.x = dirty->fb_x;
  832.         blit->body.srcOrigin.y = dirty->fb_y;
  833.         blit->body.destRect.left = dirty->unit_x1;
  834.         blit->body.destRect.top = dirty->unit_y1;
  835.         blit->body.destRect.right = dirty->unit_x2;
  836.         blit->body.destRect.bottom = dirty->unit_y2;
  837.         dirty->num_hits++;
  838. }
  839.  
  840. /**
  841.  * vmw_kms_do_dmabuf_dirty - Dirty part of a dma-buffer backed framebuffer
  842.  *
  843.  * @dev_priv: Pointer to the device private structure.
  844.  * @framebuffer: Pointer to the dma-buffer backed framebuffer.
  845.  * @clips: Array of clip rects.
  846.  * @num_clips: Number of clip rects in @clips.
  847.  * @increment: Increment to use when looping over @clips.
  848.  * @interruptible: Whether to perform waits interruptible if possible.
  849.  * @out_fence: If non-NULL, will return a ref-counted pointer to a
  850.  * struct vmw_fence_obj. The returned fence pointer may be NULL in which
  851.  * case the device has already synchronized.
  852.  *
  853.  * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
  854.  * interrupted.
  855.  */
  856. int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv,
  857.                                 struct vmw_framebuffer *framebuffer,
  858.                                 struct drm_clip_rect *clips,
  859.                                 unsigned num_clips, int increment,
  860.                                 bool interruptible,
  861.                                 struct vmw_fence_obj **out_fence)
  862. {
  863.         struct vmw_dma_buffer *buf =
  864.                 container_of(framebuffer, struct vmw_framebuffer_dmabuf,
  865.                              base)->buffer;
  866.         struct vmw_kms_dirty dirty;
  867.         int ret;
  868.  
  869.         ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible,
  870.                                             false);
  871.         if (ret)
  872.                 return ret;
  873.  
  874.         ret = do_dmabuf_define_gmrfb(dev_priv, framebuffer);
  875.         if (unlikely(ret != 0))
  876.                 goto out_revert;
  877.  
  878.         dirty.fifo_commit = vmw_sou_dmabuf_fifo_commit;
  879.         dirty.clip = vmw_sou_dmabuf_clip;
  880.         dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) *
  881.                 num_clips;
  882.         ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, NULL,
  883.                                    0, 0, num_clips, increment, &dirty);
  884.         vmw_kms_helper_buffer_finish(dev_priv, NULL, buf, out_fence, NULL);
  885.  
  886.         return ret;
  887.  
  888. out_revert:
  889.         vmw_kms_helper_buffer_revert(buf);
  890.  
  891.         return ret;
  892. }
  893.  
  894.  
  895. /**
  896.  * vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips.
  897.  *
  898.  * @dirty: The closure structure.
  899.  *
  900.  * Commits a previously built command buffer of readback clips.
  901.  */
  902. static void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty)
  903. {
  904.         vmw_fifo_commit(dirty->dev_priv,
  905.                         sizeof(struct vmw_kms_sou_readback_blit) *
  906.                         dirty->num_hits);
  907. }
  908.  
  909. /**
  910.  * vmw_sou_readback_clip - Callback to encode a readback cliprect.
  911.  *
  912.  * @dirty: The closure structure
  913.  *
  914.  * Encodes a BLIT_SCREEN_TO_GMRFB cliprect.
  915.  */
  916. static void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty)
  917. {
  918.         struct vmw_kms_sou_readback_blit *blit = dirty->cmd;
  919.  
  920.         blit += dirty->num_hits;
  921.         blit->header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB;
  922.         blit->body.srcScreenId = dirty->unit->unit;
  923.         blit->body.destOrigin.x = dirty->fb_x;
  924.         blit->body.destOrigin.y = dirty->fb_y;
  925.         blit->body.srcRect.left = dirty->unit_x1;
  926.         blit->body.srcRect.top = dirty->unit_y1;
  927.         blit->body.srcRect.right = dirty->unit_x2;
  928.         blit->body.srcRect.bottom = dirty->unit_y2;
  929.         dirty->num_hits++;
  930. }
  931.  
  932. /**
  933.  * vmw_kms_sou_readback - Perform a readback from the screen object system to
  934.  * a dma-buffer backed framebuffer.
  935.  *
  936.  * @dev_priv: Pointer to the device private structure.
  937.  * @file_priv: Pointer to a struct drm_file identifying the caller.
  938.  * Must be set to NULL if @user_fence_rep is NULL.
  939.  * @vfb: Pointer to the dma-buffer backed framebuffer.
  940.  * @user_fence_rep: User-space provided structure for fence information.
  941.  * Must be set to non-NULL if @file_priv is non-NULL.
  942.  * @vclips: Array of clip rects.
  943.  * @num_clips: Number of clip rects in @vclips.
  944.  *
  945.  * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
  946.  * interrupted.
  947.  */
  948. int vmw_kms_sou_readback(struct vmw_private *dev_priv,
  949.                          struct drm_file *file_priv,
  950.                          struct vmw_framebuffer *vfb,
  951.                          struct drm_vmw_fence_rep __user *user_fence_rep,
  952.                          struct drm_vmw_rect *vclips,
  953.                          uint32_t num_clips)
  954. {
  955.         struct vmw_dma_buffer *buf =
  956.                 container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer;
  957.         struct vmw_kms_dirty dirty;
  958.         int ret;
  959.  
  960.         ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, true, false);
  961.         if (ret)
  962.                 return ret;
  963.  
  964.         ret = do_dmabuf_define_gmrfb(dev_priv, vfb);
  965.         if (unlikely(ret != 0))
  966.                 goto out_revert;
  967.  
  968.         dirty.fifo_commit = vmw_sou_readback_fifo_commit;
  969.         dirty.clip = vmw_sou_readback_clip;
  970.         dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) *
  971.                 num_clips;
  972.         ret = vmw_kms_helper_dirty(dev_priv, vfb, NULL, vclips,
  973.                                    0, 0, num_clips, 1, &dirty);
  974.         vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL,
  975.                                      user_fence_rep);
  976.  
  977.         return ret;
  978.  
  979. out_revert:
  980.         vmw_kms_helper_buffer_revert(buf);
  981.  
  982.         return ret;
  983. }
  984.  
  985. #if 0
  986. #include <display.h>
  987. extern display_t os_display;
  988.  
  989. bool set_mode(struct drm_device *dev, struct drm_connector *connector,
  990.               videomode_t *reqmode, bool strict)
  991. {
  992.     struct drm_display_mode  *mode = NULL, *tmpmode;
  993.     struct vmw_private *dev_priv = vmw_priv(dev);
  994.     struct vmw_screen_object_unit *sou;
  995.     display_t *os_display;
  996.  
  997.     bool ret = false;
  998.  
  999. //    dbgprintf("width %d height %d vrefresh %d\n",
  1000. //               reqmode->width, reqmode->height, reqmode->freq);
  1001.  
  1002.     list_for_each_entry(tmpmode, &connector->modes, head)
  1003.     {
  1004.         if( (drm_mode_width(tmpmode)    == reqmode->width)  &&
  1005.             (drm_mode_height(tmpmode)   == reqmode->height) &&
  1006.             (drm_mode_vrefresh(tmpmode) == reqmode->freq) )
  1007.         {
  1008.             mode = tmpmode;
  1009.             goto do_set;
  1010.         }
  1011.     };
  1012.  
  1013.     if( (mode == NULL) && (strict == false) )
  1014.     {
  1015.         list_for_each_entry(tmpmode, &connector->modes, head)
  1016.         {
  1017.             if( (drm_mode_width(tmpmode)  == reqmode->width)  &&
  1018.                 (drm_mode_height(tmpmode) == reqmode->height) )
  1019.             {
  1020.                 mode = tmpmode;
  1021.                 goto do_set;
  1022.             }
  1023.         };
  1024.     };
  1025.  
  1026. do_set:
  1027.  
  1028.     if( mode != NULL )
  1029.     {
  1030.         struct drm_framebuffer   *fb;
  1031.         struct drm_encoder       *encoder;
  1032.         struct drm_crtc          *crtc;
  1033.  
  1034. //        char  con_edid[128];
  1035.         const char *con_name;
  1036.         const char *enc_name;
  1037.  
  1038.         encoder = connector->encoder;
  1039.         crtc = encoder->crtc;
  1040.  
  1041.  
  1042. //        fb = list_first_entry(&dev->mode_config.fb_kernel_list,
  1043. //                              struct drm_framebuffer, filp_head);
  1044.  
  1045. //        memcpy(con_edid, connector->edid_blob_ptr->data, 128);
  1046.  
  1047. //        dbgprintf("Manufacturer: %s Model %x Serial Number %u\n",
  1048. //        manufacturer_name(con_edid + 0x08),
  1049. //        (unsigned short)(con_edid[0x0A] + (con_edid[0x0B] << 8)),
  1050. //        (unsigned int)(con_edid[0x0C] + (con_edid[0x0D] << 8)
  1051. //            + (con_edid[0x0E] << 16) + (con_edid[0x0F] << 24)));
  1052.  
  1053.         con_name = drm_get_connector_name(connector);
  1054.         enc_name = drm_get_encoder_name(encoder);
  1055.  
  1056.         dbgprintf("set mode %d %d connector %s encoder %s\n",
  1057.                    mode->hdisplay, mode->vdisplay, con_name, enc_name);
  1058.  
  1059.         os_display = GetDisplay();
  1060.  
  1061. #if 0
  1062.         sou = vmw_crtc_to_sou(crtc);
  1063.         sou->defined = true;
  1064.  
  1065.         ret = vmw_sou_fifo_destroy(dev_priv, sou);
  1066.         if (unlikely(ret != 0))
  1067.             return ret;
  1068.  
  1069.         ret = vmw_sou_fifo_create(dev_priv, sou, 0, 0, mode);
  1070.  
  1071. #else   /*   sledgehammer  */
  1072.  
  1073.         vmw_write(dev_priv,SVGA_REG_WIDTH,  mode->hdisplay);
  1074.         vmw_write(dev_priv,SVGA_REG_HEIGHT, mode->vdisplay);
  1075.         vmw_write(dev_priv,SVGA_REG_BITS_PER_PIXEL, 32);
  1076.         os_display->select_cursor(os_display->cursor);
  1077.         ret = 0;
  1078. #endif
  1079.         if (ret == 0)
  1080.         {
  1081.             os_display->width    = mode->hdisplay;
  1082.             os_display->height   = mode->vdisplay;
  1083.             os_display->pitch    = mode->hdisplay*4;
  1084.             os_display->vrefresh = drm_mode_vrefresh(mode);
  1085.  
  1086.             sysSetScreen(os_display->width, os_display->height, os_display->pitch);
  1087.  
  1088.             dbgprintf("new mode %d x %d pitch %d\n",
  1089.                        os_display->width, os_display->height, os_display->pitch);
  1090.         }
  1091.         else
  1092.             DRM_ERROR("failed to set mode %d_%d on crtc %p\n",
  1093.                        os_display->width, os_display->height, crtc);
  1094.     }
  1095.  
  1096.     return ret;
  1097. };
  1098. #endif
  1099.