Merge tag 'mmc-v4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
[cascardo/linux.git] / drivers / gpu / drm / qxl / qxl_fb.c
1 /*
2  * Copyright © 2013 Red Hat
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *     David Airlie
25  */
26 #include <linux/module.h>
27
28 #include "drmP.h"
29 #include "drm/drm.h"
30 #include "drm/drm_crtc.h"
31 #include "drm/drm_crtc_helper.h"
32 #include "qxl_drv.h"
33
34 #include "qxl_object.h"
35 #include "drm_fb_helper.h"
36
37 #define QXL_DIRTY_DELAY (HZ / 30)
38
39 struct qxl_fbdev {
40         struct drm_fb_helper helper;
41         struct qxl_framebuffer  qfb;
42         struct qxl_device       *qdev;
43
44         spinlock_t delayed_ops_lock;
45         struct list_head delayed_ops;
46         void *shadow;
47         int size;
48 };
49
50 static void qxl_fb_image_init(struct qxl_fb_image *qxl_fb_image,
51                               struct qxl_device *qdev, struct fb_info *info,
52                               const struct fb_image *image)
53 {
54         qxl_fb_image->qdev = qdev;
55         if (info) {
56                 qxl_fb_image->visual = info->fix.visual;
57                 if (qxl_fb_image->visual == FB_VISUAL_TRUECOLOR ||
58                     qxl_fb_image->visual == FB_VISUAL_DIRECTCOLOR)
59                         memcpy(&qxl_fb_image->pseudo_palette,
60                                info->pseudo_palette,
61                                sizeof(qxl_fb_image->pseudo_palette));
62         } else {
63                  /* fallback */
64                 if (image->depth == 1)
65                         qxl_fb_image->visual = FB_VISUAL_MONO10;
66                 else
67                         qxl_fb_image->visual = FB_VISUAL_DIRECTCOLOR;
68         }
69         if (image) {
70                 memcpy(&qxl_fb_image->fb_image, image,
71                        sizeof(qxl_fb_image->fb_image));
72         }
73 }
74
75 #ifdef CONFIG_DRM_FBDEV_EMULATION
76 static struct fb_deferred_io qxl_defio = {
77         .delay          = QXL_DIRTY_DELAY,
78         .deferred_io    = drm_fb_helper_deferred_io,
79 };
80 #endif
81
82 static struct fb_ops qxlfb_ops = {
83         .owner = THIS_MODULE,
84         .fb_check_var = drm_fb_helper_check_var,
85         .fb_set_par = drm_fb_helper_set_par, /* TODO: copy vmwgfx */
86         .fb_fillrect = drm_fb_helper_sys_fillrect,
87         .fb_copyarea = drm_fb_helper_sys_copyarea,
88         .fb_imageblit = drm_fb_helper_sys_imageblit,
89         .fb_pan_display = drm_fb_helper_pan_display,
90         .fb_blank = drm_fb_helper_blank,
91         .fb_setcmap = drm_fb_helper_setcmap,
92         .fb_debug_enter = drm_fb_helper_debug_enter,
93         .fb_debug_leave = drm_fb_helper_debug_leave,
94 };
95
96 static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj)
97 {
98         struct qxl_bo *qbo = gem_to_qxl_bo(gobj);
99         int ret;
100
101         ret = qxl_bo_reserve(qbo, false);
102         if (likely(ret == 0)) {
103                 qxl_bo_kunmap(qbo);
104                 qxl_bo_unpin(qbo);
105                 qxl_bo_unreserve(qbo);
106         }
107         drm_gem_object_unreference_unlocked(gobj);
108 }
109
110 int qxl_get_handle_for_primary_fb(struct qxl_device *qdev,
111                                   struct drm_file *file_priv,
112                                   uint32_t *handle)
113 {
114         int r;
115         struct drm_gem_object *gobj = qdev->fbdev_qfb->obj;
116
117         BUG_ON(!gobj);
118         /* drm_get_handle_create adds a reference - good */
119         r = drm_gem_handle_create(file_priv, gobj, handle);
120         if (r)
121                 return r;
122         return 0;
123 }
124
125 static int qxlfb_create_pinned_object(struct qxl_fbdev *qfbdev,
126                                       const struct drm_mode_fb_cmd2 *mode_cmd,
127                                       struct drm_gem_object **gobj_p)
128 {
129         struct qxl_device *qdev = qfbdev->qdev;
130         struct drm_gem_object *gobj = NULL;
131         struct qxl_bo *qbo = NULL;
132         int ret;
133         int aligned_size, size;
134         int height = mode_cmd->height;
135
136         size = mode_cmd->pitches[0] * height;
137         aligned_size = ALIGN(size, PAGE_SIZE);
138         /* TODO: unallocate and reallocate surface0 for real. Hack to just
139          * have a large enough surface0 for 1024x768 Xorg 32bpp mode */
140         ret = qxl_gem_object_create(qdev, aligned_size, 0,
141                                     QXL_GEM_DOMAIN_SURFACE,
142                                     false, /* is discardable */
143                                     false, /* is kernel (false means device) */
144                                     NULL,
145                                     &gobj);
146         if (ret) {
147                 pr_err("failed to allocate framebuffer (%d)\n",
148                        aligned_size);
149                 return -ENOMEM;
150         }
151         qbo = gem_to_qxl_bo(gobj);
152
153         qbo->surf.width = mode_cmd->width;
154         qbo->surf.height = mode_cmd->height;
155         qbo->surf.stride = mode_cmd->pitches[0];
156         qbo->surf.format = SPICE_SURFACE_FMT_32_xRGB;
157         ret = qxl_bo_reserve(qbo, false);
158         if (unlikely(ret != 0))
159                 goto out_unref;
160         ret = qxl_bo_pin(qbo, QXL_GEM_DOMAIN_SURFACE, NULL);
161         if (ret) {
162                 qxl_bo_unreserve(qbo);
163                 goto out_unref;
164         }
165         ret = qxl_bo_kmap(qbo, NULL);
166         qxl_bo_unreserve(qbo); /* unreserve, will be mmaped */
167         if (ret)
168                 goto out_unref;
169
170         *gobj_p = gobj;
171         return 0;
172 out_unref:
173         qxlfb_destroy_pinned_object(gobj);
174         *gobj_p = NULL;
175         return ret;
176 }
177
178 /*
179  * FIXME
180  * It should not be necessary to have a special dirty() callback for fbdev.
181  */
182 static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb,
183                                    struct drm_file *file_priv,
184                                    unsigned flags, unsigned color,
185                                    struct drm_clip_rect *clips,
186                                    unsigned num_clips)
187 {
188         struct qxl_device *qdev = fb->dev->dev_private;
189         struct fb_info *info = qdev->fbdev_info;
190         struct qxl_fbdev *qfbdev = info->par;
191         struct qxl_fb_image qxl_fb_image;
192         struct fb_image *image = &qxl_fb_image.fb_image;
193
194         /* TODO: hard coding 32 bpp */
195         int stride = qfbdev->qfb.base.pitches[0];
196
197         /*
198          * we are using a shadow draw buffer, at qdev->surface0_shadow
199          */
200         qxl_io_log(qdev, "dirty x[%d, %d], y[%d, %d]", clips->x1, clips->x2,
201                    clips->y1, clips->y2);
202         image->dx = clips->x1;
203         image->dy = clips->y1;
204         image->width = clips->x2 - clips->x1;
205         image->height = clips->y2 - clips->y1;
206         image->fg_color = 0xffffffff; /* unused, just to avoid uninitialized
207                                          warnings */
208         image->bg_color = 0;
209         image->depth = 32;           /* TODO: take from somewhere? */
210         image->cmap.start = 0;
211         image->cmap.len = 0;
212         image->cmap.red = NULL;
213         image->cmap.green = NULL;
214         image->cmap.blue = NULL;
215         image->cmap.transp = NULL;
216         image->data = qfbdev->shadow + (clips->x1 * 4) + (stride * clips->y1);
217
218         qxl_fb_image_init(&qxl_fb_image, qdev, info, NULL);
219         qxl_draw_opaque_fb(&qxl_fb_image, stride);
220
221         return 0;
222 }
223
224 static const struct drm_framebuffer_funcs qxlfb_fb_funcs = {
225         .destroy = qxl_user_framebuffer_destroy,
226         .dirty = qxlfb_framebuffer_dirty,
227 };
228
229 static int qxlfb_create(struct qxl_fbdev *qfbdev,
230                         struct drm_fb_helper_surface_size *sizes)
231 {
232         struct qxl_device *qdev = qfbdev->qdev;
233         struct fb_info *info;
234         struct drm_framebuffer *fb = NULL;
235         struct drm_mode_fb_cmd2 mode_cmd;
236         struct drm_gem_object *gobj = NULL;
237         struct qxl_bo *qbo = NULL;
238         int ret;
239         int size;
240         int bpp = sizes->surface_bpp;
241         int depth = sizes->surface_depth;
242         void *shadow;
243
244         mode_cmd.width = sizes->surface_width;
245         mode_cmd.height = sizes->surface_height;
246
247         mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 1) / 8), 64);
248         mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
249
250         ret = qxlfb_create_pinned_object(qfbdev, &mode_cmd, &gobj);
251         if (ret < 0)
252                 return ret;
253
254         qbo = gem_to_qxl_bo(gobj);
255         QXL_INFO(qdev, "%s: %dx%d %d\n", __func__, mode_cmd.width,
256                  mode_cmd.height, mode_cmd.pitches[0]);
257
258         shadow = vmalloc(mode_cmd.pitches[0] * mode_cmd.height);
259         /* TODO: what's the usual response to memory allocation errors? */
260         BUG_ON(!shadow);
261         QXL_INFO(qdev,
262         "surface0 at gpu offset %lld, mmap_offset %lld (virt %p, shadow %p)\n",
263                  qxl_bo_gpu_offset(qbo),
264                  qxl_bo_mmap_offset(qbo),
265                  qbo->kptr,
266                  shadow);
267         size = mode_cmd.pitches[0] * mode_cmd.height;
268
269         info = drm_fb_helper_alloc_fbi(&qfbdev->helper);
270         if (IS_ERR(info)) {
271                 ret = PTR_ERR(info);
272                 goto out_unref;
273         }
274
275         info->par = qfbdev;
276
277         qxl_framebuffer_init(qdev->ddev, &qfbdev->qfb, &mode_cmd, gobj,
278                              &qxlfb_fb_funcs);
279
280         fb = &qfbdev->qfb.base;
281
282         /* setup helper with fb data */
283         qfbdev->helper.fb = fb;
284
285         qfbdev->shadow = shadow;
286         strcpy(info->fix.id, "qxldrmfb");
287
288         drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
289
290         info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
291         info->fbops = &qxlfb_ops;
292
293         /*
294          * TODO: using gobj->size in various places in this function. Not sure
295          * what the difference between the different sizes is.
296          */
297         info->fix.smem_start = qdev->vram_base; /* TODO - correct? */
298         info->fix.smem_len = gobj->size;
299         info->screen_base = qfbdev->shadow;
300         info->screen_size = gobj->size;
301
302         drm_fb_helper_fill_var(info, &qfbdev->helper, sizes->fb_width,
303                                sizes->fb_height);
304
305         /* setup aperture base/size for vesafb takeover */
306         info->apertures->ranges[0].base = qdev->ddev->mode_config.fb_base;
307         info->apertures->ranges[0].size = qdev->vram_size;
308
309         info->fix.mmio_start = 0;
310         info->fix.mmio_len = 0;
311
312         if (info->screen_base == NULL) {
313                 ret = -ENOSPC;
314                 goto out_destroy_fbi;
315         }
316
317 #ifdef CONFIG_DRM_FBDEV_EMULATION
318         info->fbdefio = &qxl_defio;
319         fb_deferred_io_init(info);
320 #endif
321
322         qdev->fbdev_info = info;
323         qdev->fbdev_qfb = &qfbdev->qfb;
324         DRM_INFO("fb mappable at 0x%lX, size %lu\n",  info->fix.smem_start, (unsigned long)info->screen_size);
325         DRM_INFO("fb: depth %d, pitch %d, width %d, height %d\n", fb->depth, fb->pitches[0], fb->width, fb->height);
326         return 0;
327
328 out_destroy_fbi:
329         drm_fb_helper_release_fbi(&qfbdev->helper);
330 out_unref:
331         if (qbo) {
332                 ret = qxl_bo_reserve(qbo, false);
333                 if (likely(ret == 0)) {
334                         qxl_bo_kunmap(qbo);
335                         qxl_bo_unpin(qbo);
336                         qxl_bo_unreserve(qbo);
337                 }
338         }
339         if (fb && ret) {
340                 drm_gem_object_unreference_unlocked(gobj);
341                 drm_framebuffer_cleanup(fb);
342                 kfree(fb);
343         }
344         drm_gem_object_unreference_unlocked(gobj);
345         return ret;
346 }
347
348 static int qxl_fb_find_or_create_single(
349                 struct drm_fb_helper *helper,
350                 struct drm_fb_helper_surface_size *sizes)
351 {
352         struct qxl_fbdev *qfbdev =
353                 container_of(helper, struct qxl_fbdev, helper);
354         int new_fb = 0;
355         int ret;
356
357         if (!helper->fb) {
358                 ret = qxlfb_create(qfbdev, sizes);
359                 if (ret)
360                         return ret;
361                 new_fb = 1;
362         }
363         return new_fb;
364 }
365
366 static int qxl_fbdev_destroy(struct drm_device *dev, struct qxl_fbdev *qfbdev)
367 {
368         struct qxl_framebuffer *qfb = &qfbdev->qfb;
369
370         drm_fb_helper_unregister_fbi(&qfbdev->helper);
371         drm_fb_helper_release_fbi(&qfbdev->helper);
372
373         if (qfb->obj) {
374                 qxlfb_destroy_pinned_object(qfb->obj);
375                 qfb->obj = NULL;
376         }
377         drm_fb_helper_fini(&qfbdev->helper);
378         vfree(qfbdev->shadow);
379         drm_framebuffer_cleanup(&qfb->base);
380
381         return 0;
382 }
383
384 static const struct drm_fb_helper_funcs qxl_fb_helper_funcs = {
385         .fb_probe = qxl_fb_find_or_create_single,
386 };
387
388 int qxl_fbdev_init(struct qxl_device *qdev)
389 {
390         struct qxl_fbdev *qfbdev;
391         int bpp_sel = 32; /* TODO: parameter from somewhere? */
392         int ret;
393
394         qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL);
395         if (!qfbdev)
396                 return -ENOMEM;
397
398         qfbdev->qdev = qdev;
399         qdev->mode_info.qfbdev = qfbdev;
400         spin_lock_init(&qfbdev->delayed_ops_lock);
401         INIT_LIST_HEAD(&qfbdev->delayed_ops);
402
403         drm_fb_helper_prepare(qdev->ddev, &qfbdev->helper,
404                               &qxl_fb_helper_funcs);
405
406         ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper,
407                                  qxl_num_crtc /* num_crtc - QXL supports just 1 */,
408                                  QXLFB_CONN_LIMIT);
409         if (ret)
410                 goto free;
411
412         ret = drm_fb_helper_single_add_all_connectors(&qfbdev->helper);
413         if (ret)
414                 goto fini;
415
416         ret = drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel);
417         if (ret)
418                 goto fini;
419
420         return 0;
421
422 fini:
423         drm_fb_helper_fini(&qfbdev->helper);
424 free:
425         kfree(qfbdev);
426         return ret;
427 }
428
429 void qxl_fbdev_fini(struct qxl_device *qdev)
430 {
431         if (!qdev->mode_info.qfbdev)
432                 return;
433
434         qxl_fbdev_destroy(qdev->ddev, qdev->mode_info.qfbdev);
435         kfree(qdev->mode_info.qfbdev);
436         qdev->mode_info.qfbdev = NULL;
437 }
438
439 void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state)
440 {
441         drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state);
442 }
443
444 bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj)
445 {
446         if (qobj == gem_to_qxl_bo(qdev->mode_info.qfbdev->qfb.obj))
447                 return true;
448         return false;
449 }