Add support for displays that can be operated using a simple vtable.
Geared towards controllers that can represent it's registers using
regmap.

Signed-off-by: Noralf Trønnes <nor...@tronnes.org>
---
 Documentation/gpu/tinydrm.rst                |  12 +
 drivers/gpu/drm/tinydrm/Kconfig              |   1 +
 drivers/gpu/drm/tinydrm/core/Makefile        |   2 +-
 drivers/gpu/drm/tinydrm/core/tinydrm-panel.c | 532 +++++++++++++++++++++++++++
 include/drm/tinydrm/tinydrm-panel.h          | 153 ++++++++
 5 files changed, 699 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/tinydrm/core/tinydrm-panel.c
 create mode 100644 include/drm/tinydrm/tinydrm-panel.h

diff --git a/Documentation/gpu/tinydrm.rst b/Documentation/gpu/tinydrm.rst
index a913644..bb78433 100644
--- a/Documentation/gpu/tinydrm.rst
+++ b/Documentation/gpu/tinydrm.rst
@@ -20,6 +20,18 @@ Core functionality
 .. kernel-doc:: drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
    :export:
 
+Panel
+=====
+
+.. kernel-doc:: drivers/gpu/drm/tinydrm/core/tinydrm-panel.c
+   :doc: overview
+
+.. kernel-doc:: include/drm/tinydrm/tinydrm-panel.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/tinydrm/core/tinydrm-panel.c
+   :export:
+
 Additional helpers
 ==================
 
diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig
index 3504c53..4ea0fbc 100644
--- a/drivers/gpu/drm/tinydrm/Kconfig
+++ b/drivers/gpu/drm/tinydrm/Kconfig
@@ -1,6 +1,7 @@
 menuconfig DRM_TINYDRM
        tristate "Support for simple displays"
        depends on DRM
+       select REGMAP
        select DRM_KMS_HELPER
        select DRM_KMS_CMA_HELPER
        select BACKLIGHT_LCD_SUPPORT
diff --git a/drivers/gpu/drm/tinydrm/core/Makefile 
b/drivers/gpu/drm/tinydrm/core/Makefile
index fb221e6..213b479 100644
--- a/drivers/gpu/drm/tinydrm/core/Makefile
+++ b/drivers/gpu/drm/tinydrm/core/Makefile
@@ -1,3 +1,3 @@
-tinydrm-y := tinydrm-core.o tinydrm-pipe.o tinydrm-helpers.o
+tinydrm-y := tinydrm-core.o tinydrm-pipe.o tinydrm-panel.o tinydrm-helpers.o
 
 obj-$(CONFIG_DRM_TINYDRM) += tinydrm.o
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-panel.c 
b/drivers/gpu/drm/tinydrm/core/tinydrm-panel.c
new file mode 100644
index 0000000..f3e5fb1
--- /dev/null
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-panel.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright 2017 Noralf Trønnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/tinydrm/tinydrm-helpers.h>
+#include <drm/tinydrm/tinydrm-panel.h>
+
+/**
+ * DOC: overview
+ *
+ * This library provides helpers for displays/panels that can be operated
+ * using a simple vtable.
+ *
+ * Many controllers are operated through a register making &regmap a useful
+ * abstraction for the register interface code. This helper is geared towards
+ * such controllers. Often controllers also support more than one bus, and
+ * should for instance a controller be connected in a non-standard way
+ * (e.g. memory mapped), then only the regmap needs to be changed.
+ */
+
+static int tinydrm_panel_prepare(struct tinydrm_panel *panel)
+{
+       if (panel->funcs && panel->funcs->prepare)
+               return panel->funcs->prepare(panel);
+
+       if (panel->regulator)
+               return regulator_enable(panel->regulator);
+
+       return 0;
+}
+
+static int tinydrm_panel_enable(struct tinydrm_panel *panel)
+{
+       if (panel->funcs && panel->funcs->enable)
+               return panel->funcs->enable(panel);
+
+       return tinydrm_enable_backlight(panel->backlight);
+}
+
+static int tinydrm_panel_disable(struct tinydrm_panel *panel)
+{
+       if (panel->funcs && panel->funcs->disable)
+               return panel->funcs->disable(panel);
+
+       return tinydrm_disable_backlight(panel->backlight);
+}
+
+static int tinydrm_panel_unprepare(struct tinydrm_panel *panel)
+{
+       if (panel->funcs && panel->funcs->unprepare)
+               return panel->funcs->unprepare(panel);
+
+       if (panel->regulator)
+               return regulator_disable(panel->regulator);
+
+       return 0;
+}
+
+static void tinydrm_panel_pipe_enable(struct drm_simple_display_pipe *pipe,
+                                     struct drm_crtc_state *crtc_state)
+{
+       struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+       struct tinydrm_panel *panel = tinydrm_to_panel(tdev);
+       struct drm_framebuffer *fb = pipe->plane.fb;
+
+       panel->enabled = true;
+       fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0);
+       tinydrm_panel_enable(panel);
+}
+
+static void tinydrm_panel_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+       struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+       struct tinydrm_panel *panel = tinydrm_to_panel(tdev);
+
+       panel->enabled = false;
+       tinydrm_panel_disable(panel);
+}
+
+static void tinydrm_panel_pipe_update(struct drm_simple_display_pipe *pipe,
+                                     struct drm_plane_state *old_state)
+{
+       struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+       struct tinydrm_panel *panel = tinydrm_to_panel(tdev);
+       struct drm_framebuffer *fb = pipe->plane.state->fb;
+
+       /* fb is set (not changed) */
+       if (fb && !old_state->fb)
+               tinydrm_panel_prepare(panel);
+
+       tinydrm_display_pipe_update(pipe, old_state);
+
+       /* fb is unset */
+       if (!fb)
+               tinydrm_panel_unprepare(panel);
+}
+
+static const struct drm_simple_display_pipe_funcs tinydrm_panel_pipe_funcs = {
+       .enable = tinydrm_panel_pipe_enable,
+       .disable = tinydrm_panel_pipe_disable,
+       .update = tinydrm_panel_pipe_update,
+       .prepare_fb = tinydrm_display_pipe_prepare_fb,
+};
+
+static int tinydrm_panel_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 tinydrm_panel *panel = tinydrm_to_panel(tdev);
+       struct drm_clip_rect rect;
+       int ret = 0;
+
+       if (!panel->funcs || !panel->funcs->flush)
+               return 0;
+
+       mutex_lock(&tdev->dirty_lock);
+
+       if (!panel->enabled)
+               goto out_unlock;
+
+       /* fbdev can flush even when we're not interested */
+       if (tdev->pipe.plane.fb != fb)
+               goto out_unlock;
+
+       tinydrm_merge_clips(&rect, clips, num_clips, flags,
+                           fb->width, fb->height);
+
+       ret = panel->funcs->flush(panel, fb, &rect);
+
+out_unlock:
+       mutex_unlock(&tdev->dirty_lock);
+
+       if (ret)
+               dev_err_once(fb->dev->dev, "Failed to update display %d\n",
+                            ret);
+
+       return ret;
+}
+
+static const struct drm_framebuffer_funcs tinydrm_panel_fb_funcs = {
+       .destroy        = drm_fb_cma_destroy,
+       .create_handle  = drm_fb_cma_create_handle,
+       .dirty          = tinydrm_panel_fb_dirty,
+};
+
+/**
+ * tinydrm_panel_init - Initialize &tinydrm_panel
+ * @dev: Parent device
+ * @panel: &tinydrm_panel structure to initialize
+ * @funcs: Callbacks for the panel (optional)
+ * @formats: Array of supported formats (DRM_FORMAT\_\*). The first format is
+ *           considered the default format and &tinydrm_panel->tx_buf is
+ *           allocated a buffer that can hold a framebuffer with that format.
+ * @format_count: Number of elements in @formats
+ * @driver: DRM driver
+ * @mode: Display mode
+ * @rotation: Initial rotation in degrees Counter Clock Wise
+ *
+ * This function initializes a &tinydrm_panel structure and it's underlying
+ * @tinydrm_device. It also sets up the display pipeline.
+ *
+ * Objects created by this function will be automatically freed on driver
+ * detach (devres).
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int tinydrm_panel_init(struct device *dev, struct tinydrm_panel *panel,
+                      const struct tinydrm_panel_funcs *funcs,
+                      const uint32_t *formats, unsigned int format_count,
+                      struct drm_driver *driver,
+                      const struct drm_display_mode *mode,
+                      unsigned int rotation)
+{
+       struct tinydrm_device *tdev = &panel->tinydrm;
+       const struct drm_format_info *format_info;
+       size_t bufsize;
+       int ret;
+
+       format_info = drm_format_info(formats[0]);
+       bufsize = mode->vdisplay * mode->hdisplay * format_info->cpp[0];
+
+       panel->tx_buf = devm_kmalloc(dev, bufsize, GFP_KERNEL);
+       if (!panel->tx_buf)
+               return -ENOMEM;
+
+       ret = devm_tinydrm_init(dev, tdev, &tinydrm_panel_fb_funcs, driver);
+       if (ret)
+               return ret;
+
+       ret = tinydrm_display_pipe_init(tdev, &tinydrm_panel_pipe_funcs,
+                                       DRM_MODE_CONNECTOR_VIRTUAL,
+                                       formats, format_count, mode,
+                                       rotation);
+       if (ret)
+               return ret;
+
+       tdev->drm->mode_config.preferred_depth = format_info->depth;
+
+       panel->rotation = rotation;
+       panel->funcs = funcs;
+
+       drm_mode_config_reset(tdev->drm);
+
+       DRM_DEBUG_KMS("preferred_depth=%u, rotation = %u\n",
+                     tdev->drm->mode_config.preferred_depth, rotation);
+
+       return 0;
+}
+EXPORT_SYMBOL(tinydrm_panel_init);
+
+/**
+ * tinydrm_panel_rgb565_buf - Return RGB565 buffer to scanout
+ * @panel: tinydrm panel
+ * @fb: DRM framebuffer
+ * @rect: Clip rectangle area to scanout
+ *
+ * This function returns the RGB565 framebuffer rectangle to scanout.
+ * It converts XRGB8888 to RGB565 if necessary.
+ * If copying isn't necessary (RGB565 full rect, no swap), then the backing
+ * CMA buffer is returned.
+ *
+ * Returns:
+ * Buffer to scanout on success, ERR_PTR on failure.
+ */
+void *tinydrm_panel_rgb565_buf(struct tinydrm_panel *panel,
+                              struct drm_framebuffer *fb,
+                              struct drm_clip_rect *rect)
+{
+       struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       bool swap = panel->swap_bytes;
+       bool full;
+       void *buf;
+       int ret;
+
+       full = (rect->x2 - rect->x1) == fb->width &&
+              (rect->y2 - rect->y1) == fb->height;
+
+       if (panel->always_tx_buf || swap || !full ||
+           fb->format->format == DRM_FORMAT_XRGB8888) {
+               buf = panel->tx_buf;
+               ret = tinydrm_rgb565_buf_copy(buf, fb, rect, swap);
+               if (ret)
+                       return ERR_PTR(ret);
+       } else {
+               buf = cma_obj->vaddr;
+       }
+
+       return buf;
+}
+EXPORT_SYMBOL(tinydrm_panel_rgb565_buf);
+
+/**
+ * tinydrm_panel_pm_suspend - tinydrm_panel PM suspend helper
+ * @dev: Device
+ *
+ * tinydrm_panel drivers can use this in their &device_driver->pm operations.
+ * Use dev_set_drvdata() or similar to set &tinydrm_panel as driver data.
+ */
+int tinydrm_panel_pm_suspend(struct device *dev)
+{
+       struct tinydrm_panel *panel = dev_get_drvdata(dev);
+       int ret;
+
+       ret = tinydrm_suspend(&panel->tinydrm);
+       if (ret)
+               return ret;
+
+       /* fb isn't set to NULL by suspend, do .unprepare() explicitly */
+       tinydrm_panel_unprepare(panel);
+
+       return 0;
+}
+EXPORT_SYMBOL(tinydrm_panel_pm_suspend);
+
+/**
+ * tinydrm_panel_pm_resume - tinydrm_panel PM resume helper
+ * @dev: Device
+ *
+ * tinydrm_panel drivers can use this in their &device_driver->pm operations.
+ * Use dev_set_drvdata() or similar to set &tinydrm_panel as driver data.
+ */
+int tinydrm_panel_pm_resume(struct device *dev)
+{
+       struct tinydrm_panel *panel = dev_get_drvdata(dev);
+
+       /* fb is NULL on resume, .prepare() will be called in pipe_update */
+
+       return tinydrm_resume(&panel->tinydrm);
+}
+EXPORT_SYMBOL(tinydrm_panel_pm_resume);
+
+/**
+ * tinydrm_panel_spi_shutdown - tinydrm_panel SPI shutdown helper
+ * @spi: SPI device
+ *
+ * tinydrm_panel drivers can use this as their shutdown callback to turn off
+ * the display on machine shutdown and reboot. Use spi_set_drvdata() or
+ * similar to set &tinydrm_panel as driver data.
+ */
+void tinydrm_panel_spi_shutdown(struct spi_device *spi)
+{
+       struct tinydrm_panel *panel = spi_get_drvdata(spi);
+
+       tinydrm_shutdown(&panel->tinydrm);
+}
+EXPORT_SYMBOL(tinydrm_panel_spi_shutdown);
+
+/**
+ * tinydrm_panel_i2c_shutdown - tinydrm_panel I2C shutdown helper
+ * @i2c: I2C client device
+ *
+ * tinydrm_panel drivers can use this as their shutdown callback to turn off
+ * the display on machine shutdown and reboot. Use i2c_set_clientdata() or
+ * similar to set &tinydrm_panel as driver data.
+ */
+void tinydrm_panel_i2c_shutdown(struct i2c_client *i2c)
+{
+       struct tinydrm_panel *panel = i2c_get_clientdata(i2c);
+
+       tinydrm_shutdown(&panel->tinydrm);
+}
+EXPORT_SYMBOL(tinydrm_panel_i2c_shutdown);
+
+/**
+ * tinydrm_panel_platform_shutdown - tinydrm_panel platform driver shutdown
+ *                                   helper
+ * @pdev: Platform device
+ *
+ * tinydrm_panel drivers can use this as their shutdown callback to turn off
+ * the display on machine shutdown and reboot. Use platform_set_drvdata() or
+ * similar to set &tinydrm_panel as driver data.
+ */
+void tinydrm_panel_platform_shutdown(struct platform_device *pdev)
+{
+       struct tinydrm_panel *panel = platform_get_drvdata(pdev);
+
+       tinydrm_shutdown(&panel->tinydrm);
+}
+EXPORT_SYMBOL(tinydrm_panel_platform_shutdown);
+
+/**
+ * tinydrm_regmap_raw_swap_bytes - Does a raw write require swapping bytes?
+ * @reg: Regmap
+ *
+ * If the bus doesn't support the full regwidth, it has to break up the word.
+ * Additionally if the bus and machine doesn't match endian wise, this requires
+ * byteswapping the buffer when using regmap_raw_write().
+ *
+ * Returns:
+ * True if byte swapping is needed, otherwise false
+ */
+bool tinydrm_regmap_raw_swap_bytes(struct regmap *reg)
+{
+       int val_bytes = regmap_get_val_bytes(reg);
+       unsigned int bus_val;
+       u16 val16 = 0x00ff;
+
+       if (val_bytes == 1)
+               return false;
+
+       if (WARN_ON_ONCE(val_bytes != 2))
+               return false;
+
+       regmap_parse_val(reg, &val16, &bus_val);
+
+       return val16 != bus_val;
+}
+EXPORT_SYMBOL(tinydrm_regmap_raw_swap_bytes);
+
+#ifdef CONFIG_DEBUG_FS
+
+static int
+tinydrm_kstrtoul_array_from_user(const char __user *s, size_t count,
+                                unsigned int base,
+                                unsigned long *vals, size_t num_vals)
+{
+       char *buf, *pos, *token;
+       int ret, i = 0;
+
+       buf = memdup_user_nul(s, count);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       pos = buf;
+       while (pos) {
+               if (i == num_vals) {
+                       ret = -E2BIG;
+                       goto err_free;
+               }
+
+               token = strsep(&pos, " ");
+               if (!token) {
+                       ret = -EINVAL;
+                       goto err_free;
+               }
+
+               ret = kstrtoul(token, base, vals++);
+               if (ret < 0)
+                       goto err_free;
+               i++;
+       }
+
+err_free:
+       kfree(buf);
+
+       return ret ? ret : i;
+}
+
+static ssize_t tinydrm_regmap_debugfs_reg_write(struct file *file,
+                                               const char __user *user_buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct seq_file *m = file->private_data;
+       struct regmap *reg = m->private;
+       unsigned long vals[2];
+       int ret;
+
+       ret = tinydrm_kstrtoul_array_from_user(user_buf, count, 16, vals, 2);
+       if (ret <= 0)
+               return ret;
+
+       if (ret != 2)
+               return -EINVAL;
+
+       ret = regmap_write(reg, vals[0], vals[1]);
+
+       return ret < 0 ? ret : count;
+}
+
+static int tinydrm_regmap_debugfs_reg_show(struct seq_file *m, void *d)
+{
+       struct regmap *reg = m->private;
+       int max_reg = regmap_get_max_register(reg);
+       int val_bytes = regmap_get_val_bytes(reg);
+       unsigned int val;
+       int regnr, ret;
+
+       for (regnr = 0; regnr < max_reg; regnr++) {
+               seq_printf(m, "%.*x: ", val_bytes * 2, regnr);
+               ret = regmap_read(reg, regnr, &val);
+               if (ret)
+                       seq_puts(m, "XX\n");
+               else
+                       seq_printf(m, "%.*x\n", val_bytes * 2, val);
+       }
+
+       return 0;
+}
+
+static int tinydrm_regmap_debugfs_reg_open(struct inode *inode,
+                                          struct file *file)
+{
+       return single_open(file, tinydrm_regmap_debugfs_reg_show,
+                          inode->i_private);
+}
+
+static const struct file_operations tinydrm_regmap_debugfs_reg_fops = {
+       .owner = THIS_MODULE,
+       .open = tinydrm_regmap_debugfs_reg_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .write = tinydrm_regmap_debugfs_reg_write,
+};
+
+static int
+tinydrm_regmap_debugfs_init(struct regmap *reg, struct dentry *parent)
+{
+       umode_t mode = 0200;
+
+       if (regmap_get_max_register(reg))
+               mode |= 0444;
+
+       debugfs_create_file("registers", mode, parent, reg,
+                           &tinydrm_regmap_debugfs_reg_fops);
+       return 0;
+}
+
+static const struct drm_info_list tinydrm_panel_debugfslist[] = {
+       { "fb",   drm_fb_cma_debugfs_show, 0 },
+};
+
+/**
+ * tinydrm_panel_debugfs_init - Create tinydrm panel debugfs entries
+ * @minor: DRM minor
+ *
+ * &tinydrm_panel drivers can use this as their
+ * &drm_driver->debugfs_init callback.
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int tinydrm_panel_debugfs_init(struct drm_minor *minor)
+{
+       struct tinydrm_device *tdev = minor->dev->dev_private;
+       struct tinydrm_panel *panel = tinydrm_to_panel(tdev);
+       struct regmap *reg = panel->reg;
+       int ret;
+
+       if (reg) {
+               ret = tinydrm_regmap_debugfs_init(reg, minor->debugfs_root);
+               if (ret)
+                       return ret;
+       }
+
+       return drm_debugfs_create_files(tinydrm_panel_debugfslist,
+                                       ARRAY_SIZE(tinydrm_panel_debugfslist),
+                                       minor->debugfs_root, minor);
+}
+EXPORT_SYMBOL(tinydrm_panel_debugfs_init);
+
+#endif
diff --git a/include/drm/tinydrm/tinydrm-panel.h 
b/include/drm/tinydrm/tinydrm-panel.h
new file mode 100644
index 0000000..fc4348d
--- /dev/null
+++ b/include/drm/tinydrm/tinydrm-panel.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2017 Noralf Trønnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_TINYDRM_PANEL_H
+#define __LINUX_TINYDRM_PANEL_H
+
+#include <drm/tinydrm/tinydrm.h>
+
+struct backlight_device;
+struct platform_device;
+struct tinydrm_panel;
+struct spi_device;
+struct regulator;
+struct gpio_desc;
+struct regmap;
+
+/**
+ * struct tinydrm_panel_funcs - tinydrm panel functions
+ *
+ * All functions are optional.
+ */
+struct tinydrm_panel_funcs {
+       /**
+        * @prepare:
+        *
+        * Prepare controller/display.
+        *
+        * This function is called before framebuffer flushing starts.
+        * Drivers can use this callback to power on and configure the
+        * controller/display.
+        * If this is not set and &tinydrm_panel->regulator is set,
+        * the regulator is enabled.
+        */
+       int (*prepare)(struct tinydrm_panel *panel);
+
+       /**
+        * @enable:
+        *
+        * Enable display.
+        *
+        * This function is called when the display pipeline is enabled.
+        * Drivers can use this callback to turn on the display.
+        * If this is not set and &tinydrm_panel->backlight is set,
+        * the backlight is turned on.
+        */
+       int (*enable)(struct tinydrm_panel *panel);
+
+       /**
+        * @disable:
+        *
+        * Disable display.
+        *
+        * This function is called when the display pipeline is disabled.
+        * Drivers can use this callback to turn off the display.
+        * If this is not set and &tinydrm_panel->backlight is set,
+        * the backlight is turned off.
+        */
+       int (*disable)(struct tinydrm_panel *panel);
+
+       /**
+        * @unprepare:
+        *
+        * Unprepare controller/display.
+        *
+        * This function is called when framebuffer is unset on the plane.
+        * Drivers can use this callback to power down the controller/display.
+        * If this is not set and &tinydrm_panel->regulator is set,
+        * the regulator is disabled.
+        */
+       int (*unprepare)(struct tinydrm_panel *panel);
+
+       /**
+        * @flush:
+        *
+        * Flush framebuffer to controller/display.
+        *
+        * This function is called when the framebuffer is flushed. This
+        * happens when userspace calls ioctl DRM_IOCTL_MODE_DIRTYFB, when the
+        * framebuffer is changed on the plane and when the pipeline is
+        * enabled. If multiple clip rectangles are passed in, they are merged
+        * into one rectangle and passed to @flush. No flushing happens
+        * during the time the pipeline is disabled.
+        */
+       int (*flush)(struct tinydrm_panel *panel, struct drm_framebuffer *fb,
+                    struct drm_clip_rect *rect);
+};
+
+/**
+ * struct tinydrm_panel - tinydrm panel device
+ * @tinydrm: Base &tinydrm_device
+ * @funcs: tinydrm panel functions (optional)
+ * @reg: Register map (optional)
+ * @enabled: Pipeline is enabled
+ * @tx_buf: Transmit buffer
+ * @swap_bytes: Swap pixel data bytes
+ * @always_tx_buf: Always use @tx_buf
+ * @rotation: Rotation in degrees Counter Clock Wise
+ * @reset: Optional reset gpio
+ * @backlight: Optional backlight device
+ * @regulator: Optional regulator
+ */
+struct tinydrm_panel {
+       struct tinydrm_device tinydrm;
+       const struct tinydrm_panel_funcs *funcs;
+       struct regmap *reg;
+       bool enabled;
+       void *tx_buf;
+       bool swap_bytes;
+       bool always_tx_buf;
+       unsigned int rotation;
+       struct gpio_desc *reset;
+       struct backlight_device *backlight;
+       struct regulator *regulator;
+};
+
+static inline struct tinydrm_panel *
+tinydrm_to_panel(struct tinydrm_device *tdev)
+{
+       return container_of(tdev, struct tinydrm_panel, tinydrm);
+}
+
+int tinydrm_panel_init(struct device *dev, struct tinydrm_panel *panel,
+                       const struct tinydrm_panel_funcs *funcs,
+                       const uint32_t *formats, unsigned int format_count,
+                       struct drm_driver *driver,
+                       const struct drm_display_mode *mode,
+                       unsigned int rotation);
+
+void *tinydrm_panel_rgb565_buf(struct tinydrm_panel *panel,
+                              struct drm_framebuffer *fb,
+                              struct drm_clip_rect *rect);
+
+int tinydrm_panel_pm_suspend(struct device *dev);
+int tinydrm_panel_pm_resume(struct device *dev);
+void tinydrm_panel_spi_shutdown(struct spi_device *spi);
+void tinydrm_panel_i2c_shutdown(struct i2c_client *i2c);
+void tinydrm_panel_platform_shutdown(struct platform_device *pdev);
+
+bool tinydrm_regmap_raw_swap_bytes(struct regmap *reg);
+
+#ifdef CONFIG_DEBUG_FS
+int tinydrm_panel_debugfs_init(struct drm_minor *minor);
+#else
+#define tinydrm_panel_debugfs_init     NULL
+#endif
+
+#endif /* __LINUX_TINYDRM_PANEL_H */
-- 
2.10.2

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

Reply via email to