aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/omap_fb.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-01-22 19:17:06 -0500
committerDave Airlie <airlied@redhat.com>2017-01-22 19:17:06 -0500
commit01f5e6912c8abc8a23248e6cf66939756f0fb27c (patch)
treed2bfbad945b715a433eec6200c827f5b4e2138b4 /drivers/gpu/drm/omapdrm/omap_fb.c
parentd64a1661c8f783214e1a4fd9d38c2919d5b8231d (diff)
parent42f7f3c4811b3149253ecf2e133832c969884466 (diff)
Merge tag 'omapdrm-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next
omapdrm changes for 4.11 The main change here is the IRQ code cleanup, which gives us properly working vblank counts and timestamps. We also get much less calls to runtime PM gets & puts. * tag 'omapdrm-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (26 commits) drm/omap: panel-sony-acx565akm.c: Add MODULE_ALIAS drm/omap: dsi: fix compile errors when enabling debug prints drm: omapdrm: Perform initialization/cleanup at probe/remove time drm: Move vblank cleanup from unregister to release drm: omapdrm: Use sizeof(*var) instead of sizeof(type) for structures drm: omapdrm: Remove global variables drm: omapdrm: Simplify IRQ wait implementation drm: omapdrm: Inline the pipe2vbl function drm: omapdrm: Don't call DISPC power handling in IRQ wait functions drm: omapdrm: Remove unused parameter from omap_drm_irq handler drm: omapdrm: Don't expose the omap_irq_(un)register() functions drm: omapdrm: Keep vblank interrupt enabled while CRTC is active drm: omapdrm: Use a spinlock to protect the CRTC pending flag drm: omapdrm: Prevent processing the same event multiple times drm: omapdrm: Check the CRTC software state at enable/disable time drm: omapdrm: Let the DRM core skip plane commit on inactive CRTCs drm: omapdrm: Replace DSS manager state check with omapdrm CRTC state drm: omapdrm: Handle OCP error IRQ directly drm: omapdrm: Handle CRTC error IRQs directly drm: omapdrm: Handle FIFO underflow IRQs internally ...
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_fb.c')
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.c164
1 files changed, 84 insertions, 80 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index bd6b94c38613..29dc677dd4d3 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -29,37 +29,30 @@
29 * framebuffer funcs 29 * framebuffer funcs
30 */ 30 */
31 31
32/* per-format info: */ 32/* DSS to DRM formats mapping */
33struct format { 33static const struct {
34 enum omap_color_mode dss_format; 34 enum omap_color_mode dss_format;
35 uint32_t pixel_format; 35 uint32_t pixel_format;
36 struct { 36} formats[] = {
37 int stride_bpp; /* this times width is stride */
38 int sub_y; /* sub-sample in y dimension */
39 } planes[4];
40 bool yuv;
41};
42
43static const struct format formats[] = {
44 /* 16bpp [A]RGB: */ 37 /* 16bpp [A]RGB: */
45 { OMAP_DSS_COLOR_RGB16, DRM_FORMAT_RGB565, {{2, 1}}, false }, /* RGB16-565 */ 38 { OMAP_DSS_COLOR_RGB16, DRM_FORMAT_RGB565 }, /* RGB16-565 */
46 { OMAP_DSS_COLOR_RGB12U, DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */ 39 { OMAP_DSS_COLOR_RGB12U, DRM_FORMAT_RGBX4444 }, /* RGB12x-4444 */
47 { OMAP_DSS_COLOR_RGBX16, DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */ 40 { OMAP_DSS_COLOR_RGBX16, DRM_FORMAT_XRGB4444 }, /* xRGB12-4444 */
48 { OMAP_DSS_COLOR_RGBA16, DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */ 41 { OMAP_DSS_COLOR_RGBA16, DRM_FORMAT_RGBA4444 }, /* RGBA12-4444 */
49 { OMAP_DSS_COLOR_ARGB16, DRM_FORMAT_ARGB4444, {{2, 1}}, false }, /* ARGB16-4444 */ 42 { OMAP_DSS_COLOR_ARGB16, DRM_FORMAT_ARGB4444 }, /* ARGB16-4444 */
50 { OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555, {{2, 1}}, false }, /* xRGB15-1555 */ 43 { OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555 }, /* xRGB15-1555 */
51 { OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555, {{2, 1}}, false }, /* ARGB16-1555 */ 44 { OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555 }, /* ARGB16-1555 */
52 /* 24bpp RGB: */ 45 /* 24bpp RGB: */
53 { OMAP_DSS_COLOR_RGB24P, DRM_FORMAT_RGB888, {{3, 1}}, false }, /* RGB24-888 */ 46 { OMAP_DSS_COLOR_RGB24P, DRM_FORMAT_RGB888 }, /* RGB24-888 */
54 /* 32bpp [A]RGB: */ 47 /* 32bpp [A]RGB: */
55 { OMAP_DSS_COLOR_RGBX32, DRM_FORMAT_RGBX8888, {{4, 1}}, false }, /* RGBx24-8888 */ 48 { OMAP_DSS_COLOR_RGBX32, DRM_FORMAT_RGBX8888 }, /* RGBx24-8888 */
56 { OMAP_DSS_COLOR_RGB24U, DRM_FORMAT_XRGB8888, {{4, 1}}, false }, /* xRGB24-8888 */ 49 { OMAP_DSS_COLOR_RGB24U, DRM_FORMAT_XRGB8888 }, /* xRGB24-8888 */
57 { OMAP_DSS_COLOR_RGBA32, DRM_FORMAT_RGBA8888, {{4, 1}}, false }, /* RGBA32-8888 */ 50 { OMAP_DSS_COLOR_RGBA32, DRM_FORMAT_RGBA8888 }, /* RGBA32-8888 */
58 { OMAP_DSS_COLOR_ARGB32, DRM_FORMAT_ARGB8888, {{4, 1}}, false }, /* ARGB32-8888 */ 51 { OMAP_DSS_COLOR_ARGB32, DRM_FORMAT_ARGB8888 }, /* ARGB32-8888 */
59 /* YUV: */ 52 /* YUV: */
60 { OMAP_DSS_COLOR_NV12, DRM_FORMAT_NV12, {{1, 1}, {1, 2}}, true }, 53 { OMAP_DSS_COLOR_NV12, DRM_FORMAT_NV12 },
61 { OMAP_DSS_COLOR_YUV2, DRM_FORMAT_YUYV, {{2, 1}}, true }, 54 { OMAP_DSS_COLOR_YUV2, DRM_FORMAT_YUYV },
62 { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY, {{2, 1}}, true }, 55 { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY },
63}; 56};
64 57
65/* convert from overlay's pixel formats bitmask to an array of fourcc's */ 58/* convert from overlay's pixel formats bitmask to an array of fourcc's */
@@ -89,8 +82,9 @@ struct plane {
89struct omap_framebuffer { 82struct omap_framebuffer {
90 struct drm_framebuffer base; 83 struct drm_framebuffer base;
91 int pin_count; 84 int pin_count;
92 const struct format *format; 85 const struct drm_format_info *format;
93 struct plane planes[4]; 86 enum omap_color_mode dss_format;
87 struct plane planes[2];
94 /* lock for pinning (pin_count and planes.paddr) */ 88 /* lock for pinning (pin_count and planes.paddr) */
95 struct mutex lock; 89 struct mutex lock;
96}; 90};
@@ -128,13 +122,13 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
128}; 122};
129 123
130static uint32_t get_linear_addr(struct plane *plane, 124static uint32_t get_linear_addr(struct plane *plane,
131 const struct format *format, int n, int x, int y) 125 const struct drm_format_info *format, int n, int x, int y)
132{ 126{
133 uint32_t offset; 127 uint32_t offset;
134 128
135 offset = plane->offset + 129 offset = plane->offset
136 (x * format->planes[n].stride_bpp) + 130 + (x * format->cpp[n] / (n == 0 ? 1 : format->hsub))
137 (y * plane->pitch / format->planes[n].sub_y); 131 + (y * plane->pitch / (n == 0 ? 1 : format->vsub));
138 132
139 return plane->paddr + offset; 133 return plane->paddr + offset;
140} 134}
@@ -153,11 +147,11 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
153 struct omap_drm_window *win, struct omap_overlay_info *info) 147 struct omap_drm_window *win, struct omap_overlay_info *info)
154{ 148{
155 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 149 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
156 const struct format *format = omap_fb->format; 150 const struct drm_format_info *format = omap_fb->format;
157 struct plane *plane = &omap_fb->planes[0]; 151 struct plane *plane = &omap_fb->planes[0];
158 uint32_t x, y, orient = 0; 152 uint32_t x, y, orient = 0;
159 153
160 info->color_mode = format->dss_format; 154 info->color_mode = omap_fb->dss_format;
161 155
162 info->pos_x = win->crtc_x; 156 info->pos_x = win->crtc_x;
163 info->pos_y = win->crtc_y; 157 info->pos_y = win->crtc_y;
@@ -231,9 +225,9 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
231 } 225 }
232 226
233 /* convert to pixels: */ 227 /* convert to pixels: */
234 info->screen_width /= format->planes[0].stride_bpp; 228 info->screen_width /= format->cpp[0];
235 229
236 if (format->dss_format == OMAP_DSS_COLOR_NV12) { 230 if (omap_fb->dss_format == OMAP_DSS_COLOR_NV12) {
237 plane = &omap_fb->planes[1]; 231 plane = &omap_fb->planes[1];
238 232
239 if (info->rotation_type == OMAP_DSS_ROT_TILER) { 233 if (info->rotation_type == OMAP_DSS_ROT_TILER) {
@@ -360,47 +354,58 @@ void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
360struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, 354struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
361 struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) 355 struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
362{ 356{
357 unsigned int num_planes = drm_format_num_planes(mode_cmd->pixel_format);
363 struct drm_gem_object *bos[4]; 358 struct drm_gem_object *bos[4];
364 struct drm_framebuffer *fb; 359 struct drm_framebuffer *fb;
365 int ret; 360 int i;
366 361
367 ret = objects_lookup(file, mode_cmd->pixel_format, 362 for (i = 0; i < num_planes; i++) {
368 bos, mode_cmd->handles); 363 bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
369 if (ret) 364 if (!bos[i]) {
370 return ERR_PTR(ret); 365 fb = ERR_PTR(-ENOENT);
366 goto error;
367 }
368 }
371 369
372 fb = omap_framebuffer_init(dev, mode_cmd, bos); 370 fb = omap_framebuffer_init(dev, mode_cmd, bos);
373 if (IS_ERR(fb)) { 371 if (IS_ERR(fb))
374 int i, n = drm_format_num_planes(mode_cmd->pixel_format); 372 goto error;
375 for (i = 0; i < n; i++) 373
376 drm_gem_object_unreference_unlocked(bos[i]); 374 return fb;
377 return fb; 375
378 } 376error:
377 while (--i > 0)
378 drm_gem_object_unreference_unlocked(bos[i]);
379
379 return fb; 380 return fb;
380} 381}
381 382
382struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, 383struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
383 const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) 384 const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
384{ 385{
386 const struct drm_format_info *format = NULL;
385 struct omap_framebuffer *omap_fb = NULL; 387 struct omap_framebuffer *omap_fb = NULL;
386 struct drm_framebuffer *fb = NULL; 388 struct drm_framebuffer *fb = NULL;
387 const struct format *format = NULL; 389 enum omap_color_mode dss_format = 0;
388 int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format); 390 unsigned int pitch = mode_cmd->pitches[0];
391 int ret, i;
389 392
390 DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", 393 DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
391 dev, mode_cmd, mode_cmd->width, mode_cmd->height, 394 dev, mode_cmd, mode_cmd->width, mode_cmd->height,
392 (char *)&mode_cmd->pixel_format); 395 (char *)&mode_cmd->pixel_format);
393 396
397 format = drm_format_info(mode_cmd->pixel_format);
398
394 for (i = 0; i < ARRAY_SIZE(formats); i++) { 399 for (i = 0; i < ARRAY_SIZE(formats); i++) {
395 if (formats[i].pixel_format == mode_cmd->pixel_format) { 400 if (formats[i].pixel_format == mode_cmd->pixel_format) {
396 format = &formats[i]; 401 dss_format = formats[i].dss_format;
397 break; 402 break;
398 } 403 }
399 } 404 }
400 405
401 if (!format) { 406 if (!format || !dss_format) {
402 dev_err(dev->dev, "unsupported pixel format: %4.4s\n", 407 dev_dbg(dev->dev, "unsupported pixel format: %4.4s\n",
403 (char *)&mode_cmd->pixel_format); 408 (char *)&mode_cmd->pixel_format);
404 ret = -EINVAL; 409 ret = -EINVAL;
405 goto fail; 410 goto fail;
406 } 411 }
@@ -413,40 +418,39 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
413 418
414 fb = &omap_fb->base; 419 fb = &omap_fb->base;
415 omap_fb->format = format; 420 omap_fb->format = format;
421 omap_fb->dss_format = dss_format;
416 mutex_init(&omap_fb->lock); 422 mutex_init(&omap_fb->lock);
417 423
418 for (i = 0; i < n; i++) { 424 /*
419 struct plane *plane = &omap_fb->planes[i]; 425 * The code below assumes that no format use more than two planes, and
420 int size, pitch = mode_cmd->pitches[i]; 426 * that the two planes of multiplane formats need the same number of
421 427 * bytes per pixel.
422 if (pitch < (mode_cmd->width * format->planes[i].stride_bpp)) { 428 */
423 dev_err(dev->dev, "provided buffer pitch is too small! %d < %d\n", 429 if (format->num_planes == 2 && pitch != mode_cmd->pitches[1]) {
424 pitch, mode_cmd->width * format->planes[i].stride_bpp); 430 dev_dbg(dev->dev, "pitches differ between planes 0 and 1\n");
425 ret = -EINVAL; 431 ret = -EINVAL;
426 goto fail; 432 goto fail;
427 } 433 }
428 434
429 if (pitch % format->planes[i].stride_bpp != 0) { 435 if (pitch % format->cpp[0]) {
430 dev_err(dev->dev, 436 dev_dbg(dev->dev,
431 "buffer pitch (%d bytes) is not a multiple of pixel size (%d bytes)\n", 437 "buffer pitch (%u bytes) is not a multiple of pixel size (%u bytes)\n",
432 pitch, format->planes[i].stride_bpp); 438 pitch, format->cpp[0]);
433 ret = -EINVAL; 439 ret = -EINVAL;
434 goto fail; 440 goto fail;
435 } 441 }
436 442
437 size = pitch * mode_cmd->height / format->planes[i].sub_y; 443 for (i = 0; i < format->num_planes; i++) {
444 struct plane *plane = &omap_fb->planes[i];
445 unsigned int vsub = i == 0 ? 1 : format->vsub;
446 unsigned int size;
438 447
439 if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) { 448 size = pitch * mode_cmd->height / vsub;
440 dev_err(dev->dev, "provided buffer object is too small! %d < %d\n",
441 bos[i]->size - mode_cmd->offsets[i], size);
442 ret = -EINVAL;
443 goto fail;
444 }
445 449
446 if (i > 0 && pitch != mode_cmd->pitches[i - 1]) { 450 if (size > omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i]) {
447 dev_err(dev->dev, 451 dev_dbg(dev->dev,
448 "pitches are not the same between framebuffer planes %d != %d\n", 452 "provided buffer object is too small! %d < %d\n",
449 pitch, mode_cmd->pitches[i - 1]); 453 bos[i]->size - mode_cmd->offsets[i], size);
450 ret = -EINVAL; 454 ret = -EINVAL;
451 goto fail; 455 goto fail;
452 } 456 }