[PATCH 2/5] drm/tinydrm: Add tinydrm_panel abstraction
Noralf Trønnes
noralf at tronnes.org
Sat Mar 11 21:35:33 UTC 2017
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 <noralf at 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 ®map 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
More information about the dri-devel
mailing list