Commit af741381 authored by Noralf Trønnes's avatar Noralf Trønnes

drm/tinydrm: Use damage helper for dirtyfb

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: default avatarNoralf Trønnes <noralf@tronnes.org>
Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: default avatarSam Ravnborg <sam@ravnborg.org>
Tested-by: default avatarDavid Lechner <david@lechnology.com>
Reviewed-by: default avatarDavid Lechner <david@lechnology.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190115043643.2364-5-noralf@tronnes.org
parent b051b345
......@@ -39,31 +39,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
......@@ -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;
......
......@@ -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
......
......@@ -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)
{
......
......@@ -176,7 +176,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,
};
......
......@@ -20,12 +20,14 @@
#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;
......
......@@ -132,7 +132,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,
};
......
......@@ -140,7 +140,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,
};
......
......@@ -17,15 +17,16 @@
#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;
......
......@@ -26,11 +26,13 @@
#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 @@ 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 */
......@@ -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,
......
......@@ -17,11 +17,13 @@
#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,
};
......
......@@ -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,
};
......
......@@ -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);
......
......@@ -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,
......
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment