[RFC v2 0/5] Common Display Framework

Vikas Sajjan vikas.sajjan at linaro.org
Thu Dec 27 19:26:49 PST 2012


On 27 December 2012 20:13, Tomasz Figa <t.figa at samsung.com> wrote:
> 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);
> +}
> +

As per the discussion what Laurent and Tomi had (
http://lists.freedesktop.org/archives/dri-devel/2012-December/032038.html),
both  DSI and DBI doesn't need to be registered as real bus. Please
refer to Tomi's pacthset for DSI support. (
git://gitorious.org/linux-omap-dss2/linux.git work/dss-dev-model-cdf )

anyways i am working on Exynos MIPI DSI as per the new CDF proposed by
Tomi and Laurent.

> +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
>
>



--
Thanks and Regards
 Vikas Sajjan


More information about the dri-devel mailing list