summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/omapdrm/omap_fb.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-01-23 03:17:06 +0300
committerDave Airlie <airlied@redhat.com>2017-01-23 03:17:06 +0300
commit01f5e6912c8abc8a23248e6cf66939756f0fb27c (patch)
treed2bfbad945b715a433eec6200c827f5b4e2138b4 /drivers/gpu/drm/omapdrm/omap_fb.c
parentd64a1661c8f783214e1a4fd9d38c2919d5b8231d (diff)
parent42f7f3c4811b3149253ecf2e133832c969884466 (diff)
downloadlinux-01f5e6912c8abc8a23248e6cf66939756f0fb27c.tar.xz
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 @@
* framebuffer funcs
*/
-/* per-format info: */
-struct format {
+/* DSS to DRM formats mapping */
+static const struct {
enum omap_color_mode dss_format;
uint32_t pixel_format;
- struct {
- int stride_bpp; /* this times width is stride */
- int sub_y; /* sub-sample in y dimension */
- } planes[4];
- bool yuv;
-};
-
-static const struct format formats[] = {
+} formats[] = {
/* 16bpp [A]RGB: */
- { OMAP_DSS_COLOR_RGB16, DRM_FORMAT_RGB565, {{2, 1}}, false }, /* RGB16-565 */
- { OMAP_DSS_COLOR_RGB12U, DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */
- { OMAP_DSS_COLOR_RGBX16, DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */
- { OMAP_DSS_COLOR_RGBA16, DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */
- { OMAP_DSS_COLOR_ARGB16, DRM_FORMAT_ARGB4444, {{2, 1}}, false }, /* ARGB16-4444 */
- { OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555, {{2, 1}}, false }, /* xRGB15-1555 */
- { OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555, {{2, 1}}, false }, /* ARGB16-1555 */
+ { OMAP_DSS_COLOR_RGB16, DRM_FORMAT_RGB565 }, /* RGB16-565 */
+ { OMAP_DSS_COLOR_RGB12U, DRM_FORMAT_RGBX4444 }, /* RGB12x-4444 */
+ { OMAP_DSS_COLOR_RGBX16, DRM_FORMAT_XRGB4444 }, /* xRGB12-4444 */
+ { OMAP_DSS_COLOR_RGBA16, DRM_FORMAT_RGBA4444 }, /* RGBA12-4444 */
+ { OMAP_DSS_COLOR_ARGB16, DRM_FORMAT_ARGB4444 }, /* ARGB16-4444 */
+ { OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555 }, /* xRGB15-1555 */
+ { OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555 }, /* ARGB16-1555 */
/* 24bpp RGB: */
- { OMAP_DSS_COLOR_RGB24P, DRM_FORMAT_RGB888, {{3, 1}}, false }, /* RGB24-888 */
+ { OMAP_DSS_COLOR_RGB24P, DRM_FORMAT_RGB888 }, /* RGB24-888 */
/* 32bpp [A]RGB: */
- { OMAP_DSS_COLOR_RGBX32, DRM_FORMAT_RGBX8888, {{4, 1}}, false }, /* RGBx24-8888 */
- { OMAP_DSS_COLOR_RGB24U, DRM_FORMAT_XRGB8888, {{4, 1}}, false }, /* xRGB24-8888 */
- { OMAP_DSS_COLOR_RGBA32, DRM_FORMAT_RGBA8888, {{4, 1}}, false }, /* RGBA32-8888 */
- { OMAP_DSS_COLOR_ARGB32, DRM_FORMAT_ARGB8888, {{4, 1}}, false }, /* ARGB32-8888 */
+ { OMAP_DSS_COLOR_RGBX32, DRM_FORMAT_RGBX8888 }, /* RGBx24-8888 */
+ { OMAP_DSS_COLOR_RGB24U, DRM_FORMAT_XRGB8888 }, /* xRGB24-8888 */
+ { OMAP_DSS_COLOR_RGBA32, DRM_FORMAT_RGBA8888 }, /* RGBA32-8888 */
+ { OMAP_DSS_COLOR_ARGB32, DRM_FORMAT_ARGB8888 }, /* ARGB32-8888 */
/* YUV: */
- { OMAP_DSS_COLOR_NV12, DRM_FORMAT_NV12, {{1, 1}, {1, 2}}, true },
- { OMAP_DSS_COLOR_YUV2, DRM_FORMAT_YUYV, {{2, 1}}, true },
- { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY, {{2, 1}}, true },
+ { OMAP_DSS_COLOR_NV12, DRM_FORMAT_NV12 },
+ { OMAP_DSS_COLOR_YUV2, DRM_FORMAT_YUYV },
+ { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY },
};
/* convert from overlay's pixel formats bitmask to an array of fourcc's */
@@ -89,8 +82,9 @@ struct plane {
struct omap_framebuffer {
struct drm_framebuffer base;
int pin_count;
- const struct format *format;
- struct plane planes[4];
+ const struct drm_format_info *format;
+ enum omap_color_mode dss_format;
+ struct plane planes[2];
/* lock for pinning (pin_count and planes.paddr) */
struct mutex lock;
};
@@ -128,13 +122,13 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
};
static uint32_t get_linear_addr(struct plane *plane,
- const struct format *format, int n, int x, int y)
+ const struct drm_format_info *format, int n, int x, int y)
{
uint32_t offset;
- offset = plane->offset +
- (x * format->planes[n].stride_bpp) +
- (y * plane->pitch / format->planes[n].sub_y);
+ offset = plane->offset
+ + (x * format->cpp[n] / (n == 0 ? 1 : format->hsub))
+ + (y * plane->pitch / (n == 0 ? 1 : format->vsub));
return plane->paddr + offset;
}
@@ -153,11 +147,11 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
struct omap_drm_window *win, struct omap_overlay_info *info)
{
struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
- const struct format *format = omap_fb->format;
+ const struct drm_format_info *format = omap_fb->format;
struct plane *plane = &omap_fb->planes[0];
uint32_t x, y, orient = 0;
- info->color_mode = format->dss_format;
+ info->color_mode = omap_fb->dss_format;
info->pos_x = win->crtc_x;
info->pos_y = win->crtc_y;
@@ -231,9 +225,9 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
}
/* convert to pixels: */
- info->screen_width /= format->planes[0].stride_bpp;
+ info->screen_width /= format->cpp[0];
- if (format->dss_format == OMAP_DSS_COLOR_NV12) {
+ if (omap_fb->dss_format == OMAP_DSS_COLOR_NV12) {
plane = &omap_fb->planes[1];
if (info->rotation_type == OMAP_DSS_ROT_TILER) {
@@ -360,47 +354,58 @@ void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
{
+ unsigned int num_planes = drm_format_num_planes(mode_cmd->pixel_format);
struct drm_gem_object *bos[4];
struct drm_framebuffer *fb;
- int ret;
+ int i;
- ret = objects_lookup(file, mode_cmd->pixel_format,
- bos, mode_cmd->handles);
- if (ret)
- return ERR_PTR(ret);
+ for (i = 0; i < num_planes; i++) {
+ bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
+ if (!bos[i]) {
+ fb = ERR_PTR(-ENOENT);
+ goto error;
+ }
+ }
fb = omap_framebuffer_init(dev, mode_cmd, bos);
- if (IS_ERR(fb)) {
- int i, n = drm_format_num_planes(mode_cmd->pixel_format);
- for (i = 0; i < n; i++)
- drm_gem_object_unreference_unlocked(bos[i]);
- return fb;
- }
+ if (IS_ERR(fb))
+ goto error;
+
+ return fb;
+
+error:
+ while (--i > 0)
+ drm_gem_object_unreference_unlocked(bos[i]);
+
return fb;
}
struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
{
+ const struct drm_format_info *format = NULL;
struct omap_framebuffer *omap_fb = NULL;
struct drm_framebuffer *fb = NULL;
- const struct format *format = NULL;
- int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
+ enum omap_color_mode dss_format = 0;
+ unsigned int pitch = mode_cmd->pitches[0];
+ int ret, i;
DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
dev, mode_cmd, mode_cmd->width, mode_cmd->height,
(char *)&mode_cmd->pixel_format);
+ format = drm_format_info(mode_cmd->pixel_format);
+
for (i = 0; i < ARRAY_SIZE(formats); i++) {
if (formats[i].pixel_format == mode_cmd->pixel_format) {
- format = &formats[i];
+ dss_format = formats[i].dss_format;
break;
}
}
- if (!format) {
- dev_err(dev->dev, "unsupported pixel format: %4.4s\n",
- (char *)&mode_cmd->pixel_format);
+ if (!format || !dss_format) {
+ dev_dbg(dev->dev, "unsupported pixel format: %4.4s\n",
+ (char *)&mode_cmd->pixel_format);
ret = -EINVAL;
goto fail;
}
@@ -413,40 +418,39 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
fb = &omap_fb->base;
omap_fb->format = format;
+ omap_fb->dss_format = dss_format;
mutex_init(&omap_fb->lock);
- for (i = 0; i < n; i++) {
- struct plane *plane = &omap_fb->planes[i];
- int size, pitch = mode_cmd->pitches[i];
-
- if (pitch < (mode_cmd->width * format->planes[i].stride_bpp)) {
- dev_err(dev->dev, "provided buffer pitch is too small! %d < %d\n",
- pitch, mode_cmd->width * format->planes[i].stride_bpp);
- ret = -EINVAL;
- goto fail;
- }
+ /*
+ * The code below assumes that no format use more than two planes, and
+ * that the two planes of multiplane formats need the same number of
+ * bytes per pixel.
+ */
+ if (format->num_planes == 2 && pitch != mode_cmd->pitches[1]) {
+ dev_dbg(dev->dev, "pitches differ between planes 0 and 1\n");
+ ret = -EINVAL;
+ goto fail;
+ }
- if (pitch % format->planes[i].stride_bpp != 0) {
- dev_err(dev->dev,
- "buffer pitch (%d bytes) is not a multiple of pixel size (%d bytes)\n",
- pitch, format->planes[i].stride_bpp);
- ret = -EINVAL;
- goto fail;
- }
+ if (pitch % format->cpp[0]) {
+ dev_dbg(dev->dev,
+ "buffer pitch (%u bytes) is not a multiple of pixel size (%u bytes)\n",
+ pitch, format->cpp[0]);
+ ret = -EINVAL;
+ goto fail;
+ }
- size = pitch * mode_cmd->height / format->planes[i].sub_y;
+ for (i = 0; i < format->num_planes; i++) {
+ struct plane *plane = &omap_fb->planes[i];
+ unsigned int vsub = i == 0 ? 1 : format->vsub;
+ unsigned int size;
- if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) {
- dev_err(dev->dev, "provided buffer object is too small! %d < %d\n",
- bos[i]->size - mode_cmd->offsets[i], size);
- ret = -EINVAL;
- goto fail;
- }
+ size = pitch * mode_cmd->height / vsub;
- if (i > 0 && pitch != mode_cmd->pitches[i - 1]) {
- dev_err(dev->dev,
- "pitches are not the same between framebuffer planes %d != %d\n",
- pitch, mode_cmd->pitches[i - 1]);
+ if (size > omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i]) {
+ dev_dbg(dev->dev,
+ "provided buffer object is too small! %d < %d\n",
+ bos[i]->size - mode_cmd->offsets[i], size);
ret = -EINVAL;
goto fail;
}