On 10/07/2013 12:47 PM, Bert Kenward wrote: > On Tuesday September 24 2013 at 15:23, Andrzej Hajda wrote: >> MIPI DSI is a high-speed serial interface to transmit >> data from/to host to display module. >> >> Signed-off-by: Andrzej Hajda <a.hajda@xxxxxxxxxxx> >> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> >> --- >> drivers/video/display/Kconfig | 4 + >> drivers/video/display/Makefile | 1 + >> drivers/video/display/mipi-dsi-bus.c | 332 >> +++++++++++++++++++++++++++++++++++ >> include/video/display.h | 3 + >> include/video/mipi-dsi-bus.h | 144 +++++++++++++++ >> 5 files changed, 484 insertions(+) > <snipped as far as mipi-dsi-bus.h > >> diff --git a/include/video/mipi-dsi-bus.h b/include/video/mipi-dsi-bus.h >> new file mode 100644 >> index 0000000..a78792d >> --- /dev/null >> +++ b/include/video/mipi-dsi-bus.h >> @@ -0,0 +1,144 @@ >> +/* >> + * MIPI DSI Bus >> + * >> + * Copyright (C) 2013, Samsung Electronics, Co., Ltd. >> + * Andrzej Hajda <a.hajda@xxxxxxxxxxx> >> + * >> + * 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> >> +#include <video/videomode.h> >> + >> +struct mipi_dsi_bus; >> +struct mipi_dsi_device; >> + >> +struct mipi_dsi_bus_ops { >> + int (*set_power)(struct mipi_dsi_bus *bus, struct mipi_dsi_device >> *dev, >> + bool on); >> + int (*set_stream)(struct mipi_dsi_bus *bus, struct mipi_dsi_device >> *dev, >> + bool on); >> + int (*transfer)(struct mipi_dsi_bus *bus, struct mipi_dsi_device >> *dev, >> + u8 type, const u8 *tx_buf, size_t tx_len, u8 *rx_buf, >> + size_t rx_len); >> +}; >> + >> +#define DSI_MODE_VIDEO (1 << 0) >> +#define DSI_MODE_VIDEO_BURST (1 << 1) >> +#define DSI_MODE_VIDEO_SYNC_PULSE (1 << 2) >> +#define DSI_MODE_VIDEO_AUTO_VERT (1 << 3) >> +#define DSI_MODE_VIDEO_HSE (1 << 4) >> +#define DSI_MODE_VIDEO_HFP (1 << 5) >> +#define DSI_MODE_VIDEO_HBP (1 << 6) >> +#define DSI_MODE_VIDEO_HSA (1 << 7) >> +#define DSI_MODE_VSYNC_FLUSH (1 << 8) >> +#define DSI_MODE_EOT_PACKET (1 << 9) >> + >> +enum mipi_dsi_pixel_format { >> + DSI_FMT_RGB888, >> + DSI_FMT_RGB666, >> + DSI_FMT_RGB666_PACKED, >> + DSI_FMT_RGB565, >> +}; >> + >> +struct mipi_dsi_interface_params { >> + enum mipi_dsi_pixel_format format; >> + unsigned long mode; >> + unsigned long hs_clk_freq; >> + unsigned long esc_clk_freq; >> + unsigned char data_lanes; >> + unsigned char cmd_allow; >> +}; >> + >> +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 { >> + char name[MIPI_DSI_NAME_SIZE]; >> + int id; >> + struct device dev; >> + >> + const struct mipi_dsi_device_id *id_entry; >> + struct mipi_dsi_bus *bus; >> + struct videomode vm; >> + struct mipi_dsi_interface_params params; >> +}; >> + >> +#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); >> +} >> + >> +int of_mipi_dsi_register_devices(struct mipi_dsi_bus *bus); >> +void mipi_dsi_unregister_devices(struct mipi_dsi_bus *bus); >> + >> +/* 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_set_power(struct mipi_dsi_device *dev, bool on); >> +int mipi_dsi_set_stream(struct mipi_dsi_device *dev, bool on); >> +int mipi_dsi_dcs_write(struct mipi_dsi_device *dev, int channel, const u8 >> *data, >> + size_t len); >> +int mipi_dsi_dcs_read(struct mipi_dsi_device *dev, int channel, u8 cmd, >> + u8 *data, size_t len); >> + >> +#define mipi_dsi_dcs_write_seq(dev, channel, seq...) \ >> +({\ >> + const u8 d[] = { seq };\ >> + BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too long for >> stack");\ >> + mipi_dsi_dcs_write(dev, channel, d, ARRAY_SIZE(d));\ >> +}) >> + >> +#define mipi_dsi_dcs_write_static_seq(dev, channel, seq...) \ >> +({\ >> + static const u8 d[] = { seq };\ >> + mipi_dsi_dcs_write(dev, channel, d, ARRAY_SIZE(d));\ >> +}) >> + >> +#endif /* __MIPI_DSI_BUS__ */ > I may well have missed something, > but I can't see exactly how a command mode > update would be done with this interface. Would this require repeated calls to > .transfer? Such transfers would need to be flagged as requiring > synchronisation with a tearing effect control signal - either the inband > method or a dedicated line. I suspect many hardware implementations will have > a specific method for transferring pixel data in a DSI command mode transfer. > > The command sending period during video mode should probably be configurable > on a per-transfer basis. Some commands have to be synchronised with vertical > blanking, others do not. This could perhaps be combined with a wider > configuration option for a given panel or interface. Similarly, selection of > low power (LP) and high speed (HS) mode on a per-transfer basis can be needed > for some panels. > > Is there a mechanism for controlling ultra-low power state (ULPS) entry? Also, > is there a method for sending arbitrary trigger messages (eg the reset > trigger)? Thanks for the feedback. The current dsi bus implementation was just made to work with the hw I have. It should be extended to be more generic, but I hope now it is just matter of adding good opses and parameters. Feel free to propose new opses. Andrzej > > Thanks, > > Bert. _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel