Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright © 2007 David Airlie
  4.  * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA
  5.  * All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the
  9.  * "Software"), to deal in the Software without restriction, including
  10.  * without limitation the rights to use, copy, modify, merge, publish,
  11.  * distribute, sub license, and/or sell copies of the Software, and to
  12.  * permit persons to whom the Software is furnished to do so, subject to
  13.  * the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice (including the
  16.  * next paragraph) shall be included in all copies or substantial portions
  17.  * of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21.  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  22.  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  23.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  24.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  25.  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  *
  27.  **************************************************************************/
  28.  
  29. #include <linux/export.h>
  30.  
  31. #include <drm/drmP.h>
  32. #include "vmwgfx_drv.h"
  33. #include "vmwgfx_kms.h"
  34.  
  35. #include <drm/ttm/ttm_placement.h>
  36.  
  37. #define VMW_DIRTY_DELAY 0
  38.  
  39. struct vmw_fb_par {
  40.         struct vmw_private *vmw_priv;
  41.  
  42.         void *vmalloc;
  43.  
  44.         struct mutex bo_mutex;
  45.         struct vmw_dma_buffer *vmw_bo;
  46.         struct ttm_bo_kmap_obj map;
  47.         void *bo_ptr;
  48.         unsigned bo_size;
  49.         struct drm_framebuffer *set_fb;
  50.         struct drm_display_mode *set_mode;
  51.         u32 fb_x;
  52.         u32 fb_y;
  53.         bool bo_iowrite;
  54.  
  55.         u32 pseudo_palette[17];
  56.  
  57.         unsigned max_width;
  58.         unsigned max_height;
  59.  
  60.         struct {
  61.                 spinlock_t lock;
  62.                 bool active;
  63.                 unsigned x1;
  64.                 unsigned y1;
  65.                 unsigned x2;
  66.                 unsigned y2;
  67.         } dirty;
  68.  
  69.         struct drm_crtc *crtc;
  70.         struct drm_connector *con;
  71.         struct delayed_work local_work;
  72. };
  73.  
  74. static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
  75.                             unsigned blue, unsigned transp,
  76.                             struct fb_info *info)
  77. {
  78.         struct vmw_fb_par *par = info->par;
  79.         u32 *pal = par->pseudo_palette;
  80.  
  81.         if (regno > 15) {
  82.                 DRM_ERROR("Bad regno %u.\n", regno);
  83.                 return 1;
  84.         }
  85.  
  86.         switch (par->set_fb->depth) {
  87.         case 24:
  88.         case 32:
  89.                 pal[regno] = ((red & 0xff00) << 8) |
  90.                               (green & 0xff00) |
  91.                              ((blue  & 0xff00) >> 8);
  92.                 break;
  93.         default:
  94.                 DRM_ERROR("Bad depth %u, bpp %u.\n", par->set_fb->depth,
  95.                           par->set_fb->bits_per_pixel);
  96.                 return 1;
  97.         }
  98.  
  99.         return 0;
  100. }
  101.  
  102. static int vmw_fb_check_var(struct fb_var_screeninfo *var,
  103.                             struct fb_info *info)
  104. {
  105.         int depth = var->bits_per_pixel;
  106.         struct vmw_fb_par *par = info->par;
  107.         struct vmw_private *vmw_priv = par->vmw_priv;
  108.  
  109.         switch (var->bits_per_pixel) {
  110.         case 32:
  111.                 depth = (var->transp.length > 0) ? 32 : 24;
  112.                 break;
  113.         default:
  114.                 DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel);
  115.                 return -EINVAL;
  116.         }
  117.  
  118.         switch (depth) {
  119.         case 24:
  120.                 var->red.offset = 16;
  121.                 var->green.offset = 8;
  122.                 var->blue.offset = 0;
  123.                 var->red.length = 8;
  124.                 var->green.length = 8;
  125.                 var->blue.length = 8;
  126.                 var->transp.length = 0;
  127.                 var->transp.offset = 0;
  128.                 break;
  129.         case 32:
  130.                 var->red.offset = 16;
  131.                 var->green.offset = 8;
  132.                 var->blue.offset = 0;
  133.                 var->red.length = 8;
  134.                 var->green.length = 8;
  135.                 var->blue.length = 8;
  136.                 var->transp.length = 8;
  137.                 var->transp.offset = 24;
  138.                 break;
  139.         default:
  140.                 DRM_ERROR("Bad depth %u.\n", depth);
  141.                 return -EINVAL;
  142.         }
  143.  
  144.         if ((var->xoffset + var->xres) > par->max_width ||
  145.             (var->yoffset + var->yres) > par->max_height) {
  146.                 DRM_ERROR("Requested geom can not fit in framebuffer\n");
  147.                 return -EINVAL;
  148.         }
  149.  
  150.         if (!vmw_kms_validate_mode_vram(vmw_priv,
  151.                                         var->xres * var->bits_per_pixel/8,
  152.                                         var->yoffset + var->yres)) {
  153.                 DRM_ERROR("Requested geom can not fit in framebuffer\n");
  154.                 return -EINVAL;
  155.         }
  156.  
  157.         return 0;
  158. }
  159.  
  160. static int vmw_fb_blank(int blank, struct fb_info *info)
  161. {
  162.         return 0;
  163. }
  164.  
  165. /*
  166.  * Dirty code
  167.  */
  168.  
  169. static void vmw_fb_dirty_flush(struct work_struct *work)
  170. {
  171.         struct vmw_fb_par *par = container_of(work, struct vmw_fb_par,
  172.                                               local_work.work);
  173.         struct vmw_private *vmw_priv = par->vmw_priv;
  174.         struct fb_info *info = vmw_priv->fb_info;
  175.         unsigned long irq_flags;
  176.         s32 dst_x1, dst_x2, dst_y1, dst_y2, w, h;
  177.         u32 cpp, max_x, max_y;
  178.         struct drm_clip_rect clip;
  179.         struct drm_framebuffer *cur_fb;
  180.         u8 *src_ptr, *dst_ptr;
  181.  
  182.         if (vmw_priv->suspended)
  183.                 return;
  184.  
  185.         mutex_lock(&par->bo_mutex);
  186.         cur_fb = par->set_fb;
  187.         if (!cur_fb)
  188.                 goto out_unlock;
  189.  
  190.         spin_lock_irqsave(&par->dirty.lock, irq_flags);
  191.         if (!par->dirty.active) {
  192.                 spin_unlock_irqrestore(&par->dirty.lock, irq_flags);
  193.                 goto out_unlock;
  194.         }
  195.  
  196.         /*
  197.          * Handle panning when copying from vmalloc to framebuffer.
  198.          * Clip dirty area to framebuffer.
  199.          */
  200.         cpp = (cur_fb->bits_per_pixel + 7) / 8;
  201.         max_x = par->fb_x + cur_fb->width;
  202.         max_y = par->fb_y + cur_fb->height;
  203.  
  204.         dst_x1 = par->dirty.x1 - par->fb_x;
  205.         dst_y1 = par->dirty.y1 - par->fb_y;
  206.         dst_x1 = max_t(s32, dst_x1, 0);
  207.         dst_y1 = max_t(s32, dst_y1, 0);
  208.  
  209.         dst_x2 = par->dirty.x2 - par->fb_x;
  210.         dst_y2 = par->dirty.y2 - par->fb_y;
  211.         dst_x2 = min_t(s32, dst_x2, max_x);
  212.         dst_y2 = min_t(s32, dst_y2, max_y);
  213.         w = dst_x2 - dst_x1;
  214.         h = dst_y2 - dst_y1;
  215.         w = max_t(s32, 0, w);
  216.         h = max_t(s32, 0, h);
  217.  
  218.         par->dirty.x1 = par->dirty.x2 = 0;
  219.         par->dirty.y1 = par->dirty.y2 = 0;
  220.         spin_unlock_irqrestore(&par->dirty.lock, irq_flags);
  221.  
  222.         if (w && h) {
  223.                 dst_ptr = (u8 *)par->bo_ptr  +
  224.                         (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp);
  225.                 src_ptr = (u8 *)par->vmalloc +
  226.                         ((dst_y1 + par->fb_y) * info->fix.line_length +
  227.                          (dst_x1 + par->fb_x) * cpp);
  228.  
  229. //              while (h-- > 0) {
  230. //                      memcpy(dst_ptr, src_ptr, w*cpp);
  231. //                      dst_ptr += par->set_fb->pitches[0];
  232. //                      src_ptr += info->fix.line_length;
  233. //              }
  234.  
  235.                 clip.x1 = dst_x1;
  236.                 clip.x2 = dst_x2;
  237.                 clip.y1 = dst_y1;
  238.                 clip.y2 = dst_y2;
  239.  
  240.                 WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0,
  241.                                                        &clip, 1));
  242.                 vmw_fifo_flush(vmw_priv, false);
  243.         }
  244. out_unlock:
  245.         mutex_unlock(&par->bo_mutex);
  246. }
  247.  
  248. static void vmw_fb_dirty_mark(struct vmw_fb_par *par,
  249.                               unsigned x1, unsigned y1,
  250.                               unsigned width, unsigned height)
  251. {
  252.         unsigned long flags;
  253.         unsigned x2 = x1 + width;
  254.         unsigned y2 = y1 + height;
  255.  
  256.         spin_lock_irqsave(&par->dirty.lock, flags);
  257.         if (par->dirty.x1 == par->dirty.x2) {
  258.                 par->dirty.x1 = x1;
  259.                 par->dirty.y1 = y1;
  260.                 par->dirty.x2 = x2;
  261.                 par->dirty.y2 = y2;
  262.                 /* if we are active start the dirty work
  263.                  * we share the work with the defio system */
  264.                 if (par->dirty.active)
  265.                         schedule_delayed_work(&par->local_work,
  266.                                               VMW_DIRTY_DELAY);
  267.         } else {
  268.                 if (x1 < par->dirty.x1)
  269.                         par->dirty.x1 = x1;
  270.                 if (y1 < par->dirty.y1)
  271.                         par->dirty.y1 = y1;
  272.                 if (x2 > par->dirty.x2)
  273.                         par->dirty.x2 = x2;
  274.                 if (y2 > par->dirty.y2)
  275.                         par->dirty.y2 = y2;
  276.         }
  277.         spin_unlock_irqrestore(&par->dirty.lock, flags);
  278. }
  279.  
  280. static int vmw_fb_pan_display(struct fb_var_screeninfo *var,
  281.                               struct fb_info *info)
  282. {
  283.         struct vmw_fb_par *par = info->par;
  284.  
  285.         if ((var->xoffset + var->xres) > var->xres_virtual ||
  286.             (var->yoffset + var->yres) > var->yres_virtual) {
  287.                 DRM_ERROR("Requested panning can not fit in framebuffer\n");
  288.                 return -EINVAL;
  289.         }
  290.  
  291.         mutex_lock(&par->bo_mutex);
  292.         par->fb_x = var->xoffset;
  293.         par->fb_y = var->yoffset;
  294.         if (par->set_fb)
  295.                 vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, par->set_fb->width,
  296.                                   par->set_fb->height);
  297.         mutex_unlock(&par->bo_mutex);
  298.  
  299.         return 0;
  300. }
  301.  
  302. #if 0
  303. static void vmw_deferred_io(struct fb_info *info,
  304.                             struct list_head *pagelist)
  305. {
  306.         struct vmw_fb_par *par = info->par;
  307.         unsigned long start, end, min, max;
  308.         unsigned long flags;
  309.         struct page *page;
  310.         int y1, y2;
  311.  
  312.         min = ULONG_MAX;
  313.         max = 0;
  314.         list_for_each_entry(page, pagelist, lru) {
  315.                 start = page->index << PAGE_SHIFT;
  316.                 end = start + PAGE_SIZE - 1;
  317.                 min = min(min, start);
  318.                 max = max(max, end);
  319.         }
  320.  
  321.         if (min < max) {
  322.                 y1 = min / info->fix.line_length;
  323.                 y2 = (max / info->fix.line_length) + 1;
  324.  
  325.                 spin_lock_irqsave(&par->dirty.lock, flags);
  326.                 par->dirty.x1 = 0;
  327.                 par->dirty.y1 = y1;
  328.                 par->dirty.x2 = info->var.xres;
  329.                 par->dirty.y2 = y2;
  330.                 spin_unlock_irqrestore(&par->dirty.lock, flags);
  331.  
  332.                 /*
  333.                  * Since we've already waited on this work once, try to
  334.                  * execute asap.
  335.                  */
  336.                 cancel_delayed_work(&par->local_work);
  337.                 schedule_delayed_work(&par->local_work, 0);
  338.         }
  339. };
  340.  
  341. static struct fb_deferred_io vmw_defio = {
  342.         .delay          = VMW_DIRTY_DELAY,
  343.     .deferred_io    = vmw_deferred_io,
  344. };
  345. #endif
  346.  
  347. /*
  348.  * Draw code
  349.  */
  350.  
  351. static void vmw_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
  352. {
  353.         cfb_fillrect(info, rect);
  354.         vmw_fb_dirty_mark(info->par, rect->dx, rect->dy,
  355.                           rect->width, rect->height);
  356. }
  357.  
  358. static void vmw_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
  359. {
  360.         cfb_copyarea(info, region);
  361.         vmw_fb_dirty_mark(info->par, region->dx, region->dy,
  362.                           region->width, region->height);
  363. }
  364.  
  365. static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image)
  366. {
  367.         cfb_imageblit(info, image);
  368.         vmw_fb_dirty_mark(info->par, image->dx, image->dy,
  369.                           image->width, image->height);
  370. }
  371.  
  372. /*
  373.  * Bring up code
  374.  */
  375.  
  376. static int vmw_fb_create_bo(struct vmw_private *vmw_priv,
  377.                             size_t size, struct vmw_dma_buffer **out)
  378. {
  379.         struct vmw_dma_buffer *vmw_bo;
  380.         int ret;
  381.  
  382.         (void) ttm_write_lock(&vmw_priv->reservation_sem, false);
  383.  
  384.         vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL);
  385.         if (!vmw_bo) {
  386.                 ret = -ENOMEM;
  387.                 goto err_unlock;
  388.         }
  389.  
  390.         ret = vmw_dmabuf_init(vmw_priv, vmw_bo, size,
  391.                               &vmw_sys_placement,
  392.                               false,
  393.                               &vmw_dmabuf_bo_free);
  394.         if (unlikely(ret != 0))
  395.                 goto err_unlock; /* init frees the buffer on failure */
  396.  
  397.         *out = vmw_bo;
  398.         ttm_write_unlock(&vmw_priv->reservation_sem);
  399.  
  400.         return 0;
  401.  
  402. err_unlock:
  403.         ttm_write_unlock(&vmw_priv->reservation_sem);
  404.         return ret;
  405. }
  406.  
  407. static int vmw_fb_compute_depth(struct fb_var_screeninfo *var,
  408.                                 int *depth)
  409. {
  410.         switch (var->bits_per_pixel) {
  411.         case 32:
  412.                 *depth = (var->transp.length > 0) ? 32 : 24;
  413.                 break;
  414.         default:
  415.                 DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel);
  416.                 return -EINVAL;
  417.         }
  418.  
  419.         return 0;
  420. }
  421.  
  422. static int vmw_fb_kms_detach(struct vmw_fb_par *par,
  423.                              bool detach_bo,
  424.                              bool unref_bo)
  425. {
  426.         struct drm_framebuffer *cur_fb = par->set_fb;
  427.         int ret;
  428.  
  429.         /* Detach the KMS framebuffer from crtcs */
  430.         if (par->set_mode) {
  431.                 struct drm_mode_set set;
  432.  
  433.                 set.crtc = par->crtc;
  434.                 set.x = 0;
  435.                 set.y = 0;
  436.                 set.mode = NULL;
  437.                 set.fb = NULL;
  438.                 set.num_connectors = 1;
  439.                 set.connectors = &par->con;
  440.                 ret = drm_mode_set_config_internal(&set);
  441.                 if (ret) {
  442.                         DRM_ERROR("Could not unset a mode.\n");
  443.                         return ret;
  444.                 }
  445.                 drm_mode_destroy(par->vmw_priv->dev, par->set_mode);
  446.                 par->set_mode = NULL;
  447.         }
  448.  
  449.         if (cur_fb) {
  450.                 drm_framebuffer_unreference(cur_fb);
  451.                 par->set_fb = NULL;
  452.         }
  453.  
  454.         if (par->vmw_bo && detach_bo) {
  455.                 if (par->bo_ptr) {
  456.                         ttm_bo_kunmap(&par->map);
  457.                         par->bo_ptr = NULL;
  458.                 }
  459.                 if (unref_bo)
  460.                         vmw_dmabuf_unreference(&par->vmw_bo);
  461.                 else
  462.                         vmw_dmabuf_unpin(par->vmw_priv, par->vmw_bo, false);
  463.         }
  464.  
  465.         return 0;
  466. }
  467.  
  468. static int vmw_fb_kms_framebuffer(struct fb_info *info)
  469. {
  470.         struct drm_mode_fb_cmd mode_cmd;
  471.         struct vmw_fb_par *par = info->par;
  472.         struct fb_var_screeninfo *var = &info->var;
  473.         struct drm_framebuffer *cur_fb;
  474.         struct vmw_framebuffer *vfb;
  475.         int ret = 0;
  476.         size_t new_bo_size;
  477.  
  478.         ret = vmw_fb_compute_depth(var, &mode_cmd.depth);
  479.         if (ret)
  480.                 return ret;
  481.  
  482.         mode_cmd.width = var->xres;
  483.         mode_cmd.height = var->yres;
  484.         mode_cmd.bpp = var->bits_per_pixel;
  485.         mode_cmd.pitch = ((mode_cmd.bpp + 7) / 8) * mode_cmd.width;
  486.  
  487.         cur_fb = par->set_fb;
  488.         if (cur_fb && cur_fb->width == mode_cmd.width &&
  489.             cur_fb->height == mode_cmd.height &&
  490.             cur_fb->bits_per_pixel == mode_cmd.bpp &&
  491.             cur_fb->depth == mode_cmd.depth &&
  492.             cur_fb->pitches[0] == mode_cmd.pitch)
  493.                 return 0;
  494.  
  495.         /* Need new buffer object ? */
  496.         new_bo_size = (size_t) mode_cmd.pitch * (size_t) mode_cmd.height;
  497.         ret = vmw_fb_kms_detach(par,
  498.                                 par->bo_size < new_bo_size ||
  499.                                 par->bo_size > 2*new_bo_size,
  500.                                 true);
  501.         if (ret)
  502.                 return ret;
  503.  
  504.         if (!par->vmw_bo) {
  505.                 ret = vmw_fb_create_bo(par->vmw_priv, new_bo_size,
  506.                                        &par->vmw_bo);
  507.                 if (ret) {
  508.                         DRM_ERROR("Failed creating a buffer object for "
  509.                                   "fbdev.\n");
  510.                         return ret;
  511.                 }
  512.                 par->bo_size = new_bo_size;
  513.         }
  514.  
  515.         vfb = vmw_kms_new_framebuffer(par->vmw_priv, par->vmw_bo, NULL,
  516.                                       true, &mode_cmd);
  517.         if (IS_ERR(vfb))
  518.                 return PTR_ERR(vfb);
  519.  
  520.         par->set_fb = &vfb->base;
  521.  
  522.         if (!par->bo_ptr) {
  523.                 /*
  524.                  * Pin before mapping. Since we don't know in what placement
  525.                  * to pin, call into KMS to do it for us.
  526.                  */
  527.                 ret = vfb->pin(vfb);
  528.                 if (ret) {
  529.                         DRM_ERROR("Could not pin the fbdev framebuffer.\n");
  530.                         return ret;
  531.                 }
  532.  
  533.                 ret = ttm_bo_kmap(&par->vmw_bo->base, 0,
  534.                                   par->vmw_bo->base.num_pages, &par->map);
  535.                 if (ret) {
  536.                         vfb->unpin(vfb);
  537.                         DRM_ERROR("Could not map the fbdev framebuffer.\n");
  538.                         return ret;
  539.                 }
  540.  
  541.                 par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite);
  542.         }
  543.  
  544.         return 0;
  545. }
  546.  
  547. static int vmw_fb_set_par(struct fb_info *info)
  548. {
  549.         struct vmw_fb_par *par = info->par;
  550.         struct vmw_private *vmw_priv = par->vmw_priv;
  551.         struct drm_mode_set set;
  552.         struct fb_var_screeninfo *var = &info->var;
  553.         struct drm_display_mode new_mode = { DRM_MODE("fb_mode",
  554.                 DRM_MODE_TYPE_DRIVER,
  555.                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  556.                 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
  557.         };
  558.         struct drm_display_mode *old_mode;
  559.         struct drm_display_mode *mode;
  560.         int ret;
  561.  
  562.         old_mode = par->set_mode;
  563.         mode = drm_mode_duplicate(vmw_priv->dev, &new_mode);
  564.         if (!mode) {
  565.                 DRM_ERROR("Could not create new fb mode.\n");
  566.                 return -ENOMEM;
  567.         }
  568.  
  569.         mode->hdisplay = var->xres;
  570.         mode->vdisplay = var->yres;
  571.         vmw_guess_mode_timing(mode);
  572.  
  573.         if (old_mode && drm_mode_equal(old_mode, mode)) {
  574.                 drm_mode_destroy(vmw_priv->dev, mode);
  575.                 mode = old_mode;
  576.                 old_mode = NULL;
  577.         } else if (!vmw_kms_validate_mode_vram(vmw_priv,
  578.                                                mode->hdisplay *
  579.                                                (var->bits_per_pixel + 7) / 8,
  580.                                                mode->vdisplay)) {
  581.                 drm_mode_destroy(vmw_priv->dev, mode);
  582.                 return -EINVAL;
  583.         }
  584.  
  585.         mutex_lock(&par->bo_mutex);
  586.         drm_modeset_lock_all(vmw_priv->dev);
  587.         ret = vmw_fb_kms_framebuffer(info);
  588.         if (ret)
  589.                 goto out_unlock;
  590.  
  591.         par->fb_x = var->xoffset;
  592.         par->fb_y = var->yoffset;
  593.  
  594.         set.crtc = par->crtc;
  595.         set.x = 0;
  596.         set.y = 0;
  597.         set.mode = mode;
  598.         set.fb = par->set_fb;
  599.         set.num_connectors = 1;
  600.         set.connectors = &par->con;
  601.  
  602.         ret = drm_mode_set_config_internal(&set);
  603.         if (ret)
  604.                 goto out_unlock;
  605.  
  606.         vmw_fb_dirty_mark(par, par->fb_x, par->fb_y,
  607.                           par->set_fb->width, par->set_fb->height);
  608.  
  609.         /* If there already was stuff dirty we wont
  610.          * schedule a new work, so lets do it now */
  611.  
  612. //      schedule_delayed_work(&par->local_work, 0);
  613.  
  614. out_unlock:
  615.         if (old_mode)
  616.                 drm_mode_destroy(vmw_priv->dev, old_mode);
  617.         par->set_mode = mode;
  618.  
  619.         drm_modeset_unlock_all(vmw_priv->dev);
  620.         mutex_unlock(&par->bo_mutex);
  621.  
  622.         return ret;
  623. }
  624.  
  625.  
  626. static struct fb_ops vmw_fb_ops = {
  627.         .owner = THIS_MODULE,
  628.         .fb_check_var = vmw_fb_check_var,
  629.         .fb_set_par = vmw_fb_set_par,
  630.         .fb_setcolreg = vmw_fb_setcolreg,
  631. //   .fb_fillrect = vmw_fb_fillrect,
  632. //   .fb_copyarea = vmw_fb_copyarea,
  633. //   .fb_imageblit = vmw_fb_imageblit,
  634. //   .fb_pan_display = vmw_fb_pan_display,
  635.         .fb_blank = vmw_fb_blank,
  636. };
  637.  
  638. int vmw_fb_init(struct vmw_private *vmw_priv)
  639. {
  640.         struct device *device = &vmw_priv->dev->pdev->dev;
  641.         struct vmw_fb_par *par;
  642.         struct fb_info *info;
  643.         unsigned fb_width, fb_height;
  644.         unsigned fb_bpp, fb_depth, fb_offset, fb_pitch, fb_size;
  645.         struct drm_display_mode *init_mode;
  646.         int ret;
  647.  
  648.         fb_bpp = 32;
  649.         fb_depth = 24;
  650.  
  651.         /* XXX As shouldn't these be as well. */
  652.         fb_width = min(vmw_priv->fb_max_width, (unsigned)2048);
  653.         fb_height = min(vmw_priv->fb_max_height, (unsigned)2048);
  654.  
  655.         fb_pitch = fb_width * fb_bpp / 8;
  656.         fb_size = fb_pitch * fb_height;
  657.         fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET);
  658.  
  659.         info = framebuffer_alloc(sizeof(*par), device);
  660.         if (!info)
  661.                 return -ENOMEM;
  662.  
  663.         /*
  664.          * Par
  665.          */
  666.         vmw_priv->fb_info = info;
  667.         par = info->par;
  668.         memset(par, 0, sizeof(*par));
  669.         INIT_DELAYED_WORK(&par->local_work, &vmw_fb_dirty_flush);
  670.         par->vmw_priv = vmw_priv;
  671.         par->vmalloc = NULL;
  672.         par->max_width = fb_width;
  673.         par->max_height = fb_height;
  674.  
  675.         drm_modeset_lock_all(vmw_priv->dev);
  676.         ret = vmw_kms_fbdev_init_data(vmw_priv, 0, par->max_width,
  677.                                       par->max_height, &par->con,
  678.                                       &par->crtc, &init_mode);
  679.         if (ret) {
  680.                 drm_modeset_unlock_all(vmw_priv->dev);
  681.                 goto err_kms;
  682.         }
  683.  
  684.         info->var.xres = init_mode->hdisplay;
  685.         info->var.yres = init_mode->vdisplay;
  686.         drm_modeset_unlock_all(vmw_priv->dev);
  687.  
  688.         /*
  689.          * Create buffers and alloc memory
  690.          */
  691.         par->vmalloc = vzalloc(fb_size);
  692.         if (unlikely(par->vmalloc == NULL)) {
  693.                 ret = -ENOMEM;
  694.                 goto err_free;
  695.         }
  696.  
  697.         /*
  698.          * Fixed and var
  699.          */
  700.         strcpy(info->fix.id, "svgadrmfb");
  701.         info->fix.type = FB_TYPE_PACKED_PIXELS;
  702.         info->fix.visual = FB_VISUAL_TRUECOLOR;
  703.         info->fix.type_aux = 0;
  704.         info->fix.xpanstep = 1; /* doing it in hw */
  705.         info->fix.ypanstep = 1; /* doing it in hw */
  706.         info->fix.ywrapstep = 0;
  707.         info->fix.accel = FB_ACCEL_NONE;
  708.         info->fix.line_length = fb_pitch;
  709.  
  710.         info->fix.smem_start = 0;
  711.         info->fix.smem_len = fb_size;
  712.  
  713.         info->pseudo_palette = par->pseudo_palette;
  714.         info->screen_base = (char __iomem *)par->vmalloc;
  715.         info->screen_size = fb_size;
  716.  
  717.         info->flags = FBINFO_DEFAULT;
  718.         info->fbops = &vmw_fb_ops;
  719.  
  720.         /* 24 depth per default */
  721.         info->var.red.offset = 16;
  722.         info->var.green.offset = 8;
  723.         info->var.blue.offset = 0;
  724.         info->var.red.length = 8;
  725.         info->var.green.length = 8;
  726.         info->var.blue.length = 8;
  727.         info->var.transp.offset = 0;
  728.         info->var.transp.length = 0;
  729.  
  730.         info->var.xres_virtual = fb_width;
  731.         info->var.yres_virtual = fb_height;
  732.         info->var.bits_per_pixel = fb_bpp;
  733.         info->var.xoffset = 0;
  734.         info->var.yoffset = 0;
  735.         info->var.activate = FB_ACTIVATE_NOW;
  736.         info->var.height = -1;
  737.         info->var.width = -1;
  738.  
  739.         /*
  740.          * Dirty & Deferred IO
  741.          */
  742.         par->dirty.x1 = par->dirty.x2 = 0;
  743.         par->dirty.y1 = par->dirty.y2 = 0;
  744.         par->dirty.active = true;
  745.         spin_lock_init(&par->dirty.lock);
  746.         mutex_init(&par->bo_mutex);
  747. //   fb_deferred_io_init(info);
  748.  
  749.         vmw_fb_set_par(info);
  750.  
  751.         return 0;
  752.  
  753. err_defio:
  754.         fb_deferred_io_cleanup(info);
  755. err_aper:
  756. err_free:
  757.         vfree(par->vmalloc);
  758. err_kms:
  759.         framebuffer_release(info);
  760.         vmw_priv->fb_info = NULL;
  761.  
  762.         return ret;
  763. }
  764.  
  765. int vmw_fb_close(struct vmw_private *vmw_priv)
  766. {
  767.         struct fb_info *info;
  768.         struct vmw_fb_par *par;
  769.  
  770.         if (!vmw_priv->fb_info)
  771.                 return 0;
  772.  
  773.         info = vmw_priv->fb_info;
  774.         par = info->par;
  775.  
  776.         /* ??? order */
  777.  
  778.         (void) vmw_fb_kms_detach(par, true, true);
  779.  
  780.         vfree(par->vmalloc);
  781.         framebuffer_release(info);
  782.  
  783.         return 0;
  784. }
  785.  
  786. int vmw_fb_off(struct vmw_private *vmw_priv)
  787. {
  788.         struct fb_info *info;
  789.         struct vmw_fb_par *par;
  790.         unsigned long flags;
  791.  
  792.         if (!vmw_priv->fb_info)
  793.                 return -EINVAL;
  794.  
  795.         info = vmw_priv->fb_info;
  796.         par = info->par;
  797.  
  798.         spin_lock_irqsave(&par->dirty.lock, flags);
  799.         par->dirty.active = false;
  800.         spin_unlock_irqrestore(&par->dirty.lock, flags);
  801.  
  802.         mutex_lock(&par->bo_mutex);
  803.         (void) vmw_fb_kms_detach(par, true, false);
  804.         mutex_unlock(&par->bo_mutex);
  805.  
  806.         return 0;
  807. }
  808.  
  809. int vmw_fb_on(struct vmw_private *vmw_priv)
  810. {
  811.         struct fb_info *info;
  812.         struct vmw_fb_par *par;
  813.         unsigned long flags;
  814.  
  815.         if (!vmw_priv->fb_info)
  816.                 return -EINVAL;
  817.  
  818.         info = vmw_priv->fb_info;
  819.         par = info->par;
  820.  
  821.         vmw_fb_set_par(info);
  822.         spin_lock_irqsave(&par->dirty.lock, flags);
  823.         par->dirty.active = true;
  824.         spin_unlock_irqrestore(&par->dirty.lock, flags);
  825.  
  826.         return 0;
  827. }
  828.  
  829. void vmw_fb_update(struct vmw_private *vmw_priv)
  830. {
  831.         struct fb_info *info = vmw_priv->fb_info;
  832.         struct vmw_fb_par *par = info->par;
  833.         vmw_fb_dirty_mark(par, 0, 0,
  834.                                           par->set_fb->width, par->set_fb->height);
  835. }
  836.