Merge tag 'omapdrm-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux...
authorDave Airlie <airlied@redhat.com>
Mon, 23 Jan 2017 00:17:06 +0000 (10:17 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 23 Jan 2017 00:17:06 +0000 (10:17 +1000)
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
  ...

1  2 
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/omapdrm/omap_fb.c

@@@ -298,7 -298,7 +298,7 @@@ void drm_minor_release(struct drm_mino
  /**
   * DOC: driver instance overview
   *
 - * A device instance for a drm driver is represented by struct &drm_device. This
 + * A device instance for a drm driver is represented by &struct drm_device. This
   * is allocated with drm_dev_alloc(), usually from bus-specific ->probe()
   * callbacks implemented by the driver. The driver then needs to initialize all
   * the various subsystems for the drm device like memory management, vblank
   * historical baggage. Hence use the reference counting provided by
   * drm_dev_ref() and drm_dev_unref() only carefully.
   *
 - * Also note that embedding of &drm_device is currently not (yet) supported (but
 - * it would be easy to add). Drivers can store driver-private data in the
 - * dev_priv field of &drm_device.
 + * It is recommended that drivers embed &struct drm_device into their own device
 + * structure, which is supported through drm_dev_init().
   */
  
  /**
@@@ -461,11 -462,7 +461,11 @@@ static void drm_fs_inode_free(struct in
   * Note that for purely virtual devices @parent can be NULL.
   *
   * Drivers that do not want to allocate their own device struct
 - * embedding struct &drm_device can call drm_dev_alloc() instead.
 + * embedding &struct drm_device can call drm_dev_alloc() instead. For drivers
 + * that do embed &struct drm_device it must be placed first in the overall
 + * structure, and the overall structure must be allocated using kmalloc(): The
 + * drm core's release function unconditionally calls kfree() on the @dev pointer
 + * when the final reference is released.
   *
   * RETURNS:
   * 0 on success, or error code on failure.
@@@ -568,7 -565,7 +568,7 @@@ EXPORT_SYMBOL(drm_dev_init)
   *
   * Note that for purely virtual devices @parent can be NULL.
   *
 - * Drivers that wish to subclass or embed struct &drm_device into their
 + * Drivers that wish to subclass or embed &struct drm_device into their
   * own struct should look at using drm_dev_init() instead.
   *
   * RETURNS:
@@@ -598,6 -595,8 +598,8 @@@ static void drm_dev_release(struct kre
  {
        struct drm_device *dev = container_of(ref, struct drm_device, ref);
  
+       drm_vblank_cleanup(dev);
        if (drm_core_check_feature(dev, DRIVER_GEM))
                drm_gem_destroy(dev);
  
@@@ -728,7 -727,6 +730,7 @@@ static void remove_compat_control_link(
   */
  int drm_dev_register(struct drm_device *dev, unsigned long flags)
  {
 +      struct drm_driver *driver = dev->driver;
        int ret;
  
        mutex_lock(&drm_global_mutex);
                drm_modeset_register_all(dev);
  
        ret = 0;
 +
 +      DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
 +               driver->name, driver->major, driver->minor,
 +               driver->patchlevel, driver->date,
 +               dev->dev ? dev_name(dev->dev) : "virtual device",
 +               dev->primary->index);
 +
        goto out_unlock;
  
  err_minors:
@@@ -805,8 -796,6 +807,6 @@@ void drm_dev_unregister(struct drm_devi
        if (dev->agp)
                drm_pci_agp_destroy(dev);
  
-       drm_vblank_cleanup(dev);
        list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
                drm_legacy_rmmap(dev, r_list->map);
  
@@@ -932,7 -921,7 +932,7 @@@ static int __init drm_core_init(void
        if (ret < 0)
                goto error;
  
 -      DRM_INFO("Initialized\n");
 +      DRM_DEBUG("Initialized\n");
        return 0;
  
  error:
   * 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 +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;
  };
@@@ -107,7 -101,7 +101,7 @@@ static int omap_framebuffer_create_hand
  static void omap_framebuffer_destroy(struct drm_framebuffer *fb)
  {
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
 -      int i, n = drm_format_num_planes(fb->pixel_format);
 +      int i, n = fb->format->num_planes;
  
        DBG("destroy: FB ID: %d (%p)", fb->base.id, fb);
  
@@@ -128,13 -122,13 +122,13 @@@ static const struct drm_framebuffer_fun
  };
  
  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 +147,11 @@@ void omap_framebuffer_update_scanout(st
                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;
        }
  
        /* 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) {
  int omap_framebuffer_pin(struct drm_framebuffer *fb)
  {
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
 -      int ret, i, n = drm_format_num_planes(fb->pixel_format);
 +      int ret, i, n = fb->format->num_planes;
  
        mutex_lock(&omap_fb->lock);
  
@@@ -292,7 -286,7 +286,7 @@@ fail
  void omap_framebuffer_unpin(struct drm_framebuffer *fb)
  {
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
 -      int i, n = drm_format_num_planes(fb->pixel_format);
 +      int i, n = fb->format->num_planes;
  
        mutex_lock(&omap_fb->lock);
  
@@@ -343,10 -337,10 +337,10 @@@ struct drm_connector *omap_framebuffer_
  void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
  {
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
 -      int i, n = drm_format_num_planes(fb->pixel_format);
 +      int i, n = fb->format->num_planes;
  
        seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height,
 -                      (char *)&fb->pixel_format);
 +                      (char *)&fb->format->format);
  
        for (i = 0; i < n; i++) {
                struct plane *plane = &omap_fb->planes[i];
  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;
        }
  
        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;
                }
                plane->paddr  = 0;
        }
  
 -      drm_helper_mode_fill_fb_struct(fb, mode_cmd);
 +      drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
  
        ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs);
        if (ret) {