Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH 1/5] OMAPDSS: DSI: Maintain copy of pixel format in driver data
From: Archit Taneja @ 2012-08-10 10:49 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344595026-10607-1-git-send-email-archit@ti.com>

The DSI driver currently relies on the omap_dss_device struct to receive the
desired pixel format of the panel. This makes the DSI interface driver dependent
on the omap_dss_device struct.

Make the DSI driver data maintain it's own pixel format field. The panel driver
is expected to call omapdss_dsi_set_pixel_format() to configure the pixel format
before the interface is enabled.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/displays/panel-taal.c |    1 +
 drivers/video/omap2/dss/dsi.c             |   34 +++++++++++++++++++++--------
 include/video/omapdss.h                   |    2 ++
 3 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index c3bca2f..d220f19 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -1062,6 +1062,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
 
 	omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res,
 		dssdev->panel.timings.y_res);
+	omapdss_dsi_set_pixel_format(dssdev, dssdev->panel.dsi_pix_fmt);
 
 	r = omapdss_dsi_display_enable(dssdev);
 	if (r) {
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 6e1c74b..2497adb 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -334,6 +334,7 @@ struct dsi_data {
 
 	struct dss_lcd_mgr_config mgr_config;
 	struct omap_video_timings timings;
+	enum omap_dss_dsi_pixel_format pix_fmt;
 };
 
 struct dsi_packet_sent_handler_data {
@@ -3609,7 +3610,7 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)
 
 	if (dssdev->panel.dsi_mode = OMAP_DSS_DSI_VIDEO_MODE) {
 		struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-		int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+		int bpp = dsi_get_pixel_size(dsi->pix_fmt);
 		unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
 		struct omap_video_timings *timings = &dsi->timings;
 		/*
@@ -3741,7 +3742,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
 	int tclk_trail, ths_exit, exiths_clk;
 	bool ddr_alwon;
 	struct omap_video_timings *timings = &dsi->timings;
-	int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+	int bpp = dsi_get_pixel_size(dsi->pix_fmt);
 	int ndl = dsi->num_lanes_used - 1;
 	const struct omapdss_clock_config *clks;
 	int dsi_fclk_hsdiv;
@@ -3856,6 +3857,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
 static int dsi_proto_config(struct omap_dss_device *dssdev)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	u32 r;
 	int buswidth = 0;
 
@@ -3875,7 +3877,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
 	dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
 	dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
 
-	switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) {
+	switch (dsi_get_pixel_size(dsi->pix_fmt)) {
 	case 16:
 		buswidth = 0;
 		break;
@@ -3999,7 +4001,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
 		int window_sync = dssdev->panel.dsi_vm_data.window_sync;
 		bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
 		struct omap_video_timings *timings = &dsi->timings;
-		int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+		int bpp = dsi_get_pixel_size(dsi->pix_fmt);
 		int tl, t_he, width_bytes;
 
 		t_he = hsync_end ?
@@ -4108,13 +4110,13 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+	int bpp = dsi_get_pixel_size(dsi->pix_fmt);
 	u8 data_type;
 	u16 word_count;
 	int r;
 
 	if (dssdev->panel.dsi_mode = OMAP_DSS_DSI_VIDEO_MODE) {
-		switch (dssdev->panel.dsi_pix_fmt) {
+		switch (dsi->pix_fmt) {
 		case OMAP_DSS_DSI_FMT_RGB888:
 			data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
 			break;
@@ -4201,7 +4203,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
 
 	dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
 
-	bytespp	= dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+	bytespp	= dsi_get_pixel_size(dsi->pix_fmt) / 8;
 	bytespl = w * bytespp;
 	bytespf = bytespl * h;
 
@@ -4338,7 +4340,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
 
 #ifdef DEBUG
 	dsi->update_bytes = dw * dh *
-		dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+		dsi_get_pixel_size(dsi->pix_fmt) / 8;
 #endif
 	dsi_update_screen_dispc(dssdev);
 
@@ -4438,7 +4440,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 
 	dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 	dsi->mgr_config.video_port_width -			dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+			dsi_get_pixel_size(dsi->pix_fmt);
 	dsi->mgr_config.lcden_sig_polarity = 0;
 
 	dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config);
@@ -4714,6 +4716,20 @@ void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
 }
 EXPORT_SYMBOL(omapdss_dsi_set_size);
 
+void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
+		enum omap_dss_dsi_pixel_format fmt)
+{
+	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+	mutex_lock(&dsi->lock);
+
+	dsi->pix_fmt = fmt;
+
+	mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_pixel_format);
+
 static int __init dsi_init_display(struct omap_dss_device *dssdev)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index c5c013e..6e33c6f 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -739,6 +739,8 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
 void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings);
 void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h);
+void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
+		enum omap_dss_dsi_pixel_format fmt);
 
 int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
 		void (*callback)(int, void *), void *data);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 0/5] Pass data lines and pixel format info from panel driver to interface
From: Archit Taneja @ 2012-08-10 10:49 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja

This is a continuation of the work started in the series:

http://marc.info/?l=linux-omap&m\x134381744304672&w=2

This makes the panel driver call interface specific functions to configure the
data lines and pixel format requested by the panel.

Configuration of data lines doesn't happen for DSI or HDMI. For DSI, this
information is more complex and is taken care by omapdss_dsi_configure_pins(),
for HDMI, the number of TMDS lines is always fixed.

Configuration of pixel format is done only for DSI in command mode and RFBI.
Currently, these new functions take different arguments,
omapdss_dsi_set_pixel_format() takes pixel format of type
omap_dss_dsi_pixel_format enum, and RFBI omapdss_rfbi_set_pixel_size() takes
the pixel size directly. It would be good if these could be merged by using
some sort of MIPI standard for pixel formats. Having the same argument would
help in having a common interface op in the future.

Reference tree:

git://gitorious.org/~boddob/linux-omap-dss2/archit-dss2-clone.git pass_timings_and_others

Archit Taneja (5):
  OMAPDSS: DSI: Maintain copy of pixel format in driver data
  OMAPDSS: RFBI: Maintain copy of pixel size in driver data
  OMAPDSS: RFBI: Maintain copy of number of data lines in driver data
  OMAPDSS: DPI: Maitain copy of number of data lines in driver data
  OMAPDSS: SDI: Maintain copy of data pairs in driver data

 drivers/video/omap2/displays/panel-acx565akm.c     |    1 +
 drivers/video/omap2/displays/panel-generic-dpi.c   |    1 +
 .../omap2/displays/panel-lgphilips-lb035q02.c      |    1 +
 drivers/video/omap2/displays/panel-n8x0.c          |   13 ++++++--
 .../omap2/displays/panel-nec-nl8048hl11-01b.c      |    1 +
 drivers/video/omap2/displays/panel-picodlp.c       |    1 +
 .../video/omap2/displays/panel-sharp-ls037v7dw01.c |    1 +
 drivers/video/omap2/displays/panel-taal.c          |    1 +
 drivers/video/omap2/displays/panel-tfp410.c        |    1 +
 .../video/omap2/displays/panel-tpo-td043mtea1.c    |    1 +
 drivers/video/omap2/dss/dpi.c                      |   13 +++++++-
 drivers/video/omap2/dss/dsi.c                      |   34 ++++++++++++++------
 drivers/video/omap2/dss/dss.c                      |    2 +-
 drivers/video/omap2/dss/dss.h                      |    2 +-
 drivers/video/omap2/dss/rfbi.c                     |   28 ++++++++++++----
 drivers/video/omap2/dss/sdi.c                      |   10 +++++-
 include/video/omapdss.h                            |    9 +++++-
 17 files changed, 97 insertions(+), 23 deletions(-)

-- 
1.7.9.5


^ permalink raw reply

* Re: [PATCH 0/7] HID: picoLCD updates
From: Bruno Prémont @ 2012-08-09 18:09 UTC (permalink / raw)
  To: Tejun Heo; +Cc: linux-input, linux-kernel, Jiri Kosina, linux-fbdev
In-Reply-To: <20120730213656.0a9f6d30@neptune.home>

Hi Tejun,

As you are working on workqueues and related code, could you have a look
at my usage of them in combination with db_defio?

The delayed memory corruptions or system reboots after unbinding/unplugging
the PicoLCD seem very much related to workqueue used to handle the deferred
IO to framebuffer.

I think things don't get cleaned-up as they should though I'm not sure
where the trouble lies.

For ease of reading, I'm inlineing below the framebuffer related code of
PicoLCD (for complete driver after this patch series apply the whole series
on top of 3.5 https://lkml.org/lkml/2012/7/30/375 )

Thanks,
Bruno

On Mon, 30 July 2012 Bruno Prémont <bonbons@linux-vserver.org> wrote:
> This series updates picoLCD driver:
> - split the driver functions into separate files which get included
>   depending on Kconfig selection
>   (implementation for CIR using RC_CORE will follow later)
> - drop private framebuffer refcounting in favor of refcounting added
>   to fb_info some time ago
> - fix various bugs issues
> - disabled firmware version checking in probe() as it does not work
>   anymore since commit 4ea5454203d991ec85264f64f89ca8855fce69b0
>   [HID: Fix race condition between driver core and ll-driver]
> 
> Note: I still get weird behavior on quick unbind/bind sequences
> issued via sysfs (CONFIG_SMP=n system) that are triggered by framebuffer
> support and apparently more specifically fb_defio part of it.
> 
> Unfortunately I'm out of ideas as to how to track down the problem which
> shows either as SLAB corruption (detected with SLUB debugging, e.g.
> 
> [ 6383.521833] ======================================> [ 6383.530020] BUG kmalloc-64 (Not tainted): Object already free
> [ 6383.530020] -----------------------------------------------------------------------------
> [ 6383.530020] 
> [ 6383.530020] INFO: Slab 0xdde0ea20 objectsQ used@ fp=0xcef516e0 flags=0x40000080
> [ 6383.530020] INFO: Object 0xcef51190 @offset@0 fp=0xcef51f50
> [ 6383.530020] 
> [ 6383.530020] Bytes b4 cef51180: cc cc cc cc d0 12 f5 ce 5a 5a 5a 5a 5a 5a 5a 5a  ........ZZZZZZZZ
> [ 6383.530020] Object cef51190: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> [ 6383.530020] Object cef511a0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> [ 6383.530020] Object cef511b0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> [ 6383.530020] Object cef511c0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5  kkkkkkkkkkkkkkk.
> [ 6383.530020] Redzone cef511d0: bb bb bb bb                                      ....
> [ 6383.530020] Padding cef511d8: 5a 5a 5a 5a 5a 5a 5a 5a                          ZZZZZZZZ
> [ 6383.530020] Pid: 1922, comm: bash Not tainted 3.5.0-jupiter-00003-g8d858b1-dirty #2
> [ 6383.530020] Call Trace:
> [ 6383.530020]  [<c10bd3cc>] print_trailer+0x11c/0x130
> [ 6383.530020]  [<c10bd415>] object_err+0x35/0x40
> [ 6383.530020]  [<c10be809>] free_debug_processing+0x99/0x200
> [ 6383.530020]  [<c10bf77e>] __slab_free+0x2e/0x280
> [ 6383.530020]  [<c1322284>] ? hid_submit_out+0xa4/0x120
> [ 6383.530020]  [<c1322870>] ? __usbhid_submit_report+0xc0/0x3c0
> [ 6383.530020]  [<c10bfbda>] ? kfree+0xfa/0x110
> [ 6383.530020]  [<de932aa4>] ? picolcd_debug_out_report+0x8c4/0x8e0 [hid_picolcd]
> [ 6383.530020]  [<c10bfbda>] kfree+0xfa/0x110
> [ 6383.530020]  [<c1322284>] ? hid_submit_out+0xa4/0x120
> [ 6383.530020]  [<c1322284>] ? hid_submit_out+0xa4/0x120
> [ 6383.530020]  [<c1322284>] ? hid_submit_out+0xa4/0x120
> [ 6383.530020]  [<c1322284>] hid_submit_out+0xa4/0x120
> [ 6383.530020]  [<c1322908>] __usbhid_submit_report+0x158/0x3c0
> [ 6383.530020]  [<c1322c2b>] usbhid_submit_report+0x1b/0x30
> [ 6383.530020]  [<de930789>] picolcd_fb_reset+0xb9/0x180 [hid_picolcd]
> [ 6383.530020]  [<de930f1d>] picolcd_init_framebuffer+0x20d/0x2e0 [hid_picolcd]
> [ 6383.530020]  [<de92fb9c>] picolcd_probe+0x3cc/0x580 [hid_picolcd]
> [ 6383.530020]  [<c1319147>] hid_device_probe+0x67/0xf0
> [ 6383.530020]  [<c1282f97>] ? driver_sysfs_add+0x57/0x80
> [ 6383.530020]  [<c128329d>] driver_probe_device+0xbd/0x1c0
> [ 6383.530020]  [<c1318a1b>] ? hid_match_device+0x7b/0x90
> [ 6383.530020]  [<c12821e5>] driver_bind+0x75/0xd0
> [ 6383.530020]  [<c1282170>] ? driver_unbind+0x90/0x90
> [ 6383.530020]  [<c12818b7>] drv_attr_store+0x27/0x30
> [ 6383.530020]  [<c1114aec>] sysfs_write_file+0xac/0xf0
> [ 6383.530020]  [<c10c794c>] vfs_write+0x9c/0x130
> [ 6383.530020]  [<c10d4a1f>] ? sys_dup3+0x11f/0x160
> [ 6383.530020]  [<c1114a40>] ? sysfs_poll+0x90/0x90
> [ 6383.530020]  [<c10c7bbd>] sys_write+0x3d/0x70
> [ 6383.530020]  [<c13f2557>] sysenter_do_call+0x12/0x26
> [ 6383.530020] FIX kmalloc-64: Object at 0xcef51190 not freed
> 
> or worse spontaneous reboot of the system without any trace on netconsole or
> serial console.
> 
> echo $devid > bind; echo $devid > unbind
> or
> echo $devid > bind; echo $devid > unbind; sleep 0.2; echo $devid > bind; echo $devid > unbind
> 
> is sufficient to trigger the above issue while waiting a few seconds between bind and unbind
> shows no sign of trouble.
> 
> Suggestions as to how to debug this and fix it are welcome!

========= driver/hid/hid-picolcd_fb.c ===============
/***************************************************************************
 *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
 *                                                                         *
 *   Based on Logitech G13 driver (v0.4)                                   *
 *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
 *                                                                         *
 *   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, version 2 of the License.               *
 *                                                                         *
 *   This driver is distributed in the hope that it will be useful, but    *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 *   General Public License for more details.                              *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/

#include <linux/hid.h>
#include "usbhid/usbhid.h"
#include <linux/usb.h>

#include <linux/fb.h>
#include <linux/module.h>

#include "hid-picolcd.h"

/* Framebuffer
 *
 * The PicoLCD use a Topway LCD module of 256x64 pixel
 * This display area is tiled over 4 controllers with 8 tiles
 * each. Each tile has 8x64 pixel, each data byte representing
 * a 1-bit wide vertical line of the tile.
 *
 * The display can be updated at a tile granularity.
 *
 *       Chip 1           Chip 2           Chip 3           Chip 4
 * +----------------+----------------+----------------+----------------+
 * |     Tile 1     |     Tile 1     |     Tile 1     |     Tile 1     |
 * +----------------+----------------+----------------+----------------+
 * |     Tile 2     |     Tile 2     |     Tile 2     |     Tile 2     |
 * +----------------+----------------+----------------+----------------+
 *                                  ...
 * +----------------+----------------+----------------+----------------+
 * |     Tile 8     |     Tile 8     |     Tile 8     |     Tile 8     |
 * +----------------+----------------+----------------+----------------+
 */
#define PICOLCDFB_NAME "picolcdfb"
#define PICOLCDFB_WIDTH (256)
#define PICOLCDFB_HEIGHT (64)
#define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)

#define PICOLCDFB_UPDATE_RATE_LIMIT   10
#define PICOLCDFB_UPDATE_RATE_DEFAULT  2

/* Framebuffer visual structures */
static const struct fb_fix_screeninfo picolcdfb_fix = {
	.id          = PICOLCDFB_NAME,
	.type        = FB_TYPE_PACKED_PIXELS,
	.visual      = FB_VISUAL_MONO01,
	.xpanstep    = 0,
	.ypanstep    = 0,
	.ywrapstep   = 0,
	.line_length = PICOLCDFB_WIDTH / 8,
	.accel       = FB_ACCEL_NONE,
};

static const struct fb_var_screeninfo picolcdfb_var = {
	.xres           = PICOLCDFB_WIDTH,
	.yres           = PICOLCDFB_HEIGHT,
	.xres_virtual   = PICOLCDFB_WIDTH,
	.yres_virtual   = PICOLCDFB_HEIGHT,
	.width          = 103,
	.height         = 26,
	.bits_per_pixel = 1,
	.grayscale      = 1,
	.red            = {
		.offset = 0,
		.length = 1,
		.msb_right = 0,
	},
	.green          = {
		.offset = 0,
		.length = 1,
		.msb_right = 0,
	},
	.blue           = {
		.offset = 0,
		.length = 1,
		.msb_right = 0,
	},
	.transp         = {
		.offset = 0,
		.length = 0,
		.msb_right = 0,
	},
};

/* Send a given tile to PicoLCD */
static int picolcd_fb_send_tile(struct hid_device *hdev, int chip, int tile)
{
	struct picolcd_data *data = hid_get_drvdata(hdev);
	struct hid_report *report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, hdev);
	struct hid_report *report2 = picolcd_out_report(REPORT_LCD_DATA, hdev);
	unsigned long flags;
	u8 *tdata;
	int i;

	if (!report1 || report1->maxfield != 1 || !report2 || report2->maxfield != 1)
		return -ENODEV;

	spin_lock_irqsave(&data->lock, flags);
	hid_set_field(report1->field[0],  0, chip << 2);
	hid_set_field(report1->field[0],  1, 0x02);
	hid_set_field(report1->field[0],  2, 0x00);
	hid_set_field(report1->field[0],  3, 0x00);
	hid_set_field(report1->field[0],  4, 0xb8 | tile);
	hid_set_field(report1->field[0],  5, 0x00);
	hid_set_field(report1->field[0],  6, 0x00);
	hid_set_field(report1->field[0],  7, 0x40);
	hid_set_field(report1->field[0],  8, 0x00);
	hid_set_field(report1->field[0],  9, 0x00);
	hid_set_field(report1->field[0], 10,   32);

	hid_set_field(report2->field[0],  0, (chip << 2) | 0x01);
	hid_set_field(report2->field[0],  1, 0x00);
	hid_set_field(report2->field[0],  2, 0x00);
	hid_set_field(report2->field[0],  3,   32);

	tdata = data->fb_vbitmap + (tile * 4 + chip) * 64;
	for (i = 0; i < 64; i++)
		if (i < 32)
			hid_set_field(report1->field[0], 11 + i, tdata[i]);
		else
			hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);

	usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
	usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
	spin_unlock_irqrestore(&data->lock, flags);
	return 0;
}

/* Translate a single tile*/
static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
		int chip, int tile)
{
	int i, b, changed = 0;
	u8 tdata[64];
	u8 *vdata = vbitmap + (tile * 4 + chip) * 64;

	if (bpp = 1) {
		for (b = 7; b >= 0; b--) {
			const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
			for (i = 0; i < 64; i++) {
				tdata[i] <<= 1;
				tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
			}
		}
	} else if (bpp = 8) {
		for (b = 7; b >= 0; b--) {
			const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8;
			for (i = 0; i < 64; i++) {
				tdata[i] <<= 1;
				tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00;
			}
		}
	} else {
		/* Oops, we should never get here! */
		WARN_ON(1);
		return 0;
	}

	for (i = 0; i < 64; i++)
		if (tdata[i] != vdata[i]) {
			changed = 1;
			vdata[i] = tdata[i];
		}
	return changed;
}

void picolcd_fb_refresh(struct picolcd_data *data)
{
	if (data->fb_info)
		schedule_delayed_work(&data->fb_info->deferred_work, 0);
}

/* Reconfigure LCD display */
int picolcd_fb_reset(struct picolcd_data *data, int clear)
{
	struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev);
	int i, j;
	unsigned long flags;
	static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };

	if (!report || report->maxfield != 1)
		return -ENODEV;

	spin_lock_irqsave(&data->lock, flags);
	for (i = 0; i < 4; i++) {
		for (j = 0; j < report->field[0]->maxusage; j++)
			if (j = 0)
				hid_set_field(report->field[0], j, i << 2);
			else if (j < sizeof(mapcmd))
				hid_set_field(report->field[0], j, mapcmd[j]);
			else
				hid_set_field(report->field[0], j, 0);
		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
	}

	data->status |= PICOLCD_READY_FB;
	spin_unlock_irqrestore(&data->lock, flags);

	if (data->fb_bitmap) {
		if (clear) {
			memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
			memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
		}
		data->fb_force = 1;
	}

	/* schedule first output of framebuffer */
	picolcd_fb_refresh(data);

	return 0;
}

/* Update fb_vbitmap from the screen_base and send changed tiles to device */
static void picolcd_fb_update(struct fb_info *info)
{
	int chip, tile, n;
	unsigned long flags;
	struct picolcd_data *data;

	mutex_lock(&info->lock);
	data = info->par;
	if (!data)
		goto out;

	spin_lock_irqsave(&data->lock, flags);
	if (!(data->status & PICOLCD_READY_FB)) {
		spin_unlock_irqrestore(&data->lock, flags);
		picolcd_fb_reset(data, 0);
	} else {
		spin_unlock_irqrestore(&data->lock, flags);
	}

	/*
	 * Translate the framebuffer into the format needed by the PicoLCD.
	 * See display layout above.
	 * Do this one tile after the other and push those tiles that changed.
	 *
	 * Wait for our IO to complete as otherwise we might flood the queue!
	 */
	n = 0;
	for (chip = 0; chip < 4; chip++)
		for (tile = 0; tile < 8; tile++)
			if (picolcd_fb_update_tile(data->fb_vbitmap,
					data->fb_bitmap, data->fb_bpp, chip, tile) ||
				data->fb_force) {
				n += 2;
				if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
					mutex_unlock(&info->lock);
					usbhid_wait_io(data->hdev);
					mutex_lock(&info->lock);
					data = info->par;
					if (!data)
						goto out;
					spin_lock_irqsave(&data->lock, flags);
					if (data->status & PICOLCD_FAILED) {
						spin_unlock_irqrestore(&data->lock, flags);
						goto out;
					}
					spin_unlock_irqrestore(&data->lock, flags);
					n = 0;
				}
				picolcd_fb_send_tile(data->hdev, chip, tile);
			}
	data->fb_force = false;
	if (n) {
		mutex_unlock(&info->lock);
		usbhid_wait_io(data->hdev);
		return;
	}
out:
	mutex_unlock(&info->lock);
}

/* Stub to call the system default and update the image on the picoLCD */
static void picolcd_fb_fillrect(struct fb_info *info,
		const struct fb_fillrect *rect)
{
	if (!info->par)
		return;
	sys_fillrect(info, rect);

	schedule_delayed_work(&info->deferred_work, 0);
}

/* Stub to call the system default and update the image on the picoLCD */
static void picolcd_fb_copyarea(struct fb_info *info,
		const struct fb_copyarea *area)
{
	if (!info->par)
		return;
	sys_copyarea(info, area);

	schedule_delayed_work(&info->deferred_work, 0);
}

/* Stub to call the system default and update the image on the picoLCD */
static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image)
{
	if (!info->par)
		return;
	sys_imageblit(info, image);

	schedule_delayed_work(&info->deferred_work, 0);
}

/*
 * this is the slow path from userspace. they can seek and write to
 * the fb. it's inefficient to do anything less than a full screen draw
 */
static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf,
		size_t count, loff_t *ppos)
{
	ssize_t ret;
	if (!info->par)
		return -ENODEV;
	ret = fb_sys_write(info, buf, count, ppos);
	if (ret >= 0)
		schedule_delayed_work(&info->deferred_work, 0);
	return ret;
}

static int picolcd_fb_blank(int blank, struct fb_info *info)
{
	if (!info->par)
		return -ENODEV;
	/* We let fb notification do this for us via lcd/backlight device */
	return 0;
}

static void picolcd_fb_destroy(struct fb_info *info)
{
	/* make sure no work is deferred */
	fb_deferred_io_cleanup(info);

	vfree((u8 *)info->fix.smem_start);
	framebuffer_release(info);
	printk(KERN_DEBUG "picolcd_fb_destroy(%p)\n", info);
}

static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
	__u32 bpp      = var->bits_per_pixel;
	__u32 activate = var->activate;

	/* only allow 1/8 bit depth (8-bit is grayscale) */
	*var = picolcdfb_var;
	var->activate = activate;
	if (bpp >= 8) {
		var->bits_per_pixel = 8;
		var->red.length     = 8;
		var->green.length   = 8;
		var->blue.length    = 8;
	} else {
		var->bits_per_pixel = 1;
		var->red.length     = 1;
		var->green.length   = 1;
		var->blue.length    = 1;
	}
	return 0;
}

static int picolcd_set_par(struct fb_info *info)
{
	struct picolcd_data *data = info->par;
	u8 *tmp_fb, *o_fb;
	if (!data)
		return -ENODEV;
	if (info->var.bits_per_pixel = data->fb_bpp)
		return 0;
	/* switch between 1/8 bit depths */
	if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
		return -EINVAL;

	o_fb   = data->fb_bitmap;
	tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
	if (!tmp_fb)
		return -ENOMEM;

	/* translate FB content to new bits-per-pixel */
	if (info->var.bits_per_pixel = 1) {
		int i, b;
		for (i = 0; i < PICOLCDFB_SIZE; i++) {
			u8 p = 0;
			for (b = 0; b < 8; b++) {
				p <<= 1;
				p |= o_fb[i*8+b] ? 0x01 : 0x00;
			}
			tmp_fb[i] = p;
		}
		memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
		info->fix.visual = FB_VISUAL_MONO01;
		info->fix.line_length = PICOLCDFB_WIDTH / 8;
	} else {
		int i;
		memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
		for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
			o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
		info->fix.line_length = PICOLCDFB_WIDTH;
	}

	kfree(tmp_fb);
	data->fb_bpp      = info->var.bits_per_pixel;
	return 0;
}

/* Note this can't be const because of struct fb_info definition */
static struct fb_ops picolcdfb_ops = {
	.owner        = THIS_MODULE,
	.fb_destroy   = picolcd_fb_destroy,
	.fb_read      = fb_sys_read,
	.fb_write     = picolcd_fb_write,
	.fb_blank     = picolcd_fb_blank,
	.fb_fillrect  = picolcd_fb_fillrect,
	.fb_copyarea  = picolcd_fb_copyarea,
	.fb_imageblit = picolcd_fb_imageblit,
	.fb_check_var = picolcd_fb_check_var,
	.fb_set_par   = picolcd_set_par,
};


/* Callback from deferred IO workqueue */
static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist)
{
	picolcd_fb_update(info);
}

static const struct fb_deferred_io picolcd_fb_defio = {
	.delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT,
	.deferred_io = picolcd_fb_deferred_io,
};


/*
 * The "fb_update_rate" sysfs attribute
 */
static ssize_t picolcd_fb_update_rate_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct picolcd_data *data = dev_get_drvdata(dev);
	unsigned i, fb_update_rate = data->fb_update_rate;
	size_t ret = 0;

	for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++)
		if (ret >= PAGE_SIZE)
			break;
		else if (i = fb_update_rate)
			ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
		else
			ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
	if (ret > 0)
		buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n';
	return ret;
}

static ssize_t picolcd_fb_update_rate_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct picolcd_data *data = dev_get_drvdata(dev);
	int i;
	unsigned u;

	if (count < 1 || count > 10)
		return -EINVAL;

	i = sscanf(buf, "%u", &u);
	if (i != 1)
		return -EINVAL;

	if (u > PICOLCDFB_UPDATE_RATE_LIMIT)
		return -ERANGE;
	else if (u = 0)
		u = PICOLCDFB_UPDATE_RATE_DEFAULT;

	data->fb_update_rate = u;
	data->fb_info->fbdefio->delay = HZ / data->fb_update_rate;
	return count;
}

static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show,
		picolcd_fb_update_rate_store);

/* initialize Framebuffer device */
int picolcd_init_framebuffer(struct picolcd_data *data)
{
	struct device *dev = &data->hdev->dev;
	struct fb_info *info = NULL;
	int i, error = -ENOMEM;
	u8 *fb_vbitmap = NULL;
	u8 *fb_bitmap  = NULL;
	u32 *palette;

	fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
	if (fb_bitmap = NULL) {
		dev_err(dev, "can't get a free page for framebuffer\n");
		goto err_nomem;
	}

	fb_vbitmap = kmalloc(PICOLCDFB_SIZE, GFP_KERNEL);
	if (fb_vbitmap = NULL) {
		dev_err(dev, "can't alloc vbitmap image buffer\n");
		goto err_nomem;
	}

	data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
	/* The extra memory is:
	 * - 256*u32 for pseudo_palette
	 * - struct fb_deferred_io
	 */
	info = framebuffer_alloc(256 * sizeof(u32) +
			sizeof(struct fb_deferred_io), dev);
	if (info = NULL) {
		dev_err(dev, "failed to allocate a framebuffer\n");
		goto err_nomem;
	}

	info->fbdefio = info->par;
	*info->fbdefio = picolcd_fb_defio;
	palette  = info->par + sizeof(struct fb_deferred_io);
	for (i = 0; i < 256; i++)
		palette[i] = i > 0 && i < 16 ? 0xff : 0;
	info->pseudo_palette = palette;
	info->screen_base = (char __force __iomem *)fb_bitmap;
	info->fbops = &picolcdfb_ops;
	info->var = picolcdfb_var;
	info->fix = picolcdfb_fix;
	info->fix.smem_len   = PICOLCDFB_SIZE*8;
	info->fix.smem_start = (unsigned long)fb_bitmap;
	info->par = data;
	info->flags = FBINFO_FLAG_DEFAULT;

	data->fb_vbitmap = fb_vbitmap;
	data->fb_bitmap  = fb_bitmap;
	data->fb_bpp     = picolcdfb_var.bits_per_pixel;
	error = picolcd_fb_reset(data, 1);
	if (error) {
		dev_err(dev, "failed to configure display\n");
		goto err_cleanup;
	}
	error = device_create_file(dev, &dev_attr_fb_update_rate);
	if (error) {
		dev_err(dev, "failed to create sysfs attributes\n");
		goto err_cleanup;
	}
	fb_deferred_io_init(info);
	data->fb_info    = info;
	error = register_framebuffer(info);
	if (error) {
		dev_err(dev, "failed to register framebuffer\n");
		goto err_sysfs;
	}
	/* schedule first output of framebuffer */
	data->fb_force = 1;
	schedule_delayed_work(&info->deferred_work, 0);
	return 0;

err_sysfs:
	fb_deferred_io_cleanup(info);
	device_remove_file(dev, &dev_attr_fb_update_rate);
err_cleanup:
	data->fb_vbitmap = NULL;
	data->fb_bitmap  = NULL;
	data->fb_bpp     = 0;
	data->fb_info    = NULL;

err_nomem:
	framebuffer_release(info);
	vfree(fb_bitmap);
	kfree(fb_vbitmap);
	return error;
}

void picolcd_exit_framebuffer(struct picolcd_data *data)
{
	struct fb_info *info = data->fb_info;
	u8 *fb_vbitmap = data->fb_vbitmap;

	if (!info)
		return;

	device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
	info->par = NULL;
	unregister_framebuffer(info);
	data->fb_vbitmap = NULL;
	data->fb_bitmap  = NULL;
	data->fb_bpp     = 0;
	data->fb_info    = NULL;
	kfree(fb_vbitmap);
}

^ permalink raw reply

* Re: [PATCH 4/5] drivers/video/msm/mddi_client_dummy.c: use devm_ functions
From: David Brown @ 2012-08-09 17:57 UTC (permalink / raw)
  To: Damien Cassou
  Cc: kernel-janitors, Daniel Walker, Bryan Huntsman,
	Florian Tobias Schandinat, linux-arm-msm, linux-fbdev,
	linux-kernel
In-Reply-To: <1344008414-2894-6-git-send-email-damien.cassou@lifl.fr>

On Fri, Aug 03, 2012 at 05:40:14PM +0200, Damien Cassou wrote:
> From: Damien Cassou <damien.cassou@lifl.fr>
> 
> The various devm_ functions allocate memory that is released when a driver
> detaches. This patch replaces the use of kzalloc by devm_kzalloc.
> 
> Signed-off-by: Damien Cassou <damien.cassou@lifl.fr>
> 
> ---
>  drivers/video/msm/mddi_client_dummy.c |   12 ++----------
>  1 file changed, 2 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/video/msm/mddi_client_dummy.c b/drivers/video/msm/mddi_client_dummy.c
> index d2a091c..4c31325 100644
> --- a/drivers/video/msm/mddi_client_dummy.c
> +++ b/drivers/video/msm/mddi_client_dummy.c
> @@ -51,7 +51,7 @@ static int mddi_dummy_probe(struct platform_device *pdev)
>  {
>  	struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
>  	struct panel_info *panel > -		kzalloc(sizeof(struct panel_info), GFP_KERNEL);
> +		devm_kzalloc(&pdev->dev, sizeof(struct panel_info), GFP_KERNEL);
>  	int ret;
>  	if (!panel)
>  		return -ENOMEM;
> @@ -67,18 +67,11 @@ static int mddi_dummy_probe(struct platform_device *pdev)
>  				      client_data->fb_resource, 1);
>  	panel->panel_data.fb_data = client_data->private_client_data;
>  	panel->pdev.dev.platform_data = &panel->panel_data;
> -	ret = platform_device_register(&panel->pdev);
> -	if (ret) {
> -		kfree(panel);
> -		return ret;
> -	}
> -	return 0;
> +	return platform_device_register(&panel->pdev);

Removing this block causes a warning:
kernel/drivers/video/msm/mddi_client_dummy.c: In function 'mddi_dummy_probe':
kernel/drivers/video/msm/mddi_client_dummy.c:55:6: warning: unused variable 'ret' [-Wunused-variable]

Please remove the 'int ret;' line above as well.

Thanks,
David Brown

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* Re: [PATCH 4/5] drivers/video/msm/mddi_client_dummy.c: use devm_ functions
From: David Brown @ 2012-08-09 17:39 UTC (permalink / raw)
  To: Damien Cassou
  Cc: kernel-janitors, Daniel Walker, Bryan Huntsman,
	Florian Tobias Schandinat, linux-arm-msm, linux-fbdev,
	linux-kernel
In-Reply-To: <1344008414-2894-6-git-send-email-damien.cassou@lifl.fr>

On Fri, Aug 03, 2012 at 05:40:14PM +0200, Damien Cassou wrote:
> From: Damien Cassou <damien.cassou@lifl.fr>
> 
> The various devm_ functions allocate memory that is released when a driver
> detaches. This patch replaces the use of kzalloc by devm_kzalloc.
> 
> Signed-off-by: Damien Cassou <damien.cassou@lifl.fr>
> 
> ---
>  drivers/video/msm/mddi_client_dummy.c |   12 ++----------
>  1 file changed, 2 insertions(+), 10 deletions(-)

Acked-by: David Brown <davidb@codeaurora.org>

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* Re: [PATCH 5/5] drivers/video/msm/mddi_client_nt35399.c: use devm_ functions
From: David Brown @ 2012-08-09 17:38 UTC (permalink / raw)
  To: Damien Cassou
  Cc: kernel-janitors, Daniel Walker, Bryan Huntsman,
	Florian Tobias Schandinat, linux-arm-msm, linux-fbdev,
	linux-kernel
In-Reply-To: <1344008414-2894-5-git-send-email-damien.cassou@lifl.fr>

On Fri, Aug 03, 2012 at 05:40:13PM +0200, Damien Cassou wrote:
> From: Damien Cassou <damien.cassou@lifl.fr>
> 
> The various devm_ functions allocate memory that is released when a driver
> detaches. This patch replaces the use of kzalloc by devm_kzalloc.
> 
> Additionally, this patch fixes a memory leak: some memory was allocated for
> 'panel' but not released when the subsequent call to setup_vsync fails.
> 
> Signed-off-by: Damien Cassou <damien.cassou@lifl.fr>

Acked-by: David Brown <davidb@codeaurora.org>

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* [PATCH v2 13/13] OMAPDSS: VENC: Add a get_timing function for VENC interface
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

Add function omapdss_venc_get_timing() which returns the timings
maintained by the VENC interface driver in it's driver data. This is just used
once by the driver during it's probe. This prevents the need for the panel
driver to configure default timings in it's probe.

Int the VENC interface's probe, the timings field is set to PAL as a default
value. The get_timing op makes more sense for interfaces which can be configured
to a default timing.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/dss.h        |    2 ++
 drivers/video/omap2/dss/venc.c       |   13 +++++++++++++
 drivers/video/omap2/dss/venc_panel.c |   11 +++++------
 3 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 69b6ab9..3fe76c0 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -474,6 +474,8 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev);
 void omapdss_venc_display_disable(struct omap_dss_device *dssdev);
 void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings);
+void omapdss_venc_get_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings);
 int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings);
 u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev);
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index d96025e..42f97ac 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -579,6 +579,18 @@ void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
 	mutex_unlock(&venc.venc_lock);
 }
 
+void omapdss_venc_get_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	DSSDBG("venc_set_timings\n");
+
+	mutex_lock(&venc.venc_lock);
+
+	*timings = venc.timings;
+
+	mutex_unlock(&venc.venc_lock);
+}
+
 int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
@@ -768,6 +780,7 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
 	mutex_init(&venc.venc_lock);
 
 	venc.wss_data = 0;
+	venc.timings = omap_dss_pal_timings;
 
 	venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
 	if (!venc_mem) {
diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c
index 350b0d9..fe9958d 100644
--- a/drivers/video/omap2/dss/venc_panel.c
+++ b/drivers/video/omap2/dss/venc_panel.c
@@ -84,14 +84,13 @@ static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
 
 static int venc_panel_probe(struct omap_dss_device *dssdev)
 {
+	struct omap_video_timings timings;
+
 	mutex_init(&venc_panel.lock);
 
-	/* set initial timings to PAL */
-	dssdev->panel.timings = (struct omap_video_timings)
-		{ 720, 574, 13500, 64, 12, 68, 5, 5, 41,
-			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
-			true,
-		};
+	omapdss_venc_get_timings(dssdev, &timings);
+
+	dssdev->panel.timings = timings;
 
 	return device_create_file(&dssdev->dev, &dev_attr_output_type);
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 12/13] OMAPDSS: VENC: Maintain our own timings field in driver data
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

The VENC driver currently relies on the timings in omap_dss_device struct to
configure the DISPC and VENC blocks accordingly. This makes the VENC interface
driver dependent on the omap_dss_device struct.

Make the VENC driver data maintain it's own timings field. The panel driver is
expected to call omapdss_venc_set_timings() to set these timings before the
panel is enabled.

Make the VENC panel driver configure the new timings is the omap_dss_device
struct(dssdev->panel.timings). The VENC driver is responsible for maintaining
only it's own copy of timings.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/venc.c       |   12 +++++++-----
 drivers/video/omap2/dss/venc_panel.c |    1 +
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index ffca542..d96025e 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -300,6 +300,8 @@ static struct {
 	struct regulator *vdda_dac_reg;
 
 	struct clk	*tv_dac_clk;
+
+	struct omap_video_timings timings;
 } venc;
 
 static inline void venc_write_reg(int idx, u32 val)
@@ -432,7 +434,7 @@ static int venc_power_on(struct omap_dss_device *dssdev)
 		goto err0;
 
 	venc_reset();
-	venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
+	venc_write_config(venc_timings_to_config(&venc.timings));
 
 	dss_set_venc_output(dssdev->phy.venc.type);
 	dss_set_dac_pwrdn_bgz(1);
@@ -449,7 +451,7 @@ static int venc_power_on(struct omap_dss_device *dssdev)
 
 	venc_write_reg(VENC_OUTPUT_CONTROL, l);
 
-	dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
+	dss_mgr_set_timings(dssdev->manager, &venc.timings);
 
 	r = regulator_enable(venc.vdda_dac_reg);
 	if (r)
@@ -556,10 +558,10 @@ void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
 	mutex_lock(&venc.venc_lock);
 
 	/* Reset WSS data when the TV standard changes. */
-	if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
+	if (memcmp(&venc.timings, timings, sizeof(*timings)))
 		venc.wss_data = 0;
 
-	dssdev->panel.timings = *timings;
+	venc.timings = *timings;
 
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
 		int r;
@@ -606,7 +608,7 @@ int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
 
 	mutex_lock(&venc.venc_lock);
 
-	config = venc_timings_to_config(&dssdev->panel.timings);
+	config = venc_timings_to_config(&venc.timings);
 
 	/* Invert due to VENC_L21_WC_CTL:INV=1 */
 	venc.wss_data = (wss ^ 0xfffff) << 8;
diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c
index 6b31298..350b0d9 100644
--- a/drivers/video/omap2/dss/venc_panel.c
+++ b/drivers/video/omap2/dss/venc_panel.c
@@ -170,6 +170,7 @@ static void venc_panel_set_timings(struct omap_dss_device *dssdev,
 	mutex_lock(&venc_panel.lock);
 
 	omapdss_venc_set_timings(dssdev, timings);
+	dssdev->panel.timings = *timings;
 
 	mutex_unlock(&venc_panel.lock);
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 11/13] OMAPDSS: VENC: Split VENC into interface and panel driver
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

The current venc.c driver contains both the interface and panel driver code.
This makes the driver hard to read, and difficult to understand the work split
between the interface and panel driver and the how the locking works.

This also makes it easier to clearly define the VENC interface ops called by the
panel driver.

Split venc.c into venc.c and venc_panel.c representing the interface and panel
driver respectively. This split is done along the lines of the HDMI interface
and panel drivers.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/Makefile     |    2 +-
 drivers/video/omap2/dss/dss.h        |   10 ++
 drivers/video/omap2/dss/venc.c       |  208 ++++++++----------------------
 drivers/video/omap2/dss/venc_panel.c |  231 ++++++++++++++++++++++++++++++++++
 4 files changed, 295 insertions(+), 156 deletions(-)
 create mode 100644 drivers/video/omap2/dss/venc_panel.c

diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index 5c450b0..30a48fb 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -3,7 +3,7 @@ omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
 	manager.o overlay.o apply.o
 omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
 omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
-omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
+omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o
 omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
 omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
 omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index df49c5d..69b6ab9 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -470,6 +470,16 @@ static inline unsigned long venc_get_pixel_clock(void)
 	return 0;
 }
 #endif
+int omapdss_venc_display_enable(struct omap_dss_device *dssdev);
+void omapdss_venc_display_disable(struct omap_dss_device *dssdev);
+void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings);
+int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings);
+u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev);
+int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss);
+int venc_panel_init(void);
+void venc_panel_exit(void);
 
 /* HDMI */
 #ifdef CONFIG_OMAP4_DSS_HDMI
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 3a22087..ffca542 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -427,6 +427,10 @@ static int venc_power_on(struct omap_dss_device *dssdev)
 	u32 l;
 	int r;
 
+	r = venc_runtime_get();
+	if (r)
+		goto err0;
+
 	venc_reset();
 	venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
 
@@ -449,26 +453,22 @@ static int venc_power_on(struct omap_dss_device *dssdev)
 
 	r = regulator_enable(venc.vdda_dac_reg);
 	if (r)
-		goto err;
-
-	if (dssdev->platform_enable)
-		dssdev->platform_enable(dssdev);
+		goto err1;
 
 	r = dss_mgr_enable(dssdev->manager);
 	if (r)
-		goto err;
+		goto err2;
 
 	return 0;
 
-err:
+err2:
+	regulator_disable(venc.vdda_dac_reg);
+err1:
 	venc_write_reg(VENC_OUTPUT_CONTROL, 0);
 	dss_set_dac_pwrdn_bgz(0);
 
-	if (dssdev->platform_disable)
-		dssdev->platform_disable(dssdev);
-
-	regulator_disable(venc.vdda_dac_reg);
-
+	venc_runtime_put();
+err0:
 	return r;
 }
 
@@ -479,10 +479,9 @@ static void venc_power_off(struct omap_dss_device *dssdev)
 
 	dss_mgr_disable(dssdev->manager);
 
-	if (dssdev->platform_disable)
-		dssdev->platform_disable(dssdev);
-
 	regulator_disable(venc.vdda_dac_reg);
+
+	venc_runtime_put();
 }
 
 unsigned long venc_get_pixel_clock(void)
@@ -491,171 +490,95 @@ unsigned long venc_get_pixel_clock(void)
 	return 13500000;
 }
 
-static ssize_t display_output_type_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
+int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
 {
-	struct omap_dss_device *dssdev = to_dss_device(dev);
-	const char *ret;
-
-	switch (dssdev->phy.venc.type) {
-	case OMAP_DSS_VENC_TYPE_COMPOSITE:
-		ret = "composite";
-		break;
-	case OMAP_DSS_VENC_TYPE_SVIDEO:
-		ret = "svideo";
-		break;
-	default:
-		return -EINVAL;
-	}
+	int r;
 
-	return snprintf(buf, PAGE_SIZE, "%s\n", ret);
-}
-
-static ssize_t display_output_type_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t size)
-{
-	struct omap_dss_device *dssdev = to_dss_device(dev);
-	enum omap_dss_venc_type new_type;
-
-	if (sysfs_streq("composite", buf))
-		new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
-	else if (sysfs_streq("svideo", buf))
-		new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
-	else
-		return -EINVAL;
+	DSSDBG("venc_display_enable\n");
 
 	mutex_lock(&venc.venc_lock);
 
-	if (dssdev->phy.venc.type != new_type) {
-		dssdev->phy.venc.type = new_type;
-		if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
-			venc_power_off(dssdev);
-			venc_power_on(dssdev);
-		}
+	if (dssdev->manager = NULL) {
+		DSSERR("Failed to enable display: no manager\n");
+		r = -ENODEV;
+		goto err0;
 	}
 
-	mutex_unlock(&venc.venc_lock);
-
-	return size;
-}
-
-static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
-		display_output_type_show, display_output_type_store);
-
-/* driver */
-static int venc_panel_probe(struct omap_dss_device *dssdev)
-{
-	dssdev->panel.timings = omap_dss_pal_timings;
-
-	return device_create_file(&dssdev->dev, &dev_attr_output_type);
-}
-
-static void venc_panel_remove(struct omap_dss_device *dssdev)
-{
-	device_remove_file(&dssdev->dev, &dev_attr_output_type);
-}
-
-static int venc_panel_enable(struct omap_dss_device *dssdev)
-{
-	int r = 0;
-
-	DSSDBG("venc_enable_display\n");
-
-	mutex_lock(&venc.venc_lock);
-
 	r = omap_dss_start_device(dssdev);
 	if (r) {
 		DSSERR("failed to start device\n");
 		goto err0;
 	}
 
-	if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
-		r = -EINVAL;
-		goto err1;
-	}
+	if (dssdev->platform_enable)
+		dssdev->platform_enable(dssdev);
 
-	r = venc_runtime_get();
-	if (r)
-		goto err1;
 
 	r = venc_power_on(dssdev);
 	if (r)
-		goto err2;
+		goto err1;
 
 	venc.wss_data = 0;
 
-	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
 	mutex_unlock(&venc.venc_lock);
+
 	return 0;
-err2:
-	venc_runtime_put();
 err1:
+	if (dssdev->platform_disable)
+		dssdev->platform_disable(dssdev);
 	omap_dss_stop_device(dssdev);
 err0:
 	mutex_unlock(&venc.venc_lock);
-
 	return r;
 }
 
-static void venc_panel_disable(struct omap_dss_device *dssdev)
+void omapdss_venc_display_disable(struct omap_dss_device *dssdev)
 {
-	DSSDBG("venc_disable_display\n");
+	DSSDBG("venc_display_disable\n");
 
 	mutex_lock(&venc.venc_lock);
 
-	if (dssdev->state = OMAP_DSS_DISPLAY_DISABLED)
-		goto end;
-
-	if (dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED) {
-		/* suspended is the same as disabled with venc */
-		dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-		goto end;
-	}
-
 	venc_power_off(dssdev);
 
-	venc_runtime_put();
-
-	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
 	omap_dss_stop_device(dssdev);
-end:
-	mutex_unlock(&venc.venc_lock);
-}
 
-static int venc_panel_suspend(struct omap_dss_device *dssdev)
-{
-	venc_panel_disable(dssdev);
-	return 0;
-}
+	if (dssdev->platform_disable)
+		dssdev->platform_disable(dssdev);
 
-static int venc_panel_resume(struct omap_dss_device *dssdev)
-{
-	return venc_panel_enable(dssdev);
+	mutex_unlock(&venc.venc_lock);
 }
 
-static void venc_set_timings(struct omap_dss_device *dssdev,
-			struct omap_video_timings *timings)
+void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
 {
 	DSSDBG("venc_set_timings\n");
 
+	mutex_lock(&venc.venc_lock);
+
 	/* Reset WSS data when the TV standard changes. */
 	if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
 		venc.wss_data = 0;
 
 	dssdev->panel.timings = *timings;
+
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
+		int r;
+
 		/* turn the venc off and on to get new timings to use */
-		venc_panel_disable(dssdev);
-		venc_panel_enable(dssdev);
+		venc_power_off(dssdev);
+
+		r = venc_power_on(dssdev);
+		if (r)
+			DSSERR("failed to power on VENC\n");
 	} else {
 		dss_mgr_set_timings(dssdev->manager, timings);
 	}
+
+	mutex_unlock(&venc.venc_lock);
 }
 
-static int venc_check_timings(struct omap_dss_device *dssdev,
-			struct omap_video_timings *timings)
+int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
 {
 	DSSDBG("venc_check_timings\n");
 
@@ -668,13 +591,13 @@ static int venc_check_timings(struct omap_dss_device *dssdev,
 	return -EINVAL;
 }
 
-static u32 venc_get_wss(struct omap_dss_device *dssdev)
+u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev)
 {
 	/* Invert due to VENC_L21_WC_CTL:INV=1 */
 	return (venc.wss_data >> 8) ^ 0xfffff;
 }
 
-static int venc_set_wss(struct omap_dss_device *dssdev,	u32 wss)
+int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
 {
 	const struct venc_config *config;
 	int r;
@@ -703,31 +626,6 @@ err:
 	return r;
 }
 
-static struct omap_dss_driver venc_driver = {
-	.probe		= venc_panel_probe,
-	.remove		= venc_panel_remove,
-
-	.enable		= venc_panel_enable,
-	.disable	= venc_panel_disable,
-	.suspend	= venc_panel_suspend,
-	.resume		= venc_panel_resume,
-
-	.get_resolution	= omapdss_default_get_resolution,
-	.get_recommended_bpp = omapdss_default_get_recommended_bpp,
-
-	.set_timings	= venc_set_timings,
-	.check_timings	= venc_check_timings,
-
-	.get_wss	= venc_get_wss,
-	.set_wss	= venc_set_wss,
-
-	.driver         = {
-		.name   = "venc",
-		.owner  = THIS_MODULE,
-	},
-};
-/* driver end */
-
 static int __init venc_init_display(struct omap_dss_device *dssdev)
 {
 	DSSDBG("init_display\n");
@@ -897,9 +795,9 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
 
 	venc_runtime_put();
 
-	r = omap_dss_register_driver(&venc_driver);
+	r = venc_panel_init();
 	if (r)
-		goto err_reg_panel_driver;
+		goto err_panel_init;
 
 	dss_debugfs_create_file("venc", venc_dump_regs);
 
@@ -907,7 +805,7 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
 
 	return 0;
 
-err_reg_panel_driver:
+err_panel_init:
 err_runtime_get:
 	pm_runtime_disable(&pdev->dev);
 	venc_put_clocks();
@@ -923,7 +821,7 @@ static int __exit omap_venchw_remove(struct platform_device *pdev)
 		venc.vdda_dac_reg = NULL;
 	}
 
-	omap_dss_unregister_driver(&venc_driver);
+	venc_panel_exit();
 
 	pm_runtime_disable(&pdev->dev);
 	venc_put_clocks();
diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c
new file mode 100644
index 0000000..6b31298
--- /dev/null
+++ b/drivers/video/omap2/dss/venc_panel.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * VENC panel driver
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+static struct {
+	struct mutex lock;
+} venc_panel;
+
+static ssize_t display_output_type_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	const char *ret;
+
+	switch (dssdev->phy.venc.type) {
+	case OMAP_DSS_VENC_TYPE_COMPOSITE:
+		ret = "composite";
+		break;
+	case OMAP_DSS_VENC_TYPE_SVIDEO:
+		ret = "svideo";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", ret);
+}
+
+static ssize_t display_output_type_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	enum omap_dss_venc_type new_type;
+
+	if (sysfs_streq("composite", buf))
+		new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
+	else if (sysfs_streq("svideo", buf))
+		new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
+	else
+		return -EINVAL;
+
+	mutex_lock(&venc_panel.lock);
+
+	if (dssdev->phy.venc.type != new_type) {
+		dssdev->phy.venc.type = new_type;
+		if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
+			omapdss_venc_display_disable(dssdev);
+			omapdss_venc_display_enable(dssdev);
+		}
+	}
+
+	mutex_unlock(&venc_panel.lock);
+
+	return size;
+}
+
+static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
+		display_output_type_show, display_output_type_store);
+
+static int venc_panel_probe(struct omap_dss_device *dssdev)
+{
+	mutex_init(&venc_panel.lock);
+
+	/* set initial timings to PAL */
+	dssdev->panel.timings = (struct omap_video_timings)
+		{ 720, 574, 13500, 64, 12, 68, 5, 5, 41,
+			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
+			true,
+		};
+
+	return device_create_file(&dssdev->dev, &dev_attr_output_type);
+}
+
+static void venc_panel_remove(struct omap_dss_device *dssdev)
+{
+	device_remove_file(&dssdev->dev, &dev_attr_output_type);
+}
+
+static int venc_panel_enable(struct omap_dss_device *dssdev)
+{
+	int r;
+
+	dev_dbg(&dssdev->dev, "venc_panel_enable\n");
+
+	mutex_lock(&venc_panel.lock);
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+		r = -EINVAL;
+		goto err;
+	}
+
+	r = omapdss_venc_display_enable(dssdev);
+	if (r)
+		goto err;
+
+	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+	mutex_unlock(&venc_panel.lock);
+
+	return 0;
+err:
+	mutex_unlock(&venc_panel.lock);
+
+	return r;
+}
+
+static void venc_panel_disable(struct omap_dss_device *dssdev)
+{
+	dev_dbg(&dssdev->dev, "venc_panel_disable\n");
+
+	mutex_lock(&venc_panel.lock);
+
+	if (dssdev->state = OMAP_DSS_DISPLAY_DISABLED)
+		goto end;
+
+	if (dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED) {
+		/* suspended is the same as disabled with venc */
+		dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+		goto end;
+	}
+
+	omapdss_venc_display_disable(dssdev);
+
+	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+end:
+	mutex_unlock(&venc_panel.lock);
+}
+
+static int venc_panel_suspend(struct omap_dss_device *dssdev)
+{
+	venc_panel_disable(dssdev);
+	return 0;
+}
+
+static int venc_panel_resume(struct omap_dss_device *dssdev)
+{
+	return venc_panel_enable(dssdev);
+}
+
+static void venc_panel_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	dev_dbg(&dssdev->dev, "venc_panel_set_timings\n");
+
+	mutex_lock(&venc_panel.lock);
+
+	omapdss_venc_set_timings(dssdev, timings);
+
+	mutex_unlock(&venc_panel.lock);
+}
+
+static int venc_panel_check_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	dev_dbg(&dssdev->dev, "venc_panel_check_timings\n");
+
+	return omapdss_venc_check_timings(dssdev, timings);
+}
+
+static u32 venc_panel_get_wss(struct omap_dss_device *dssdev)
+{
+	dev_dbg(&dssdev->dev, "venc_panel_get_wss\n");
+
+	return omapdss_venc_get_wss(dssdev);
+}
+
+static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss)
+{
+	dev_dbg(&dssdev->dev, "venc_panel_set_wss\n");
+
+	return omapdss_venc_set_wss(dssdev, wss);
+}
+
+static struct omap_dss_driver venc_driver = {
+	.probe		= venc_panel_probe,
+	.remove		= venc_panel_remove,
+
+	.enable		= venc_panel_enable,
+	.disable	= venc_panel_disable,
+	.suspend	= venc_panel_suspend,
+	.resume		= venc_panel_resume,
+
+	.get_resolution	= omapdss_default_get_resolution,
+	.get_recommended_bpp = omapdss_default_get_recommended_bpp,
+
+	.set_timings	= venc_panel_set_timings,
+	.check_timings	= venc_panel_check_timings,
+
+	.get_wss	= venc_panel_get_wss,
+	.set_wss	= venc_panel_set_wss,
+
+	.driver         = {
+		.name   = "venc",
+		.owner  = THIS_MODULE,
+	},
+};
+
+int venc_panel_init(void)
+{
+	return omap_dss_register_driver(&venc_driver);
+}
+
+void venc_panel_exit(void)
+{
+	omap_dss_unregister_driver(&venc_driver);
+}
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 10/13] OMAPDSS: SDI: Maintain our own timings field in driver data
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

The SDI driver currently relies on the timings in omap_dss_device struct to
configure the DISPC accordingly. This makes the SDI interface driver dependent
on the omap_dss_device struct.

Make the SDI driver data maintain it's own timings field. The panel driver is
expected to call omapdss_sdi_set_timings() to set these timings before the panel
is enabled.

Make the SDI panel driver configure the new timings is the omap_dss_device
struct(dssdev->panel.timings). The SDI driver is responsible for maintaining
only it's own copy of timings.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/displays/panel-acx565akm.c |    4 ++++
 drivers/video/omap2/dss/sdi.c                  |    5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index 11bdc88..77fe59f 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -600,6 +600,8 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
 
 	mutex_lock(&md->mutex);
 
+	omapdss_sdi_set_timings(dssdev, &dssdev->panel.timings);
+
 	r = omapdss_sdi_display_enable(dssdev);
 	if (r) {
 		pr_err("%s sdi enable failed\n", __func__);
@@ -732,6 +734,8 @@ static void acx_panel_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
 	omapdss_sdi_set_timings(dssdev, timings);
+
+	dssdev->panel.timings = *timings;
 }
 
 static int acx_panel_check_timings(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 0474962..243e96d 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -34,6 +34,7 @@ static struct {
 	struct regulator *vdds_sdi_reg;
 
 	struct dss_lcd_mgr_config mgr_config;
+	struct omap_video_timings timings;
 } sdi;
 
 static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
@@ -51,7 +52,7 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
 
 int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
 {
-	struct omap_video_timings *t = &dssdev->panel.timings;
+	struct omap_video_timings *t = &sdi.timings;
 	struct dss_clock_info dss_cinfo;
 	struct dispc_clock_info dispc_cinfo;
 	unsigned long pck;
@@ -151,7 +152,7 @@ void omapdss_sdi_set_timings(struct omap_dss_device *dssdev,
 {
 	int r;
 
-	dssdev->panel.timings = *timings;
+	sdi.timings = *timings;
 
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
 		omapdss_sdi_display_disable(dssdev);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 09/13] OMAPDSS: SDI: Create a function to set timings
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

Create function omapdss_sdi_set_timings(). Configuring new timings is done the
same way as before, SDI is disabled, and re-enabled with the new timings in
dssdev. This just moves the code from the panel drivers to the SDI driver.

The panel drivers shouldn't be aware of how SDI manages to configure a new set
of timings. This should be taken care of by the SDI driver itself.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/displays/panel-acx565akm.c |   13 +------------
 drivers/video/omap2/dss/sdi.c                  |   17 +++++++++++++++++
 include/video/omapdss.h                        |    2 ++
 3 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index eaeed43..11bdc88 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -731,18 +731,7 @@ static int acx_panel_resume(struct omap_dss_device *dssdev)
 static void acx_panel_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
-	int r;
-
-	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE)
-		omapdss_sdi_display_disable(dssdev);
-
-	dssdev->panel.timings = *timings;
-
-	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
-		r = omapdss_sdi_display_enable(dssdev);
-		if (r)
-			dev_err(&dssdev->dev, "%s enable failed\n", __func__);
-	}
+	omapdss_sdi_set_timings(dssdev, timings);
 }
 
 static int acx_panel_check_timings(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 5d31699..0474962 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -146,6 +146,23 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
 }
 EXPORT_SYMBOL(omapdss_sdi_display_disable);
 
+void omapdss_sdi_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	int r;
+
+	dssdev->panel.timings = *timings;
+
+	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
+		omapdss_sdi_display_disable(dssdev);
+
+		r = omapdss_sdi_display_enable(dssdev);
+		if (r)
+			DSSERR("failed to set new timings\n");
+	}
+}
+EXPORT_SYMBOL(omapdss_sdi_set_timings);
+
 static int __init sdi_init_display(struct omap_dss_device *dssdev)
 {
 	DSSDBG("SDI init\n");
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index a85b3fb..c5c013e 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -761,6 +761,8 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
 
 int omapdss_sdi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_sdi_display_disable(struct omap_dss_device *dssdev);
+void omapdss_sdi_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings);
 
 int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 08/13] OMAPDSS: HDMI: Add locking for hdmi interface get/set timing functions
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

The hdmi interface driver exposes functions to the hdmi panel driver to
get and configure the interface timings maintained by the hdmi driver.

These timings(stored in hdmi.ip_data.cfg) should be protected by the hdmi lock
to ensure they are called sequentially, this is similar to how hdmi enable and
disable functions need locking.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/hdmi.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index f577c8e..171c695 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -547,7 +547,11 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
 void omapdss_hdmi_display_get_timing(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
+	mutex_lock(&hdmi.lock);
+
 	*timings = hdmi.ip_data.cfg.timings;
+
+	mutex_unlock(&hdmi.lock);
 }
 
 int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
@@ -570,6 +574,8 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
 	struct hdmi_cm cm;
 	const struct hdmi_config *t;
 
+	mutex_lock(&hdmi.lock);
+
 	cm = hdmi_get_code(timings);
 	hdmi.ip_data.cfg.cm = cm;
 
@@ -588,6 +594,8 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
 	} else {
 		dss_mgr_set_timings(dssdev->manager, &t->timings);
 	}
+
+	mutex_unlock(&hdmi.lock);
 }
 
 static void hdmi_dump_regs(struct seq_file *s)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 07/13] OMAPDSS: HDMI: Add a get_timing function for HDMI interface
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

Add function omapdss_hdmi_display_get_timing() which returns the timings
maintained by the HDMI interface driver in it's hdmi_config field. This
prevents the need for the panel driver to configure default timings in it's
probe.

This function is just intended to be used once during the panel driver's probe.
It makes sense for those interfaces which can be configured to a default timing.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/dss.h        |    2 ++
 drivers/video/omap2/dss/hdmi.c       |    6 ++++++
 drivers/video/omap2/dss/hdmi_panel.c |   10 +++++-----
 3 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 7e38ffd..df49c5d 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -485,6 +485,8 @@ static inline unsigned long hdmi_get_pixel_clock(void)
 #endif
 int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_get_timing(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings);
 void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings);
 int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index bdf1c33..f577c8e 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -544,6 +544,12 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
 	hdmi_runtime_put();
 }
 
+void omapdss_hdmi_display_get_timing(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	*timings = hdmi.ip_data.cfg.timings;
+}
+
 int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
 					struct omap_video_timings *timings)
 {
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c
index 8dce206..8473193 100644
--- a/drivers/video/omap2/dss/hdmi_panel.c
+++ b/drivers/video/omap2/dss/hdmi_panel.c
@@ -41,13 +41,13 @@ static struct {
 
 static int hdmi_panel_probe(struct omap_dss_device *dssdev)
 {
+	struct omap_video_timings timings;
+
 	DSSDBG("ENTER hdmi_panel_probe\n");
 
-	dssdev->panel.timings = (struct omap_video_timings)
-			{ 640, 480, 25175, 96, 16, 48, 2, 11, 31,
-				OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
-				false,
-			};
+	omapdss_hdmi_display_get_timing(dssdev, &timings);
+
+	dssdev->panel.timings = timings;
 
 	DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
 		dssdev->panel.timings.x_res,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 06/13] OMAPDSS: HDMI: Use our own omap_video_timings field when setting interface timings
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

The hdmi driver currently updates only the 'code' member of hdmi_config when
the op omapdss_hdmi_display_set_timing() is called by the hdmi panel driver.
The 'timing' field of hdmi_config is updated only when hdmi_power_on is called.
It makes more sense to configure the whole hdmi_config field in the set_timing
op called by the panel driver. This way, we don't need to call both functions
to ensure that our hdmi_config is configured correctly. Also, we don't need to
calculate hdmi_config during hdmi_power_on, or rely on the omap_video_timings
in the panel's omap_dss_device struct.

A default timing is now configured in hdmi's probe if the panel driver doesn't
set any timing, or doesn't set a valid timing before enabling the panel. Also,
when setting manager timings, use the omap_video_timing calculated by
hdmi_get_timings(), this returns the timings as specified in the CEA/VESA
tables, don't use the one provided by the panel driver directly.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/dss.h        |    3 ++-
 drivers/video/omap2/dss/hdmi.c       |   41 +++++++++++++++++-----------------
 drivers/video/omap2/dss/hdmi_panel.c |    2 +-
 3 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 8a9630b..7e38ffd 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -485,7 +485,8 @@ static inline unsigned long hdmi_get_pixel_clock(void)
 #endif
 int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
-void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings);
 int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
 					struct omap_video_timings *timings);
 int omapdss_hdmi_read_edid(u8 *buf, int len);
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 6635b09..bdf1c33 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -462,7 +462,6 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 {
 	const struct omapdss_clock_config *clks;
 	int r;
-	const struct hdmi_config *timing;
 	struct omap_video_timings *p;
 	unsigned long phy;
 
@@ -472,22 +471,10 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 
 	dss_mgr_disable(dssdev->manager);
 
-	p = &dssdev->panel.timings;
+	p = &hdmi.ip_data.cfg.timings;
 
-	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n",
-		dssdev->panel.timings.x_res,
-		dssdev->panel.timings.y_res);
+	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
 
-	timing = hdmi_get_timings();
-	if (timing = NULL) {
-		/* HDMI code 4 corresponds to 640 * 480 VGA */
-		hdmi.ip_data.cfg.cm.code = 4;
-		/* DVI mode 1 corresponds to HDMI 0 to DVI */
-		hdmi.ip_data.cfg.cm.mode = HDMI_DVI;
-		hdmi.ip_data.cfg = vesa_timings[0];
-	} else {
-		hdmi.ip_data.cfg = *timing;
-	}
 	phy = p->pixel_clock;
 
 	hdmi_compute_pll(phy, &hdmi.ip_data.pll_data);
@@ -525,7 +512,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 	dispc_enable_gamma_table(0);
 
 	/* tv size */
-	dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
+	dss_mgr_set_timings(dssdev->manager, p);
 
 	r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
 	if (r)
@@ -571,13 +558,18 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
 
 }
 
-void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
 {
 	struct hdmi_cm cm;
+	const struct hdmi_config *t;
+
+	cm = hdmi_get_code(timings);
+	hdmi.ip_data.cfg.cm = cm;
 
-	cm = hdmi_get_code(&dssdev->panel.timings);
-	hdmi.ip_data.cfg.cm.code = cm.code;
-	hdmi.ip_data.cfg.cm.mode = cm.mode;
+	t = hdmi_get_timings();
+	if (t != NULL)
+		hdmi.ip_data.cfg = *t;
 
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
 		int r;
@@ -588,7 +580,7 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
 		if (r)
 			DSSERR("failed to power on device\n");
 	} else {
-		dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
+		dss_mgr_set_timings(dssdev->manager, &t->timings);
 	}
 }
 
@@ -933,6 +925,13 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
 	hdmi.ip_data.core_av_offset = HDMI_CORE_AV;
 	hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
 	hdmi.ip_data.phy_offset = HDMI_PHY;
+
+	/*
+	 * initialize hdmi timings to default value:
+	 * HDMI code 4(VGA) and HDMI mode 1(DVI)
+	 */
+	hdmi.ip_data.cfg = vesa_timings[0];
+
 	mutex_init(&hdmi.ip_data.lock);
 
 	hdmi_panel_init();
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c
index e10844f..8dce206 100644
--- a/drivers/video/omap2/dss/hdmi_panel.c
+++ b/drivers/video/omap2/dss/hdmi_panel.c
@@ -336,8 +336,8 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev,
 	 */
 	hdmi_panel_audio_disable(dssdev);
 
+	omapdss_hdmi_display_set_timing(dssdev, timings);
 	dssdev->panel.timings = *timings;
-	omapdss_hdmi_display_set_timing(dssdev);
 
 	mutex_unlock(&hdmi.lock);
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 05/13] OMAPDSS: DSI: Update manager timings on a manual update
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

During a command mode update using DISPC video port, we may need to swap the
connected overlay manager's width and height when 90 or 270 degree rotation is
done via the panel by changing it's address mode.

Call dss_mgr_set_timings() in update_screen_dispc() before starting the manager
update. The new manager size is updated in the 'timings' field of DSI driver's
private data via omapdss_dsi_set_size(). A panel driver is expected to call this
when performing rotation.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/dsi.c |    9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index eb364d4..6e1c74b 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -4180,8 +4180,7 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
 }
 EXPORT_SYMBOL(dsi_disable_video_output);
 
-static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
-		u16 w, u16 h)
+static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
@@ -4195,6 +4194,8 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
 	int r;
 	const unsigned channel = dsi->update_channel;
 	const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
+	u16 w = dsi->timings.x_res;
+	u16 h = dsi->timings.y_res;
 
 	DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
 
@@ -4244,6 +4245,8 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
 		msecs_to_jiffies(250));
 	BUG_ON(r = 0);
 
+	dss_mgr_set_timings(dssdev->manager, &dsi->timings);
+
 	dss_mgr_start_update(dssdev->manager);
 
 	if (dsi->te_enabled) {
@@ -4337,7 +4340,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
 	dsi->update_bytes = dw * dh *
 		dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
 #endif
-	dsi_update_screen_dispc(dssdev, dw, dh);
+	dsi_update_screen_dispc(dssdev);
 
 	return 0;
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 04/13] OMAPDSS: DSI: Add function to set panel size for command mode panels
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

DSI command mode panels don't need to configure a full set of timings to
configure DSI, they only require the width and the height of the panel in
pixels.

Use omapdss_dsi_set_size for command mode panels, omapdss_dsi_set_timings is
meant for video mode panels. When performing rotation via chaning the address
mode of the panel, we would need to swap width and height when doing 90 or 270
rotation. Make sure that omapdss_dsi_set_size() makes the new width and height
visible to DSI.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/displays/panel-taal.c |   14 ++++++++++++++
 drivers/video/omap2/dss/dsi.c             |   23 ++++++++++++++++-------
 include/video/omapdss.h                   |    1 +
 3 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 3f5acc7..c3bca2f 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -1060,6 +1060,9 @@ static int taal_power_on(struct omap_dss_device *dssdev)
 		goto err0;
 	};
 
+	omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res,
+		dssdev->panel.timings.y_res);
+
 	r = omapdss_dsi_display_enable(dssdev);
 	if (r) {
 		dev_err(&dssdev->dev, "failed to enable DSI\n");
@@ -1487,6 +1490,7 @@ static int taal_get_te(struct omap_dss_device *dssdev)
 static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
 {
 	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	u16 dw, dh;
 	int r;
 
 	dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
@@ -1508,6 +1512,16 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
 			goto err;
 	}
 
+	if (rotate = 0 || rotate = 2) {
+		dw = dssdev->panel.timings.x_res;
+		dh = dssdev->panel.timings.y_res;
+	} else {
+		dw = dssdev->panel.timings.y_res;
+		dh = dssdev->panel.timings.x_res;
+	}
+
+	omapdss_dsi_set_size(dssdev, dw, dh);
+
 	td->rotate = rotate;
 
 	dsi_bus_unlock(dssdev);
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 815b606..eb364d4 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -4330,7 +4330,8 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
 	dsi->framedone_callback = callback;
 	dsi->framedone_data = data;
 
-	dssdev->driver->get_resolution(dssdev, &dw, &dh);
+	dw = dsi->timings.x_res;
+	dh = dsi->timings.y_res;
 
 #ifdef DEBUG
 	dsi->update_bytes = dw * dh *
@@ -4378,12 +4379,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 	u32 irq = 0;
 
 	if (dssdev->panel.dsi_mode = OMAP_DSS_DSI_CMD_MODE) {
-		u16 dw, dh;
-
-		dssdev->driver->get_resolution(dssdev, &dw, &dh);
-
-		dsi->timings.x_res = dw;
-		dsi->timings.y_res = dh;
 		dsi->timings.hsw = 1;
 		dsi->timings.hfp = 1;
 		dsi->timings.hbp = 1;
@@ -4702,6 +4697,20 @@ void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
 }
 EXPORT_SYMBOL(omapdss_dsi_set_timings);
 
+void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
+{
+	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+	mutex_lock(&dsi->lock);
+
+	dsi->timings.x_res = w;
+	dsi->timings.y_res = h;
+
+	mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_size);
+
 static int __init dsi_init_display(struct omap_dss_device *dssdev)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index a2cd133..a85b3fb 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -738,6 +738,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
 void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings);
+void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h);
 
 int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
 		void (*callback)(int, void *), void *data);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 03/13] OMAPDSS: DSI: Maintain own copy of timings in driver data
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

The DSI driver currently relies on the timings in omap_dss_device struct to
configure the DISPC and DSI blocks accordingly. This makes the DSI interface
driver dependent on the omap_dss_device struct.

Make the DSI driver data maintain it's own timings field. A DSI video mode panel
driver is expected to call omapdss_dsi_set_timings() to set these timings before
the panel is enabled.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/dsi.c |   58 +++++++++++++++++++++++++----------------
 include/video/omapdss.h       |    2 ++
 2 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 27c27c4..815b606 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -333,6 +333,7 @@ struct dsi_data {
 	unsigned scp_clk_refcount;
 
 	struct dss_lcd_mgr_config mgr_config;
+	struct omap_video_timings timings;
 };
 
 struct dsi_packet_sent_handler_data {
@@ -3607,9 +3608,10 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)
 	int num_line_buffers;
 
 	if (dssdev->panel.dsi_mode = OMAP_DSS_DSI_VIDEO_MODE) {
+		struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 		int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
 		unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
-		struct omap_video_timings *timings = &dssdev->panel.timings;
+		struct omap_video_timings *timings = &dsi->timings;
 		/*
 		 * Don't use line buffers if width is greater than the video
 		 * port's line buffer size
@@ -3738,7 +3740,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
 	int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
 	int tclk_trail, ths_exit, exiths_clk;
 	bool ddr_alwon;
-	struct omap_video_timings *timings = &dssdev->panel.timings;
+	struct omap_video_timings *timings = &dsi->timings;
 	int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
 	int ndl = dsi->num_lanes_used - 1;
 	const struct omapdss_clock_config *clks;
@@ -3996,7 +3998,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
 		int vbp = dssdev->panel.dsi_vm_data.vbp;
 		int window_sync = dssdev->panel.dsi_vm_data.window_sync;
 		bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
-		struct omap_video_timings *timings = &dssdev->panel.timings;
+		struct omap_video_timings *timings = &dsi->timings;
 		int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
 		int tl, t_he, width_bytes;
 
@@ -4105,6 +4107,7 @@ EXPORT_SYMBOL(omapdss_dsi_configure_pins);
 int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
 	u8 data_type;
 	u16 word_count;
@@ -4135,7 +4138,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
 		/* MODE, 1 = video mode */
 		REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
 
-		word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8);
+		word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8);
 
 		dsi_vc_write_long_header(dsidev, channel, data_type,
 				word_count, 0);
@@ -4370,7 +4373,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	struct omap_video_timings timings;
 	const struct omapdss_clock_config *clks;
 	int r, lcd_id;
 	u32 irq = 0;
@@ -4380,14 +4382,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 
 		dssdev->driver->get_resolution(dssdev, &dw, &dh);
 
-		timings.x_res = dw;
-		timings.y_res = dh;
-		timings.hsw = 1;
-		timings.hfp = 1;
-		timings.hbp = 1;
-		timings.vsw = 1;
-		timings.vfp = 0;
-		timings.vbp = 0;
+		dsi->timings.x_res = dw;
+		dsi->timings.y_res = dh;
+		dsi->timings.hsw = 1;
+		dsi->timings.hfp = 1;
+		dsi->timings.hbp = 1;
+		dsi->timings.vsw = 1;
+		dsi->timings.vfp = 0;
+		dsi->timings.vbp = 0;
 
 		irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
 
@@ -4401,8 +4403,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 		dsi->mgr_config.stallmode = true;
 		dsi->mgr_config.fifohandcheck = true;
 	} else {
-		timings = dssdev->panel.timings;
-
 		dsi->mgr_config.stallmode = false;
 		dsi->mgr_config.fifohandcheck = false;
 	}
@@ -4411,14 +4411,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 	 * override interlace, logic level and edge related parameters in
 	 * omap_video_timings with default values
 	 */
-	timings.interlace = false;
-	timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
-	timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
-	timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
-	timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
-	timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
+	dsi->timings.interlace = false;
+	dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+	dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+	dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+	dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+	dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
 
-	dss_mgr_set_timings(dssdev->manager, &timings);
+	dss_mgr_set_timings(dssdev->manager, &dsi->timings);
 
 	switch (dssdev->manager->id) {
 	case OMAP_DSS_CHANNEL_LCD:
@@ -4688,6 +4688,20 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 }
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
 
+void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+	mutex_lock(&dsi->lock);
+
+	dsi->timings = *timings;
+
+	mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_timings);
+
 static int __init dsi_init_display(struct omap_dss_device *dssdev)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index ebf2ebd..a2cd133 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -736,6 +736,8 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
 void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
 		bool enable);
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
+void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings);
 
 int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
 		void (*callback)(int, void *), void *data);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 02/13] OMAPDSS: DPI displays: Take care of panel timings in the driver itself
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

The timings maintained in omap_dss_device(dssdev->panel.timings) should be
maintained by the panel driver itself. It's the panel drivers responsibility
to update it if a new set of timings is to be configured. The DPI interface
driver shouldn't be responsible of updating the panel timings, it's responsible
of maintianing it's own copy of timings.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/displays/panel-generic-dpi.c   |    2 ++
 drivers/video/omap2/displays/panel-tfp410.c        |    1 +
 .../video/omap2/displays/panel-tpo-td043mtea1.c    |    2 ++
 drivers/video/omap2/dss/dpi.c                      |    1 -
 4 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
index 8d4e102..a07e18c 100644
--- a/drivers/video/omap2/displays/panel-generic-dpi.c
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -730,6 +730,8 @@ static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
 
 	omapdss_dpi_set_timings(dssdev, timings);
 
+	dssdev->panel.timings = *timings;
+
 	mutex_unlock(&drv_data->lock);
 }
 
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c
index c6f9503..9397236 100644
--- a/drivers/video/omap2/displays/panel-tfp410.c
+++ b/drivers/video/omap2/displays/panel-tfp410.c
@@ -234,6 +234,7 @@ static void tfp410_set_timings(struct omap_dss_device *dssdev,
 
 	mutex_lock(&ddata->lock);
 	omapdss_dpi_set_timings(dssdev, timings);
+	dssdev->panel.timings = *timings;
 	mutex_unlock(&ddata->lock);
 }
 
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index ecb163e..3f47f5f 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -483,6 +483,8 @@ static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
 	omapdss_dpi_set_timings(dssdev, timings);
+
+	dssdev->panel.timings = *timings;
 }
 
 static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 96dd1a4..6c43d80 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -304,7 +304,6 @@ void omapdss_dpi_set_timings(struct omap_dss_device *dssdev,
 	mutex_lock(&dpi.lock);
 
 	dpi.timings = *timings;
-	dssdev->panel.timings = *timings;
 
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
 		r = dispc_runtime_get();
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 01/13] OMAPDSS: DPI: Maintain our own timings field in driver data
From: Archit Taneja @ 2012-08-09 11:56 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344512989-4071-1-git-send-email-archit@ti.com>

The DPI driver currently relies on the timings in omap_dss_device struct to
configure the DISPC accordingly. This makes the DPI interface driver dependent
on the omap_dss_device struct.

Make the DPI driver data maintain it's own timings field. The panel driver is
expected to call dpi_set_timings()(renamed to omapdss_dpi_set_timings) to set
these timings before the panel is enabled.

In the set_timings() op, we still ensure that the omap_dss_device timings
(dssdev->panel.timings) are configured. This will later be configured only by
the DPI panel drivers.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/displays/panel-generic-dpi.c   |    4 +++-
 .../omap2/displays/panel-lgphilips-lb035q02.c      |    2 ++
 .../omap2/displays/panel-nec-nl8048hl11-01b.c      |    2 ++
 drivers/video/omap2/displays/panel-picodlp.c       |    3 +++
 .../video/omap2/displays/panel-sharp-ls037v7dw01.c |    2 ++
 drivers/video/omap2/displays/panel-tfp410.c        |    4 +++-
 .../video/omap2/displays/panel-tpo-td043mtea1.c    |    4 +++-
 drivers/video/omap2/dss/dpi.c                      |   11 +++++++----
 include/video/omapdss.h                            |    4 ++--
 9 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
index 69e78a5..8d4e102 100644
--- a/drivers/video/omap2/displays/panel-generic-dpi.c
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -565,6 +565,8 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE)
 		return 0;
 
+	omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+
 	r = omapdss_dpi_display_enable(dssdev);
 	if (r)
 		goto err0;
@@ -726,7 +728,7 @@ static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
 
 	mutex_lock(&drv_data->lock);
 
-	dpi_set_timings(dssdev, timings);
+	omapdss_dpi_set_timings(dssdev, timings);
 
 	mutex_unlock(&drv_data->lock);
 }
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
index 8028077..7e52aee 100644
--- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
@@ -55,6 +55,8 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev)
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE)
 		return 0;
 
+	omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+
 	r = omapdss_dpi_display_enable(dssdev);
 	if (r)
 		goto err0;
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
index b122b0f..e501c40 100644
--- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
+++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
@@ -175,6 +175,8 @@ static int nec_8048_panel_power_on(struct omap_dss_device *dssdev)
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE)
 		return 0;
 
+	omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+
 	r = omapdss_dpi_display_enable(dssdev);
 	if (r)
 		goto err0;
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c
index 2d35bd3..0d7a8ff 100644
--- a/drivers/video/omap2/displays/panel-picodlp.c
+++ b/drivers/video/omap2/displays/panel-picodlp.c
@@ -377,6 +377,9 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
 	 * then only i2c commands can be successfully sent to dpp2600
 	 */
 	msleep(1000);
+
+	omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+
 	r = omapdss_dpi_display_enable(dssdev);
 	if (r) {
 		dev_err(&dssdev->dev, "failed to enable DPI\n");
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
index bd86ba9..1486a81 100644
--- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -142,6 +142,8 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev)
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE)
 		return 0;
 
+	omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+
 	r = omapdss_dpi_display_enable(dssdev);
 	if (r)
 		goto err0;
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c
index 40cc0cfa..c6f9503 100644
--- a/drivers/video/omap2/displays/panel-tfp410.c
+++ b/drivers/video/omap2/displays/panel-tfp410.c
@@ -65,6 +65,8 @@ static int tfp410_power_on(struct omap_dss_device *dssdev)
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE)
 		return 0;
 
+	omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+
 	r = omapdss_dpi_display_enable(dssdev);
 	if (r)
 		goto err0;
@@ -231,7 +233,7 @@ static void tfp410_set_timings(struct omap_dss_device *dssdev,
 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
 	mutex_lock(&ddata->lock);
-	dpi_set_timings(dssdev, timings);
+	omapdss_dpi_set_timings(dssdev, timings);
 	mutex_unlock(&ddata->lock);
 }
 
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index fa7baa6..ecb163e 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -337,6 +337,8 @@ static int tpo_td043_enable_dss(struct omap_dss_device *dssdev)
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE)
 		return 0;
 
+	omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+
 	r = omapdss_dpi_display_enable(dssdev);
 	if (r)
 		goto err0;
@@ -480,7 +482,7 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev)
 static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
-	dpi_set_timings(dssdev, timings);
+	omapdss_dpi_set_timings(dssdev, timings);
 }
 
 static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index add47fe..96dd1a4 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -41,6 +41,7 @@ static struct {
 
 	struct mutex lock;
 
+	struct omap_video_timings timings;
 	struct dss_lcd_mgr_config mgr_config;
 } dpi;
 
@@ -138,7 +139,7 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
 
 static int dpi_set_mode(struct omap_dss_device *dssdev)
 {
-	struct omap_video_timings *t = &dssdev->panel.timings;
+	struct omap_video_timings *t = &dpi.timings;
 	int lck_div = 0, pck_div = 0;
 	unsigned long fck = 0;
 	unsigned long pck;
@@ -293,8 +294,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
 }
 EXPORT_SYMBOL(omapdss_dpi_display_disable);
 
-void dpi_set_timings(struct omap_dss_device *dssdev,
-			struct omap_video_timings *timings)
+void omapdss_dpi_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
 {
 	int r;
 
@@ -302,7 +303,9 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
 
 	mutex_lock(&dpi.lock);
 
+	dpi.timings = *timings;
 	dssdev->panel.timings = *timings;
+
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
 		r = dispc_runtime_get();
 		if (r)
@@ -317,7 +320,7 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
 
 	mutex_unlock(&dpi.lock);
 }
-EXPORT_SYMBOL(dpi_set_timings);
+EXPORT_SYMBOL(omapdss_dpi_set_timings);
 
 int dpi_check_timings(struct omap_dss_device *dssdev,
 			struct omap_video_timings *timings)
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 6f7581b..ebf2ebd 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -751,8 +751,8 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
 
 int omapdss_dpi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_dpi_display_disable(struct omap_dss_device *dssdev);
-void dpi_set_timings(struct omap_dss_device *dssdev,
-			struct omap_video_timings *timings);
+void omapdss_dpi_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings);
 int dpi_check_timings(struct omap_dss_device *dssdev,
 			struct omap_video_timings *timings);
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 00/13] OMAPDSS: Change way of passing timings from panel driver to interface
From: Archit Taneja @ 2012-08-09 11:55 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1343817088-29645-1-git-send-email-archit@ti.com>

This is a follow up series. The orginal one can be seen here:

http://marc.info/?l=linux-omap&m\x134381744304672&w=2

Changes in v2:
- Removed misc fixes out of this set
- Not trying to optimize SDI when setting new timings, using the old strategy
- Added a function for setting size for DSI command mode panels
- Added a fix which ensures the manager sizes is correctly set for rotation in
  command mode panels.

The tree/branch can be found here:

git://gitorious.org/~boddob/linux-omap-dss2/archit-dss2-clone.git pass_timings_interface_2

Archit Taneja (13):
  OMAPDSS: DPI: Maintain our own timings field in driver data
  OMAPDSS: DPI displays: Take care of panel timings in the driver
    itself
  OMAPDSS: DSI: Maintain own copy of timings in driver data
  OMAPDSS: DSI: Add function to set panel size for command mode panels
  OMAPDSS: DSI: Update manager timings on a manual update
  OMAPDSS: HDMI: Use our own omap_video_timings field when setting
    interface timings
  OMAPDSS: HDMI: Add a get_timing function for HDMI interface
  OMAPDSS: HDMI: Add locking for hdmi interface get/set timing
    functions
  OMAPDSS: SDI: Create a function to set timings
  OMAPDSS: SDI: Maintain our own timings field in driver data
  OMAPDSS: VENC: Split VENC into interface and panel driver
  OMAPDSS: VENC: Maintain our own timings field in driver data
  OMAPDSS: VENC: Add a get_timing function for VENC interface

 drivers/video/omap2/displays/panel-acx565akm.c     |   13 +-
 drivers/video/omap2/displays/panel-generic-dpi.c   |    6 +-
 .../omap2/displays/panel-lgphilips-lb035q02.c      |    2 +
 .../omap2/displays/panel-nec-nl8048hl11-01b.c      |    2 +
 drivers/video/omap2/displays/panel-picodlp.c       |    3 +
 .../video/omap2/displays/panel-sharp-ls037v7dw01.c |    2 +
 drivers/video/omap2/displays/panel-taal.c          |   14 ++
 drivers/video/omap2/displays/panel-tfp410.c        |    5 +-
 .../video/omap2/displays/panel-tpo-td043mtea1.c    |    6 +-
 drivers/video/omap2/dss/Makefile                   |    2 +-
 drivers/video/omap2/dss/dpi.c                      |   12 +-
 drivers/video/omap2/dss/dsi.c                      |   86 +++++---
 drivers/video/omap2/dss/dss.h                      |   17 +-
 drivers/video/omap2/dss/hdmi.c                     |   55 +++--
 drivers/video/omap2/dss/hdmi_panel.c               |   12 +-
 drivers/video/omap2/dss/sdi.c                      |   20 +-
 drivers/video/omap2/dss/venc.c                     |  233 ++++++--------------
 drivers/video/omap2/dss/venc_panel.c               |  231 +++++++++++++++++++
 include/video/omapdss.h                            |    9 +-
 19 files changed, 490 insertions(+), 240 deletions(-)
 create mode 100644 drivers/video/omap2/dss/venc_panel.c

-- 
1.7.9.5


^ permalink raw reply

* Re: [PATCH 3/6] OMAPDSS: DSS: Cleanup cpu_is_xxxx checks
From: Mahapatra, Chandrabhanu @ 2012-08-09 11:51 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1344431772.4932.89.camel@deskari>

On Wed, Aug 8, 2012 at 6:46 PM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> On Wed, 2012-08-08 at 17:08 +0530, Chandrabhanu Mahapatra wrote:
>> All the cpu_is checks have been moved to dss_init_features function providing a
>> much more generic and cleaner interface. The OMAP version and revision specific
>> functions are initialized by dss_features structure local to dss.c.
>
> Most of the comments for the dispc patch apply also to this patch.

Yes, both do almost the same thing but on different files. Any
suggestions if please!

>
>> Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
>> ---
>>  drivers/video/omap2/dss/dss.c |  154 ++++++++++++++++++++++++++++++-----------
>>  1 file changed, 114 insertions(+), 40 deletions(-)
>>
>> diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
>> index 7b1c6ac..f5971ac 100644
>> --- a/drivers/video/omap2/dss/dss.c
>> +++ b/drivers/video/omap2/dss/dss.c
>> @@ -65,6 +65,20 @@ struct dss_reg {
>>  static int dss_runtime_get(void);
>>  static void dss_runtime_put(void);
>>
>> +static bool check_dss_cinfo_fck(void);
>> +static bool check_dss_cinfo_fck_34xx(void);
>> +
>> +static int dss_get_clk_24xx(struct clk *clk);
>> +static int dss_get_clk_3xxx(struct clk *clk);
>> +static int dss_get_clk_44xx(struct clk *clk);
>> +
>> +struct dss_features {
>> +     u16 fck_div_max;
>> +     int factor;
>> +     bool (*check_cinfo_fck) (void);
>> +     int (*get_clk) (struct clk *clk);
>> +};
>> +
>>  static struct {
>>       struct platform_device *pdev;
>>       void __iomem    *base;
>> @@ -83,6 +97,8 @@ static struct {
>>
>>       bool            ctx_valid;
>>       u32             ctx[DSS_SZ_REGS / sizeof(u32)];
>> +
>> +     const struct dss_features *feat;
>>  } dss;
>>
>>  static const char * const dss_generic_clk_source_names[] = {
>> @@ -91,6 +107,34 @@ static const char * const dss_generic_clk_source_names[] = {
>>       [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCK",
>>  };
>>
>> +static const struct dss_features omap2_dss_features = {
>> +     .fck_div_max            =       16,
>> +     .factor                 =       2,
>> +     .check_cinfo_fck        =       check_dss_cinfo_fck,
>> +     .get_clk                =       dss_get_clk_24xx,
>> +};
>> +
>> +static const struct dss_features omap34_dss_features = {
>> +     .fck_div_max            =       16,
>> +     .factor                 =       2,
>> +     .check_cinfo_fck        =       check_dss_cinfo_fck_34xx,
>> +     .get_clk                =       dss_get_clk_3xxx,
>> +};
>> +
>> +static const struct dss_features omap36_dss_features = {
>> +     .fck_div_max            =       32,
>> +     .factor                 =       1,
>> +     .check_cinfo_fck        =       check_dss_cinfo_fck,
>> +     .get_clk                =       dss_get_clk_3xxx,
>> +};
>> +
>> +static const struct dss_features omap4_dss_features = {
>> +     .fck_div_max            =       32,
>> +     .factor                 =       1,
>> +     .check_cinfo_fck        =       check_dss_cinfo_fck,
>> +     .get_clk                =       dss_get_clk_44xx,
>> +};
>> +

In my opinion these structures should also be initialized with
__initdata and dss_init_features should be __init as dss_features
pointer should be used as like in dispc.c to make the data constant.
But these structures are better placed at top of the file as it highly
unlikely in dss.c that new functions come in and so function
prototypes.

>>  static inline void dss_write_reg(const struct dss_reg idx, u32 val)
>>  {
>>       __raw_writel(val, dss.base + idx.idx);
>> @@ -236,7 +280,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
>>       return dss_generic_clk_source_names[clk_src];
>>  }
>>
>> -
>>  void dss_dump_clocks(struct seq_file *s)
>>  {
>>       unsigned long dpll4_ck_rate;
>> @@ -259,18 +302,10 @@ void dss_dump_clocks(struct seq_file *s)
>>
>>               seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
>>
>> -             if (cpu_is_omap3630() || cpu_is_omap44xx())
>> -                     seq_printf(s, "%s (%s) = %lu / %lu  = %lu\n",
>> -                                     fclk_name, fclk_real_name,
>> -                                     dpll4_ck_rate,
>> -                                     dpll4_ck_rate / dpll4_m4_ck_rate,
>> -                                     fclk_rate);
>> -             else
>> -                     seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
>> -                                     fclk_name, fclk_real_name,
>> -                                     dpll4_ck_rate,
>> -                                     dpll4_ck_rate / dpll4_m4_ck_rate,
>> -                                     fclk_rate);
>> +             seq_printf(s, "%s (%s) = %lu / %lu * %d  = %lu\n",
>> +                             fclk_name, fclk_real_name, dpll4_ck_rate,
>> +                             dpll4_ck_rate / dpll4_m4_ck_rate,
>> +                             dss.feat->factor, fclk_rate);
>>       } else {
>>               seq_printf(s, "%s (%s) = %lu\n",
>>                               fclk_name, fclk_real_name,
>> @@ -461,6 +496,25 @@ unsigned long dss_get_dpll4_rate(void)
>>               return 0;
>>  }
>>
>> +static bool check_dss_cinfo_fck_34xx(void)
>> +{
>> +     unsigned long prate = dss_get_dpll4_rate();
>> +     unsigned long fck = clk_get_rate(dss.dss_clk);
>> +
>> +     if (prate = dss.cache_prate || dss.cache_dss_cinfo.fck = fck)
>> +             return true;
>> +     return false;
>> +}
>> +
>> +static bool check_dss_cinfo_fck(void)
>> +{
>> +     unsigned long fck = clk_get_rate(dss.dss_clk);
>> +
>> +     if (dss.cache_dss_cinfo.fck = fck)
>> +             return true;
>> +     return false;
>
> Often code like this is cleaner written as:
>
>         return dss.cache_dss_cinfo.fck = fck;
>

ok.

>> +}
>> +
>>  int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
>>               struct dispc_clock_info *dispc_cinfo)
>>  {
>> @@ -470,7 +524,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
>>
>>       unsigned long fck, max_dss_fck;
>>
>> -     u16 fck_div, fck_div_max = 16;
>> +     u16 fck_div;
>>
>>       int match = 0;
>>       int min_fck_per_pck;
>> @@ -479,10 +533,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
>>
>>       max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
>>
>> -     fck = clk_get_rate(dss.dss_clk);
>> -     if (req_pck = dss.cache_req_pck &&
>> -                     ((cpu_is_omap34xx() && prate = dss.cache_prate) ||
>> -                      dss.cache_dss_cinfo.fck = fck)) {
>> +     if (req_pck = dss.cache_req_pck && dss.feat->check_cinfo_fck()) {
>
> This change, and the check_cinfo_fck() doesn't look correct. I mean,
> looking at the code, I think it does the same thing as the old code, but
> the line above does look very confusing =). Okay, the original code also
> looks confusing.
>
> I don't think the original code is even correct. I think it should
> include omap4 also in the prate check... And why does it have || instead
> of &&? Shouldn't we check both the prate _and_ the fck, instead of just
> either one of those... Who writes this stuff without any clarifying
> comments! (I think I wrote the code)
>
> If I'm not mistaken, the whole cpu check could be just discarded. On
> OMAP2, where prate does not exist/matter, prate should be always 0. If
> it's always 0 in the dss.cache_prate also, we can compare them without
> any cpu checks.
>
> Can you verify this, and if I'm right, just get rid of the cpu check
> there, and we don't even need the feat thing here.
>

Yes, you are right the whole cpu_is check should be discarded. Only in
OMAP2 in dss_get_clocks() the dss.dpll4_m4_ck will be NULL and so does
prate. In other cases it will initialized including OMAP4. But I am
still in doubt whether it should be be || or a && operation, most
probably &&.

>>               DSSDBG("dispc clock info found from cache.\n");
>>               *dss_cinfo = dss.cache_dss_cinfo;
>>               *dispc_cinfo = dss.cache_dispc_cinfo;
>> @@ -519,13 +570,10 @@ retry:
>>
>>               goto found;
>>       } else {
>> -             if (cpu_is_omap3630() || cpu_is_omap44xx())
>> -                     fck_div_max = 32;
>> -
>> -             for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
>> +             for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
>>                       struct dispc_clock_info cur_dispc;
>>
>> -                     if (fck_div_max = 32)
>> +                     if (dss.feat->fck_div_max = 32)
>>                               fck = prate / fck_div;
>>                       else
>>                               fck = prate / fck_div * 2;
>
> Hmm, I think this one should use the "factor" field for the multiply.

Yes.

>
>> @@ -619,6 +667,32 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
>>       return REG_GET(DSS_CONTROL, 15, 15);
>>  }
>>
>> +static int dss_get_clk_24xx(struct clk *clk)
>> +{
>> +     clk = NULL;
>> +     return true;
>> +}
>> +
>> +static int dss_get_clk_3xxx(struct clk *clk)
>> +{
>> +     clk = clk_get(NULL, "dpll4_m4_ck");
>> +     if (IS_ERR(clk)) {
>> +             DSSERR("Failed to get dpll4_m4_ck\n");
>> +             return PTR_ERR(clk);
>> +     }
>> +     return true;
>> +}
>> +
>> +static int dss_get_clk_44xx(struct clk *clk)
>> +{
>> +     clk = clk_get(NULL, "dpll_per_m5x2_ck");
>> +     if (IS_ERR(clk)) {
>> +             DSSERR("Failed to get dpll_per_m5x2_ck\n");
>> +             return PTR_ERR(clk);
>> +     }
>> +     return true;
>> +}
>
> These are almost the same functions. Rather than having separate
> functions, perhaps add the clock name into the feat struct. And NULL for
> omap2.
>
> The clock name shouldn't really even be in dss, it should come as
> parameter, or even better, we wouldn't need it an we could use the clk
> framework without this clock. But that was not possible the last time I
> looked at it, so let's have it in dss feat struct for now.
>
>  Tomi
>

ok.

-- 
Chandrabhanu Mahapatra
Texas Instruments India Pvt. Ltd.

^ permalink raw reply

* [PATCH v2 5/5] OMAPDSS: Displays: Add locking in generic DPI panel driver
From: Archit Taneja @ 2012-08-09  9:19 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344503230-18550-1-git-send-email-archit@ti.com>

The generic DPI panel driver doesn't currently have locking to ensure that
the display states and the driver data is maintained correctly. Add mutex
locking to take care of this. Add a new get_timings driver op to override the
default get_timings op. The new driver op contains locking to ensure the correct
panel timings are seen when a DSS2 user calls device->driver->get_timings.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/displays/panel-generic-dpi.c |   69 +++++++++++++++++++---
 1 file changed, 62 insertions(+), 7 deletions(-)

diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
index bc5af25..69e78a5 100644
--- a/drivers/video/omap2/displays/panel-generic-dpi.c
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -545,6 +545,8 @@ struct panel_drv_data {
 	struct omap_dss_device *dssdev;
 
 	struct panel_config *panel_config;
+
+	struct mutex lock;
 };
 
 static inline struct panel_generic_dpi_data
@@ -634,6 +636,8 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
 	drv_data->dssdev = dssdev;
 	drv_data->panel_config = panel_config;
 
+	mutex_init(&drv_data->lock);
+
 	dev_set_drvdata(&dssdev->dev, drv_data);
 
 	return 0;
@@ -652,56 +656,106 @@ static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
 
 static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
 {
-	int r = 0;
+	struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+	int r;
+
+	mutex_lock(&drv_data->lock);
 
 	r = generic_dpi_panel_power_on(dssdev);
 	if (r)
-		return r;
+		goto err;
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+err:
+	mutex_unlock(&drv_data->lock);
 
-	return 0;
+	return r;
 }
 
 static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
 {
+	struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&drv_data->lock);
+
 	generic_dpi_panel_power_off(dssdev);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+	mutex_unlock(&drv_data->lock);
 }
 
 static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
 {
+	struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&drv_data->lock);
+
 	generic_dpi_panel_power_off(dssdev);
 
 	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
 
+	mutex_unlock(&drv_data->lock);
+
 	return 0;
 }
 
 static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
 {
-	int r = 0;
+	struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+	int r;
+
+	mutex_lock(&drv_data->lock);
 
 	r = generic_dpi_panel_power_on(dssdev);
 	if (r)
-		return r;
+		goto err;
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
-	return 0;
+err:
+	mutex_unlock(&drv_data->lock);
+
+	return r;
 }
 
 static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
+	struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&drv_data->lock);
+
 	dpi_set_timings(dssdev, timings);
+
+	mutex_unlock(&drv_data->lock);
+}
+
+static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&drv_data->lock);
+
+	*timings = dssdev->panel.timings;
+
+	mutex_unlock(&drv_data->lock);
 }
 
 static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
-	return dpi_check_timings(dssdev, timings);
+	struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+	int r;
+
+	mutex_lock(&drv_data->lock);
+
+	r = dpi_check_timings(dssdev, timings);
+
+	mutex_unlock(&drv_data->lock);
+
+	return r;
 }
 
 static struct omap_dss_driver dpi_driver = {
@@ -714,6 +768,7 @@ static struct omap_dss_driver dpi_driver = {
 	.resume		= generic_dpi_panel_resume,
 
 	.set_timings	= generic_dpi_panel_set_timings,
+	.get_timings	= generic_dpi_panel_get_timings,
 	.check_timings	= generic_dpi_panel_check_timings,
 
 	.driver         = {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 4/5] OMAPDSS: DPI: Add locking for DPI interface
From: Archit Taneja @ 2012-08-09  9:19 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344503230-18550-1-git-send-email-archit@ti.com>

The DPI interface driver currently relies on the panel driver to ensure calls
like omapdss_dpi_display_enable() and omapdss_dpi_display_disable() are executed
sequentially. Also, currently, there is no way to protect the DPI driver data.

All DPI panel drivers don't ensure this, and in general, a DPI panel driver
should use it's lock to that ensure it's own driver data and omap_dss_device
states are taken care of, and not worry about the DPI interface.

Add mutex locking in the DPI enable/disable/set_timings ops.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/dpi.c |   26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index c20fe23..add47fe 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -39,6 +39,8 @@ static struct {
 	struct regulator *vdds_dsi_reg;
 	struct platform_device *dsidev;
 
+	struct mutex lock;
+
 	struct dss_lcd_mgr_config mgr_config;
 } dpi;
 
@@ -184,14 +186,18 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 {
 	int r;
 
+	mutex_lock(&dpi.lock);
+
 	if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) {
 		DSSERR("no VDSS_DSI regulator\n");
-		return -ENODEV;
+		r = -ENODEV;
+		goto err_no_reg;
 	}
 
 	if (dssdev->manager = NULL) {
 		DSSERR("failed to enable display: no manager\n");
-		return -ENODEV;
+		r = -ENODEV;
+		goto err_no_mgr;
 	}
 
 	if (dpi_use_dsi_pll(dssdev)) {
@@ -238,6 +244,8 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 	if (r)
 		goto err_mgr_enable;
 
+	mutex_unlock(&dpi.lock);
+
 	return 0;
 
 err_mgr_enable:
@@ -255,12 +263,17 @@ err_get_dispc:
 err_reg_enable:
 	omap_dss_stop_device(dssdev);
 err_start_dev:
+err_no_mgr:
+err_no_reg:
+	mutex_unlock(&dpi.lock);
 	return r;
 }
 EXPORT_SYMBOL(omapdss_dpi_display_enable);
 
 void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
 {
+	mutex_lock(&dpi.lock);
+
 	dss_mgr_disable(dssdev->manager);
 
 	if (dpi_use_dsi_pll(dssdev)) {
@@ -275,6 +288,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
 		regulator_disable(dpi.vdds_dsi_reg);
 
 	omap_dss_stop_device(dssdev);
+
+	mutex_unlock(&dpi.lock);
 }
 EXPORT_SYMBOL(omapdss_dpi_display_disable);
 
@@ -284,6 +299,9 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
 	int r;
 
 	DSSDBG("dpi_set_timings\n");
+
+	mutex_lock(&dpi.lock);
+
 	dssdev->panel.timings = *timings;
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
 		r = dispc_runtime_get();
@@ -296,6 +314,8 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
 	} else {
 		dss_mgr_set_timings(dssdev->manager, timings);
 	}
+
+	mutex_unlock(&dpi.lock);
 }
 EXPORT_SYMBOL(dpi_set_timings);
 
@@ -392,6 +412,8 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
 
 static int __init omap_dpi_probe(struct platform_device *pdev)
 {
+	mutex_init(&dpi.lock);
+
 	dpi_probe_pdata(pdev);
 
 	return 0;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 3/5] OMAPDSS: HDMI: Remove omap_dss_device argument from hdmi_compute_pll
From: Archit Taneja @ 2012-08-09  9:19 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344503230-18550-1-git-send-email-archit@ti.com>

The clock related info for DSS modules is not tied anymore to a panel's
omap_dss_device struct. It's now passed via platform data. The function
hdmi_compute_pll() do not need the omap_dss_device argument to retieve these
clocks. They use the api dss_get_platform_clock_config() get the clocks. Remove
the omap_dss_device argument from hdmi_compute_pll()

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/hdmi.c |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 16b2386..6635b09 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -405,8 +405,7 @@ unsigned long hdmi_get_pixel_clock(void)
 	return hdmi.ip_data.cfg.timings.pixel_clock * 1000;
 }
 
-static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
-		struct hdmi_pll_info *pi)
+static void hdmi_compute_pll(int phy, struct hdmi_pll_info *pi)
 {
 	const struct omapdss_clock_config *clks;
 	unsigned long clkin, refclk;
@@ -491,7 +490,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 	}
 	phy = p->pixel_clock;
 
-	hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
+	hdmi_compute_pll(phy, &hdmi.ip_data.pll_data);
 
 	hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 2/5] OMAPDSS: DPI: Remove omap_dss_device arguments in dpi_set_dsi_clk/dpi_set_dispc_clk
From: Archit Taneja @ 2012-08-09  9:19 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1344503230-18550-1-git-send-email-archit@ti.com>

The clock related info for DSS modules is not tied anymore to a panel's
omap_dss_device struct. It's now passed via platform data. The functions
dpi_set_dsi_clk() and dpi_set_dispc_clk() do not need the omap_dss_device
argument to retieve these clocks. They use the api dss_get_platform_clock_config
to get the clocks. Remove the omap_dss_device arguments from these functions.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/dpi.c |   14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 5fec180..c20fe23 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -80,9 +80,8 @@ static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)
 		lcd_src = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
 }
 
-static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
-		unsigned long pck_req, unsigned long *fck, int *lck_div,
-		int *pck_div)
+static int dpi_set_dsi_clk(unsigned long pck_req, unsigned long *fck,
+		int *lck_div, int *pck_div)
 {
 	const struct omapdss_clock_config *clks;
 	struct dsi_clock_info dsi_cinfo;
@@ -111,9 +110,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
 	return 0;
 }
 
-static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,
-		unsigned long pck_req, unsigned long *fck, int *lck_div,
-		int *pck_div)
+static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
+		int *lck_div, int *pck_div)
 {
 	struct dss_clock_info dss_cinfo;
 	struct dispc_clock_info dispc_cinfo;
@@ -145,10 +143,10 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
 	int r = 0;
 
 	if (dpi_use_dsi_pll(dssdev))
-		r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck,
+		r = dpi_set_dsi_clk(t->pixel_clock * 1000, &fck,
 				&lck_div, &pck_div);
 	else
-		r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck,
+		r = dpi_set_dispc_clk(t->pixel_clock * 1000, &fck,
 				&lck_div, &pck_div);
 	if (r)
 		return r;
-- 
1.7.9.5


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox