drm/tinydrm: Use damage helper for dirtyfb
authorNoralf Trønnes <noralf@tronnes.org>
Tue, 15 Jan 2019 04:36:42 +0000 (05:36 +0100)
committerNoralf Trønnes <noralf@tronnes.org>
Thu, 17 Jan 2019 09:57:15 +0000 (10:57 +0100)
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.

v3: Include vblank header (Sam)
    ili9225 and st7586 can't use mipi_dbi_enable_flush() (David)

v2: Remove fb check in mipi_dbi_enable_flush() it can't be NULL
    (kbuild test robot)

Cc: David Lechner <david@lechnology.com>
Cc: Eric Anholt <eric@anholt.net>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
Tested-by: David Lechner <david@lechnology.com>
Reviewed-by: David Lechner <david@lechnology.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190115043643.2364-5-noralf@tronnes.org
14 files changed:
drivers/gpu/drm/tinydrm/core/tinydrm-core.c
drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
drivers/gpu/drm/tinydrm/hx8357d.c
drivers/gpu/drm/tinydrm/ili9225.c
drivers/gpu/drm/tinydrm/ili9341.c
drivers/gpu/drm/tinydrm/mi0283qt.c
drivers/gpu/drm/tinydrm/mipi-dbi.c
drivers/gpu/drm/tinydrm/repaper.c
drivers/gpu/drm/tinydrm/st7586.c
drivers/gpu/drm/tinydrm/st7735r.c
include/drm/tinydrm/mipi-dbi.h
include/drm/tinydrm/tinydrm-helpers.h
include/drm/tinydrm/tinydrm.h

index aeb93eadb04716d038cef17fc6dae674673d998a..614f532ea89f652755a9ebca76c522e89573973d 100644 (file)
  * 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
@@ -86,7 +72,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);
 }
@@ -100,7 +85,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
@@ -111,12 +95,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;
 
index d0ece6ad4a1c4a9ea561b19c4d5189b351a331bc..2737b6fdadc85d5e60ef939fd5fd82d88ef5d526 100644 (file)
 #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
index d4576d6e8ce4a8b3f29c7dae206a284c48291f62..323564329535ef6b6bcb955d96411231d4e3c78f 100644 (file)
@@ -13,7 +13,6 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_modes.h>
 #include <drm/drm_print.h>
-#include <drm/drm_vblank.h>
 #include <drm/tinydrm/tinydrm.h>
 
 struct tinydrm_connector {
@@ -111,36 +110,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)
 {
index 3ae11aa4b73b50831fe272cbda23c816600f108d..8bbd0beafc6a415fb134db7ddacb03e62685c2f5 100644 (file)
@@ -176,7 +176,7 @@ out_enable:
 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,
 };
 
index ad644069089fe60eba97934bb7eedeb6f8612004..43a3b68d90a20a1f6e023433f16e840d2eb038e9 100644 (file)
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_vblank.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 
@@ -76,17 +78,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;
@@ -94,10 +93,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));
 
@@ -106,7 +104,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;
        }
@@ -155,16 +153,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,
@@ -172,7 +183,14 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
 {
        struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
        struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+       struct drm_framebuffer *fb = plane_state->fb;
        struct device *dev = tdev->drm->dev;
+       struct drm_rect rect = {
+               .x1 = 0,
+               .x2 = fb->width,
+               .y1 = 0,
+               .y2 = fb->height,
+       };
        int ret;
        u8 am_id;
 
@@ -260,7 +278,8 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
 
        ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x1017);
 
-       mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
+       mipi->enabled = true;
+       ili9225_fb_dirty(fb, &rect);
 }
 
 static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe)
@@ -305,59 +324,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,
 };
 
@@ -424,8 +394,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;
 
index bcdf10906adea3e561c675cf3413cdf7be03ce59..713bb2dd7e04c6582ab516dbd41371b922b862b4 100644 (file)
@@ -132,7 +132,7 @@ out_enable:
 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,
 };
 
index 97805ca37a04f08792acaac8399aa9b31f2ea1d5..82a92ec9ae3cedbe776a1bd9997c8b186d110918 100644 (file)
@@ -140,7 +140,7 @@ out_enable:
 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,
 };
 
index 1e7e8cfc99f04c292155a539ec509f3a4dd9a726..918f77c7de34e149080808e0161bad941bd8b3e3 100644 (file)
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_vblank.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 */
@@ -212,27 +213,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));
 
@@ -241,7 +237,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;
        }
@@ -254,16 +250,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
@@ -274,18 +292,25 @@ static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = {
  * This function sets &mipi_dbi->enabled, flushes the whole framebuffer and
  * enables the backlight. Drivers can use this in their
  * &drm_simple_display_pipe_funcs->enable callback.
+ *
+ * Note: Drivers which don't use mipi_dbi_pipe_update() because they have custom
+ * framebuffer flushing, can't use this function since they both use the same
+ * flushing code.
  */
 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);
 }
 EXPORT_SYMBOL(mipi_dbi_enable_flush);
@@ -377,12 +402,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,
@@ -392,6 +415,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;
 
index 238515de449e6a491515b2568355ec8b7dc6cf65..b037c6540cf389de2dd8777ab909309bcdf83a10 100644 (file)
 #include <linux/spi/spi.h>
 #include <linux/thermal.h>
 
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_drv.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/drm_vblank.h>
 #include <drm/tinydrm/tinydrm.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 
@@ -523,11 +525,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;
@@ -626,12 +624,6 @@ out_free:
        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 */
@@ -795,9 +787,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++)
@@ -840,10 +830,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,
 };
 
@@ -1057,12 +1065,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,
index a52bc3b02606440acb245b036cec5700dd2cbaf7..01a8077954b341046087ae0d8c6230e10ff18707 100644 (file)
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_drv.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/drm_vblank.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 
@@ -112,23 +114,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);
@@ -138,7 +132,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;
@@ -154,15 +148,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,
@@ -170,6 +177,13 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
 {
        struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
        struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+       struct drm_framebuffer *fb = plane_state->fb;
+       struct drm_rect rect = {
+               .x1 = 0,
+               .x2 = fb->width,
+               .y1 = 0,
+               .y2 = fb->height,
+       };
        int ret;
        u8 addr_mode;
 
@@ -226,9 +240,10 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
 
        msleep(100);
 
-       mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
+       mipi->enabled = true;
+       st7586_fb_dirty(fb, &rect);
 
-       mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
+       mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
 }
 
 static void st7586_pipe_disable(struct drm_simple_display_pipe *pipe)
@@ -264,12 +279,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,
@@ -278,6 +291,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;
 
@@ -292,7 +307,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,
 };
 
index 9bc93d5a04011ff523fc02bd7e7a6fbb5b25d11b..3bab9a9569a67744b86e856368a6cfbb30401e77 100644 (file)
@@ -106,7 +106,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,
 };
 
index b52f32897f23cfabfde1b28a1b2d2eef7f3d0e23..f4ec2834bc229ba55939ea8a3a64aeb866536d2d 100644 (file)
@@ -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);
index 8edb75df4e31824ba2d2bf6f672abab6a1135432..f0d598789e4d34adbd461215c6782df6337735ae 100644 (file)
@@ -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,
index 448aa5ea4722da2007fcfe8ee79855ccb22bb6ef..5621688edcc0aec7f9f23fd4ab60886a45502c8b 100644 (file)
 #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,