[RFC v2 0/5] Common Display Framework
Tomasz Figa
t.figa at samsung.com
Thu Dec 27 06:43:34 PST 2012
Hi Laurent,
On Monday 24 of December 2012 15:12:28 Laurent Pinchart wrote:
> Hi Tomasz,
>
> On Friday 21 December 2012 11:00:52 Tomasz Figa wrote:
> > On Tuesday 18 of December 2012 08:31:30 Vikas Sajjan wrote:
> > > On 17 December 2012 20:55, Laurent Pinchart wrote:
> > > > Hi Vikas,
> > > >
> > > > Sorry for the late reply. I now have more time to work on CDF, so
> > > > delays should be much shorter.
> > > >
> > > > On Thursday 06 December 2012 10:51:15 Vikas Sajjan wrote:
> > > > > Hi Laurent,
> > > > >
> > > > > I was thinking of porting CDF to samsung EXYNOS 5250 platform,
> > > > > what
> > > > > I found is that, the exynos display controller is MIPI DSI based
> > > > > controller.
> > > > >
> > > > > But if I look at CDF patches, it has only support for MIPI DBI
> > > > > based
> > > > > Display controller.
> > > > >
> > > > > So my question is, do we have any generic framework for MIPI DSI
> > > > > based display controller? basically I wanted to know, how to go
> > > > > about
> > > > > porting CDF for such kind of display controller.
> > > >
> > > > MIPI DSI support is not available yet. The only reason for that is
> > > > that I don't have any MIPI DSI hardware to write and test the code
> > > > with :-)
> > > >
> > > > The common display framework should definitely support MIPI DSI. I
> > > > think the existing MIPI DBI code could be used as a base, so the
> > > > implementation shouldn't be too high.
> > > >
> > > > Yeah, i was also thinking in similar lines, below is my though for
> > > > MIPI DSI support in CDF.
> > >
> > > o MIPI DSI support as part of CDF framework will expose
> > > § mipi_dsi_register_device(mpi_device) (will be called
> > > mach-xxx-dt.c
> > > file )
> > > § mipi_dsi_register_driver(mipi_driver, bus ops) (will be called
> > > from
> > > platform specific init driver call )
> > > · bus ops will be
> > > o read data
> > > o write data
> > > o write command
> > > § MIPI DSI will be registered as bus_register()
> > >
> > > When MIPI DSI probe is called, it (e.g., Exynos or OMAP MIPI DSI)
> > > will
> > > initialize the MIPI DSI HW IP.
> > >
> > > This probe will also parse the DT file for MIPI DSI based panel, add
> > > the panel device (device_add() ) to kernel and register the display
> > > entity with its control and video ops with CDF.
> > >
> > > I can give this a try.
> >
> > I am currently in progress of reworking Exynos MIPI DSIM code and
> > s6e8ax0 LCD driver to use the v2 RFC of Common Display Framework. I
> > have most of the work done, I have just to solve several remaining
> > problems.
> Do you already have code that you can publish ? I'm particularly
> interested (and I think Tomi Valkeinen would be as well) in looking at
> the DSI operations you expose to DSI sinks (panels, transceivers, ...).
Well, I'm afraid this might be little below your expectations, but here's
an initial RFC of the part defining just the DSI bus. I need a bit more
time for patches for Exynos MIPI DSI master and s6e8ax0 LCD.
The implementation is very simple and heavily based on your MIPI DBI
support and existing Exynos MIPI DSIM framework. Provided operation set is
based on operation set used by Exynos s6e8ax0 LCD driver. Unfortunately
this is my only source of information about MIPI DSI.
Best regards,
--
Tomasz Figa
Samsung Poland R&D Center
SW Solution Development, Linux Platform
>From bad07d8bdce0ff76cbc81a9da597c0d01e5244f7 Mon Sep 17 00:00:00 2001
From: Tomasz Figa <t.figa at samsung.com>
Date: Thu, 27 Dec 2012 12:36:15 +0100
Subject: [RFC] video: display: Add generic MIPI DSI bus
Signed-off-by: Tomasz Figa <t.figa at samsung.com>
---
drivers/video/display/Kconfig | 4 +
drivers/video/display/Makefile | 1 +
drivers/video/display/mipi-dsi-bus.c | 214
+++++++++++++++++++++++++++++++++++
include/video/display.h | 1 +
include/video/mipi-dsi-bus.h | 98 ++++++++++++++++
5 files changed, 318 insertions(+)
create mode 100644 drivers/video/display/mipi-dsi-bus.c
create mode 100644 include/video/mipi-dsi-bus.h
diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig
index 13b6aaf..dbaff9d 100644
--- a/drivers/video/display/Kconfig
+++ b/drivers/video/display/Kconfig
@@ -9,6 +9,10 @@ config DISPLAY_MIPI_DBI
tristate
default n
+config DISPLAY_MIPI_DSI
+ tristate
+ default n
+
config DISPLAY_PANEL_DPI
tristate "DPI (Parallel) Display Panels"
---help---
diff --git a/drivers/video/display/Makefile
b/drivers/video/display/Makefile
index 482bec7..429b3ac8 100644
--- a/drivers/video/display/Makefile
+++ b/drivers/video/display/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_DISPLAY_CORE) += display-core.o
obj-$(CONFIG_DISPLAY_MIPI_DBI) += mipi-dbi-bus.o
+obj-$(CONFIG_DISPLAY_MIPI_DSI) += mipi-dsi-bus.o
obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o
obj-$(CONFIG_DISPLAY_PANEL_R61505) += panel-r61505.o
obj-$(CONFIG_DISPLAY_PANEL_R61517) += panel-r61517.o
diff --git a/drivers/video/display/mipi-dsi-bus.c
b/drivers/video/display/mipi-dsi-bus.c
new file mode 100644
index 0000000..2998522
--- /dev/null
+++ b/drivers/video/display/mipi-dsi-bus.c
@@ -0,0 +1,214 @@
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Contacts: Tomasz Figa <t.figa at samsung.com>
+ *
+ * Heavily based ond mipi-dbi-bus.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+
+#include <video/mipi-dsi-bus.h>
+
+/*
-----------------------------------------------------------------------------
+ * Bus operations
+ */
+
+int mipi_dsi_write_command(struct mipi_dsi_device *dev, unsigned int cmd,
+ const unsigned char *buf, unsigned int len)
+{
+ return dev->bus->ops->write_command(dev->bus, dev, cmd, buf, len);
+}
+EXPORT_SYMBOL_GPL(mipi_dsi_write_command);
+
+int mipi_dsi_read_command(struct mipi_dsi_device *dev, unsigned int cmd,
+ unsigned int addr, unsigned char *buf, unsigned int len)
+{
+ return dev->bus->ops->read_command(dev->bus, dev, cmd, addr, buf,
len);
+}
+EXPORT_SYMBOL_GPL(mipi_dsi_read_command);
+
+/*
-----------------------------------------------------------------------------
+ * Bus type
+ */
+
+static const struct mipi_dsi_device_id *
+mipi_dsi_match_id(const struct mipi_dsi_device_id *id,
+ struct mipi_dsi_device *dev)
+{
+ while (id->name[0]) {
+ if (strcmp(dev->name, id->name) == 0) {
+ dev->id_entry = id;
+ return id;
+ }
+ id++;
+ }
+ return NULL;
+}
+
+static int mipi_dsi_match(struct device *_dev, struct device_driver
*_drv)
+{
+ struct mipi_dsi_device *dev = to_mipi_dsi_device(_dev);
+ struct mipi_dsi_driver *drv = to_mipi_dsi_driver(_drv);
+
+ if (drv->id_table)
+ return mipi_dsi_match_id(drv->id_table, dev) != NULL;
+
+ return (strcmp(dev->name, _drv->name) == 0);
+}
+
+static ssize_t modalias_show(struct device *_dev, struct device_attribute
*a,
+ char *buf)
+{
+ struct mipi_dsi_device *dev = to_mipi_dsi_device(_dev);
+ int len = snprintf(buf, PAGE_SIZE, MIPI_DSI_MODULE_PREFIX "%s\n",
+ dev->name);
+
+ return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute mipi_dsi_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+static int mipi_dsi_uevent(struct device *_dev, struct kobj_uevent_env
*env)
+{
+ struct mipi_dsi_device *dev = to_mipi_dsi_device(_dev);
+
+ add_uevent_var(env, "MODALIAS=%s%s", MIPI_DSI_MODULE_PREFIX,
+ dev->name);
+ return 0;
+}
+
+static const struct dev_pm_ops mipi_dsi_dev_pm_ops = {
+ .runtime_suspend = pm_generic_runtime_suspend,
+ .runtime_resume = pm_generic_runtime_resume,
+ .runtime_idle = pm_generic_runtime_idle,
+ .suspend = pm_generic_suspend,
+ .resume = pm_generic_resume,
+ .freeze = pm_generic_freeze,
+ .thaw = pm_generic_thaw,
+ .poweroff = pm_generic_poweroff,
+ .restore = pm_generic_restore,
+};
+
+static struct bus_type mipi_dsi_bus_type = {
+ .name = "mipi-dsi",
+ .dev_attrs = mipi_dsi_dev_attrs,
+ .match = mipi_dsi_match,
+ .uevent = mipi_dsi_uevent,
+ .pm = &mipi_dsi_dev_pm_ops,
+};
+
+/*
-----------------------------------------------------------------------------
+ * Device and driver (un)registration
+ */
+
+/**
+ * mipi_dsi_device_register - register a DSI device
+ * @dev: DSI device we're registering
+ */
+int mipi_dsi_device_register(struct mipi_dsi_device *dev,
+ struct mipi_dsi_bus *bus)
+{
+ device_initialize(&dev->dev);
+
+ dev->bus = bus;
+ dev->dev.bus = &mipi_dsi_bus_type;
+ dev->dev.parent = bus->dev;
+
+ if (dev->id != -1)
+ dev_set_name(&dev->dev, "%s.%d", dev->name, dev->id);
+ else
+ dev_set_name(&dev->dev, "%s", dev->name);
+
+ return device_add(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(mipi_dsi_device_register);
+
+/**
+ * mipi_dsi_device_unregister - unregister a DSI device
+ * @dev: DSI device we're unregistering
+ */
+void mipi_dsi_device_unregister(struct mipi_dsi_device *dev)
+{
+ device_del(&dev->dev);
+ put_device(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(mipi_dsi_device_unregister);
+
+static int mipi_dsi_drv_probe(struct device *_dev)
+{
+ struct mipi_dsi_driver *drv = to_mipi_dsi_driver(_dev->driver);
+ struct mipi_dsi_device *dev = to_mipi_dsi_device(_dev);
+
+ return drv->probe(dev);
+}
+
+static int mipi_dsi_drv_remove(struct device *_dev)
+{
+ struct mipi_dsi_driver *drv = to_mipi_dsi_driver(_dev->driver);
+ struct mipi_dsi_device *dev = to_mipi_dsi_device(_dev);
+
+ return drv->remove(dev);
+}
+
+/**
+ * mipi_dsi_driver_register - register a driver for DSI devices
+ * @drv: DSI driver structure
+ */
+int mipi_dsi_driver_register(struct mipi_dsi_driver *drv)
+{
+ drv->driver.bus = &mipi_dsi_bus_type;
+ if (drv->probe)
+ drv->driver.probe = mipi_dsi_drv_probe;
+ if (drv->remove)
+ drv->driver.remove = mipi_dsi_drv_remove;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(mipi_dsi_driver_register);
+
+/**
+ * mipi_dsi_driver_unregister - unregister a driver for DSI devices
+ * @drv: DSI driver structure
+ */
+void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(mipi_dsi_driver_unregister);
+
+/*
-----------------------------------------------------------------------------
+ * Init/exit
+ */
+
+static int __init mipi_dsi_init(void)
+{
+ return bus_register(&mipi_dsi_bus_type);
+}
+
+static void __exit mipi_dsi_exit(void)
+{
+ bus_unregister(&mipi_dsi_bus_type);
+}
+
+module_init(mipi_dsi_init);
+module_exit(mipi_dsi_exit)
+
+MODULE_AUTHOR("Tomasz Figa <t.figa at samsung.com>");
+MODULE_DESCRIPTION("MIPI DSI Bus");
+MODULE_LICENSE("GPL");
diff --git a/include/video/display.h b/include/video/display.h
index 75ba270..f86ea6e 100644
--- a/include/video/display.h
+++ b/include/video/display.h
@@ -70,6 +70,7 @@ enum display_entity_stream_state {
enum display_entity_interface_type {
DISPLAY_ENTITY_INTERFACE_DPI,
DISPLAY_ENTITY_INTERFACE_DBI,
+ DISPLAY_ENTITY_INTERFACE_DSI,
};
struct display_entity_interface_params {
diff --git a/include/video/mipi-dsi-bus.h b/include/video/mipi-dsi-bus.h
new file mode 100644
index 0000000..3efcb39
--- /dev/null
+++ b/include/video/mipi-dsi-bus.h
@@ -0,0 +1,98 @@
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Contacts: Tomasz Figa <t.figa at samsung.com>
+ *
+ * Heavily based ond mipi-dbi-bus.h.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MIPI_DSI_BUS_H__
+#define __MIPI_DSI_BUS_H__
+
+#include <linux/device.h>
+
+struct mipi_dsi_bus;
+struct mipi_dsi_device;
+
+struct mipi_dsi_bus_ops {
+ int (*write_command)(struct mipi_dsi_bus *bus,
+ struct mipi_dsi_device *dev, unsigned int cmd,
+ const unsigned char *buf, unsigned int len);
+ int (*read_command)(struct mipi_dsi_bus *bus,
+ struct mipi_dsi_device *dev, unsigned int cmd,
+ unsigned int addr, unsigned char *buf,
+ unsigned int len);
+};
+
+struct mipi_dsi_bus {
+ struct device *dev;
+ const struct mipi_dsi_bus_ops *ops;
+};
+
+#define MIPI_DSI_MODULE_PREFIX "mipi-dsi:"
+#define MIPI_DSI_NAME_SIZE 32
+
+struct mipi_dsi_device_id {
+ char name[MIPI_DSI_NAME_SIZE];
+ __kernel_ulong_t driver_data /* Data private to the driver */
+ __aligned(sizeof(__kernel_ulong_t));
+};
+
+struct mipi_dsi_device {
+ const char *name;
+ int id;
+ struct device dev;
+
+ const struct mipi_dsi_device_id *id_entry;
+ struct mipi_dsi_bus *bus;
+};
+
+#define to_mipi_dsi_device(d) container_of(d, struct mipi_dsi_device,
dev)
+
+int mipi_dsi_device_register(struct mipi_dsi_device *dev,
+ struct mipi_dsi_bus *bus);
+void mipi_dsi_device_unregister(struct mipi_dsi_device *dev);
+
+struct mipi_dsi_driver {
+ int(*probe)(struct mipi_dsi_device *);
+ int(*remove)(struct mipi_dsi_device *);
+ struct device_driver driver;
+ const struct mipi_dsi_device_id *id_table;
+};
+
+#define to_mipi_dsi_driver(d) container_of(d, struct mipi_dsi_driver,
driver)
+
+int mipi_dsi_driver_register(struct mipi_dsi_driver *drv);
+void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv);
+
+static inline void *mipi_dsi_get_drvdata(const struct mipi_dsi_device
*dev)
+{
+ return dev_get_drvdata(&dev->dev);
+}
+
+static inline void mipi_dsi_set_drvdata(struct mipi_dsi_device *dev,
+ void *data)
+{
+ dev_set_drvdata(&dev->dev, data);
+}
+
+/* module_mipi_dsi_driver() - Helper macro for drivers that don't do
+ * anything special in module init/exit. This eliminates a lot of
+ * boilerplate. Each module may only use this macro once, and
+ * calling it replaces module_init() and module_exit()
+ */
+#define module_mipi_dsi_driver(__mipi_dsi_driver) \
+ module_driver(__mipi_dsi_driver, mipi_dsi_driver_register, \
+ mipi_dsi_driver_unregister)
+
+int mipi_dsi_write_command(struct mipi_dsi_device *dev, unsigned int cmd,
+ const unsigned char *buf, unsigned int len);
+int mipi_dsi_read_command(struct mipi_dsi_device *dev, unsigned int cmd,
+ unsigned int addr, unsigned char *buf, unsigned int len);
+
+#endif /* __MIPI_DSI_BUS__ */
--
1.8.0.2
More information about the dri-devel
mailing list