mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-10 07:10:27 +00:00
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: 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
This commit is contained in:
parent
b051b3459b
commit
af74138160
@ -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 @@ 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,
|
||||
};
|
||||
|
||||
|
@ -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 @@ 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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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 @@ 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,
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user