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

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
Loading
Loading
Loading
Loading
+2 −19
Original line number Diff line number Diff line
@@ -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;

+1 −90
Original line number Diff line number Diff line
@@ -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
+0 −31
Original line number Diff line number Diff line
@@ -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)
{
+1 −1
Original line number Diff line number Diff line
@@ -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,
};

+41 −71
Original line number Diff line number Diff line
@@ -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,7 +394,7 @@ 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,
	ret = mipi_dbi_init(&spi->dev, mipi, &ili9225_pipe_funcs,
			    &ili9225_driver, &ili9225_mode, rotation);
	if (ret)
		return ret;
Loading