This switches to drm_atomic_helper_dirtyfb() as the framebuffer dirty
handler. All flushing will now happen in the pipe functions.

Also enable the damage plane property for all except repaper which can
only do full updates.

ili9225:
This change made ili9225_init() equal to mipi_dbi_init() so use it.

Cc: David Lechner <da...@lechnology.com>
Cc: Eric Anholt <e...@anholt.net>
Signed-off-by: Noralf Trønnes <nor...@tronnes.org>
---
 drivers/gpu/drm/tinydrm/core/tinydrm-core.c   |  21 +---
 .../gpu/drm/tinydrm/core/tinydrm-helpers.c    |  91 +---------------
 drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c   |  30 ------
 drivers/gpu/drm/tinydrm/hx8357d.c             |   2 +-
 drivers/gpu/drm/tinydrm/ili9225.c             | 101 ++++++------------
 drivers/gpu/drm/tinydrm/ili9341.c             |   2 +-
 drivers/gpu/drm/tinydrm/mi0283qt.c            |   2 +-
 drivers/gpu/drm/tinydrm/mipi-dbi.c            |  72 ++++++++-----
 drivers/gpu/drm/tinydrm/repaper.c             |  39 ++++---
 drivers/gpu/drm/tinydrm/st7586.c              |  50 +++++----
 drivers/gpu/drm/tinydrm/st7735r.c             |   2 +-
 include/drm/tinydrm/mipi-dbi.h                |   2 +
 include/drm/tinydrm/tinydrm-helpers.h         |  11 +-
 include/drm/tinydrm/tinydrm.h                 |  26 -----
 14 files changed, 138 insertions(+), 313 deletions(-)

diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c 
b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
index 01a6f2d42440..dca0f642fee6 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
@@ -36,31 +36,17 @@
  * and registers the DRM device using devm_tinydrm_register().
  */
 
-static struct drm_framebuffer *
-tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv,
-                 const struct drm_mode_fb_cmd2 *mode_cmd)
-{
-       struct tinydrm_device *tdev = drm->dev_private;
-
-       return drm_gem_fb_create_with_funcs(drm, file_priv, mode_cmd,
-                                           tdev->fb_funcs);
-}
-
 static const struct drm_mode_config_funcs tinydrm_mode_config_funcs = {
-       .fb_create = tinydrm_fb_create,
+       .fb_create = drm_gem_fb_create_with_dirty,
        .atomic_check = drm_atomic_helper_check,
        .atomic_commit = drm_atomic_helper_commit,
 };
 
 static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
-                       const struct drm_framebuffer_funcs *fb_funcs,
                        struct drm_driver *driver)
 {
        struct drm_device *drm;
 
-       mutex_init(&tdev->dirty_lock);
-       tdev->fb_funcs = fb_funcs;
-
        /*
         * We don't embed drm_device, because that prevent us from using
         * devm_kzalloc() to allocate tinydrm_device in the driver since
@@ -83,7 +69,6 @@ static int tinydrm_init(struct device *parent, struct 
tinydrm_device *tdev,
 static void tinydrm_fini(struct tinydrm_device *tdev)
 {
        drm_mode_config_cleanup(tdev->drm);
-       mutex_destroy(&tdev->dirty_lock);
        tdev->drm->dev_private = NULL;
        drm_dev_put(tdev->drm);
 }
@@ -97,7 +82,6 @@ static void devm_tinydrm_release(void *data)
  * devm_tinydrm_init - Initialize tinydrm device
  * @parent: Parent device object
  * @tdev: tinydrm device
- * @fb_funcs: Framebuffer functions
  * @driver: DRM driver
  *
  * This function initializes @tdev, the underlying DRM device and it's
@@ -108,12 +92,11 @@ static void devm_tinydrm_release(void *data)
  * Zero on success, negative error code on failure.
  */
 int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
-                     const struct drm_framebuffer_funcs *fb_funcs,
                      struct drm_driver *driver)
 {
        int ret;
 
-       ret = tinydrm_init(parent, tdev, fb_funcs, driver);
+       ret = tinydrm_init(parent, tdev, driver);
        if (ret)
                return ret;
 
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c 
b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
index d0ece6ad4a1c..2737b6fdadc8 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
@@ -17,104 +17,15 @@
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
 #include <drm/drm_print.h>
 #include <drm/drm_rect.h>
-#include <drm/tinydrm/tinydrm.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
-#include <uapi/drm/drm.h>
 
 static unsigned int spi_max;
 module_param(spi_max, uint, 0400);
 MODULE_PARM_DESC(spi_max, "Set a lower SPI max transfer size");
 
-/**
- * tinydrm_merge_clips - Merge clip rectangles
- * @dst: Destination clip rectangle
- * @src: Source clip rectangle(s)
- * @num_clips: Number of @src clip rectangles
- * @flags: Dirty fb ioctl flags
- * @max_width: Maximum width of @dst
- * @max_height: Maximum height of @dst
- *
- * This function merges @src clip rectangle(s) into @dst. If @src is NULL,
- * @max_width and @min_width is used to set a full @dst clip rectangle.
- *
- * Returns:
- * true if it's a full clip, false otherwise
- */
-bool tinydrm_merge_clips(struct drm_rect *dst,
-                        struct drm_clip_rect *src, unsigned int num_clips,
-                        unsigned int flags, u32 max_width, u32 max_height)
-{
-       unsigned int i;
-
-       if (!src || !num_clips) {
-               dst->x1 = 0;
-               dst->x2 = max_width;
-               dst->y1 = 0;
-               dst->y2 = max_height;
-               return true;
-       }
-
-       dst->x1 = ~0;
-       dst->y1 = ~0;
-       dst->x2 = 0;
-       dst->y2 = 0;
-
-       for (i = 0; i < num_clips; i++) {
-               if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY)
-                       i++;
-               dst->x1 = min_t(int, dst->x1, src[i].x1);
-               dst->x2 = max_t(int, dst->x2, src[i].x2);
-               dst->y1 = min_t(int, dst->y1, src[i].y1);
-               dst->y2 = max_t(int, dst->y2, src[i].y2);
-       }
-
-       if (dst->x2 > max_width || dst->y2 > max_height ||
-           dst->x1 >= dst->x2 || dst->y1 >= dst->y2) {
-               DRM_DEBUG_KMS("Illegal clip: x1=%u, x2=%u, y1=%u, y2=%u\n",
-                             dst->x1, dst->x2, dst->y1, dst->y2);
-               dst->x1 = 0;
-               dst->y1 = 0;
-               dst->x2 = max_width;
-               dst->y2 = max_height;
-       }
-
-       return (dst->x2 - dst->x1) == max_width &&
-              (dst->y2 - dst->y1) == max_height;
-}
-EXPORT_SYMBOL(tinydrm_merge_clips);
-
-int tinydrm_fb_dirty(struct drm_framebuffer *fb,
-                    struct drm_file *file_priv,
-                    unsigned int flags, unsigned int color,
-                    struct drm_clip_rect *clips,
-                    unsigned int num_clips)
-{
-       struct tinydrm_device *tdev = fb->dev->dev_private;
-       struct drm_plane *plane = &tdev->pipe.plane;
-       int ret = 0;
-
-       drm_modeset_lock(&plane->mutex, NULL);
-
-       /* fbdev can flush even when we're not interested */
-       if (plane->state->fb == fb) {
-               mutex_lock(&tdev->dirty_lock);
-               ret = tdev->fb_dirty(fb, file_priv, flags,
-                                    color, clips, num_clips);
-               mutex_unlock(&tdev->dirty_lock);
-       }
-
-       drm_modeset_unlock(&plane->mutex);
-
-       if (ret)
-               dev_err_once(fb->dev->dev,
-                            "Failed to update display %d\n", ret);
-
-       return ret;
-}
-EXPORT_SYMBOL(tinydrm_fb_dirty);
-
 /**
  * tinydrm_memcpy - Copy clip buffer
  * @dst: Destination buffer
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c 
b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
index eacfc0ec8ff1..5a184ac65f9f 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
@@ -108,36 +108,6 @@ tinydrm_connector_create(struct drm_device *drm,
        return connector;
 }
 
-/**
- * tinydrm_display_pipe_update - Display pipe update helper
- * @pipe: Simple display pipe
- * @old_state: Old plane state
- *
- * This function does a full framebuffer flush if the plane framebuffer
- * has changed. It also handles vblank events. Drivers can use this as their
- * &drm_simple_display_pipe_funcs->update callback.
- */
-void tinydrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
-                                struct drm_plane_state *old_state)
-{
-       struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
-       struct drm_framebuffer *fb = pipe->plane.state->fb;
-       struct drm_crtc *crtc = &tdev->pipe.crtc;
-
-       if (fb && (fb != old_state->fb)) {
-               if (tdev->fb_dirty)
-                       tdev->fb_dirty(fb, NULL, 0, 0, NULL, 0);
-       }
-
-       if (crtc->state->event) {
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               spin_unlock_irq(&crtc->dev->event_lock);
-               crtc->state->event = NULL;
-       }
-}
-EXPORT_SYMBOL(tinydrm_display_pipe_update);
-
 static int tinydrm_rotate_mode(struct drm_display_mode *mode,
                               unsigned int rotation)
 {
diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c 
b/drivers/gpu/drm/tinydrm/hx8357d.c
index 81a2bbeb25d4..bb275204e5bb 100644
--- a/drivers/gpu/drm/tinydrm/hx8357d.c
+++ b/drivers/gpu/drm/tinydrm/hx8357d.c
@@ -175,7 +175,7 @@ static void yx240qv29_enable(struct drm_simple_display_pipe 
*pipe,
 static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
        .enable = yx240qv29_enable,
        .disable = mipi_dbi_pipe_disable,
-       .update = tinydrm_display_pipe_update,
+       .update = mipi_dbi_pipe_update,
        .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
 };
 
diff --git a/drivers/gpu/drm/tinydrm/ili9225.c 
b/drivers/gpu/drm/tinydrm/ili9225.c
index cea70f9addcf..ee70e8842751 100644
--- a/drivers/gpu/drm/tinydrm/ili9225.c
+++ b/drivers/gpu/drm/tinydrm/ili9225.c
@@ -20,6 +20,7 @@
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -74,17 +75,14 @@ static inline int ili9225_command(struct mipi_dbi *mipi, u8 
cmd, u16 data)
        return mipi_dbi_command_buf(mipi, cmd, par, 2);
 }
 
-static int ili9225_fb_dirty(struct drm_framebuffer *fb,
-                           struct drm_file *file_priv, unsigned int flags,
-                           unsigned int color, struct drm_clip_rect *clips,
-                           unsigned int num_clips)
+static void ili9225_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
 {
        struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
        struct tinydrm_device *tdev = fb->dev->dev_private;
        struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+       unsigned int height = rect->y2 - rect->y1;
+       unsigned int width = rect->x2 - rect->x1;
        bool swap = mipi->swap_bytes;
-       struct drm_rect clip;
-       struct drm_rect *rect = &clip;
        u16 x_start, y_start;
        u16 x1, x2, y1, y2;
        int ret = 0;
@@ -92,10 +90,9 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
        void *tr;
 
        if (!mipi->enabled)
-               return 0;
+               return;
 
-       full = tinydrm_merge_clips(&clip, clips, num_clips, flags,
-                                  fb->width, fb->height);
+       full = width == fb->width && height == fb->height;
 
        DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, 
DRM_RECT_ARG(rect));
 
@@ -104,7 +101,7 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
                tr = mipi->tx_buf;
                ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, rect, swap);
                if (ret)
-                       return ret;
+                       goto err_msg;
        } else {
                tr = cma_obj->vaddr;
        }
@@ -153,16 +150,29 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
        ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_2, y_start);
 
        ret = mipi_dbi_command_buf(mipi, ILI9225_WRITE_DATA_TO_GRAM, tr,
-                                  (rect->x2 - rect->x1) * (rect->y2 - 
rect->y1) * 2);
-
-       return ret;
+                                  width * height * 2);
+err_msg:
+       if (ret)
+               dev_err_once(fb->dev->dev, "Failed to update display %d\n", 
ret);
 }
 
-static const struct drm_framebuffer_funcs ili9225_fb_funcs = {
-       .destroy        = drm_gem_fb_destroy,
-       .create_handle  = drm_gem_fb_create_handle,
-       .dirty          = tinydrm_fb_dirty,
-};
+static void ili9225_pipe_update(struct drm_simple_display_pipe *pipe,
+                               struct drm_plane_state *old_state)
+{
+       struct drm_plane_state *state = pipe->plane.state;
+       struct drm_crtc *crtc = &pipe->crtc;
+       struct drm_rect rect;
+
+       if (drm_atomic_helper_damage_merged(old_state, state, &rect))
+               ili9225_fb_dirty(state->fb, &rect);
+
+       if (crtc->state->event) {
+               spin_lock_irq(&crtc->dev->event_lock);
+               drm_crtc_send_vblank_event(crtc, crtc->state->event);
+               spin_unlock_irq(&crtc->dev->event_lock);
+               crtc->state->event = NULL;
+       }
+}
 
 static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
                                struct drm_crtc_state *crtc_state,
@@ -303,59 +313,10 @@ static int ili9225_dbi_command(struct mipi_dbi *mipi, u8 
cmd, u8 *par,
        return tinydrm_spi_transfer(spi, speed_hz, NULL, bpw, par, num);
 }
 
-static const u32 ili9225_formats[] = {
-       DRM_FORMAT_RGB565,
-       DRM_FORMAT_XRGB8888,
-};
-
-static int ili9225_init(struct device *dev, struct mipi_dbi *mipi,
-                       const struct drm_simple_display_pipe_funcs *pipe_funcs,
-                       struct drm_driver *driver,
-                       const struct drm_display_mode *mode,
-                       unsigned int rotation)
-{
-       size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16);
-       struct tinydrm_device *tdev = &mipi->tinydrm;
-       int ret;
-
-       if (!mipi->command)
-               return -EINVAL;
-
-       mutex_init(&mipi->cmdlock);
-
-       mipi->tx_buf = devm_kmalloc(dev, bufsize, GFP_KERNEL);
-       if (!mipi->tx_buf)
-               return -ENOMEM;
-
-       ret = devm_tinydrm_init(dev, tdev, &ili9225_fb_funcs, driver);
-       if (ret)
-               return ret;
-
-       tdev->fb_dirty = ili9225_fb_dirty;
-
-       ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
-                                       DRM_MODE_CONNECTOR_VIRTUAL,
-                                       ili9225_formats,
-                                       ARRAY_SIZE(ili9225_formats), mode,
-                                       rotation);
-       if (ret)
-               return ret;
-
-       tdev->drm->mode_config.preferred_depth = 16;
-       mipi->rotation = rotation;
-
-       drm_mode_config_reset(tdev->drm);
-
-       DRM_DEBUG_KMS("preferred_depth=%u, rotation = %u\n",
-                     tdev->drm->mode_config.preferred_depth, rotation);
-
-       return 0;
-}
-
 static const struct drm_simple_display_pipe_funcs ili9225_pipe_funcs = {
        .enable         = ili9225_pipe_enable,
        .disable        = ili9225_pipe_disable,
-       .update         = tinydrm_display_pipe_update,
+       .update         = ili9225_pipe_update,
        .prepare_fb     = drm_gem_fb_simple_display_pipe_prepare_fb,
 };
 
@@ -422,8 +383,8 @@ static int ili9225_probe(struct spi_device *spi)
        /* override the command function set in  mipi_dbi_spi_init() */
        mipi->command = ili9225_dbi_command;
 
-       ret = ili9225_init(&spi->dev, mipi, &ili9225_pipe_funcs,
-                          &ili9225_driver, &ili9225_mode, rotation);
+       ret = mipi_dbi_init(&spi->dev, mipi, &ili9225_pipe_funcs,
+                           &ili9225_driver, &ili9225_mode, rotation);
        if (ret)
                return ret;
 
diff --git a/drivers/gpu/drm/tinydrm/ili9341.c 
b/drivers/gpu/drm/tinydrm/ili9341.c
index 51395bdc6ca2..84aa7eebaee7 100644
--- a/drivers/gpu/drm/tinydrm/ili9341.c
+++ b/drivers/gpu/drm/tinydrm/ili9341.c
@@ -131,7 +131,7 @@ static void yx240qv29_enable(struct drm_simple_display_pipe 
*pipe,
 static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = {
        .enable = yx240qv29_enable,
        .disable = mipi_dbi_pipe_disable,
-       .update = tinydrm_display_pipe_update,
+       .update = mipi_dbi_pipe_update,
        .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
 };
 
diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c 
b/drivers/gpu/drm/tinydrm/mi0283qt.c
index 3fa62e77c30b..184dd09ede5a 100644
--- a/drivers/gpu/drm/tinydrm/mi0283qt.c
+++ b/drivers/gpu/drm/tinydrm/mi0283qt.c
@@ -139,7 +139,7 @@ static void mi0283qt_enable(struct drm_simple_display_pipe 
*pipe,
 static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = {
        .enable = mi0283qt_enable,
        .disable = mipi_dbi_pipe_disable,
-       .update = tinydrm_display_pipe_update,
+       .update = mipi_dbi_pipe_update,
        .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
 };
 
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c 
b/drivers/gpu/drm/tinydrm/mipi-dbi.c
index e6e82de78d70..0da9915027f7 100644
--- a/drivers/gpu/drm/tinydrm/mipi-dbi.c
+++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c
@@ -16,13 +16,13 @@
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_rect.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
-#include <uapi/drm/drm.h>
 #include <video/mipi_display.h>
 
 #define MIPI_DBI_MAX_SPI_READ_SPEED 2000000 /* 2MHz */
@@ -209,27 +209,22 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer 
*fb,
 }
 EXPORT_SYMBOL(mipi_dbi_buf_copy);
 
-static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
-                            struct drm_file *file_priv,
-                            unsigned int flags, unsigned int color,
-                            struct drm_clip_rect *clips,
-                            unsigned int num_clips)
+static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect 
*rect)
 {
        struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
        struct tinydrm_device *tdev = fb->dev->dev_private;
        struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+       unsigned int height = rect->y2 - rect->y1;
+       unsigned int width = rect->x2 - rect->x1;
        bool swap = mipi->swap_bytes;
-       struct drm_rect clip;
-       struct drm_rect *rect = &clip;
        int ret = 0;
        bool full;
        void *tr;
 
        if (!mipi->enabled)
-               return 0;
+               return;
 
-       full = tinydrm_merge_clips(&clip, clips, num_clips, flags,
-                                  fb->width, fb->height);
+       full = width == fb->width && height == fb->height;
 
        DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, 
DRM_RECT_ARG(rect));
 
@@ -238,7 +233,7 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
                tr = mipi->tx_buf;
                ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, rect, swap);
                if (ret)
-                       return ret;
+                       goto err_msg;
        } else {
                tr = cma_obj->vaddr;
        }
@@ -251,16 +246,38 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
                         ((rect->y2 - 1) >> 8) & 0xff, (rect->y2 - 1) & 0xff);
 
        ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, tr,
-                                  (rect->x2 - rect->x1) * (rect->y2 - 
rect->y1) * 2);
-
-       return ret;
+                                  width * height * 2);
+err_msg:
+       if (ret)
+               dev_err_once(fb->dev->dev, "Failed to update display %d\n", 
ret);
 }
 
-static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = {
-       .destroy        = drm_gem_fb_destroy,
-       .create_handle  = drm_gem_fb_create_handle,
-       .dirty          = tinydrm_fb_dirty,
-};
+/**
+ * mipi_dbi_pipe_update - Display pipe update helper
+ * @pipe: Simple display pipe
+ * @old_state: Old plane state
+ *
+ * This function handles framebuffer flushing and vblank events. Drivers can 
use
+ * this as their &drm_simple_display_pipe_funcs->update callback.
+ */
+void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe,
+                         struct drm_plane_state *old_state)
+{
+       struct drm_plane_state *state = pipe->plane.state;
+       struct drm_crtc *crtc = &pipe->crtc;
+       struct drm_rect rect;
+
+       if (drm_atomic_helper_damage_merged(old_state, state, &rect))
+               mipi_dbi_fb_dirty(state->fb, &rect);
+
+       if (crtc->state->event) {
+               spin_lock_irq(&crtc->dev->event_lock);
+               drm_crtc_send_vblank_event(crtc, crtc->state->event);
+               spin_unlock_irq(&crtc->dev->event_lock);
+               crtc->state->event = NULL;
+       }
+}
+EXPORT_SYMBOL(mipi_dbi_pipe_update);
 
 /**
  * mipi_dbi_enable_flush - MIPI DBI enable helper
@@ -276,12 +293,17 @@ void mipi_dbi_enable_flush(struct mipi_dbi *mipi,
                           struct drm_crtc_state *crtc_state,
                           struct drm_plane_state *plane_state)
 {
-       struct tinydrm_device *tdev = &mipi->tinydrm;
        struct drm_framebuffer *fb = plane_state->fb;
+       struct drm_rect rect = {
+               .x1 = 0,
+               .x2 = fb->width,
+               .y1 = 0,
+               .y2 = fb->height,
+       };
 
        mipi->enabled = true;
        if (fb)
-               tdev->fb_dirty(fb, NULL, 0, 0, NULL, 0);
+               mipi_dbi_fb_dirty(fb, &rect);
 
        backlight_enable(mipi->backlight);
 }
@@ -374,12 +396,10 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi 
*mipi,
        if (!mipi->tx_buf)
                return -ENOMEM;
 
-       ret = devm_tinydrm_init(dev, tdev, &mipi_dbi_fb_funcs, driver);
+       ret = devm_tinydrm_init(dev, tdev, driver);
        if (ret)
                return ret;
 
-       tdev->fb_dirty = mipi_dbi_fb_dirty;
-
        /* TODO: Maybe add DRM_MODE_CONNECTOR_SPI */
        ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
                                        DRM_MODE_CONNECTOR_VIRTUAL,
@@ -389,6 +409,8 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi,
        if (ret)
                return ret;
 
+       drm_plane_enable_fb_damage_clips(&tdev->pipe.plane);
+
        tdev->drm->mode_config.preferred_depth = 16;
        mipi->rotation = rotation;
 
diff --git a/drivers/gpu/drm/tinydrm/repaper.c 
b/drivers/gpu/drm/tinydrm/repaper.c
index 1e53d97472e5..1194bdacdc66 100644
--- a/drivers/gpu/drm/tinydrm/repaper.c
+++ b/drivers/gpu/drm/tinydrm/repaper.c
@@ -26,6 +26,7 @@
 #include <linux/spi/spi.h>
 #include <linux/thermal.h>
 
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -522,11 +523,7 @@ static void repaper_gray8_to_mono_reversed(u8 *buf, u32 
width, u32 height)
                }
 }
 
-static int repaper_fb_dirty(struct drm_framebuffer *fb,
-                           struct drm_file *file_priv,
-                           unsigned int flags, unsigned int color,
-                           struct drm_clip_rect *clips,
-                           unsigned int num_clips)
+static int repaper_fb_dirty(struct drm_framebuffer *fb)
 {
        struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
        struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
@@ -625,12 +622,6 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb,
        return ret;
 }
 
-static const struct drm_framebuffer_funcs repaper_fb_funcs = {
-       .destroy        = drm_gem_fb_destroy,
-       .create_handle  = drm_gem_fb_create_handle,
-       .dirty          = tinydrm_fb_dirty,
-};
-
 static void power_off(struct repaper_epd *epd)
 {
        /* Turn off power and all signals */
@@ -794,9 +785,7 @@ static void repaper_pipe_disable(struct 
drm_simple_display_pipe *pipe)
 
        DRM_DEBUG_DRIVER("\n");
 
-       mutex_lock(&tdev->dirty_lock);
        epd->enabled = false;
-       mutex_unlock(&tdev->dirty_lock);
 
        /* Nothing frame */
        for (line = 0; line < epd->height; line++)
@@ -839,10 +828,28 @@ static void repaper_pipe_disable(struct 
drm_simple_display_pipe *pipe)
        power_off(epd);
 }
 
+static void repaper_pipe_update(struct drm_simple_display_pipe *pipe,
+                               struct drm_plane_state *old_state)
+{
+       struct drm_plane_state *state = pipe->plane.state;
+       struct drm_crtc *crtc = &pipe->crtc;
+       struct drm_rect rect;
+
+       if (drm_atomic_helper_damage_merged(old_state, state, &rect))
+               repaper_fb_dirty(state->fb);
+
+       if (crtc->state->event) {
+               spin_lock_irq(&crtc->dev->event_lock);
+               drm_crtc_send_vblank_event(crtc, crtc->state->event);
+               spin_unlock_irq(&crtc->dev->event_lock);
+               crtc->state->event = NULL;
+       }
+}
+
 static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = {
        .enable = repaper_pipe_enable,
        .disable = repaper_pipe_disable,
-       .update = tinydrm_display_pipe_update,
+       .update = repaper_pipe_update,
        .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
 };
 
@@ -1056,12 +1063,10 @@ static int repaper_probe(struct spi_device *spi)
 
        tdev = &epd->tinydrm;
 
-       ret = devm_tinydrm_init(dev, tdev, &repaper_fb_funcs, &repaper_driver);
+       ret = devm_tinydrm_init(dev, tdev, &repaper_driver);
        if (ret)
                return ret;
 
-       tdev->fb_dirty = repaper_fb_dirty;
-
        ret = tinydrm_display_pipe_init(tdev, &repaper_pipe_funcs,
                                        DRM_MODE_CONNECTOR_VIRTUAL,
                                        repaper_formats,
diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c
index 64a7354c326a..47f5c37bd387 100644
--- a/drivers/gpu/drm/tinydrm/st7586.c
+++ b/drivers/gpu/drm/tinydrm/st7586.c
@@ -17,6 +17,7 @@
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -111,23 +112,15 @@ static int st7586_buf_copy(void *dst, struct 
drm_framebuffer *fb,
        return ret;
 }
 
-static int st7586_fb_dirty(struct drm_framebuffer *fb,
-                          struct drm_file *file_priv, unsigned int flags,
-                          unsigned int color, struct drm_clip_rect *clips,
-                          unsigned int num_clips)
+static void st7586_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
 {
        struct tinydrm_device *tdev = fb->dev->dev_private;
        struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
-       struct drm_rect clip;
-       struct drm_rect *rect = &clip;
        int start, end;
        int ret = 0;
 
        if (!mipi->enabled)
-               return 0;
-
-       tinydrm_merge_clips(&clip, clips, num_clips, flags, fb->width,
-                           fb->height);
+               return;
 
        /* 3 pixels per byte, so grow clip to nearest multiple of 3 */
        rect->x1 = rounddown(rect->x1, 3);
@@ -137,7 +130,7 @@ static int st7586_fb_dirty(struct drm_framebuffer *fb,
 
        ret = st7586_buf_copy(mipi->tx_buf, fb, rect);
        if (ret)
-               return ret;
+               goto err_msg;
 
        /* Pixels are packed 3 per byte */
        start = rect->x1 / 3;
@@ -153,15 +146,28 @@ static int st7586_fb_dirty(struct drm_framebuffer *fb,
        ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START,
                                   (u8 *)mipi->tx_buf,
                                   (end - start) * (rect->y2 - rect->y1));
-
-       return ret;
+err_msg:
+       if (ret)
+               dev_err_once(fb->dev->dev, "Failed to update display %d\n", 
ret);
 }
 
-static const struct drm_framebuffer_funcs st7586_fb_funcs = {
-       .destroy        = drm_gem_fb_destroy,
-       .create_handle  = drm_gem_fb_create_handle,
-       .dirty          = tinydrm_fb_dirty,
-};
+static void st7586_pipe_update(struct drm_simple_display_pipe *pipe,
+                              struct drm_plane_state *old_state)
+{
+       struct drm_plane_state *state = pipe->plane.state;
+       struct drm_crtc *crtc = &pipe->crtc;
+       struct drm_rect rect;
+
+       if (drm_atomic_helper_damage_merged(old_state, state, &rect))
+               st7586_fb_dirty(state->fb, &rect);
+
+       if (crtc->state->event) {
+               spin_lock_irq(&crtc->dev->event_lock);
+               drm_crtc_send_vblank_event(crtc, crtc->state->event);
+               spin_unlock_irq(&crtc->dev->event_lock);
+               crtc->state->event = NULL;
+       }
+}
 
 static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
                               struct drm_crtc_state *crtc_state,
@@ -263,12 +269,10 @@ static int st7586_init(struct device *dev, struct 
mipi_dbi *mipi,
        if (!mipi->tx_buf)
                return -ENOMEM;
 
-       ret = devm_tinydrm_init(dev, tdev, &st7586_fb_funcs, driver);
+       ret = devm_tinydrm_init(dev, tdev, driver);
        if (ret)
                return ret;
 
-       tdev->fb_dirty = st7586_fb_dirty;
-
        ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
                                        DRM_MODE_CONNECTOR_VIRTUAL,
                                        st7586_formats,
@@ -277,6 +281,8 @@ static int st7586_init(struct device *dev, struct mipi_dbi 
*mipi,
        if (ret)
                return ret;
 
+       drm_plane_enable_fb_damage_clips(&tdev->pipe.plane);
+
        tdev->drm->mode_config.preferred_depth = 32;
        mipi->rotation = rotation;
 
@@ -291,7 +297,7 @@ static int st7586_init(struct device *dev, struct mipi_dbi 
*mipi,
 static const struct drm_simple_display_pipe_funcs st7586_pipe_funcs = {
        .enable         = st7586_pipe_enable,
        .disable        = st7586_pipe_disable,
-       .update         = tinydrm_display_pipe_update,
+       .update         = st7586_pipe_update,
        .prepare_fb     = drm_gem_fb_simple_display_pipe_prepare_fb,
 };
 
diff --git a/drivers/gpu/drm/tinydrm/st7735r.c 
b/drivers/gpu/drm/tinydrm/st7735r.c
index b39779e0dcd8..89c2ce5a7990 100644
--- a/drivers/gpu/drm/tinydrm/st7735r.c
+++ b/drivers/gpu/drm/tinydrm/st7735r.c
@@ -105,7 +105,7 @@ static void jd_t18003_t01_pipe_enable(struct 
drm_simple_display_pipe *pipe,
 static const struct drm_simple_display_pipe_funcs jd_t18003_t01_pipe_funcs = {
        .enable         = jd_t18003_t01_pipe_enable,
        .disable        = mipi_dbi_pipe_disable,
-       .update         = tinydrm_display_pipe_update,
+       .update         = mipi_dbi_pipe_update,
        .prepare_fb     = drm_gem_fb_simple_display_pipe_prepare_fb,
 };
 
diff --git a/include/drm/tinydrm/mipi-dbi.h b/include/drm/tinydrm/mipi-dbi.h
index b52f32897f23..f4ec2834bc22 100644
--- a/include/drm/tinydrm/mipi-dbi.h
+++ b/include/drm/tinydrm/mipi-dbi.h
@@ -68,6 +68,8 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi,
                  const struct drm_simple_display_pipe_funcs *pipe_funcs,
                  struct drm_driver *driver,
                  const struct drm_display_mode *mode, unsigned int rotation);
+void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe,
+                         struct drm_plane_state *old_state);
 void mipi_dbi_enable_flush(struct mipi_dbi *mipi,
                           struct drm_crtc_state *crtc_state,
                           struct drm_plane_state *plan_state);
diff --git a/include/drm/tinydrm/tinydrm-helpers.h 
b/include/drm/tinydrm/tinydrm-helpers.h
index 8edb75df4e31..f0d598789e4d 100644
--- a/include/drm/tinydrm/tinydrm-helpers.h
+++ b/include/drm/tinydrm/tinydrm-helpers.h
@@ -11,8 +11,7 @@
 #define __LINUX_TINYDRM_HELPERS_H
 
 struct backlight_device;
-struct tinydrm_device;
-struct drm_clip_rect;
+struct drm_framebuffer;
 struct drm_rect;
 struct spi_transfer;
 struct spi_message;
@@ -34,14 +33,6 @@ static inline bool tinydrm_machine_little_endian(void)
 #endif
 }
 
-bool tinydrm_merge_clips(struct drm_rect *dst,
-                        struct drm_clip_rect *src, unsigned int num_clips,
-                        unsigned int flags, u32 max_width, u32 max_height);
-int tinydrm_fb_dirty(struct drm_framebuffer *fb,
-                    struct drm_file *file_priv,
-                    unsigned int flags, unsigned int color,
-                    struct drm_clip_rect *clips,
-                    unsigned int num_clips);
 void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
                    struct drm_rect *clip);
 void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
diff --git a/include/drm/tinydrm/tinydrm.h b/include/drm/tinydrm/tinydrm.h
index 448aa5ea4722..5621688edcc0 100644
--- a/include/drm/tinydrm/tinydrm.h
+++ b/include/drm/tinydrm/tinydrm.h
@@ -10,14 +10,9 @@
 #ifndef __LINUX_TINYDRM_H
 #define __LINUX_TINYDRM_H
 
-#include <linux/mutex.h>
 #include <drm/drm_simple_kms_helper.h>
 
-struct drm_clip_rect;
 struct drm_driver;
-struct drm_file;
-struct drm_framebuffer;
-struct drm_framebuffer_funcs;
 
 /**
  * struct tinydrm_device - tinydrm device
@@ -32,24 +27,6 @@ struct tinydrm_device {
         * @pipe: Display pipe structure
         */
        struct drm_simple_display_pipe pipe;
-
-       /**
-        * @dirty_lock: Serializes framebuffer flushing
-        */
-       struct mutex dirty_lock;
-
-       /**
-        * @fb_funcs: Framebuffer functions used when creating framebuffers
-        */
-       const struct drm_framebuffer_funcs *fb_funcs;
-
-       /**
-        * @fb_dirty: Framebuffer dirty callback
-        */
-       int (*fb_dirty)(struct drm_framebuffer *framebuffer,
-                       struct drm_file *file_priv, unsigned flags,
-                       unsigned color, struct drm_clip_rect *clips,
-                       unsigned num_clips);
 };
 
 static inline struct tinydrm_device *
@@ -82,13 +59,10 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe)
        .clock = 1 /* pass validation */
 
 int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
-                     const struct drm_framebuffer_funcs *fb_funcs,
                      struct drm_driver *driver);
 int devm_tinydrm_register(struct tinydrm_device *tdev);
 void tinydrm_shutdown(struct tinydrm_device *tdev);
 
-void tinydrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
-                                struct drm_plane_state *old_state);
 int
 tinydrm_display_pipe_init(struct tinydrm_device *tdev,
                          const struct drm_simple_display_pipe_funcs *funcs,
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to