Subversion Repositories Kolibri OS

Rev

Rev 4080 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright © 2011 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.  
  30.  
  31. #define vmw_crtc_to_sou(x) \
  32.         container_of(x, struct vmw_screen_object_unit, base.crtc)
  33. #define vmw_encoder_to_sou(x) \
  34.         container_of(x, struct vmw_screen_object_unit, base.encoder)
  35. #define vmw_connector_to_sou(x) \
  36.         container_of(x, struct vmw_screen_object_unit, base.connector)
  37.  
  38. struct vmw_screen_object_display {
  39.         unsigned num_implicit;
  40.  
  41.         struct vmw_framebuffer *implicit_fb;
  42. };
  43.  
  44. /**
  45.  * Display unit using screen objects.
  46.  */
  47. struct vmw_screen_object_unit {
  48.         struct vmw_display_unit base;
  49.  
  50.         unsigned long buffer_size; /**< Size of allocated buffer */
  51.         struct vmw_dma_buffer *buffer; /**< Backing store buffer */
  52.  
  53.         bool defined;
  54.         bool active_implicit;
  55. };
  56.  
  57. static void vmw_sou_destroy(struct vmw_screen_object_unit *sou)
  58. {
  59. //   vmw_display_unit_cleanup(&sou->base);
  60.         kfree(sou);
  61. }
  62.  
  63.  
  64. /*
  65.  * Screen Object Display Unit CRTC functions
  66.  */
  67.  
  68. static void vmw_sou_crtc_destroy(struct drm_crtc *crtc)
  69. {
  70.         vmw_sou_destroy(vmw_crtc_to_sou(crtc));
  71. }
  72.  
  73. static void vmw_sou_del_active(struct vmw_private *vmw_priv,
  74.                               struct vmw_screen_object_unit *sou)
  75. {
  76.         struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
  77.  
  78.         if (sou->active_implicit) {
  79.                 if (--(ld->num_implicit) == 0)
  80.                         ld->implicit_fb = NULL;
  81.                 sou->active_implicit = false;
  82.         }
  83. }
  84.  
  85. static void vmw_sou_add_active(struct vmw_private *vmw_priv,
  86.                               struct vmw_screen_object_unit *sou,
  87.                               struct vmw_framebuffer *vfb)
  88. {
  89.         struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
  90.  
  91.         BUG_ON(!ld->num_implicit && ld->implicit_fb);
  92.  
  93.         if (!sou->active_implicit && sou->base.is_implicit) {
  94.                 ld->implicit_fb = vfb;
  95.                 sou->active_implicit = true;
  96.                 ld->num_implicit++;
  97.         }
  98. }
  99.  
  100. /**
  101.  * Send the fifo command to create a screen.
  102.  */
  103. static int vmw_sou_fifo_create(struct vmw_private *dev_priv,
  104.                                struct vmw_screen_object_unit *sou,
  105.                                uint32_t x, uint32_t y,
  106.                                struct drm_display_mode *mode)
  107. {
  108.         size_t fifo_size;
  109.  
  110.         struct {
  111.                 struct {
  112.                         uint32_t cmdType;
  113.                 } header;
  114.                 SVGAScreenObject obj;
  115.         } *cmd;
  116.  
  117.         BUG_ON(!sou->buffer);
  118.  
  119.         fifo_size = sizeof(*cmd);
  120.         cmd = vmw_fifo_reserve(dev_priv, fifo_size);
  121.         /* The hardware has hung, nothing we can do about it here. */
  122.         if (unlikely(cmd == NULL)) {
  123.                 DRM_ERROR("Fifo reserve failed.\n");
  124.                 return -ENOMEM;
  125.         }
  126.  
  127.         memset(cmd, 0, fifo_size);
  128.         cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN;
  129.         cmd->obj.structSize = sizeof(SVGAScreenObject);
  130.         cmd->obj.id = sou->base.unit;
  131.         cmd->obj.flags = SVGA_SCREEN_HAS_ROOT |
  132.                 (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0);
  133.         cmd->obj.size.width = mode->hdisplay;
  134.         cmd->obj.size.height = mode->vdisplay;
  135.         if (sou->base.is_implicit) {
  136.                 cmd->obj.root.x = x;
  137.                 cmd->obj.root.y = y;
  138.         } else {
  139.                 cmd->obj.root.x = sou->base.gui_x;
  140.                 cmd->obj.root.y = sou->base.gui_y;
  141.         }
  142.  
  143.         /* Ok to assume that buffer is pinned in vram */
  144.         vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr);
  145.         cmd->obj.backingStore.pitch = mode->hdisplay * 4;
  146.  
  147.         vmw_fifo_commit(dev_priv, fifo_size);
  148.  
  149.         sou->defined = true;
  150.  
  151.         return 0;
  152. }
  153.  
  154. /**
  155.  * Send the fifo command to destroy a screen.
  156.  */
  157. static int vmw_sou_fifo_destroy(struct vmw_private *dev_priv,
  158.                                 struct vmw_screen_object_unit *sou)
  159. {
  160.         size_t fifo_size;
  161.         int ret;
  162.  
  163.         struct {
  164.                 struct {
  165.                         uint32_t cmdType;
  166.                 } header;
  167.                 SVGAFifoCmdDestroyScreen body;
  168.         } *cmd;
  169.  
  170.         /* no need to do anything */
  171.         if (unlikely(!sou->defined))
  172.                 return 0;
  173.  
  174.         fifo_size = sizeof(*cmd);
  175.         cmd = vmw_fifo_reserve(dev_priv, fifo_size);
  176.         /* the hardware has hung, nothing we can do about it here */
  177.         if (unlikely(cmd == NULL)) {
  178.                 DRM_ERROR("Fifo reserve failed.\n");
  179.                 return -ENOMEM;
  180.         }
  181.  
  182.         memset(cmd, 0, fifo_size);
  183.         cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN;
  184.         cmd->body.screenId = sou->base.unit;
  185.  
  186.         vmw_fifo_commit(dev_priv, fifo_size);
  187.  
  188.         /* Force sync */
  189.         ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ);
  190.         if (unlikely(ret != 0))
  191.                 DRM_ERROR("Failed to sync with HW");
  192.         else
  193.                 sou->defined = false;
  194.  
  195.         return ret;
  196. }
  197.  
  198. /**
  199.  * Free the backing store.
  200.  */
  201. static void vmw_sou_backing_free(struct vmw_private *dev_priv,
  202.                                  struct vmw_screen_object_unit *sou)
  203. {
  204.         struct ttm_buffer_object *bo;
  205.  
  206.         if (unlikely(sou->buffer == NULL))
  207.                 return;
  208.  
  209.         bo = &sou->buffer->base;
  210.         ttm_bo_unref(&bo);
  211.         sou->buffer = NULL;
  212.         sou->buffer_size = 0;
  213. }
  214.  
  215. /**
  216.  * Allocate the backing store for the buffer.
  217.  */
  218. static int vmw_sou_backing_alloc(struct vmw_private *dev_priv,
  219.                                  struct vmw_screen_object_unit *sou,
  220.                                  unsigned long size)
  221. {
  222.         int ret;
  223.  
  224.         if (sou->buffer_size == size)
  225.                 return 0;
  226.  
  227.         if (sou->buffer)
  228.                 vmw_sou_backing_free(dev_priv, sou);
  229.  
  230.         sou->buffer = kzalloc(sizeof(*sou->buffer), GFP_KERNEL);
  231.         if (unlikely(sou->buffer == NULL))
  232.                 return -ENOMEM;
  233.  
  234.         /* After we have alloced the backing store might not be able to
  235.          * resume the overlays, this is preferred to failing to alloc.
  236.          */
  237. //    vmw_overlay_pause_all(dev_priv);
  238.         ret = vmw_dmabuf_init(dev_priv, sou->buffer, size,
  239.                               &vmw_vram_ne_placement,
  240.                               false, &vmw_dmabuf_bo_free);
  241. //   vmw_overlay_resume_all(dev_priv);
  242.  
  243.         if (unlikely(ret != 0))
  244.                 sou->buffer = NULL; /* vmw_dmabuf_init frees on error */
  245.         else
  246.                 sou->buffer_size = size;
  247.  
  248.         return ret;
  249. }
  250.  
  251. static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
  252. {
  253.         struct vmw_private *dev_priv;
  254.         struct vmw_screen_object_unit *sou;
  255.         struct drm_connector *connector;
  256.         struct drm_display_mode *mode;
  257.         struct drm_encoder *encoder;
  258.         struct vmw_framebuffer *vfb;
  259.         struct drm_framebuffer *fb;
  260.         struct drm_crtc *crtc;
  261.         int ret = 0;
  262.  
  263.         if (!set)
  264.                 return -EINVAL;
  265.  
  266.         if (!set->crtc)
  267.                 return -EINVAL;
  268.  
  269.         /* get the sou */
  270.         crtc = set->crtc;
  271.         sou = vmw_crtc_to_sou(crtc);
  272.         vfb = set->fb ? vmw_framebuffer_to_vfb(set->fb) : NULL;
  273.         dev_priv = vmw_priv(crtc->dev);
  274.  
  275.         if (set->num_connectors > 1) {
  276.                 DRM_ERROR("to many connectors\n");
  277.                 return -EINVAL;
  278.         }
  279.  
  280.         if (set->num_connectors == 1 &&
  281.             set->connectors[0] != &sou->base.connector) {
  282.                 DRM_ERROR("connector doesn't match %p %p\n",
  283.                         set->connectors[0], &sou->base.connector);
  284.                 return -EINVAL;
  285.         }
  286.  
  287.         /* sou only supports one fb active at the time */
  288.         if (sou->base.is_implicit &&
  289.             dev_priv->sou_priv->implicit_fb && vfb &&
  290.             !(dev_priv->sou_priv->num_implicit == 1 &&
  291.               sou->active_implicit) &&
  292.             dev_priv->sou_priv->implicit_fb != vfb) {
  293.                 DRM_ERROR("Multiple framebuffers not supported\n");
  294.                 return -EINVAL;
  295.         }
  296.  
  297.         /* since they always map one to one these are safe */
  298.         connector = &sou->base.connector;
  299.         encoder = &sou->base.encoder;
  300.  
  301.         /* should we turn the crtc off */
  302.         if (set->num_connectors == 0 || !set->mode || !set->fb) {
  303.                 ret = vmw_sou_fifo_destroy(dev_priv, sou);
  304.                 /* the hardware has hung don't do anything more */
  305.                 if (unlikely(ret != 0))
  306.                         return ret;
  307.  
  308.                 connector->encoder = NULL;
  309.                 encoder->crtc = NULL;
  310.                 crtc->fb = NULL;
  311.                 crtc->x = 0;
  312.                 crtc->y = 0;
  313.  
  314.                 vmw_sou_del_active(dev_priv, sou);
  315.  
  316.                 vmw_sou_backing_free(dev_priv, sou);
  317.  
  318.                 return 0;
  319.         }
  320.  
  321.  
  322.         /* we now know we want to set a mode */
  323.         mode = set->mode;
  324.         fb = set->fb;
  325.  
  326.         if (set->x + mode->hdisplay > fb->width ||
  327.             set->y + mode->vdisplay > fb->height) {
  328.                 DRM_ERROR("set outside of framebuffer\n");
  329.                 return -EINVAL;
  330.         }
  331.  
  332. //   vmw_fb_off(dev_priv);
  333.  
  334.         if (mode->hdisplay != crtc->mode.hdisplay ||
  335.             mode->vdisplay != crtc->mode.vdisplay) {
  336.                 /* no need to check if depth is different, because backing
  337.                  * store depth is forced to 4 by the device.
  338.                  */
  339.  
  340.                 ret = vmw_sou_fifo_destroy(dev_priv, sou);
  341.                 /* the hardware has hung don't do anything more */
  342.                 if (unlikely(ret != 0))
  343.                         return ret;
  344.  
  345.                 vmw_sou_backing_free(dev_priv, sou);
  346.         }
  347.  
  348.         if (!sou->buffer) {
  349.                 /* forced to depth 4 by the device */
  350.                 size_t size = mode->hdisplay * mode->vdisplay * 4;
  351.                 ret = vmw_sou_backing_alloc(dev_priv, sou, size);
  352.                 if (unlikely(ret != 0))
  353.                         return ret;
  354.         }
  355.  
  356.         ret = vmw_sou_fifo_create(dev_priv, sou, set->x, set->y, mode);
  357.         if (unlikely(ret != 0)) {
  358.                 /*
  359.                  * We are in a bit of a situation here, the hardware has
  360.                  * hung and we may or may not have a buffer hanging of
  361.                  * the screen object, best thing to do is not do anything
  362.                  * if we where defined, if not just turn the crtc of.
  363.                  * Not what userspace wants but it needs to htfu.
  364.                  */
  365.                 if (sou->defined)
  366.                         return ret;
  367.  
  368.                 connector->encoder = NULL;
  369.                 encoder->crtc = NULL;
  370.                 crtc->fb = NULL;
  371.                 crtc->x = 0;
  372.                 crtc->y = 0;
  373.  
  374.                 return ret;
  375.         }
  376.  
  377.         vmw_sou_add_active(dev_priv, sou, vfb);
  378.  
  379.         connector->encoder = encoder;
  380.         encoder->crtc = crtc;
  381.         crtc->mode = *mode;
  382.         crtc->fb = fb;
  383.         crtc->x = set->x;
  384.         crtc->y = set->y;
  385.  
  386.         return 0;
  387. }
  388.  
  389. static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
  390.         .save = vmw_du_crtc_save,
  391.         .restore = vmw_du_crtc_restore,
  392. //   .cursor_set = vmw_du_crtc_cursor_set,
  393. //   .cursor_move = vmw_du_crtc_cursor_move,
  394.         .gamma_set = vmw_du_crtc_gamma_set,
  395.         .destroy = vmw_sou_crtc_destroy,
  396.         .set_config = vmw_sou_crtc_set_config,
  397. //   .page_flip = vmw_du_page_flip,
  398. };
  399.  
  400. /*
  401.  * Screen Object Display Unit encoder functions
  402.  */
  403.  
  404. static void vmw_sou_encoder_destroy(struct drm_encoder *encoder)
  405. {
  406.         vmw_sou_destroy(vmw_encoder_to_sou(encoder));
  407. }
  408.  
  409. static struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
  410.         .destroy = vmw_sou_encoder_destroy,
  411. };
  412.  
  413. /*
  414.  * Screen Object Display Unit connector functions
  415.  */
  416.  
  417. static void vmw_sou_connector_destroy(struct drm_connector *connector)
  418. {
  419.         vmw_sou_destroy(vmw_connector_to_sou(connector));
  420. }
  421.  
  422. static struct drm_connector_funcs vmw_legacy_connector_funcs = {
  423.         .dpms = vmw_du_connector_dpms,
  424.         .save = vmw_du_connector_save,
  425.         .restore = vmw_du_connector_restore,
  426.         .detect = vmw_du_connector_detect,
  427.         .fill_modes = vmw_du_connector_fill_modes,
  428.         .set_property = vmw_du_connector_set_property,
  429.         .destroy = vmw_sou_connector_destroy,
  430. };
  431.  
  432. static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
  433. {
  434.         struct vmw_screen_object_unit *sou;
  435.         struct drm_device *dev = dev_priv->dev;
  436.         struct drm_connector *connector;
  437.         struct drm_encoder *encoder;
  438.         struct drm_crtc *crtc;
  439.  
  440.         sou = kzalloc(sizeof(*sou), GFP_KERNEL);
  441.         if (!sou)
  442.                 return -ENOMEM;
  443.  
  444.         sou->base.unit = unit;
  445.         crtc = &sou->base.crtc;
  446.         encoder = &sou->base.encoder;
  447.         connector = &sou->base.connector;
  448.  
  449.         sou->active_implicit = false;
  450.  
  451.         sou->base.pref_active = (unit == 0);
  452.         sou->base.pref_width = dev_priv->initial_width;
  453.         sou->base.pref_height = dev_priv->initial_height;
  454.         sou->base.pref_mode = NULL;
  455.         sou->base.is_implicit = true;
  456.  
  457.         drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
  458.                            DRM_MODE_CONNECTOR_VIRTUAL);
  459.         connector->status = vmw_du_connector_detect(connector, true);
  460.  
  461.         drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
  462.                          DRM_MODE_ENCODER_VIRTUAL);
  463.         drm_mode_connector_attach_encoder(connector, encoder);
  464.         encoder->possible_crtcs = (1 << unit);
  465.         encoder->possible_clones = 0;
  466.  
  467.         drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs);
  468.  
  469.         drm_mode_crtc_set_gamma_size(crtc, 256);
  470.  
  471.         drm_object_attach_property(&connector->base,
  472.                                       dev->mode_config.dirty_info_property,
  473.                                       1);
  474.  
  475.         return 0;
  476. }
  477.  
  478. int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv)
  479. {
  480.         struct drm_device *dev = dev_priv->dev;
  481.         int i, ret;
  482.  
  483.     ENTER();
  484.  
  485.         if (dev_priv->sou_priv) {
  486.                 DRM_INFO("sou system already on\n");
  487.                 return -EINVAL;
  488.         }
  489.  
  490.         if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) {
  491.                 DRM_INFO("Not using screen objects,"
  492.                          " missing cap SCREEN_OBJECT_2\n");
  493.                 return -ENOSYS;
  494.         }
  495.  
  496.         ret = -ENOMEM;
  497.         dev_priv->sou_priv = kmalloc(sizeof(*dev_priv->sou_priv), GFP_KERNEL);
  498.         if (unlikely(!dev_priv->sou_priv))
  499.                 goto err_no_mem;
  500.  
  501.         dev_priv->sou_priv->num_implicit = 0;
  502.         dev_priv->sou_priv->implicit_fb = NULL;
  503.  
  504. //   ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
  505. //   if (unlikely(ret != 0))
  506. //       goto err_free;
  507.  
  508.         ret = drm_mode_create_dirty_info_property(dev);
  509.         if (unlikely(ret != 0))
  510.                 goto err_vblank_cleanup;
  511.  
  512.         for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
  513.                 vmw_sou_init(dev_priv, i);
  514.  
  515.         DRM_INFO("Screen objects system initialized\n");
  516.  
  517.     LEAVE();
  518.         return 0;
  519.  
  520. err_vblank_cleanup:
  521. //   drm_vblank_cleanup(dev);
  522. err_free:
  523.         kfree(dev_priv->sou_priv);
  524.         dev_priv->sou_priv = NULL;
  525. err_no_mem:
  526.         return ret;
  527. }
  528.  
  529. int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv)
  530. {
  531.         struct drm_device *dev = dev_priv->dev;
  532.  
  533.         if (!dev_priv->sou_priv)
  534.                 return -ENOSYS;
  535.  
  536. //   drm_vblank_cleanup(dev);
  537.  
  538.         kfree(dev_priv->sou_priv);
  539.  
  540.         return 0;
  541. }
  542.  
  543. /**
  544.  * Returns if this unit can be page flipped.
  545.  * Must be called with the mode_config mutex held.
  546.  */
  547. bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv,
  548.                                      struct drm_crtc *crtc)
  549. {
  550.         struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
  551.  
  552.         if (!sou->base.is_implicit)
  553.                 return true;
  554.  
  555.         if (dev_priv->sou_priv->num_implicit != 1)
  556.                 return false;
  557.  
  558.         return true;
  559. }
  560.  
  561. /**
  562.  * Update the implicit fb to the current fb of this crtc.
  563.  * Must be called with the mode_config mutex held.
  564.  */
  565. void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
  566.                                               struct drm_crtc *crtc)
  567. {
  568.         struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
  569.  
  570.         BUG_ON(!sou->base.is_implicit);
  571.  
  572.         dev_priv->sou_priv->implicit_fb =
  573.                 vmw_framebuffer_to_vfb(sou->base.crtc.fb);
  574. }
  575.