Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH 04/29] ARM: OMAP1: Move board-ams-delta.h from plat to mach
From: Tony Lindgren @ 2012-09-19 21:05 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-fbdev, Mark Brown, Janusz Krzysztofik, Artem Bityutskiy,
	Dmitry Torokhov, alsa-devel, Peter Ujfalusi, Tomi Valkeinen,
	linux-mtd, linux-input, linux-omap, Liam Girdwood
In-Reply-To: <20120919205732.28074.43697.stgit@muffinssi>

This is only used by omap1.

And to fix things properly, this should not be included
from the drivers at all.

Cc: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: linux-fbdev@vger.kernel.org
Cc: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com>
Cc: linux-mtd@lists.infradead.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Peter Ujfalusi <peter.ujfalusi@ti.com>
Cc: Liam Girdwood <lrg@ti.com>
Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: alsa-devel@alsa-project.org
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 arch/arm/mach-omap1/ams-delta-fiq-handler.S        |    2 +-
 arch/arm/mach-omap1/ams-delta-fiq.c                |    2 +-
 arch/arm/mach-omap1/board-ams-delta.c              |    2 +-
 arch/arm/mach-omap1/include/mach/board-ams-delta.h |    0 
 drivers/input/serio/ams_delta_serio.c              |    2 +-
 drivers/mtd/nand/ams-delta.c                       |    2 +-
 drivers/video/omap/lcd_ams_delta.c                 |    2 +-
 sound/soc/omap/ams-delta.c                         |    2 +-
 8 files changed, 7 insertions(+), 7 deletions(-)
 rename arch/arm/{plat-omap/include/plat/board-ams-delta.h => mach-omap1/include/mach/board-ams-delta.h} (100%)

diff --git a/arch/arm/mach-omap1/ams-delta-fiq-handler.S b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
index d2b6acc..3d1e1c2 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+++ b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
@@ -16,7 +16,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 
 #include <mach/irqs.h>
 #include <mach/ams-delta-fiq.h>
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
index 68e8e56..f12a12a 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -19,7 +19,7 @@
 #include <linux/module.h>
 #include <linux/io.h>
 
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 
 #include <asm/fiq.h>
 
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 05af063..b9929cb 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -35,7 +35,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 #include <plat/keypad.h>
 #include <mach/mux.h>
 
diff --git a/arch/arm/plat-omap/include/plat/board-ams-delta.h b/arch/arm/mach-omap1/include/mach/board-ams-delta.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/board-ams-delta.h
rename to arch/arm/mach-omap1/include/mach/board-ams-delta.h
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c
index f5fbdf9..45887e3 100644
--- a/drivers/input/serio/ams_delta_serio.c
+++ b/drivers/input/serio/ams_delta_serio.c
@@ -27,7 +27,7 @@
 #include <linux/module.h>
 
 #include <asm/mach-types.h>
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 
 #include <mach/ams-delta-fiq.h>
 
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index c28eec0..9e7723a 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -29,7 +29,7 @@
 #include <asm/io.h>
 #include <asm/sizes.h>
 
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 
 #include <mach/hardware.h>
 
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index 5cca6b3..ed4cad8 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -27,7 +27,7 @@
 #include <linux/lcd.h>
 #include <linux/gpio.h>
 
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 
 #include "omapfb.h"
 
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 7b18b74..98e25d5 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -32,7 +32,7 @@
 
 #include <asm/mach-types.h>
 
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 #include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"


^ permalink raw reply related

* Re: [RFC PATCH 2/3] ARM: vexpress: Add device tree support for CLCD driver
From: Pawel Moll @ 2012-09-19 16:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1348070666-9153-3-git-send-email-ryan.harkin@linaro.org>

On Wed, 2012-09-19 at 17:04 +0100, Ryan Harkin wrote:
> Add support for device tree in the amba-clcd PL111 video driver.
> 
> Special case support is added for the A9 CoreTile which uses the "legacy"
> address map and has a PL111 device on-board.  The default case is to configure
> the device on the motherboard.
> 
> Oscillator support is added for the A9 CoreTile's CLCD driver.
> 
> Signed-off-by: Ryan Harkin <ryan.harkin@linaro.org>
> ---
>  arch/arm/mach-vexpress/v2m.c |   58 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 58 insertions(+)
> 
> diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
> index 37608f2..799e00e 100644
> --- a/arch/arm/mach-vexpress/v2m.c
> +++ b/arch/arm/mach-vexpress/v2m.c
> @@ -3,6 +3,7 @@
>   */
>  #include <linux/device.h>
>  #include <linux/amba/bus.h>
> +#include <linux/amba/clcd.h>
>  #include <linux/amba/mmci.h>
>  #include <linux/io.h>
>  #include <linux/init.h>
> @@ -37,6 +38,7 @@
>  #include <mach/ct-ca9x4.h>
>  #include <mach/motherboard.h>
>  
> +#include <plat/clcd.h>
>  #include <plat/sched_clock.h>
>  
>  #include "core.h"
> @@ -541,6 +543,54 @@ MACHINE_END
>  
>  #if defined(CONFIG_ARCH_VEXPRESS_DT)
>  
> +static struct v2m_osc v2m_dt_clcd_osc = {
> +	.rate_min = 10000000,
> +	.rate_max = 165000000,
> +	.rate_default = 23750000,
> +};
> +
> +static int v2m_dt_clcd_init(void)
> +{
> +	struct device_node *node;
> +	u32 osc;
> +	u32 clcd_site;
> +	u32 dvimode;
> +	const __be32 *prop;
> +	int len, na, ns;
> +	phys_addr_t reg_base;
> +
> +	node = of_find_compatible_node(NULL, NULL, "arm,pl111");
> +	if (!node)
> +		return -ENODEV;
> +
> +	na = of_n_addr_cells(node);
> +	ns = of_n_size_cells(node);
> +
> +	prop = of_get_property(node, "reg", &len);
> +	if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
> +		return -EINVAL;
> +	reg_base = of_read_number(prop, na);
> +
> +	switch (reg_base) {
> +	case CT_CA9X4_CLCDC:
> +		clcd_site = v2m_get_master_site();
> +		dvimode = 2;
> +		break;
> +	default:
> +		clcd_site = SYS_CFG_SITE_MB;
> +		dvimode = 0;
> +		break;
> +	}
> +
> +	if (of_property_read_u32(node, "arm,vexpress-osc", &osc) != 0)
> +		return -EINVAL;
> +	v2m_dt_clcd_osc.site = clcd_site;
> +	v2m_dt_clcd_osc.osc = osc;
> +	v2m_cfg_write(SYS_CFG_MUXFPGA | clcd_site, clcd_site);
> +	v2m_cfg_write(SYS_CFG_DVIMODE | clcd_site, dvimode);
> +	return 0;
> +}
> +
>  static struct map_desc v2m_rs1_io_desc __initdata = {
>  	.virtual	= V2M_PERIPH,
>  	.pfn		= __phys_to_pfn(0x1c000000),
> @@ -598,6 +648,8 @@ void __init v2m_dt_init_early(void)
>  			pr_warning("vexpress: DT HBI (%x) is not matching "
>  					"hardware (%x)!\n", dt_hbi, hbi);
>  	}
> +
> +	v2m_dt_clcd_init();
>  }
>  
>  static  struct of_device_id vexpress_irq_match[] __initdata = {
> @@ -631,6 +683,12 @@ static void __init v2m_dt_timer_init(void)
>  
>  	if (arch_timer_sched_clock_init() != 0)
>  		versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
> +
> +	if (v2m_dt_clcd_osc.site) {
> +		/* core tile clcd controller for A9 */
> +		clk = v2m_osc_register("10020000.clcd", &v2m_dt_clcd_osc);
> +		clk_register_clkdev(clk, NULL, "10020000.clcd");
> +	}
>  }
>  
>  static struct sys_timer v2m_dt_timer = {

When (if ;-) the changes I proposed recently make their way into
mainline, all this stuff will not be necessary - both clocking and
display control are sorted there.

Pawel



^ permalink raw reply

* [RFC PATCH 3/3] ARM: vexpress: configure CLCD driver device tree support for A9 CoreTile
From: Ryan Harkin @ 2012-09-19 16:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1348070666-9153-1-git-send-email-ryan.harkin@linaro.org>

Configuration for the amba-clcd PL111 driver is added to the A9 CoreTile's DTS
file.

Configuration of the motherboard CLCD driver is removed from the DTSI files to
prevent duplicate CLCD drivers being registered.

A generic set of CLCD panel descriptions has been split into its own DTSI file.
Currently, only XVGA and VGA monitors are described.

Signed-off-by: Ryan Harkin <ryan.harkin@linaro.org>
---
 arch/arm/boot/dts/clcd-panels.dtsi      |   52 +++++++++++++++++++++++++++++++
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |    8 ++---
 arch/arm/boot/dts/vexpress-v2m.dtsi     |    8 ++---
 arch/arm/boot/dts/vexpress-v2p-ca9.dts  |    6 ++++
 4 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/arch/arm/boot/dts/clcd-panels.dtsi b/arch/arm/boot/dts/clcd-panels.dtsi
new file mode 100644
index 0000000..0b0ff6e
--- /dev/null
+++ b/arch/arm/boot/dts/clcd-panels.dtsi
@@ -0,0 +1,52 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ */
+
+/ {
+	panels {
+		panel@0 {
+			compatible	= "panel";
+			mode		= "VGA";
+			refresh		= <60>;
+			xres		= <640>;
+			yres		= <480>;
+			pixclock	= <39721>;
+			left_margin	= <40>;
+			right_margin	= <24>;
+			upper_margin	= <32>;
+			lower_margin	= <11>;
+			hsync_len	= <96>;
+			vsync_len	= <2>;
+			sync		= <0>;
+			vmode		= "FB_VMODE_NONINTERLACED";
+
+			tim2		= "TIM2_BCD", "TIM2_IPC";
+			cntl		= "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+			caps		= "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+			bpp		= <16>;
+		};
+
+		panel@1 {
+			compatible	= "panel";
+			mode		= "XVGA";
+			refresh		= <60>;
+			xres		= <1024>;
+			yres		= <768>;
+			pixclock	= <15748>;
+			left_margin	= <152>;
+			right_margin	= <48>;
+			upper_margin	= <23>;
+			lower_margin	= <3>;
+			hsync_len	= <104>;
+			vsync_len	= <4>;
+			sync		= <0>;
+			vmode		= "FB_VMODE_NONINTERLACED";
+
+			tim2		= "TIM2_BCD", "TIM2_IPC";
+			cntl		= "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+			caps		= "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+			bpp		= <16>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index d8a827b..301d3f6 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -17,6 +17,8 @@
  * CHANGES TO vexpress-v2m.dtsi!
  */
 
+/include/ "clcd-panels.dtsi"
+
 / {
 	aliases {
 		arm,v2m_timer = &v2m_timer01;
@@ -193,12 +195,6 @@
 				       0x1a0100 0xf00>;
 				reg-shift = <2>;
 			};
-
-			clcd@1f0000 {
-				compatible = "arm,pl111", "arm,primecell";
-				reg = <0x1f0000 0x1000>;
-				interrupts = <14>;
-			};
 		};
 
 		v2m_fixed_3v3: fixedregulator@0 {
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
index dba53fd..43cd86f 100644
--- a/arch/arm/boot/dts/vexpress-v2m.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -17,6 +17,8 @@
  * CHANGES TO vexpress-v2m-rs1.dtsi!
  */
 
+/include/ "clcd-panels.dtsi"
+
 / {
 	aliases {
 		arm,v2m_timer = &v2m_timer01;
@@ -192,12 +194,6 @@
 				       0x1a100 0xf00>;
 				reg-shift = <2>;
 			};
-
-			clcd@1f000 {
-				compatible = "arm,pl111", "arm,primecell";
-				reg = <0x1f000 0x1000>;
-				interrupts = <14>;
-			};
 		};
 
 		v2m_fixed_3v3: fixedregulator@0 {
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
index 3f0c736..2ebb132 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -9,6 +9,8 @@
 
 /dts-v1/;
 
+/memreserve/ 0x9f000000 0x01000000;
+
 / {
 	model = "V2P-CA9";
 	arm,hbi = <0x191>;
@@ -70,6 +72,10 @@
 		compatible = "arm,pl111", "arm,primecell";
 		reg = <0x10020000 0x1000>;
 		interrupts = <0 44 4>;
+		mode = "XVGA";
+		arm,vexpress-osc = <1>;
+		use_dma = <1>;
+		framebuffer = <0x9f000000 0x01000000>;
 	};
 
 	memory-controller@100e0000 {
-- 
1.7.9.5


^ permalink raw reply related

* [RFC PATCH 2/3] ARM: vexpress: Add device tree support for CLCD driver
From: Ryan Harkin @ 2012-09-19 16:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1348070666-9153-1-git-send-email-ryan.harkin@linaro.org>

Add support for device tree in the amba-clcd PL111 video driver.

Special case support is added for the A9 CoreTile which uses the "legacy"
address map and has a PL111 device on-board.  The default case is to configure
the device on the motherboard.

Oscillator support is added for the A9 CoreTile's CLCD driver.

Signed-off-by: Ryan Harkin <ryan.harkin@linaro.org>
---
 arch/arm/mach-vexpress/v2m.c |   58 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 37608f2..799e00e 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -3,6 +3,7 @@
  */
 #include <linux/device.h>
 #include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
 #include <linux/amba/mmci.h>
 #include <linux/io.h>
 #include <linux/init.h>
@@ -37,6 +38,7 @@
 #include <mach/ct-ca9x4.h>
 #include <mach/motherboard.h>
 
+#include <plat/clcd.h>
 #include <plat/sched_clock.h>
 
 #include "core.h"
@@ -541,6 +543,54 @@ MACHINE_END
 
 #if defined(CONFIG_ARCH_VEXPRESS_DT)
 
+static struct v2m_osc v2m_dt_clcd_osc = {
+	.rate_min = 10000000,
+	.rate_max = 165000000,
+	.rate_default = 23750000,
+};
+
+static int v2m_dt_clcd_init(void)
+{
+	struct device_node *node;
+	u32 osc;
+	u32 clcd_site;
+	u32 dvimode;
+	const __be32 *prop;
+	int len, na, ns;
+	phys_addr_t reg_base;
+
+	node = of_find_compatible_node(NULL, NULL, "arm,pl111");
+	if (!node)
+		return -ENODEV;
+
+	na = of_n_addr_cells(node);
+	ns = of_n_size_cells(node);
+
+	prop = of_get_property(node, "reg", &len);
+	if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+		return -EINVAL;
+	reg_base = of_read_number(prop, na);
+
+	switch (reg_base) {
+	case CT_CA9X4_CLCDC:
+		clcd_site = v2m_get_master_site();
+		dvimode = 2;
+		break;
+	default:
+		clcd_site = SYS_CFG_SITE_MB;
+		dvimode = 0;
+		break;
+	}
+
+	if (of_property_read_u32(node, "arm,vexpress-osc", &osc) != 0)
+		return -EINVAL;
+	v2m_dt_clcd_osc.site = clcd_site;
+	v2m_dt_clcd_osc.osc = osc;
+	v2m_cfg_write(SYS_CFG_MUXFPGA | clcd_site, clcd_site);
+	v2m_cfg_write(SYS_CFG_DVIMODE | clcd_site, dvimode);
+	return 0;
+}
+
 static struct map_desc v2m_rs1_io_desc __initdata = {
 	.virtual	= V2M_PERIPH,
 	.pfn		= __phys_to_pfn(0x1c000000),
@@ -598,6 +648,8 @@ void __init v2m_dt_init_early(void)
 			pr_warning("vexpress: DT HBI (%x) is not matching "
 					"hardware (%x)!\n", dt_hbi, hbi);
 	}
+
+	v2m_dt_clcd_init();
 }
 
 static  struct of_device_id vexpress_irq_match[] __initdata = {
@@ -631,6 +683,12 @@ static void __init v2m_dt_timer_init(void)
 
 	if (arch_timer_sched_clock_init() != 0)
 		versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
+
+	if (v2m_dt_clcd_osc.site) {
+		/* core tile clcd controller for A9 */
+		clk = v2m_osc_register("10020000.clcd", &v2m_dt_clcd_osc);
+		clk_register_clkdev(clk, NULL, "10020000.clcd");
+	}
 }
 
 static struct sys_timer v2m_dt_timer = {
-- 
1.7.9.5


^ permalink raw reply related

* [RFC PATCH 1/3] amba-clcd: Add Device Tree support to amba-clcd driver
From: Ryan Harkin @ 2012-09-19 16:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1348070666-9153-1-git-send-email-ryan.harkin@linaro.org>

Add support to parse the display configuration from device tree.

If the board does not provide platform specific functions in the struct
clcd_board contained with the amba device info, then defaults are provided
by the driver.

The device tree configuration can either ask for a DMA setup or provide a
framebuffer address to be remapped into the driver.

Signed-off-by: Ryan Harkin <ryan.harkin@linaro.org>
---
 drivers/video/amba-clcd.c |  253 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 253 insertions(+)

diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 0a2cce7..01dbad1 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -16,7 +16,10 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/memblock.h>
 #include <linux/mm.h>
+#include <linux/of.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -391,6 +394,19 @@ static int clcdfb_blank(int blank_mode, struct fb_info *info)
 	}
 	return 0;
 }
+int clcdfb_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+	return dma_mmap_writecombine(&fb->dev->dev, vma,
+				     fb->fb.screen_base,
+				     fb->fb.fix.smem_start,
+				     fb->fb.fix.smem_len);
+}
+
+void clcdfb_remove_dma(struct clcd_fb *fb)
+{
+	dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+			      fb->fb.screen_base, fb->fb.fix.smem_start);
+}
 
 static int clcdfb_mmap(struct fb_info *info,
 		       struct vm_area_struct *vma)
@@ -542,12 +558,249 @@ static int clcdfb_register(struct clcd_fb *fb)
 	return ret;
 }
 
+struct string_lookup {
+	const char *string;
+	const u32	val;
+};
+
+static struct string_lookup vmode_lookups[] = {
+	{ "FB_VMODE_NONINTERLACED", FB_VMODE_NONINTERLACED},
+	{ "FB_VMODE_INTERLACED",    FB_VMODE_INTERLACED},
+	{ "FB_VMODE_DOUBLE",        FB_VMODE_DOUBLE},
+	{ "FB_VMODE_ODD_FLD_FIRST", FB_VMODE_ODD_FLD_FIRST},
+	{ NULL, 0 },
+};
+
+static struct string_lookup tim2_lookups[] = {
+	{ "TIM2_CLKSEL", TIM2_CLKSEL},
+	{ "TIM2_IVS",    TIM2_IVS},
+	{ "TIM2_IHS",    TIM2_IHS},
+	{ "TIM2_IPC",    TIM2_IPC},
+	{ "TIM2_IOE",    TIM2_IOE},
+	{ "TIM2_BCD",    TIM2_BCD},
+	{ NULL, 0},
+};
+static struct string_lookup cntl_lookups[] = {
+	{"CNTL_LCDEN",        CNTL_LCDEN},
+	{"CNTL_LCDBPP1",      CNTL_LCDBPP1},
+	{"CNTL_LCDBPP2",      CNTL_LCDBPP2},
+	{"CNTL_LCDBPP4",      CNTL_LCDBPP4},
+	{"CNTL_LCDBPP8",      CNTL_LCDBPP8},
+	{"CNTL_LCDBPP16",     CNTL_LCDBPP16},
+	{"CNTL_LCDBPP16_565", CNTL_LCDBPP16_565},
+	{"CNTL_LCDBPP16_444", CNTL_LCDBPP16_444},
+	{"CNTL_LCDBPP24",     CNTL_LCDBPP24},
+	{"CNTL_LCDBW",        CNTL_LCDBW},
+	{"CNTL_LCDTFT",       CNTL_LCDTFT},
+	{"CNTL_LCDMONO8",     CNTL_LCDMONO8},
+	{"CNTL_LCDDUAL",      CNTL_LCDDUAL},
+	{"CNTL_BGR",          CNTL_BGR},
+	{"CNTL_BEBO",         CNTL_BEBO},
+	{"CNTL_BEPO",         CNTL_BEPO},
+	{"CNTL_LCDPWR",       CNTL_LCDPWR},
+	{"CNTL_LCDVCOMP(1)",  CNTL_LCDVCOMP(1)},
+	{"CNTL_LCDVCOMP(2)",  CNTL_LCDVCOMP(2)},
+	{"CNTL_LCDVCOMP(3)",  CNTL_LCDVCOMP(3)},
+	{"CNTL_LCDVCOMP(4)",  CNTL_LCDVCOMP(4)},
+	{"CNTL_LCDVCOMP(5)",  CNTL_LCDVCOMP(5)},
+	{"CNTL_LCDVCOMP(6)",  CNTL_LCDVCOMP(6)},
+	{"CNTL_LCDVCOMP(7)",  CNTL_LCDVCOMP(7)},
+	{"CNTL_LDMAFIFOTIME", CNTL_LDMAFIFOTIME},
+	{"CNTL_WATERMARK",    CNTL_WATERMARK},
+	{ NULL, 0},
+};
+static struct string_lookup caps_lookups[] = {
+	{"CLCD_CAP_RGB444",  CLCD_CAP_RGB444},
+	{"CLCD_CAP_RGB5551", CLCD_CAP_RGB5551},
+	{"CLCD_CAP_RGB565",  CLCD_CAP_RGB565},
+	{"CLCD_CAP_RGB888",  CLCD_CAP_RGB888},
+	{"CLCD_CAP_BGR444",  CLCD_CAP_BGR444},
+	{"CLCD_CAP_BGR5551", CLCD_CAP_BGR5551},
+	{"CLCD_CAP_BGR565",  CLCD_CAP_BGR565},
+	{"CLCD_CAP_BGR888",  CLCD_CAP_BGR888},
+	{"CLCD_CAP_444",     CLCD_CAP_444},
+	{"CLCD_CAP_5551",    CLCD_CAP_5551},
+	{"CLCD_CAP_565",     CLCD_CAP_565},
+	{"CLCD_CAP_888",     CLCD_CAP_888},
+	{"CLCD_CAP_RGB",     CLCD_CAP_RGB},
+	{"CLCD_CAP_BGR",     CLCD_CAP_BGR},
+	{"CLCD_CAP_ALL",     CLCD_CAP_ALL},
+	{ NULL, 0},
+};
+
+u32 parse_setting(struct string_lookup *lookup, const char *name)
+{
+	int i = 0;
+	while (lookup[i].string != NULL) {
+		if (strcmp(lookup[i].string, name) = 0)
+			return lookup[i].val;
+		++i;
+	}
+	return -EINVAL;
+}
+
+u32 get_string_lookup(struct device_node *node, const char *name,
+		      struct string_lookup *lookup)
+{
+	const char *string;
+	int count, i, ret = 0;
+
+	count = of_property_count_strings(node, name);
+	if (count >= 0)
+		for (i = 0; i < count; i++)
+			if (of_property_read_string_index(node, name, i,
+					&string) = 0)
+				ret |= parse_setting(lookup, string);
+	return ret;
+}
+
+int get_val(struct device_node *node, const char *string)
+{
+	u32 ret = 0;
+
+	if (of_property_read_u32(node, string, &ret))
+		ret = -1;
+	return ret;
+}
+
+struct clcd_panel *getPanel(struct device_node *node)
+{
+	static struct clcd_panel panel;
+
+	panel.mode.refresh      = get_val(node, "refresh");
+	panel.mode.xres         = get_val(node, "xres");
+	panel.mode.yres         = get_val(node, "yres");
+	panel.mode.pixclock     = get_val(node, "pixclock");
+	panel.mode.left_margin  = get_val(node, "left_margin");
+	panel.mode.right_margin = get_val(node, "right_margin");
+	panel.mode.upper_margin = get_val(node, "upper_margin");
+	panel.mode.lower_margin = get_val(node, "lower_margin");
+	panel.mode.hsync_len    = get_val(node, "hsync_len");
+	panel.mode.vsync_len    = get_val(node, "vsync_len");
+	panel.mode.sync         = get_val(node, "sync");
+	panel.bpp               = get_val(node, "bpp");
+	panel.width             = (signed short) get_val(node, "width");
+	panel.height            = (signed short) get_val(node, "height");
+
+	panel.mode.vmode = get_string_lookup(node, "vmode", vmode_lookups);
+	panel.tim2       = get_string_lookup(node, "tim2",  tim2_lookups);
+	panel.cntl       = get_string_lookup(node, "cntl",  cntl_lookups);
+	panel.caps       = get_string_lookup(node, "caps",  caps_lookups);
+
+	return &panel;
+}
+
+struct clcd_panel *clcdfb_get_panel(const char *name)
+{
+	struct device_node *node = NULL;
+	const char *mode;
+	struct clcd_panel *panel = NULL;
+
+	do {
+		node = of_find_compatible_node(node, NULL, "panel");
+		if (node)
+			if (of_property_read_string(node, "mode", &mode) = 0)
+				if (strcmp(mode, name) = 0) {
+					panel = getPanel(node);
+					panel->mode.name = name;
+				}
+	} while (node != NULL);
+
+	return panel;
+}
+
+#ifdef CONFIG_OF
+static int clcdfb_dt_init(struct clcd_fb *fb)
+{
+	int err = 0;
+	struct device_node *node;
+	const char *mode;
+	dma_addr_t dma;
+	u32 use_dma;
+	const __be32 *prop;
+	int len, na, ns;
+	phys_addr_t fb_base, fb_size;
+
+	node = fb->dev->dev.of_node;
+	if (!node)
+		return -ENODEV;
+
+	na = of_n_addr_cells(node);
+	ns = of_n_size_cells(node);
+
+	if (WARN_ON(of_property_read_string(node, "mode", &mode)))
+		return -ENODEV;
+
+	fb->panel = clcdfb_get_panel(mode);
+	if (!fb->panel)
+		return -EINVAL;
+	fb->fb.fix.smem_len = fb->panel->mode.xres * fb->panel->mode.yres * 2;
+
+	if (of_property_read_u32(node, "use_dma", &use_dma))
+		use_dma = 0;
+	if (use_dma) {
+		fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
+			fb->fb.fix.smem_len, &dma, GFP_KERNEL);
+		if (!fb->fb.screen_base) {
+			pr_err("CLCD: unable to map framebuffer\n");
+			err = -ENOMEM;
+		} else
+			fb->fb.fix.smem_start	= dma;
+	} else {
+		prop = of_get_property(node, "framebuffer", &len);
+		if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+			return -EINVAL;
+		fb_base = of_read_number(prop, na);
+		fb_size = of_read_number(prop + na, ns);
+
+		if (memblock_remove(fb_base, fb_size) != 0)
+			return -EINVAL;
+
+		fb->fb.fix.smem_start = fb_base;
+		fb->fb.screen_base = ioremap_wc(fb->fb.fix.smem_start, fb_size);
+	}
+	return err;
+}
+#endif /* CONFIG_OF */
+
 static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
 {
 	struct clcd_board *board = dev->dev.platform_data;
 	struct clcd_fb *fb;
 	int ret;
 
+#ifdef CONFIG_OF
+	if (dev->dev.of_node) {
+		const __be32 *prop;
+		int len, na, ns;
+		phys_addr_t reg_base;
+
+		na = of_n_addr_cells(dev->dev.of_node);
+		ns = of_n_size_cells(dev->dev.of_node);
+
+		prop = of_get_property(dev->dev.of_node, "reg", &len);
+		if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+			return -EINVAL;
+		reg_base = of_read_number(prop, na);
+
+		if (dev->res.start != reg_base)
+			return -EINVAL;
+
+		if (!board) {
+			board = kzalloc(sizeof(struct clcd_board), GFP_KERNEL);
+			if (!board)
+				return -EINVAL;
+			board->name    = "Device Tree CLCD PL111";
+			board->caps    = CLCD_CAP_5551 | CLCD_CAP_565;
+			board->check   = clcdfb_check;
+			board->decode  = clcdfb_decode;
+			board->setup   = clcdfb_dt_init;
+			board->mmap    = clcdfb_mmap_dma;
+			board->remove  = clcdfb_remove_dma;
+		}
+	}
+#endif /* CONFIG_OF */
+
 	if (!board)
 		return -EINVAL;
 
-- 
1.7.9.5


^ permalink raw reply related

* [RFC PATCH 0/3] amba-clcd: add device tree support
From: Ryan Harkin @ 2012-09-19 16:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi all,

The first patch adds device tree support to the amba-clcd video driver.

The next two modify the Versatile Express platform to use device tree for CLCD.

I've tested this code on Versatile Express A5, A9, A15-TC1, A15-A7-TC2 Core
Tiles and on RTSM.

I'd appreciate it if users of this driver and vexpress could please review
these patches and provide feedback.  I'd like to get them into shape so that
I can upstream in a format suitable for all users of the driver.

Regards,
Ryan.

Ryan Harkin (3):
  amba-clcd: Add Device Tree support to amba-clcd driver
  ARM: vexpress: Add device tree support for CLCD driver
  ARM: vexpress: configure CLCD driver device tree support for A9
    CoreTile

 arch/arm/boot/dts/clcd-panels.dtsi      |   52 +++++++
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |    8 +-
 arch/arm/boot/dts/vexpress-v2m.dtsi     |    8 +-
 arch/arm/boot/dts/vexpress-v2p-ca9.dts  |    6 +
 arch/arm/mach-vexpress/v2m.c            |   58 +++++++
 drivers/video/amba-clcd.c               |  253 +++++++++++++++++++++++++++++++
 6 files changed, 373 insertions(+), 12 deletions(-)
 create mode 100644 arch/arm/boot/dts/clcd-panels.dtsi

-- 
1.7.9.5


^ permalink raw reply

* Re: [RFC 0/5] Generic panel framework
From: Tomi Valkeinen @ 2012-09-19 11:45 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-fbdev, dri-devel, linux-leds, linux-media, Bryan Wu,
	Richard Purdie, Marcus Lorentzon, Sumit Semwal, Archit Taneja,
	Sebastien Guiriec, Inki Dae, Kyungmin Park, Sascha Hauer,
	Alexandre Courbot
In-Reply-To: <1345164583-18924-1-git-send-email-laurent.pinchart@ideasonboard.com>

[-- Attachment #1: Type: text/plain, Size: 6190 bytes --]

Hi,

On Fri, 2012-08-17 at 02:49 +0200, Laurent Pinchart wrote:
> Hi everybody,
> 
> While working on DT bindings for the Renesas Mobile SoC display controller
> (a.k.a. LCDC) I quickly realized that display panel implementation based on
> board code callbacks would need to be replaced by a driver-based panel
> framework.

I thought I'd try to approach the common panel framework by creating
device tree examples that OMAP would need. I only thought about the
connections and organization, not individual properties, so I have not
filled any "compatible" or such properties.

What I have below is first DT data for OMAP SoC (more or less what omap4
has), then display examples of different board setups. The hardware
examples I have here are all real, so no imaginary use cases =).

We don't need to implement support for all these at once, but I think
the DT data structure should be right from the start, so I'm posting
this to get discussion about the format.


OMAP SoC
========

So here's first the SoC specific display nodes. OMAP has a DSS (display
subsystem) block, which contains the following elements:

- DISPC (display controller) reads the pixels from memory and outputs
them using specified video timings. DISPC has three outputs, LCD0, LCD1
and TV. These are SoC internal outputs, they do not go outside the SoC.

- DPI gets its data from DISPC's LCD0, and outputs MIPI DPI (parallel
RBG)

- Two independent DSI modules, which get their data from LCD0 or LCD1,
and output MIPI DSI (a serial two-way video bus)

- HDMI, gets data from DISPC's TV output and outputs HDMI

/ {
	ocp {
		dss {
			dispc {
				dss-lcd0: output@0 {
				};

				dss-lcd1: output@1 {
				};

				dss-tv: output@2 {
				};
			};

			dpi: dpi {
				video-source = <&dss-lcd0>;
			};

			dsi0: dsi@0 {
				video-source = <&dss-lcd0>;
			};

			dsi1: dsi@1 {
				video-source = <&dss-lcd1>;
			};

			hdmi: hdmi {
				video-source = <&dss-tv>;
			};
		};
	};
};

I have defined all the relevant nodes, and video-source property is used
to point to the source for video data. I also define aliases for the SoC
outputs so that panels can use them.

One thing to note is that the video sources for some of the blocks, like
DSI, are not hardcoded in the HW, so dsi0 could get its data from LCD0
or LCD1. However, I don't think they are usually changed during runtime,
and the dss driver cannot change them independently for sure (meaning
that some upper layer should tell it how to change the config). Thus I
specify sane defaults here, but the board dts files can of course
override the video sources.

Another thing to note is that we have more outputs from OMAP than we
have outputs from DISPC. This means that the same video source is used
by multiple sinks (LCD0 used by DPI and DSI0). DPI and DSI0 cannot be
used at the same time, obviously.

And third thing to note, DISPC node defines outputs explicitly, as it
has multiple outputs, whereas the external outputs do not as they have
only one output. Thus the node's output is implicitly the node itself.
So, instead of having:

ds0: dsi@0 {
	video-source = <&dss-lcd0>;
	dsi0-out0: output@0 {
	};
};

I have:

dsi0: dsi@0 {
	video-source = <&dss-lcd0>;
};

Of this I'm a bit unsure. I believe in most cases there's only one
output, so it'd be nice to have a shorter representation, but I'm not
sure if it's good to handle the cases for single and multiple outputs
differently. Or if it's good to mix control and data busses, as, for
example, dsi0 can be used as both control and data bus. Having the
output defined explicitly would separate the control and data bus nodes.


Simple DPI panel
================

Here a board has a DPI panel, which is controlled via i2c. Panel nodes
are children of the control bus, so in this case we define the panel
under i2c2.

&i2c2 {
	dpi-lcd-panel {
		video-source = <&dpi>;

	};
};


HDMI
====

OMAP has a HDMI output, but it cannot be connected directly to an HDMI
cable. TI uses tpd12s015 chip in its board, which provides ESD,
level-shifting and whatnot (I'm an SW guy, google for the chip to read
the details =). tpd12s015 has a few GPIOs and powers that need to be
controlled, so we need a driver for it.

There's no control bus for the tpd12s015, so it's platform device. Then
there's the device for the HDMI monitor, and the DDC lines are connected
to OMAP's i2c4, thus the hdmi monitor device is a child of i2c.

/ {
	hdmi-connector: tpd12s015 {
		video-source = <&hdmi>;
	};
};

&i2c4 {
	hdmi-monitor {
		video-source = <&hdmi-connector>;
	};
};


DSI bridge chip
===============

In this board we have a DSI bridge chip that is controlled via DSI, and
gets the pixel data via DSI video mode stream. The chip converts this to
LVDS. We then have an LVDS panel connected to this bridge chip, which is
controlled via SPI.

&dsi0 {
	dsi2lvds: dsi2lvds {
		video-source = <&dsi0>;

	};
};

&spi2 {
	lvds-lcd-panel {
		video-source = <&dsi2lvds>;
	};
};


High res dual-DSI panel
=======================

Here we have a DSI video mode panel that gets its data from two DSI
buses. This allows it to get the combined bandwidth of the DSI buses,
achieving higher resolution than with single DSI bus. The panel is
controlled via the first DSI bus.

&dsi0 {
	dual-dsi-panel {
		video-source-1 = <&dsi0>;
		video-source-2 = <&dsi1>;

	};
};


DSI buffer chip with two outputs
================================

This board has a DSI command mode buffer chip, that contains its own
framebuffer. The buffer chip has two DPI outputs, which get the pixels
from the framebuffer. Similar to OMAP's DISPC this chip has multiple
outputs so they need to be defined explicitly. And we also have two
dummy DPI panels connected to this buffer chip.

&dsi0 {
	dsibuf {
		video-source = <&dsi0>;

		dsibuf-dpi0: output@0 {
		};

		dsibuf-dpi1: output@1 {
		};
	};
};

/ {
	dpi-lcd-panel@0 {
		video-source = <&dsibuf-dpi0>;

	};

	dpi-lcd-panel@1 {
		video-source = <&dsibuf-dpi1>;

	};
};

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH 6/7 v2] HID: picoLCD: drop version check during probe
From: Jiri Kosina @ 2012-09-19 11:45 UTC (permalink / raw)
  To: Bruno Prémont; +Cc: linux-input, linux-kernel, linux-fbdev
In-Reply-To: <20120917202108.3e39dedb@neptune.home>

On Mon, 17 Sep 2012, Bruno Prémont wrote:

> You seem not to have applied this one yet (it doesn't show up in picolcd
> branch).
> 
> Could you please apply it?
> (or did I miss locking changes making it obsolete?)

No, sorry, I lost that one. Applied now.

Have you and David made any progress with the locking?

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply

* Re: [PATCH v4] of: Add videomode helper
From: Tomi Valkeinen @ 2012-09-19  9:19 UTC (permalink / raw)
  To: Steffen Trumtrar
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Laurent Pinchart,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Sascha Hauer
In-Reply-To: <1348042843-24673-1-git-send-email-s.trumtrar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 15760 bytes --]

On Wed, 2012-09-19 at 10:20 +0200, Steffen Trumtrar wrote:
> This patch adds a helper function for parsing videomodes from the devicetree.
> The videomode can be either converted to a struct drm_display_mode or a
> struct fb_videomode.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
> ---
> 
> Hi!
> 
> changes since v3:
> 	- print error messages
> 	- free alloced memory
> 	- general cleanup
> 
> Regards
> Steffen
> 
>  .../devicetree/bindings/video/displaymode          |   74 +++++
>  drivers/of/Kconfig                                 |    5 +
>  drivers/of/Makefile                                |    1 +
>  drivers/of/of_videomode.c                          |  283 ++++++++++++++++++++
>  include/linux/of_videomode.h                       |   56 ++++
>  5 files changed, 419 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/video/displaymode
>  create mode 100644 drivers/of/of_videomode.c
>  create mode 100644 include/linux/of_videomode.h
> 
> diff --git a/Documentation/devicetree/bindings/video/displaymode b/Documentation/devicetree/bindings/video/displaymode
> new file mode 100644
> index 0000000..990ca52
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/video/displaymode
> @@ -0,0 +1,74 @@
> +videomode bindings
> +==================
> +
> +Required properties:
> + - hactive, vactive: Display resolution
> + - hfront-porch, hback-porch, hsync-len: Horizontal Display timing parameters
> +   in pixels
> +   vfront-porch, vback-porch, vsync-len: Vertical display timing parameters in
> +   lines
> + - clock: displayclock in Hz
> +
> +Optional properties:
> + - width-mm, height-mm: Display dimensions in mm
> + - hsync-active-high (bool): Hsync pulse is active high
> + - vsync-active-high (bool): Vsync pulse is active high
> + - interlaced (bool): This is an interlaced mode
> + - doublescan (bool): This is a doublescan mode
> +
> +There are different ways of describing a display mode. The devicetree representation
> +corresponds to the one commonly found in datasheets for displays.
> +The description of the display and its mode is split in two parts: first the display
> +properties like size in mm and (optionally) multiple subnodes with the supported modes.
> +
> +Example:
> +
> +	display@0 {
> +		width-mm = <800>;
> +		height-mm = <480>;
> +		modes {
> +			mode0: mode@0 {
> +				/* 1920x1080p24 */
> +				clock = <52000000>;
> +				hactive = <1920>;
> +				vactive = <1080>;
> +				hfront-porch = <25>;
> +				hback-porch = <25>;
> +				hsync-len = <25>;
> +				vback-porch = <2>;
> +				vfront-porch = <2>;
> +				vsync-len = <2>;
> +				hsync-active-high;
> +			};
> +		};
> +	};
> +
> +Every property also supports the use of ranges, so the commonly used datasheet
> +description with <min typ max>-tuples can be used.
> +
> +Example:
> +
> +	mode1: mode@1 {
> +		/* 1920x1080p24 */
> +		clock = <148500000>;
> +		hactive = <1920>;
> +		vactive = <1080>;
> +		hsync-len = <0 44 60>;
> +		hfront-porch = <80 88 95>;
> +		hback-porch = <100 148 160>;
> +		vfront-porch = <0 4 6>;
> +		vback-porch = <0 36 50>;
> +		vsync-len = <0 5 6>;
> +	};
> +
> +The videomode can be linked to a connector via phandles. The connector has to
> +support the display- and default-mode-property to link to and select a mode.
> +
> +Example:
> +
> +	hdmi@00120000 {
> +		status = "okay";
> +		display = <&benq>;
> +		default-mode = <&mode1>;
> +	};
> +
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index dfba3e6..a3acaa3 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -83,4 +83,9 @@ config OF_MTD
>  	depends on MTD
>  	def_bool y
>  
> +config OF_VIDEOMODE
> +	def_bool y
> +	help
> +	  helper to parse videomodes from the devicetree
> +
>  endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index e027f44..80e6db3 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
>  obj-$(CONFIG_OF_PCI)	+= of_pci.o
>  obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
>  obj-$(CONFIG_OF_MTD)	+= of_mtd.o
> +obj-$(CONFIG_OF_VIDEOMODE)	+= of_videomode.o
> diff --git a/drivers/of/of_videomode.c b/drivers/of/of_videomode.c
> new file mode 100644
> index 0000000..52bfc74
> --- /dev/null
> +++ b/drivers/of/of_videomode.c
> @@ -0,0 +1,283 @@
> +/*
> + * OF helpers for parsing display modes
> + *
> + * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
> + * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
> + *
> + * This file is released under the GPLv2
> + */
> +#include <linux/of.h>
> +#include <linux/fb.h>
> +#include <linux/export.h>
> +#include <linux/slab.h>
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc.h>
> +#include <linux/of_videomode.h>
> +
> +static u32 of_video_get_value(struct mode_property *prop)
> +{
> +	return (prop->min >= prop->typ) ? prop->min : prop->typ;
> +}

Why is this needed? If the prop->min is higher than prop->typ, isn't
that an error in the DT data, and should be rejected when parsing?

> +
> +/* read property into new mode_property */
> +static int of_video_parse_property(struct device_node *np, char *name,
> +				struct mode_property *result)
> +{
> +	struct property *prop;
> +	int length;
> +	int cells;
> +	int ret;
> +
> +	prop = of_find_property(np, name, &length);
> +	if (!prop) {
> +		pr_err("%s: could not find property %s\n", __func__,
> +			name);
> +		return -EINVAL;
> +	}
> +
> +	cells = length / sizeof(u32);
> +
> +	memset(result, 0, sizeof(*result));
> +
> +	ret = of_property_read_u32_array(np, name, &result->min, cells);
> +
> +	return ret;

Ah, I guess this is the reason for the of_video_get_value... Wouldn't it
be cleaner to be more explicit here? If there's one cell, it's the
typical value, otherwise if there are 3 cells, they are min/typ/max,
else it's an error. And I think the above also trashes memory if there
happens to be 4+ cells.

> +}
> +
> +static int of_video_free(struct display *disp)
> +{
> +	int i;
> +
> +	for (i=0; i<disp->num_modes; i++)
> +		kfree(disp->modes[i]);
> +	kfree(disp->modes);
> +
> +	return 0;
> +}
> +
> +int videomode_to_display_mode(struct display *disp, struct drm_display_mode *dmode, int index)
> +{
> +	struct videomode *vm;
> +
> +	memset(dmode, 0, sizeof(*dmode));
> +
> +	if (index > disp->num_modes) {
> +		pr_err("%s: wrong index: %d from %d\n", __func__, index, disp->num_modes);
> +		return -EINVAL;
> +	}
> +
> +	vm = disp->modes[index];
> +
> +	dmode->hdisplay = of_video_get_value(&vm->hactive);
> +	dmode->hsync_start = of_video_get_value(&vm->hactive) + of_video_get_value(&vm->hfront_porch);
> +	dmode->hsync_end = of_video_get_value(&vm->hactive) + of_video_get_value(&vm->hfront_porch)
> +			+ of_video_get_value(&vm->hsync_len);
> +	dmode->htotal = of_video_get_value(&vm->hactive) + of_video_get_value(&vm->hfront_porch)
> +			+ of_video_get_value(&vm->hsync_len) + of_video_get_value(&vm->hback_porch);
> +
> +	dmode->vdisplay = of_video_get_value(&vm->vactive);
> +	dmode->vsync_start = of_video_get_value(&vm->vactive) + of_video_get_value(&vm->vfront_porch);
> +	dmode->vsync_end = of_video_get_value(&vm->vactive) + of_video_get_value(&vm->vfront_porch)
> +			+ of_video_get_value(&vm->vsync_len);
> +	dmode->vtotal = of_video_get_value(&vm->vactive) + of_video_get_value(&vm->vfront_porch) +
> +			of_video_get_value(&vm->vsync_len) + of_video_get_value(&vm->vback_porch);
> +
> +	dmode->width_mm = disp->width_mm;
> +	dmode->height_mm = disp->height_mm;
> +
> +	dmode->clock = of_video_get_value(&vm->clock) / 1000;
> +
> +	if (vm->hah)
> +		dmode->flags |= DRM_MODE_FLAG_PHSYNC;
> +	else
> +		dmode->flags |= DRM_MODE_FLAG_NHSYNC;
> +	if (vm->vah)
> +		dmode->flags |= DRM_MODE_FLAG_PVSYNC;
> +	else
> +		dmode->flags |= DRM_MODE_FLAG_NVSYNC;
> +	if (vm->interlaced)
> +		dmode->flags |= DRM_MODE_FLAG_INTERLACE;
> +	if (vm->doublescan)
> +		dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
> +
> +	drm_mode_set_name(dmode);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(videomode_to_display_mode);
> +
> +int videomode_to_fb_mode(struct display *disp, struct fb_videomode *fbmode, int index)
> +{
> +	struct videomode *vm;
> +
> +	memset(fbmode, 0, sizeof(*fbmode));
> +
> +	if (index > disp->num_modes) {
> +		pr_err("%s: wrong index: %d from %d\n", __func__, index, disp->num_modes);
> +		return -EINVAL;
> +	}
> +
> +	vm = disp->modes[index];
> +
> +	fbmode->xres = of_video_get_value(&vm->hactive);
> +	fbmode->left_margin = of_video_get_value(&vm->hback_porch);
> +	fbmode->right_margin = of_video_get_value(&vm->hfront_porch);
> +	fbmode->hsync_len = of_video_get_value(&vm->hsync_len);
> +
> +	fbmode->yres = of_video_get_value(&vm->vactive);
> +	fbmode->upper_margin = of_video_get_value(&vm->vback_porch);
> +	fbmode->lower_margin = of_video_get_value(&vm->vfront_porch);
> +	fbmode->vsync_len = of_video_get_value(&vm->vsync_len);
> +
> +	fbmode->pixclock = KHZ2PICOS(of_video_get_value(&vm->clock) / 1000);
> +
> +	if (vm->hah)
> +		fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
> +	if (vm->vah)
> +		fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
> +	if (vm->interlaced)
> +		fbmode->vmode |= FB_VMODE_INTERLACED;
> +	if (vm->doublescan)
> +		fbmode->vmode |= FB_VMODE_DOUBLE;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(videomode_to_fb_mode);
> +
> +int of_get_video_modes(struct device_node *np, struct display *disp)
> +{
> +	struct device_node *display_np;
> +	struct device_node *mode_np;
> +	struct device_node *modes_np;
> +	char *default_mode;
> +
> +	int ret = 0;
> +
> +	memset(disp, 0, sizeof(*disp));
> +	disp->modes = kmalloc(sizeof(struct videomode*), GFP_KERNEL);
> +
> +	if (!np) {
> +		pr_err("%s: no node provided\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	display_np = of_parse_phandle(np, "display", 0);
> +
> +	if (!display_np) {
> +		pr_err("%s: could not find display node\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	of_property_read_u32(display_np, "width-mm", &disp->width_mm);
> +	of_property_read_u32(display_np, "height-mm", &disp->height_mm);
> +
> +	mode_np = of_parse_phandle(np, "default-mode", 0);
> +
> +	if (!mode_np) {
> +		pr_info("%s: no default-mode specified.\n", __func__);
> +		mode_np = of_find_node_by_name(np, "mode");
> +	}
> +
> +	if (!mode_np) {
> +		pr_err("%s: could not find any mode specification\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	default_mode = (char *)mode_np->full_name;
> +
> +	modes_np = of_find_node_by_name(np, "modes");
> +	for_each_child_of_node(modes_np, mode_np) {
> +		struct videomode *vm;
> +
> +		vm = kmalloc(sizeof(struct videomode*), GFP_KERNEL);
> +		disp->modes[disp->num_modes] = kmalloc(sizeof(struct videomode*), GFP_KERNEL);
> +
> +		ret |= of_video_parse_property(mode_np, "hback-porch", &vm->hback_porch);
> +		ret |= of_video_parse_property(mode_np, "hfront-porch", &vm->hfront_porch);
> +		ret |= of_video_parse_property(mode_np, "hactive", &vm->hactive);
> +		ret |= of_video_parse_property(mode_np, "hsync-len", &vm->hsync_len);
> +		ret |= of_video_parse_property(mode_np, "vback-porch", &vm->vback_porch);
> +		ret |= of_video_parse_property(mode_np, "vfront-porch", &vm->vfront_porch);
> +		ret |= of_video_parse_property(mode_np, "vactive", &vm->vactive);
> +		ret |= of_video_parse_property(mode_np, "vsync-len", &vm->vsync_len);
> +		ret |= of_video_parse_property(mode_np, "clock", &vm->clock);
> +
> +		if (ret)
> +			return -EINVAL;
> +
> +		vm->hah = of_property_read_bool(mode_np, "hsync-active-high");
> +		vm->vah = of_property_read_bool(mode_np, "vsync-active-high");
> +		vm->interlaced = of_property_read_bool(mode_np, "interlaced");
> +		vm->doublescan = of_property_read_bool(mode_np, "doublescan");
> +
> +		if (strcmp(default_mode,mode_np->full_name) == 0)
> +			disp->default_mode = disp->num_modes;
> +
> +		disp->modes[disp->num_modes] = vm;
> +		disp->num_modes++;
> +	}
> +	of_node_put(display_np);
> +
> +	pr_info("%s: found %d modelines. Using #%d as default\n", __func__,
> +		disp->num_modes, disp->default_mode + 1);
> +
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_get_video_modes);
> +
> +int of_video_mode_exists(struct device_node *np)
> +{
> +	struct device_node *display_np;
> +	struct device_node *mode_np;
> +
> +	if (!np)
> +		return -EINVAL;
> +
> +	display_np = of_parse_phandle(np, "display", 0);
> +
> +	if (!display_np)
> +		return -EINVAL;
> +
> +	mode_np = of_parse_phandle(np, "default-mode", 0);
> +
> +	if (mode_np)
> +		return 0;
> +
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(of_video_mode_exists);
> +
> +int of_get_display_mode(struct device_node *np, struct drm_display_mode *dmode, int index)
> +{
> +	struct display disp;
> +
> +	of_get_video_modes(np, &disp);
> +
> +	if (index == OF_MODE_SELECTION)
> +		index = disp.default_mode;
> +	if (dmode)
> +		videomode_to_display_mode(&disp, dmode, index);
> +
> +	of_video_free(&disp);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_get_display_mode);
> +
> +int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fbmode, int index)
> +{
> +	struct display disp;
> +
> +	of_get_video_modes(np, &disp);
> +
> +	if (index == OF_MODE_SELECTION)
> +		index = disp.default_mode;
> +	if (fbmode)
> +		videomode_to_fb_mode(&disp, fbmode, index);
> +
> +	of_video_free(&disp);
> +
> +	return 0;

This and of_get_display_mode() do not handle errors from
of_get_video_modes() nor from videomode_to_xxx_mode(). And I don't see a
reason for the if (fbmode) check (and the same for dmode), as there's no
reason to call these functions except to get the video modes.

> +}
> +EXPORT_SYMBOL_GPL(of_get_fb_videomode);
> diff --git a/include/linux/of_videomode.h b/include/linux/of_videomode.h
> new file mode 100644
> index 0000000..5571ce3
> --- /dev/null
> +++ b/include/linux/of_videomode.h
> @@ -0,0 +1,56 @@
> +/*
> + * Copyright 2012 Sascha Hauer <s.hauer@pengutronix.de>
> + * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
> + *
> + * OF helpers for videomodes.
> + *
> + * This file is released under the GPLv2
> + */
> +
> +#ifndef __LINUX_OF_VIDEOMODE_H
> +#define __LINUX_OF_VIDEOMODE_H
> +
> +#define OF_MODE_SELECTION -1
> +
> +struct mode_property {
> +	u32 min;
> +	u32 typ;
> +	u32 max;
> +};
> +
> +struct display {
> +	u32 width_mm;
> +	u32 height_mm;
> +	struct videomode **modes;
> +	int default_mode;
> +	int num_modes;
> +};
> +
> +/* describe videomode in terms of hardware parameters */
> +struct videomode {
> +	struct mode_property hback_porch;
> +	struct mode_property hfront_porch;
> +	struct mode_property hactive;
> +	struct mode_property hsync_len;
> +
> +	struct mode_property vback_porch;
> +	struct mode_property vfront_porch;
> +	struct mode_property vactive;
> +	struct mode_property vsync_len;
> +
> +	struct mode_property clock;
> +
> +	bool hah;
> +	bool vah;
> +	bool interlaced;
> +	bool doublescan;
> +};

I think the names display and videomode are a bit too generic here, and
could clash with names from kernel drivers. Also, the videomode is not
really a videomode, but a "template" (or something) for videomode. A
real videomode doesn't have min & max values, only the actual value.

Perhaps these should be prefixed with "of_"? Then again, they are not
really of specific either...

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* [PATCH 8/8] OMAPDSS: alloc dssdevs dynamically
From: Tomi Valkeinen @ 2012-09-19  8:30 UTC (permalink / raw)
  To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348043438-2624-1-git-send-email-tomi.valkeinen@ti.com>

We currently create omap_dss_devices statically in board files, and use
those devices directly in the omapdss driver. This model prevents us
from having the platform data (which the dssdevs in board files
practically are) as read-only, and it's also different than what we will
use with device tree.

This patch changes the model to be in line with DT model: we allocate
the dssdevs dynamically, and initialize them according to the data in
the board file's dssdev (basically we memcopy the dssdev fields).

The allocation and registration is done in the following steps in the
output drivers:

- Use dss_alloc_and_init_device to allocate and initialize the device.
  The function uses kalloc and device_initialize to accomplish this.
- Call dss_copy_device_pdata to copy the data from the board file's
  dssdev
- Use dss_add_device to register the device.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/core.c |   72 ++++++++++++++++++++--------------------
 drivers/video/omap2/dss/dpi.c  |   17 +++++++---
 drivers/video/omap2/dss/dsi.c  |   15 +++++++--
 drivers/video/omap2/dss/dss.h  |   11 +++---
 drivers/video/omap2/dss/hdmi.c |   15 +++++++--
 drivers/video/omap2/dss/rfbi.c |   17 +++++++---
 drivers/video/omap2/dss/sdi.c  |   17 +++++++---
 drivers/video/omap2/dss/venc.c |   17 +++++++---
 8 files changed, 119 insertions(+), 62 deletions(-)

diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index c4fd768..b2af72d 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -33,6 +33,7 @@
 #include <linux/device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/suspend.h>
+#include <linux/slab.h>
 
 #include <video/omapdss.h>
 
@@ -418,55 +419,44 @@ void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
 EXPORT_SYMBOL(omap_dss_unregister_driver);
 
 /* DEVICE */
-static void reset_device(struct device *dev, int check)
-{
-	u8 *dev_p = (u8 *)dev;
-	u8 *dev_end = dev_p + sizeof(*dev);
-	void *saved_pdata;
-
-	saved_pdata = dev->platform_data;
-	if (check) {
-		/*
-		 * Check if there is any other setting than platform_data
-		 * in struct device; warn that these will be reset by our
-		 * init.
-		 */
-		dev->platform_data = NULL;
-		while (dev_p < dev_end) {
-			if (*dev_p) {
-				WARN("%s: struct device fields will be "
-						"discarded\n",
-				     __func__);
-				break;
-			}
-			dev_p++;
-		}
-	}
-	memset(dev, 0, sizeof(*dev));
-	dev->platform_data = saved_pdata;
-}
-
 
 static void omap_dss_dev_release(struct device *dev)
 {
-	reset_device(dev, 0);
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	kfree(dssdev);
 }
 
 static int disp_num_counter;
 
-int omap_dss_register_device(struct omap_dss_device *dssdev,
-		struct device *parent)
+struct omap_dss_device *dss_alloc_and_init_device(struct device *parent)
 {
-	reset_device(&dssdev->dev, 1);
+	struct omap_dss_device *dssdev;
+
+	dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL);
+	if (!dssdev)
+		return NULL;
 
 	dssdev->dev.bus = &dss_bus_type;
 	dssdev->dev.parent = parent;
 	dssdev->dev.release = omap_dss_dev_release;
 	dev_set_name(&dssdev->dev, "display%d", disp_num_counter++);
-	return device_register(&dssdev->dev);
+
+	device_initialize(&dssdev->dev);
+
+	return dssdev;
 }
 
-void omap_dss_unregister_device(struct omap_dss_device *dssdev)
+int dss_add_device(struct omap_dss_device *dssdev)
+{
+	return device_add(&dssdev->dev);
+}
+
+void dss_put_device(struct omap_dss_device *dssdev)
+{
+	put_device(&dssdev->dev);
+}
+
+void dss_unregister_device(struct omap_dss_device *dssdev)
 {
 	device_unregister(&dssdev->dev);
 }
@@ -474,15 +464,25 @@ void omap_dss_unregister_device(struct omap_dss_device *dssdev)
 static int dss_unregister_dss_dev(struct device *dev, void *data)
 {
 	struct omap_dss_device *dssdev = to_dss_device(dev);
-	omap_dss_unregister_device(dssdev);
+	dss_unregister_device(dssdev);
 	return 0;
 }
 
-void omap_dss_unregister_child_devices(struct device *parent)
+void dss_unregister_child_devices(struct device *parent)
 {
 	device_for_each_child(parent, NULL, dss_unregister_dss_dev);
 }
 
+void dss_copy_device_pdata(struct omap_dss_device *dst,
+		const struct omap_dss_device *src)
+{
+	u8 *d = (u8 *)dst;
+	u8 *s = (u8 *)src;
+	size_t dsize = sizeof(struct device);
+
+	memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize);
+}
+
 /* BUS */
 static int __init omap_dss_bus_register(void)
 {
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 6f9a199..fac19d3 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -399,25 +399,34 @@ static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *p
 	return def_dssdev;
 }
 
-static void __init dpi_probe_pdata(struct platform_device *pdev)
+static void __init dpi_probe_pdata(struct platform_device *dpidev)
 {
+	struct omap_dss_device *plat_dssdev;
 	struct omap_dss_device *dssdev;
 	int r;
 
-	dssdev = dpi_find_dssdev(pdev);
+	plat_dssdev = dpi_find_dssdev(dpidev);
 
+	if (!plat_dssdev)
+		return;
+
+	dssdev = dss_alloc_and_init_device(&dpidev->dev);
 	if (!dssdev)
 		return;
 
+	dss_copy_device_pdata(dssdev, plat_dssdev);
+
 	r = dpi_init_display(dssdev);
 	if (r) {
 		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 
-	r = omap_dss_register_device(dssdev, &pdev->dev);
+	r = dss_add_device(dssdev);
 	if (r) {
 		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 }
@@ -433,7 +442,7 @@ static int __init omap_dpi_probe(struct platform_device *pdev)
 
 static int __exit omap_dpi_remove(struct platform_device *pdev)
 {
-	omap_dss_unregister_child_devices(&pdev->dev);
+	dss_unregister_child_devices(&pdev->dev);
 
 	return 0;
 }
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index ee9ae52..1dd019c 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -5040,23 +5040,32 @@ static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *p
 
 static void __init dsi_probe_pdata(struct platform_device *dsidev)
 {
+	struct omap_dss_device *plat_dssdev;
 	struct omap_dss_device *dssdev;
 	int r;
 
-	dssdev = dsi_find_dssdev(dsidev);
+	plat_dssdev = dsi_find_dssdev(dsidev);
 
+	if (!plat_dssdev)
+		return;
+
+	dssdev = dss_alloc_and_init_device(&dsidev->dev);
 	if (!dssdev)
 		return;
 
+	dss_copy_device_pdata(dssdev, plat_dssdev);
+
 	r = dsi_init_display(dssdev);
 	if (r) {
 		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 
-	r = omap_dss_register_device(dssdev, &dsidev->dev);
+	r = dss_add_device(dssdev);
 	if (r) {
 		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 }
@@ -5184,7 +5193,7 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
 
 	WARN_ON(dsi->scp_clk_refcount > 0);
 
-	omap_dss_unregister_child_devices(&dsidev->dev);
+	dss_unregister_child_devices(&dsidev->dev);
 
 	pm_runtime_disable(&dsidev->dev);
 
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 7a3fea6..417d305 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -185,10 +185,13 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
 int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
 int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
 
-int omap_dss_register_device(struct omap_dss_device *dssdev,
-		struct device *parent);
-void omap_dss_unregister_device(struct omap_dss_device *dssdev);
-void omap_dss_unregister_child_devices(struct device *parent);
+struct omap_dss_device *dss_alloc_and_init_device(struct device *parent);
+int dss_add_device(struct omap_dss_device *dssdev);
+void dss_unregister_device(struct omap_dss_device *dssdev);
+void dss_unregister_child_devices(struct device *parent);
+void dss_put_device(struct omap_dss_device *dssdev);
+void dss_copy_device_pdata(struct omap_dss_device *dst,
+		const struct omap_dss_device *src);
 
 /* apply */
 void dss_apply_init(void);
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 3b10e18..23daf7d 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -931,15 +931,22 @@ static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *
 
 static void __init hdmi_probe_pdata(struct platform_device *pdev)
 {
+	struct omap_dss_device *plat_dssdev;
 	struct omap_dss_device *dssdev;
 	struct omap_dss_hdmi_data *priv;
 	int r;
 
-	dssdev = hdmi_find_dssdev(pdev);
+	plat_dssdev = hdmi_find_dssdev(pdev);
 
+	if (!plat_dssdev)
+		return;
+
+	dssdev = dss_alloc_and_init_device(&pdev->dev);
 	if (!dssdev)
 		return;
 
+	dss_copy_device_pdata(dssdev, plat_dssdev);
+
 	priv = dssdev->data;
 
 	hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio;
@@ -951,12 +958,14 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
 	r = hdmi_init_display(dssdev);
 	if (r) {
 		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 
-	r = omap_dss_register_device(dssdev, &pdev->dev);
+	r = dss_add_device(dssdev);
 	if (r) {
 		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 }
@@ -1020,7 +1029,7 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
 {
 	device_for_each_child(&pdev->dev, NULL, hdmi_remove_child);
 
-	omap_dss_unregister_child_devices(&pdev->dev);
+	dss_unregister_child_devices(&pdev->dev);
 
 	hdmi_panel_exit();
 
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 1127037..38d9b8e 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -970,25 +970,34 @@ static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *
 	return def_dssdev;
 }
 
-static void __init rfbi_probe_pdata(struct platform_device *pdev)
+static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
 {
+	struct omap_dss_device *plat_dssdev;
 	struct omap_dss_device *dssdev;
 	int r;
 
-	dssdev = rfbi_find_dssdev(pdev);
+	plat_dssdev = rfbi_find_dssdev(rfbidev);
 
+	if (!plat_dssdev)
+		return;
+
+	dssdev = dss_alloc_and_init_device(&rfbidev->dev);
 	if (!dssdev)
 		return;
 
+	dss_copy_device_pdata(dssdev, plat_dssdev);
+
 	r = rfbi_init_display(dssdev);
 	if (r) {
 		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 
-	r = omap_dss_register_device(dssdev, &pdev->dev);
+	r = dss_add_device(dssdev);
 	if (r) {
 		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 }
@@ -1055,7 +1064,7 @@ err_runtime_get:
 
 static int __exit omap_rfbihw_remove(struct platform_device *pdev)
 {
-	omap_dss_unregister_child_devices(&pdev->dev);
+	dss_unregister_child_devices(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	return 0;
 }
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 0aaa7f3..919ff72 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -223,25 +223,34 @@ static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *p
 	return def_dssdev;
 }
 
-static void __init sdi_probe_pdata(struct platform_device *pdev)
+static void __init sdi_probe_pdata(struct platform_device *sdidev)
 {
+	struct omap_dss_device *plat_dssdev;
 	struct omap_dss_device *dssdev;
 	int r;
 
-	dssdev = sdi_find_dssdev(pdev);
+	plat_dssdev = sdi_find_dssdev(sdidev);
 
+	if (!plat_dssdev)
+		return;
+
+	dssdev = dss_alloc_and_init_device(&sdidev->dev);
 	if (!dssdev)
 		return;
 
+	dss_copy_device_pdata(dssdev, plat_dssdev);
+
 	r = sdi_init_display(dssdev);
 	if (r) {
 		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 
-	r = omap_dss_register_device(dssdev, &pdev->dev);
+	r = dss_add_device(dssdev);
 	if (r) {
 		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 }
@@ -255,7 +264,7 @@ static int __init omap_sdi_probe(struct platform_device *pdev)
 
 static int __exit omap_sdi_remove(struct platform_device *pdev)
 {
-	omap_dss_unregister_child_devices(&pdev->dev);
+	dss_unregister_child_devices(&pdev->dev);
 
 	return 0;
 }
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 88fa6ea..996779c 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -763,27 +763,36 @@ static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *
 	return def_dssdev;
 }
 
-static void __init venc_probe_pdata(struct platform_device *pdev)
+static void __init venc_probe_pdata(struct platform_device *vencdev)
 {
+	struct omap_dss_device *plat_dssdev;
 	struct omap_dss_device *dssdev;
 	int r;
 
-	dssdev = venc_find_dssdev(pdev);
+	plat_dssdev = venc_find_dssdev(vencdev);
 
+	if (!plat_dssdev)
+		return;
+
+	dssdev = dss_alloc_and_init_device(&vencdev->dev);
 	if (!dssdev)
 		return;
 
+	dss_copy_device_pdata(dssdev, plat_dssdev);
+
 	dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
 
 	r = venc_init_display(dssdev);
 	if (r) {
 		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 
-	r = omap_dss_register_device(dssdev, &pdev->dev);
+	r = dss_add_device(dssdev);
 	if (r) {
 		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		dss_put_device(dssdev);
 		return;
 	}
 }
@@ -848,7 +857,7 @@ err_runtime_get:
 
 static int __exit omap_venchw_remove(struct platform_device *pdev)
 {
-	omap_dss_unregister_child_devices(&pdev->dev);
+	dss_unregister_child_devices(&pdev->dev);
 
 	if (venc.vdda_dac_reg != NULL) {
 		regulator_put(venc.vdda_dac_reg);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 7/8] OMAPDSS: cleanup dss_recheck_connections further
From: Tomi Valkeinen @ 2012-09-19  8:30 UTC (permalink / raw)
  To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348043438-2624-1-git-send-email-tomi.valkeinen@ti.com>

Cleanup dss_recheck_connections, move and rename it to a static
dss_init_connections function inside display.c. Improve the function to
return errors, and implement a matching dss_uninit_connections that can
be used to free the mgr->dssdev link.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/core.c    |    5 ---
 drivers/video/omap2/dss/display.c |   62 +++++++++++++++++++++++++++++++++++--
 drivers/video/omap2/dss/dss.h     |    1 -
 drivers/video/omap2/dss/overlay.c |   32 -------------------
 4 files changed, 60 insertions(+), 40 deletions(-)

diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 9315ece..c4fd768 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -352,7 +352,6 @@ static int dss_driver_probe(struct device *dev)
 	int r;
 	struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
 	struct omap_dss_device *dssdev = to_dss_device(dev);
-	bool force;
 
 	DSSDBG("driver_probe: dev %s/%s, drv %s\n",
 				dev_name(dev), dssdev->driver_name,
@@ -362,10 +361,6 @@ static int dss_driver_probe(struct device *dev)
 	if (r)
 		return r;
 
-	force = core.default_display_name &&
-		strcmp(core.default_display_name, dssdev->name) = 0;
-	dss_recheck_connections(dssdev, force);
-
 	r = dssdrv->probe(dssdev);
 
 	if (r) {
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index f719010..db83ae8 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -320,11 +320,66 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,
 }
 EXPORT_SYMBOL(omapdss_default_get_timings);
 
+/*
+ * Connect dssdev to a manager if the manager is free or if force is specified.
+ * Connect all overlays to that manager if they are free or if force is
+ * specified.
+ */
+static int dss_init_connections(struct omap_dss_device *dssdev, bool force)
+{
+	struct omap_overlay_manager *mgr;
+	int i, r;
+
+	WARN_ON(dssdev->manager);
+
+	mgr = omap_dss_get_overlay_manager(dssdev->channel);
+
+	if (mgr->device && !force)
+		return 0;
+
+	if (mgr->device)
+		mgr->unset_device(mgr);
+
+	r = mgr->set_device(mgr, dssdev);
+	if (r) {
+		DSSERR("failed to set initial manager\n");
+		return r;
+	}
+
+	for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+		struct omap_overlay *ovl = omap_dss_get_overlay(i);
+
+		if (!ovl->manager || force) {
+			if (ovl->manager)
+				ovl->unset_manager(ovl);
+
+			r = ovl->set_manager(ovl, mgr);
+			if (r) {
+				DSSERR("failed to set initial overlay\n");
+				return r;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void dss_uninit_connections(struct omap_dss_device *dssdev)
+{
+	if (dssdev->manager)
+		dssdev->manager->unset_device(dssdev->manager);
+}
+
 int dss_init_device(struct platform_device *pdev,
 		struct omap_dss_device *dssdev)
 {
 	struct device_attribute *attr;
 	int i, r;
+	const char *def_disp_name = dss_get_default_display_name();
+	bool force;
+
+	force = def_disp_name && strcmp(def_disp_name, dssdev->name) = 0;
+	dss_init_connections(dssdev, force);
 
 	/* create device sysfs files */
 	i = 0;
@@ -336,6 +391,8 @@ int dss_init_device(struct platform_device *pdev,
 				device_remove_file(&dssdev->dev, attr);
 			}
 
+			dss_uninit_connections(dssdev);
+
 			DSSERR("failed to create sysfs file\n");
 			return r;
 		}
@@ -348,6 +405,8 @@ int dss_init_device(struct platform_device *pdev,
 		while ((attr = display_sysfs_attrs[i++]) != NULL)
 			device_remove_file(&dssdev->dev, attr);
 
+		dss_uninit_connections(dssdev);
+
 		DSSERR("failed to create sysfs display link\n");
 		return r;
 	}
@@ -366,8 +425,7 @@ void dss_uninit_device(struct platform_device *pdev,
 	while ((attr = display_sysfs_attrs[i++]) != NULL)
 		device_remove_file(&dssdev->dev, attr);
 
-	if (dssdev->manager)
-		dssdev->manager->unset_device(dssdev->manager);
+	dss_uninit_connections(dssdev);
 }
 
 static int dss_suspend_device(struct device *dev, void *data)
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 98e8273..7a3fea6 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -263,7 +263,6 @@ void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr);
 void dss_init_overlays(struct platform_device *pdev);
 void dss_uninit_overlays(struct platform_device *pdev);
 void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
-void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
 int dss_ovl_simple_check(struct omap_overlay *ovl,
 		const struct omap_overlay_info *info);
 int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index 1bf05ef..52455a0 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -105,38 +105,6 @@ void dss_init_overlays(struct platform_device *pdev)
 	}
 }
 
-/* connect overlays to the new device, if not already connected. if force
- * selected, connect always. */
-void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
-{
-	struct omap_overlay_manager *mgr = NULL;
-	int i;
-
-	mgr =  omap_dss_get_overlay_manager(dssdev->channel);
-
-	if (!mgr->device || force) {
-		if (mgr->device)
-			mgr->unset_device(mgr);
-		mgr->set_device(mgr, dssdev);
-	}
-
-	if (mgr) {
-		dispc_runtime_get();
-
-		for (i = 0; i < dss_feat_get_num_ovls(); i++) {
-			struct omap_overlay *ovl;
-			ovl = omap_dss_get_overlay(i);
-			if (!ovl->manager || force) {
-				if (ovl->manager)
-					ovl->unset_manager(ovl);
-				ovl->set_manager(ovl, mgr);
-			}
-		}
-
-		dispc_runtime_put();
-	}
-}
-
 void dss_uninit_overlays(struct platform_device *pdev)
 {
 	int i;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 6/8] OMAPDSS: cleanup dss_recheck_connections
From: Tomi Valkeinen @ 2012-09-19  8:30 UTC (permalink / raw)
  To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348043438-2624-1-git-send-email-tomi.valkeinen@ti.com>

dss_recheck_connections is quite a mess. With the previous commit that
initializes the channel field for HDMI and VENC displays, we can greatly
simplify the dss_recheck_connections.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/overlay.c |   49 +++++--------------------------------
 1 file changed, 6 insertions(+), 43 deletions(-)

diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index e3d4068..1bf05ef 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -109,52 +109,15 @@ void dss_init_overlays(struct platform_device *pdev)
  * selected, connect always. */
 void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
 {
-	int i;
-	struct omap_overlay_manager *lcd_mgr;
-	struct omap_overlay_manager *tv_mgr;
-	struct omap_overlay_manager *lcd2_mgr = NULL;
-	struct omap_overlay_manager *lcd3_mgr = NULL;
 	struct omap_overlay_manager *mgr = NULL;
+	int i;
 
-	lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD);
-	tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_DIGIT);
-	if (dss_has_feature(FEAT_MGR_LCD3))
-		lcd3_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD3);
-	if (dss_has_feature(FEAT_MGR_LCD2))
-		lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD2);
-
-	if (dssdev->channel = OMAP_DSS_CHANNEL_LCD3) {
-		if (!lcd3_mgr->device || force) {
-			if (lcd3_mgr->device)
-				lcd3_mgr->unset_device(lcd3_mgr);
-			lcd3_mgr->set_device(lcd3_mgr, dssdev);
-			mgr = lcd3_mgr;
-		}
-	} else if (dssdev->channel = OMAP_DSS_CHANNEL_LCD2) {
-		if (!lcd2_mgr->device || force) {
-			if (lcd2_mgr->device)
-				lcd2_mgr->unset_device(lcd2_mgr);
-			lcd2_mgr->set_device(lcd2_mgr, dssdev);
-			mgr = lcd2_mgr;
-		}
-	} else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC
-			&& dssdev->type != OMAP_DISPLAY_TYPE_HDMI) {
-		if (!lcd_mgr->device || force) {
-			if (lcd_mgr->device)
-				lcd_mgr->unset_device(lcd_mgr);
-			lcd_mgr->set_device(lcd_mgr, dssdev);
-			mgr = lcd_mgr;
-		}
-	}
+	mgr =  omap_dss_get_overlay_manager(dssdev->channel);
 
-	if (dssdev->type = OMAP_DISPLAY_TYPE_VENC
-			|| dssdev->type = OMAP_DISPLAY_TYPE_HDMI) {
-		if (!tv_mgr->device || force) {
-			if (tv_mgr->device)
-				tv_mgr->unset_device(tv_mgr);
-			tv_mgr->set_device(tv_mgr, dssdev);
-			mgr = tv_mgr;
-		}
+	if (!mgr->device || force) {
+		if (mgr->device)
+			mgr->unset_device(mgr);
+		mgr->set_device(mgr, dssdev);
 	}
 
 	if (mgr) {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 5/8] OMAPDSS: handle errors in dss_init_device
From: Tomi Valkeinen @ 2012-09-19  8:30 UTC (permalink / raw)
  To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348043438-2624-1-git-send-email-tomi.valkeinen@ti.com>

Add error handling to dss_init_device(), which has, for some reason,
been missing.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/core.c    |    4 +++-
 drivers/video/omap2/dss/display.c |   23 ++++++++++++++++++-----
 drivers/video/omap2/dss/dss.h     |    2 +-
 3 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 315f557..9315ece 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -358,7 +358,9 @@ static int dss_driver_probe(struct device *dev)
 				dev_name(dev), dssdev->driver_name,
 				dssdrv->driver.name);
 
-	dss_init_device(core.pdev, dssdev);
+	r = dss_init_device(core.pdev, dssdev);
+	if (r)
+		return r;
 
 	force = core.default_display_name &&
 		strcmp(core.default_display_name, dssdev->name) = 0;
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 5f09d503..f719010 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -320,26 +320,39 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,
 }
 EXPORT_SYMBOL(omapdss_default_get_timings);
 
-void dss_init_device(struct platform_device *pdev,
+int dss_init_device(struct platform_device *pdev,
 		struct omap_dss_device *dssdev)
 {
 	struct device_attribute *attr;
-	int i;
-	int r;
+	int i, r;
 
 	/* create device sysfs files */
 	i = 0;
 	while ((attr = display_sysfs_attrs[i++]) != NULL) {
 		r = device_create_file(&dssdev->dev, attr);
-		if (r)
+		if (r) {
+			for (i = i - 2; i >= 0; i--) {
+				attr = display_sysfs_attrs[i];
+				device_remove_file(&dssdev->dev, attr);
+			}
+
 			DSSERR("failed to create sysfs file\n");
+			return r;
+		}
 	}
 
 	/* create display? sysfs links */
 	r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
 			dev_name(&dssdev->dev));
-	if (r)
+	if (r) {
+		while ((attr = display_sysfs_attrs[i++]) != NULL)
+			device_remove_file(&dssdev->dev, attr);
+
 		DSSERR("failed to create sysfs display link\n");
+		return r;
+	}
+
+	return 0;
 }
 
 void dss_uninit_device(struct platform_device *pdev,
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index a977826..98e8273 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -228,7 +228,7 @@ int dss_suspend_all_devices(void);
 int dss_resume_all_devices(void);
 void dss_disable_all_devices(void);
 
-void dss_init_device(struct platform_device *pdev,
+int dss_init_device(struct platform_device *pdev,
 		struct omap_dss_device *dssdev);
 void dss_uninit_device(struct platform_device *pdev,
 		struct omap_dss_device *dssdev);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 4/8] OMAPDSS: explicitely initialize dssdev->channel for new displays
From: Tomi Valkeinen @ 2012-09-19  8:30 UTC (permalink / raw)
  To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348043438-2624-1-git-send-email-tomi.valkeinen@ti.com>

HDMI and VENC outputs always use the DIGIT output from DISPC. The dssdev
struct contains "channel" field which is used to specify the DISPC
output for the display, but this was not used for HDMI and VENC.

This patch fills the channel field explicitely for HDMI and VENC
displays so that we can always rely on the channel field.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/hdmi.c |    2 ++
 drivers/video/omap2/dss/venc.c |    2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 76d100b..3b10e18 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -946,6 +946,8 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
 	hdmi.ls_oe_gpio = priv->ls_oe_gpio;
 	hdmi.hpd_gpio = priv->hpd_gpio;
 
+	dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
+
 	r = hdmi_init_display(dssdev);
 	if (r) {
 		DSSERR("device %s init failed: %d\n", dssdev->name, r);
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index b9c0a8f..88fa6ea 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -773,6 +773,8 @@ static void __init venc_probe_pdata(struct platform_device *pdev)
 	if (!dssdev)
 		return;
 
+	dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
+
 	r = venc_init_display(dssdev);
 	if (r) {
 		DSSERR("device %s init failed: %d\n", dssdev->name, r);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 3/8] OMAPDSS: register only one display device per output
From: Tomi Valkeinen @ 2012-09-19  8:30 UTC (permalink / raw)
  To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348043438-2624-1-git-send-email-tomi.valkeinen@ti.com>

We have boards with multiple panel devices connected to the same
physical output, of which only one panel can be enabled at one time.
Examples of these are Overo, where you can use different daughter boards
that have different LCDs, and 3430SDP which has an LCD and a DVI output
and a physical switch to select the active display.

These are supported by omapdss so that we add all the possible display
devices at probe, but the displays are inactive until somebody enables
one. At this point the panel driver starts using the DSS, thus reserving
the physcal resource and excluding the other panels.

This is problematic:
- Panel drivers can't allocate their resources properly at probe(),
  because the resources can be shared with other panels. Thus they can
  be only reserved at enable time.
- Managing this in omapdss is confusing. It's not natural to have
  child devices, which may not even exist (for example, a daughterboard
  that is not connected).

Only some boards have multiple displays per output, and of those, only
very few have possibility of switching the display during runtime.
Because of the above points:
- We don't want to make omapdss and all the panel drivers more complex
  just because some boards have complex setups.
- Only few boards support runtime switching, and afaik even then it's
  not required. So we don't need to support runtime switching.

Thus we'll change to a model where we will have only one display device
per output and this cannot be (currently) changed at runtime. We'll
still have the possibility to select the display from multiple options
during boot with the default display option.

This patch accomplishes the above by changing how the output drivers
register the display device. Instead of registering all the devices
given from the board file, we'll only register one. If the default
display option is set, the output driver selects that display from its
displays. If the default display is not set, or the default display is
not one of the output's displays, the output driver selects the first
display.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/dpi.c  |   47 ++++++++++++++++++++++++++-------
 drivers/video/omap2/dss/dsi.c  |   51 ++++++++++++++++++++++++++---------
 drivers/video/omap2/dss/dss.h  |    1 +
 drivers/video/omap2/dss/hdmi.c |   57 ++++++++++++++++++++++++++++++----------
 drivers/video/omap2/dss/rfbi.c |   47 ++++++++++++++++++++++++++-------
 drivers/video/omap2/dss/sdi.c  |   47 ++++++++++++++++++++++++++-------
 drivers/video/omap2/dss/venc.c |   47 ++++++++++++++++++++++++++-------
 7 files changed, 231 insertions(+), 66 deletions(-)

diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 703fc1d..6f9a199 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -371,10 +371,14 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
 	return 0;
 }
 
-static void __init dpi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev)
 {
 	struct omap_dss_board_info *pdata = pdev->dev.platform_data;
-	int i, r;
+	const char *def_disp_name = dss_get_default_display_name();
+	struct omap_dss_device *def_dssdev;
+	int i;
+
+	def_dssdev = NULL;
 
 	for (i = 0; i < pdata->num_devices; ++i) {
 		struct omap_dss_device *dssdev = pdata->devices[i];
@@ -382,16 +386,39 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
 		if (dssdev->type != OMAP_DISPLAY_TYPE_DPI)
 			continue;
 
-		r = dpi_init_display(dssdev);
-		if (r) {
-			DSSERR("device %s init failed: %d\n", dssdev->name, r);
-			continue;
+		if (def_dssdev = NULL)
+			def_dssdev = dssdev;
+
+		if (def_disp_name != NULL &&
+				strcmp(dssdev->name, def_disp_name) = 0) {
+			def_dssdev = dssdev;
+			break;
 		}
+	}
 
-		r = omap_dss_register_device(dssdev, &pdev->dev);
-		if (r)
-			DSSERR("device %s register failed: %d\n",
-					dssdev->name, r);
+	return def_dssdev;
+}
+
+static void __init dpi_probe_pdata(struct platform_device *pdev)
+{
+	struct omap_dss_device *dssdev;
+	int r;
+
+	dssdev = dpi_find_dssdev(pdev);
+
+	if (!dssdev)
+		return;
+
+	r = dpi_init_display(dssdev);
+	if (r) {
+		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		return;
+	}
+
+	r = omap_dss_register_device(dssdev, &pdev->dev);
+	if (r) {
+		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		return;
 	}
 }
 
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index f7078fc..ee9ae52 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -5006,11 +5006,15 @@ static void dsi_put_clocks(struct platform_device *dsidev)
 		clk_put(dsi->sys_clk);
 }
 
-static void __init dsi_probe_pdata(struct platform_device *dsidev)
+static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev)
 {
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	struct omap_dss_board_info *pdata = dsidev->dev.platform_data;
-	int i, r;
+	struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+	struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
+	const char *def_disp_name = dss_get_default_display_name();
+	struct omap_dss_device *def_dssdev;
+	int i;
+
+	def_dssdev = NULL;
 
 	for (i = 0; i < pdata->num_devices; ++i) {
 		struct omap_dss_device *dssdev = pdata->devices[i];
@@ -5021,16 +5025,39 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
 		if (dssdev->phy.dsi.module != dsi->module_id)
 			continue;
 
-		r = dsi_init_display(dssdev);
-		if (r) {
-			DSSERR("device %s init failed: %d\n", dssdev->name, r);
-			continue;
+		if (def_dssdev = NULL)
+			def_dssdev = dssdev;
+
+		if (def_disp_name != NULL &&
+				strcmp(dssdev->name, def_disp_name) = 0) {
+			def_dssdev = dssdev;
+			break;
 		}
+	}
 
-		r = omap_dss_register_device(dssdev, &dsidev->dev);
-		if (r)
-			DSSERR("device %s register failed: %d\n",
-					dssdev->name, r);
+	return def_dssdev;
+}
+
+static void __init dsi_probe_pdata(struct platform_device *dsidev)
+{
+	struct omap_dss_device *dssdev;
+	int r;
+
+	dssdev = dsi_find_dssdev(dsidev);
+
+	if (!dssdev)
+		return;
+
+	r = dsi_init_display(dssdev);
+	if (r) {
+		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		return;
+	}
+
+	r = omap_dss_register_device(dssdev, &dsidev->dev);
+	if (r) {
+		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		return;
 	}
 }
 
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 7bac8ee..a977826 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -175,6 +175,7 @@ struct seq_file;
 struct platform_device;
 
 /* core */
+const char *dss_get_default_display_name(void);
 struct bus_type *dss_get_bus(void);
 struct regulator *dss_get_vdds_dsi(void);
 struct regulator *dss_get_vdds_sdi(void);
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index bb07143..76d100b 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -901,32 +901,61 @@ int hdmi_audio_config(struct omap_dss_audio *audio)
 
 #endif
 
-static void __init hdmi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev)
 {
 	struct omap_dss_board_info *pdata = pdev->dev.platform_data;
-	int r, i;
+	const char *def_disp_name = dss_get_default_display_name();
+	struct omap_dss_device *def_dssdev;
+	int i;
+
+	def_dssdev = NULL;
 
 	for (i = 0; i < pdata->num_devices; ++i) {
 		struct omap_dss_device *dssdev = pdata->devices[i];
-		struct omap_dss_hdmi_data *priv = dssdev->data;
 
 		if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI)
 			continue;
 
-		hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio;
-		hdmi.ls_oe_gpio = priv->ls_oe_gpio;
-		hdmi.hpd_gpio = priv->hpd_gpio;
+		if (def_dssdev = NULL)
+			def_dssdev = dssdev;
 
-		r = hdmi_init_display(dssdev);
-		if (r) {
-			DSSERR("device %s init failed: %d\n", dssdev->name, r);
-			continue;
+		if (def_disp_name != NULL &&
+				strcmp(dssdev->name, def_disp_name) = 0) {
+			def_dssdev = dssdev;
+			break;
 		}
+	}
+
+	return def_dssdev;
+}
+
+static void __init hdmi_probe_pdata(struct platform_device *pdev)
+{
+	struct omap_dss_device *dssdev;
+	struct omap_dss_hdmi_data *priv;
+	int r;
 
-		r = omap_dss_register_device(dssdev, &pdev->dev);
-		if (r)
-			DSSERR("device %s register failed: %d\n",
-					dssdev->name, r);
+	dssdev = hdmi_find_dssdev(pdev);
+
+	if (!dssdev)
+		return;
+
+	priv = dssdev->data;
+
+	hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio;
+	hdmi.ls_oe_gpio = priv->ls_oe_gpio;
+	hdmi.hpd_gpio = priv->hpd_gpio;
+
+	r = hdmi_init_display(dssdev);
+	if (r) {
+		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		return;
+	}
+
+	r = omap_dss_register_device(dssdev, &pdev->dev);
+	if (r) {
+		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		return;
 	}
 }
 
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 845b4e7..1127037 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -942,10 +942,14 @@ static int __init rfbi_init_display(struct omap_dss_device *dssdev)
 	return 0;
 }
 
-static void __init rfbi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev)
 {
 	struct omap_dss_board_info *pdata = pdev->dev.platform_data;
-	int i, r;
+	const char *def_disp_name = dss_get_default_display_name();
+	struct omap_dss_device *def_dssdev;
+	int i;
+
+	def_dssdev = NULL;
 
 	for (i = 0; i < pdata->num_devices; ++i) {
 		struct omap_dss_device *dssdev = pdata->devices[i];
@@ -953,16 +957,39 @@ static void __init rfbi_probe_pdata(struct platform_device *pdev)
 		if (dssdev->type != OMAP_DISPLAY_TYPE_DBI)
 			continue;
 
-		r = rfbi_init_display(dssdev);
-		if (r) {
-			DSSERR("device %s init failed: %d\n", dssdev->name, r);
-			continue;
+		if (def_dssdev = NULL)
+			def_dssdev = dssdev;
+
+		if (def_disp_name != NULL &&
+				strcmp(dssdev->name, def_disp_name) = 0) {
+			def_dssdev = dssdev;
+			break;
 		}
+	}
+
+	return def_dssdev;
+}
+
+static void __init rfbi_probe_pdata(struct platform_device *pdev)
+{
+	struct omap_dss_device *dssdev;
+	int r;
+
+	dssdev = rfbi_find_dssdev(pdev);
 
-		r = omap_dss_register_device(dssdev, &pdev->dev);
-		if (r)
-			DSSERR("device %s register failed: %d\n",
-				dssdev->name, r);
+	if (!dssdev)
+		return;
+
+	r = rfbi_init_display(dssdev);
+	if (r) {
+		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		return;
+	}
+
+	r = omap_dss_register_device(dssdev, &pdev->dev);
+	if (r) {
+		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		return;
 	}
 }
 
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index c9a9045..0aaa7f3 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -195,10 +195,14 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev)
 	return 0;
 }
 
-static void __init sdi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev)
 {
 	struct omap_dss_board_info *pdata = pdev->dev.platform_data;
-	int i, r;
+	const char *def_disp_name = dss_get_default_display_name();
+	struct omap_dss_device *def_dssdev;
+	int i;
+
+	def_dssdev = NULL;
 
 	for (i = 0; i < pdata->num_devices; ++i) {
 		struct omap_dss_device *dssdev = pdata->devices[i];
@@ -206,16 +210,39 @@ static void __init sdi_probe_pdata(struct platform_device *pdev)
 		if (dssdev->type != OMAP_DISPLAY_TYPE_SDI)
 			continue;
 
-		r = sdi_init_display(dssdev);
-		if (r) {
-			DSSERR("device %s init failed: %d\n", dssdev->name, r);
-			continue;
+		if (def_dssdev = NULL)
+			def_dssdev = dssdev;
+
+		if (def_disp_name != NULL &&
+				strcmp(dssdev->name, def_disp_name) = 0) {
+			def_dssdev = dssdev;
+			break;
 		}
+	}
 
-		r = omap_dss_register_device(dssdev, &pdev->dev);
-		if (r)
-			DSSERR("device %s register failed: %d\n",
-					dssdev->name, r);
+	return def_dssdev;
+}
+
+static void __init sdi_probe_pdata(struct platform_device *pdev)
+{
+	struct omap_dss_device *dssdev;
+	int r;
+
+	dssdev = sdi_find_dssdev(pdev);
+
+	if (!dssdev)
+		return;
+
+	r = sdi_init_display(dssdev);
+	if (r) {
+		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		return;
+	}
+
+	r = omap_dss_register_device(dssdev, &pdev->dev);
+	if (r) {
+		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		return;
 	}
 }
 
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 60bfc58..b9c0a8f 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -735,10 +735,14 @@ static void venc_put_clocks(void)
 		clk_put(venc.tv_dac_clk);
 }
 
-static void __init venc_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev)
 {
 	struct omap_dss_board_info *pdata = pdev->dev.platform_data;
-	int r, i;
+	const char *def_disp_name = dss_get_default_display_name();
+	struct omap_dss_device *def_dssdev;
+	int i;
+
+	def_dssdev = NULL;
 
 	for (i = 0; i < pdata->num_devices; ++i) {
 		struct omap_dss_device *dssdev = pdata->devices[i];
@@ -746,16 +750,39 @@ static void __init venc_probe_pdata(struct platform_device *pdev)
 		if (dssdev->type != OMAP_DISPLAY_TYPE_VENC)
 			continue;
 
-		r = venc_init_display(dssdev);
-		if (r) {
-			DSSERR("device %s init failed: %d\n", dssdev->name, r);
-			continue;
+		if (def_dssdev = NULL)
+			def_dssdev = dssdev;
+
+		if (def_disp_name != NULL &&
+				strcmp(dssdev->name, def_disp_name) = 0) {
+			def_dssdev = dssdev;
+			break;
 		}
+	}
+
+	return def_dssdev;
+}
+
+static void __init venc_probe_pdata(struct platform_device *pdev)
+{
+	struct omap_dss_device *dssdev;
+	int r;
+
+	dssdev = venc_find_dssdev(pdev);
+
+	if (!dssdev)
+		return;
+
+	r = venc_init_display(dssdev);
+	if (r) {
+		DSSERR("device %s init failed: %d\n", dssdev->name, r);
+		return;
+	}
 
-		r = omap_dss_register_device(dssdev, &pdev->dev);
-		if (r)
-			DSSERR("device %s register failed: %d\n",
-					dssdev->name, r);
+	r = omap_dss_register_device(dssdev, &pdev->dev);
+	if (r) {
+		DSSERR("device %s register failed: %d\n", dssdev->name, r);
+		return;
 	}
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 2/8] OMAPDSS: Add dss_get_default_display_name()
From: Tomi Valkeinen @ 2012-09-19  8:30 UTC (permalink / raw)
  To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348043438-2624-1-git-send-email-tomi.valkeinen@ti.com>

Add function dss_get_default_display_name() which returns the name of
the default display, given from the board file or via module parameters.
The default display name can be used by output drivers to decide which
display is the wanted one.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/core.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 20c8bc8..315f557 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -57,6 +57,11 @@ bool dss_debug;
 module_param_named(debug, dss_debug, bool, 0644);
 #endif
 
+const char *dss_get_default_display_name(void)
+{
+	return core.default_display_name;
+}
+
 /* REGULATORS */
 
 struct regulator *dss_get_vdds_dsi(void)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 1/8] OMAPDSS: omap_dss_register_device() doesn't take display index
From: Tomi Valkeinen @ 2012-09-19  8:30 UTC (permalink / raw)
  To: archit, linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1348043438-2624-1-git-send-email-tomi.valkeinen@ti.com>

We used to have all the displays of the board in one list, and we made a
"displayX" directory in the sysfs, where X was the index of the display
in the list.

This doesn't work anymore with device tree, as there's no single list to
get the number from, and it doesn't work very well even with non-DT as
we need to do some tricks to get the index nowadays.

This patch changes omap_dss_register_device() so that it doesn't take
disp_num as a parameter anymore, but uses a private increasing counter
for the display number.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/core.c |    9 +++++----
 drivers/video/omap2/dss/dpi.c  |    2 +-
 drivers/video/omap2/dss/dsi.c  |    2 +-
 drivers/video/omap2/dss/dss.h  |    2 +-
 drivers/video/omap2/dss/hdmi.c |    2 +-
 drivers/video/omap2/dss/rfbi.c |    2 +-
 drivers/video/omap2/dss/sdi.c  |    2 +-
 drivers/video/omap2/dss/venc.c |    2 +-
 8 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 58bd9c2..20c8bc8 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -450,16 +450,17 @@ static void omap_dss_dev_release(struct device *dev)
 	reset_device(dev, 0);
 }
 
+static int disp_num_counter;
+
 int omap_dss_register_device(struct omap_dss_device *dssdev,
-		struct device *parent, int disp_num)
+		struct device *parent)
 {
-	WARN_ON(!dssdev->driver_name);
-
 	reset_device(&dssdev->dev, 1);
+
 	dssdev->dev.bus = &dss_bus_type;
 	dssdev->dev.parent = parent;
 	dssdev->dev.release = omap_dss_dev_release;
-	dev_set_name(&dssdev->dev, "display%d", disp_num);
+	dev_set_name(&dssdev->dev, "display%d", disp_num_counter++);
 	return device_register(&dssdev->dev);
 }
 
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 5ccce9b..703fc1d 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -388,7 +388,7 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
 			continue;
 		}
 
-		r = omap_dss_register_device(dssdev, &pdev->dev, i);
+		r = omap_dss_register_device(dssdev, &pdev->dev);
 		if (r)
 			DSSERR("device %s register failed: %d\n",
 					dssdev->name, r);
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 8d815e3..f7078fc 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -5027,7 +5027,7 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
 			continue;
 		}
 
-		r = omap_dss_register_device(dssdev, &dsidev->dev, i);
+		r = omap_dss_register_device(dssdev, &dsidev->dev);
 		if (r)
 			DSSERR("device %s register failed: %d\n",
 					dssdev->name, r);
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 5e9fd769..7bac8ee 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -185,7 +185,7 @@ int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
 int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
 
 int omap_dss_register_device(struct omap_dss_device *dssdev,
-		struct device *parent, int disp_num);
+		struct device *parent);
 void omap_dss_unregister_device(struct omap_dss_device *dssdev);
 void omap_dss_unregister_child_devices(struct device *parent);
 
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 83f1845..bb07143 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -923,7 +923,7 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
 			continue;
 		}
 
-		r = omap_dss_register_device(dssdev, &pdev->dev, i);
+		r = omap_dss_register_device(dssdev, &pdev->dev);
 		if (r)
 			DSSERR("device %s register failed: %d\n",
 					dssdev->name, r);
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 2e520d3..845b4e7 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -959,7 +959,7 @@ static void __init rfbi_probe_pdata(struct platform_device *pdev)
 			continue;
 		}
 
-		r = omap_dss_register_device(dssdev, &pdev->dev, i);
+		r = omap_dss_register_device(dssdev, &pdev->dev);
 		if (r)
 			DSSERR("device %s register failed: %d\n",
 				dssdev->name, r);
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 66c8de4..c9a9045 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -212,7 +212,7 @@ static void __init sdi_probe_pdata(struct platform_device *pdev)
 			continue;
 		}
 
-		r = omap_dss_register_device(dssdev, &pdev->dev, i);
+		r = omap_dss_register_device(dssdev, &pdev->dev);
 		if (r)
 			DSSERR("device %s register failed: %d\n",
 					dssdev->name, r);
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 17b3102..60bfc58 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -752,7 +752,7 @@ static void __init venc_probe_pdata(struct platform_device *pdev)
 			continue;
 		}
 
-		r = omap_dss_register_device(dssdev, &pdev->dev, i);
+		r = omap_dss_register_device(dssdev, &pdev->dev);
 		if (r)
 			DSSERR("device %s register failed: %d\n",
 					dssdev->name, r);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 0/8] OMAPDSS: dss device model changes
From: Tomi Valkeinen @ 2012-09-19  8:30 UTC (permalink / raw)
  To: archit, linux-omap, linux-fbdev
  Cc: Tomi Valkeinen, Steve Sakoman, Lajos Molnar, Jassi Brar,
	Grazvydas Ignotas, Vaibhav Hiremath

Hi,

This series contains patches that change how omapdss's panel devices
(omap_dss_device) are initialized and registered. There are two patches that
change behaviour, the rest should be just cleanups:

The patch "omap_dss_register_device() doesn't take display index" affects the
number for the "displayX" sysfs files. This hopefully doesn't affect the
userspace, as the number has never been a clear indication of what the
particular display is.

The patch "register only one display device per output" affects how panel
devices are created. Currently we support multiple panels per output, i.e. you
could have DVI and an LCD displays using the same DPI output, as long as the
DVI and LCD are not used at the same time.

This patch changes the omapdss driver to only register one display device per
output. If there are multiple displays for the output, either the first one is
picked or, if def_display has been defined in kernel parameters and the
def_display is one of the displays for this output, the def_display is picked.
See the patch for more information.

My belief is that neither patch should break things, but there's the
possibility. So I've tried to cc people who might have an opinion about this,
or perhaps test their setup with these patches.

The series is based on the latest omapdss master branch, and is available at:

git://gitorious.org/linux-omap-dss2/linux.git work/devtree-base

 Tomi

Tomi Valkeinen (8):
  OMAPDSS: omap_dss_register_device() doesn't take display index
  OMAPDSS: Add dss_get_default_display_name()
  OMAPDSS: register only one display device per output
  OMAPDSS: explicitely initialize dssdev->channel for new displays
  OMAPDSS: handle errors in dss_init_device
  OMAPDSS: cleanup dss_recheck_connections
  OMAPDSS: cleanup dss_recheck_connections further
  OMAPDSS: alloc dssdevs dynamically

 drivers/video/omap2/dss/core.c    |   91 +++++++++++++++++++------------------
 drivers/video/omap2/dss/display.c |   85 +++++++++++++++++++++++++++++++---
 drivers/video/omap2/dss/dpi.c     |   58 ++++++++++++++++++-----
 drivers/video/omap2/dss/dsi.c     |   62 +++++++++++++++++++------
 drivers/video/omap2/dss/dss.h     |   15 +++---
 drivers/video/omap2/dss/hdmi.c    |   70 ++++++++++++++++++++++------
 drivers/video/omap2/dss/overlay.c |   69 ----------------------------
 drivers/video/omap2/dss/rfbi.c    |   58 ++++++++++++++++++-----
 drivers/video/omap2/dss/sdi.c     |   58 ++++++++++++++++++-----
 drivers/video/omap2/dss/venc.c    |   60 +++++++++++++++++++-----
 10 files changed, 428 insertions(+), 198 deletions(-)

-- 
1.7.9.5


^ permalink raw reply

* [PATCH v4] of: Add videomode helper
From: Steffen Trumtrar @ 2012-09-19  8:20 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Laurent Pinchart,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Steffen Trumtrar

This patch adds a helper function for parsing videomodes from the devicetree.
The videomode can be either converted to a struct drm_display_mode or a
struct fb_videomode.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---

Hi!

changes since v3:
	- print error messages
	- free alloced memory
	- general cleanup

Regards
Steffen

 .../devicetree/bindings/video/displaymode          |   74 +++++
 drivers/of/Kconfig                                 |    5 +
 drivers/of/Makefile                                |    1 +
 drivers/of/of_videomode.c                          |  283 ++++++++++++++++++++
 include/linux/of_videomode.h                       |   56 ++++
 5 files changed, 419 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/video/displaymode
 create mode 100644 drivers/of/of_videomode.c
 create mode 100644 include/linux/of_videomode.h

diff --git a/Documentation/devicetree/bindings/video/displaymode b/Documentation/devicetree/bindings/video/displaymode
new file mode 100644
index 0000000..990ca52
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/displaymode
@@ -0,0 +1,74 @@
+videomode bindings
+=========
+
+Required properties:
+ - hactive, vactive: Display resolution
+ - hfront-porch, hback-porch, hsync-len: Horizontal Display timing parameters
+   in pixels
+   vfront-porch, vback-porch, vsync-len: Vertical display timing parameters in
+   lines
+ - clock: displayclock in Hz
+
+Optional properties:
+ - width-mm, height-mm: Display dimensions in mm
+ - hsync-active-high (bool): Hsync pulse is active high
+ - vsync-active-high (bool): Vsync pulse is active high
+ - interlaced (bool): This is an interlaced mode
+ - doublescan (bool): This is a doublescan mode
+
+There are different ways of describing a display mode. The devicetree representation
+corresponds to the one commonly found in datasheets for displays.
+The description of the display and its mode is split in two parts: first the display
+properties like size in mm and (optionally) multiple subnodes with the supported modes.
+
+Example:
+
+	display@0 {
+		width-mm = <800>;
+		height-mm = <480>;
+		modes {
+			mode0: mode@0 {
+				/* 1920x1080p24 */
+				clock = <52000000>;
+				hactive = <1920>;
+				vactive = <1080>;
+				hfront-porch = <25>;
+				hback-porch = <25>;
+				hsync-len = <25>;
+				vback-porch = <2>;
+				vfront-porch = <2>;
+				vsync-len = <2>;
+				hsync-active-high;
+			};
+		};
+	};
+
+Every property also supports the use of ranges, so the commonly used datasheet
+description with <min typ max>-tuples can be used.
+
+Example:
+
+	mode1: mode@1 {
+		/* 1920x1080p24 */
+		clock = <148500000>;
+		hactive = <1920>;
+		vactive = <1080>;
+		hsync-len = <0 44 60>;
+		hfront-porch = <80 88 95>;
+		hback-porch = <100 148 160>;
+		vfront-porch = <0 4 6>;
+		vback-porch = <0 36 50>;
+		vsync-len = <0 5 6>;
+	};
+
+The videomode can be linked to a connector via phandles. The connector has to
+support the display- and default-mode-property to link to and select a mode.
+
+Example:
+
+	hdmi@00120000 {
+		status = "okay";
+		display = <&benq>;
+		default-mode = <&mode1>;
+	};
+
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index dfba3e6..a3acaa3 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -83,4 +83,9 @@ config OF_MTD
 	depends on MTD
 	def_bool y
 
+config OF_VIDEOMODE
+	def_bool y
+	help
+	  helper to parse videomodes from the devicetree
+
 endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index e027f44..80e6db3 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
 obj-$(CONFIG_OF_PCI)	+= of_pci.o
 obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
 obj-$(CONFIG_OF_MTD)	+= of_mtd.o
+obj-$(CONFIG_OF_VIDEOMODE)	+= of_videomode.o
diff --git a/drivers/of/of_videomode.c b/drivers/of/of_videomode.c
new file mode 100644
index 0000000..52bfc74
--- /dev/null
+++ b/drivers/of/of_videomode.c
@@ -0,0 +1,283 @@
+/*
+ * OF helpers for parsing display modes
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
+ *
+ * This file is released under the GPLv2
+ */
+#include <linux/of.h>
+#include <linux/fb.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <linux/of_videomode.h>
+
+static u32 of_video_get_value(struct mode_property *prop)
+{
+	return (prop->min >= prop->typ) ? prop->min : prop->typ;
+}
+
+/* read property into new mode_property */
+static int of_video_parse_property(struct device_node *np, char *name,
+				struct mode_property *result)
+{
+	struct property *prop;
+	int length;
+	int cells;
+	int ret;
+
+	prop = of_find_property(np, name, &length);
+	if (!prop) {
+		pr_err("%s: could not find property %s\n", __func__,
+			name);
+		return -EINVAL;
+	}
+
+	cells = length / sizeof(u32);
+
+	memset(result, 0, sizeof(*result));
+
+	ret = of_property_read_u32_array(np, name, &result->min, cells);
+
+	return ret;
+}
+
+static int of_video_free(struct display *disp)
+{
+	int i;
+
+	for (i=0; i<disp->num_modes; i++)
+		kfree(disp->modes[i]);
+	kfree(disp->modes);
+
+	return 0;
+}
+
+int videomode_to_display_mode(struct display *disp, struct drm_display_mode *dmode, int index)
+{
+	struct videomode *vm;
+
+	memset(dmode, 0, sizeof(*dmode));
+
+	if (index > disp->num_modes) {
+		pr_err("%s: wrong index: %d from %d\n", __func__, index, disp->num_modes);
+		return -EINVAL;
+	}
+
+	vm = disp->modes[index];
+
+	dmode->hdisplay = of_video_get_value(&vm->hactive);
+	dmode->hsync_start = of_video_get_value(&vm->hactive) + of_video_get_value(&vm->hfront_porch);
+	dmode->hsync_end = of_video_get_value(&vm->hactive) + of_video_get_value(&vm->hfront_porch)
+			+ of_video_get_value(&vm->hsync_len);
+	dmode->htotal = of_video_get_value(&vm->hactive) + of_video_get_value(&vm->hfront_porch)
+			+ of_video_get_value(&vm->hsync_len) + of_video_get_value(&vm->hback_porch);
+
+	dmode->vdisplay = of_video_get_value(&vm->vactive);
+	dmode->vsync_start = of_video_get_value(&vm->vactive) + of_video_get_value(&vm->vfront_porch);
+	dmode->vsync_end = of_video_get_value(&vm->vactive) + of_video_get_value(&vm->vfront_porch)
+			+ of_video_get_value(&vm->vsync_len);
+	dmode->vtotal = of_video_get_value(&vm->vactive) + of_video_get_value(&vm->vfront_porch) +
+			of_video_get_value(&vm->vsync_len) + of_video_get_value(&vm->vback_porch);
+
+	dmode->width_mm = disp->width_mm;
+	dmode->height_mm = disp->height_mm;
+
+	dmode->clock = of_video_get_value(&vm->clock) / 1000;
+
+	if (vm->hah)
+		dmode->flags |= DRM_MODE_FLAG_PHSYNC;
+	else
+		dmode->flags |= DRM_MODE_FLAG_NHSYNC;
+	if (vm->vah)
+		dmode->flags |= DRM_MODE_FLAG_PVSYNC;
+	else
+		dmode->flags |= DRM_MODE_FLAG_NVSYNC;
+	if (vm->interlaced)
+		dmode->flags |= DRM_MODE_FLAG_INTERLACE;
+	if (vm->doublescan)
+		dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
+
+	drm_mode_set_name(dmode);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(videomode_to_display_mode);
+
+int videomode_to_fb_mode(struct display *disp, struct fb_videomode *fbmode, int index)
+{
+	struct videomode *vm;
+
+	memset(fbmode, 0, sizeof(*fbmode));
+
+	if (index > disp->num_modes) {
+		pr_err("%s: wrong index: %d from %d\n", __func__, index, disp->num_modes);
+		return -EINVAL;
+	}
+
+	vm = disp->modes[index];
+
+	fbmode->xres = of_video_get_value(&vm->hactive);
+	fbmode->left_margin = of_video_get_value(&vm->hback_porch);
+	fbmode->right_margin = of_video_get_value(&vm->hfront_porch);
+	fbmode->hsync_len = of_video_get_value(&vm->hsync_len);
+
+	fbmode->yres = of_video_get_value(&vm->vactive);
+	fbmode->upper_margin = of_video_get_value(&vm->vback_porch);
+	fbmode->lower_margin = of_video_get_value(&vm->vfront_porch);
+	fbmode->vsync_len = of_video_get_value(&vm->vsync_len);
+
+	fbmode->pixclock = KHZ2PICOS(of_video_get_value(&vm->clock) / 1000);
+
+	if (vm->hah)
+		fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (vm->vah)
+		fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
+	if (vm->interlaced)
+		fbmode->vmode |= FB_VMODE_INTERLACED;
+	if (vm->doublescan)
+		fbmode->vmode |= FB_VMODE_DOUBLE;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(videomode_to_fb_mode);
+
+int of_get_video_modes(struct device_node *np, struct display *disp)
+{
+	struct device_node *display_np;
+	struct device_node *mode_np;
+	struct device_node *modes_np;
+	char *default_mode;
+
+	int ret = 0;
+
+	memset(disp, 0, sizeof(*disp));
+	disp->modes = kmalloc(sizeof(struct videomode*), GFP_KERNEL);
+
+	if (!np) {
+		pr_err("%s: no node provided\n", __func__);
+		return -EINVAL;
+	}
+
+	display_np = of_parse_phandle(np, "display", 0);
+
+	if (!display_np) {
+		pr_err("%s: could not find display node\n", __func__);
+		return -EINVAL;
+	}
+
+	of_property_read_u32(display_np, "width-mm", &disp->width_mm);
+	of_property_read_u32(display_np, "height-mm", &disp->height_mm);
+
+	mode_np = of_parse_phandle(np, "default-mode", 0);
+
+	if (!mode_np) {
+		pr_info("%s: no default-mode specified.\n", __func__);
+		mode_np = of_find_node_by_name(np, "mode");
+	}
+
+	if (!mode_np) {
+		pr_err("%s: could not find any mode specification\n", __func__);
+		return -EINVAL;
+	}
+
+	default_mode = (char *)mode_np->full_name;
+
+	modes_np = of_find_node_by_name(np, "modes");
+	for_each_child_of_node(modes_np, mode_np) {
+		struct videomode *vm;
+
+		vm = kmalloc(sizeof(struct videomode*), GFP_KERNEL);
+		disp->modes[disp->num_modes] = kmalloc(sizeof(struct videomode*), GFP_KERNEL);
+
+		ret |= of_video_parse_property(mode_np, "hback-porch", &vm->hback_porch);
+		ret |= of_video_parse_property(mode_np, "hfront-porch", &vm->hfront_porch);
+		ret |= of_video_parse_property(mode_np, "hactive", &vm->hactive);
+		ret |= of_video_parse_property(mode_np, "hsync-len", &vm->hsync_len);
+		ret |= of_video_parse_property(mode_np, "vback-porch", &vm->vback_porch);
+		ret |= of_video_parse_property(mode_np, "vfront-porch", &vm->vfront_porch);
+		ret |= of_video_parse_property(mode_np, "vactive", &vm->vactive);
+		ret |= of_video_parse_property(mode_np, "vsync-len", &vm->vsync_len);
+		ret |= of_video_parse_property(mode_np, "clock", &vm->clock);
+
+		if (ret)
+			return -EINVAL;
+
+		vm->hah = of_property_read_bool(mode_np, "hsync-active-high");
+		vm->vah = of_property_read_bool(mode_np, "vsync-active-high");
+		vm->interlaced = of_property_read_bool(mode_np, "interlaced");
+		vm->doublescan = of_property_read_bool(mode_np, "doublescan");
+
+		if (strcmp(default_mode,mode_np->full_name) = 0)
+			disp->default_mode = disp->num_modes;
+
+		disp->modes[disp->num_modes] = vm;
+		disp->num_modes++;
+	}
+	of_node_put(display_np);
+
+	pr_info("%s: found %d modelines. Using #%d as default\n", __func__,
+		disp->num_modes, disp->default_mode + 1);
+
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_video_modes);
+
+int of_video_mode_exists(struct device_node *np)
+{
+	struct device_node *display_np;
+	struct device_node *mode_np;
+
+	if (!np)
+		return -EINVAL;
+
+	display_np = of_parse_phandle(np, "display", 0);
+
+	if (!display_np)
+		return -EINVAL;
+
+	mode_np = of_parse_phandle(np, "default-mode", 0);
+
+	if (mode_np)
+		return 0;
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(of_video_mode_exists);
+
+int of_get_display_mode(struct device_node *np, struct drm_display_mode *dmode, int index)
+{
+	struct display disp;
+
+	of_get_video_modes(np, &disp);
+
+	if (index = OF_MODE_SELECTION)
+		index = disp.default_mode;
+	if (dmode)
+		videomode_to_display_mode(&disp, dmode, index);
+
+	of_video_free(&disp);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_display_mode);
+
+int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fbmode, int index)
+{
+	struct display disp;
+
+	of_get_video_modes(np, &disp);
+
+	if (index = OF_MODE_SELECTION)
+		index = disp.default_mode;
+	if (fbmode)
+		videomode_to_fb_mode(&disp, fbmode, index);
+
+	of_video_free(&disp);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_fb_videomode);
diff --git a/include/linux/of_videomode.h b/include/linux/of_videomode.h
new file mode 100644
index 0000000..5571ce3
--- /dev/null
+++ b/include/linux/of_videomode.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * OF helpers for videomodes.
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_OF_VIDEOMODE_H
+#define __LINUX_OF_VIDEOMODE_H
+
+#define OF_MODE_SELECTION -1
+
+struct mode_property {
+	u32 min;
+	u32 typ;
+	u32 max;
+};
+
+struct display {
+	u32 width_mm;
+	u32 height_mm;
+	struct videomode **modes;
+	int default_mode;
+	int num_modes;
+};
+
+/* describe videomode in terms of hardware parameters */
+struct videomode {
+	struct mode_property hback_porch;
+	struct mode_property hfront_porch;
+	struct mode_property hactive;
+	struct mode_property hsync_len;
+
+	struct mode_property vback_porch;
+	struct mode_property vfront_porch;
+	struct mode_property vactive;
+	struct mode_property vsync_len;
+
+	struct mode_property clock;
+
+	bool hah;
+	bool vah;
+	bool interlaced;
+	bool doublescan;
+};
+
+int of_video_mode_exists(struct device_node *np);
+int videomode_to_display_mode(struct display *disp, struct drm_display_mode *dmode, int index);
+int videomode_to_fb_mode(struct display *disp, struct fb_videomode *fbmode, int index);
+int of_get_video_modes(struct device_node *np, struct display *disp);
+int of_video_mode_exists(struct device_node *np);
+int of_get_display_mode(struct device_node *np, struct drm_display_mode *dmode, int index);
+int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fbmode, int index);
+#endif /* __LINUX_OF_VIDEOMODE_H */
-- 
1.7.10.4


^ permalink raw reply related

* Re: [PATCH v6 0/4] Runtime Interpreted Power Sequences
From: Mark Brown @ 2012-09-19  3:01 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Alex Courbot, linux-fbdev@vger.kernel.org, Stephen Warren,
	linux-pm@vger.kernel.org, Leela Krishna Amudala,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	Rob Herring, Anton Vorontsov, Tomi Valkeinen,
	linux-tegra@vger.kernel.org, David Woodhouse,
	devicetree-discuss@lists.ozlabs.org
In-Reply-To: <5051FAC5.40501@wwwdotorg.org>

On Thu, Sep 13, 2012 at 09:24:53AM -0600, Stephen Warren wrote:
> On 09/13/2012 01:29 AM, Mark Brown wrote:

> > The driver knows the power sequence.  Having to type the same sequence
> > into the DT or platform data for each board using the device wouuld be
> > retarded so we need the drivers to be able to give the sequence to the
> > library if they're going to be able to reuse it (which is a lot of what
> > Tomi is talking about).

> I believe that's trivial to implement. The relevant function is:

Right, that's what I'm saying - the code is mostly there now.

> It's up to the driver whether pseq comes from platform data or is
> hard-coded into the driver (or not provided at all, for the DT case).
> So, the only change needed to convert a "hard-coded" driver to this API
> is to convert the current custom data structure (or code) that describes
> the sequence into a struct platform_power_seq_set.

The framework could still help by providing ways to avoid having to copy
the structure and fill in the blanks for GPIO numbers (and anything else
that is numbered rather than named) by hand.

^ permalink raw reply

* Re: [PATCH 2/2] video: exynos_mipi_dsi: Fix potential NULL pointer dereference
From: Sachin Kamat @ 2012-09-19  2:49 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1347968280-22343-2-git-send-email-sachin.kamat@linaro.org>

On 19 September 2012 07:58, Inki Dae <inki.dae@samsung.com> wrote:
>
>
>> -----Original Message-----
>> From: Sachin Kamat [mailto:sachin.kamat@linaro.org]
>> Sent: Tuesday, September 18, 2012 8:38 PM
>> To: linux-fbdev@vger.kernel.org
>> Cc: inki.dae@samsung.com; dh09.lee@samsung.com; FlorianSchandinat@gmx.de;
>> sachin.kamat@linaro.org; patches@linaro.org
>> Subject: [PATCH 2/2] video: exynos_mipi_dsi: Fix potential NULL pointer
>> dereference
>>
>> The error message printed when dsim is NULL references its member.
>> This will cause NULL pointer derefernce error. Hence change dev_err
>> to pr_err to avoid it.
>>
>> Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
>> ---
>>  drivers/video/exynos/exynos_mipi_dsi_common.c |    2 +-
>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c
>> b/drivers/video/exynos/exynos_mipi_dsi_common.c
>> index 7cc4113..4fc64c4 100644
>> --- a/drivers/video/exynos/exynos_mipi_dsi_common.c
>> +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c
>> @@ -80,7 +80,7 @@ irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq,
>> void *dev_id)
>>       unsigned int intsrc, intmsk;
>>
>>       if (dsim = NULL) {
>> -             dev_err(dsim->dev, "%s: wrong parameter\n", __func__);
>> +             pr_err("%s: wrong parameter\n", __func__);
>>               return IRQ_NONE;
>>       }
>
> Please, just remove above exception codes. dsim was allocated and already
> checked by probe so this exception isn't needed.

Yes, that looks better if it is already ensured to be non-NULL. I had
not checked that.
Will remove this check and re-send.

Thanks.

>
> Thanks,
> Inki Dae
>
>
>>
>> --
>> 1.7.4.1
>



-- 
With warm regards,
Sachin

^ permalink raw reply

* RE: [PATCH 2/2] video: exynos_mipi_dsi: Fix potential NULL pointer dereference
From: Inki Dae @ 2012-09-19  2:28 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1347968280-22343-2-git-send-email-sachin.kamat@linaro.org>



> -----Original Message-----
> From: Sachin Kamat [mailto:sachin.kamat@linaro.org]
> Sent: Tuesday, September 18, 2012 8:38 PM
> To: linux-fbdev@vger.kernel.org
> Cc: inki.dae@samsung.com; dh09.lee@samsung.com; FlorianSchandinat@gmx.de;
> sachin.kamat@linaro.org; patches@linaro.org
> Subject: [PATCH 2/2] video: exynos_mipi_dsi: Fix potential NULL pointer
> dereference
> 
> The error message printed when dsim is NULL references its member.
> This will cause NULL pointer derefernce error. Hence change dev_err
> to pr_err to avoid it.
> 
> Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
> ---
>  drivers/video/exynos/exynos_mipi_dsi_common.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c
> b/drivers/video/exynos/exynos_mipi_dsi_common.c
> index 7cc4113..4fc64c4 100644
> --- a/drivers/video/exynos/exynos_mipi_dsi_common.c
> +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c
> @@ -80,7 +80,7 @@ irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq,
> void *dev_id)
>  	unsigned int intsrc, intmsk;
> 
>  	if (dsim = NULL) {
> -		dev_err(dsim->dev, "%s: wrong parameter\n", __func__);
> +		pr_err("%s: wrong parameter\n", __func__);
>  		return IRQ_NONE;
>  	}

Please, just remove above exception codes. dsim was allocated and already
checked by probe so this exception isn't needed.

Thanks,
Inki Dae


> 
> --
> 1.7.4.1


^ permalink raw reply

* RE: [PATCH 1/2] video: exynos_mipi_dsi: Remove unused code
From: Inki Dae @ 2012-09-19  2:24 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1347968280-22343-1-git-send-email-sachin.kamat@linaro.org>

Acked-by: Inki Dae <inki.dae@samsung.com>

> -----Original Message-----
> From: Sachin Kamat [mailto:sachin.kamat@linaro.org]
> Sent: Tuesday, September 18, 2012 8:38 PM
> To: linux-fbdev@vger.kernel.org
> Cc: inki.dae@samsung.com; dh09.lee@samsung.com; FlorianSchandinat@gmx.de;
> sachin.kamat@linaro.org; patches@linaro.org
> Subject: [PATCH 1/2] video: exynos_mipi_dsi: Remove unused code
> 
> This code is never executed and hence removed.
> 
> Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
> ---
>  drivers/video/exynos/exynos_mipi_dsi_common.c |    3 ---
>  1 files changed, 0 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c
> b/drivers/video/exynos/exynos_mipi_dsi_common.c
> index 47b533a..7cc4113 100644
> --- a/drivers/video/exynos/exynos_mipi_dsi_common.c
> +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c
> @@ -288,9 +288,6 @@ int exynos_mipi_dsi_wr_data(struct mipi_dsim_device
> *dsim, unsigned int data_id,
>  		mutex_unlock(&dsim->lock);
>  		return -EINVAL;
>  	}
> -
> -	mutex_unlock(&dsim->lock);
> -	return 0;
>  }
> 
>  static unsigned int exynos_mipi_dsi_long_data_rd(struct mipi_dsim_device
> *dsim,
> --
> 1.7.4.1


^ permalink raw reply

* [PATCH v2 02/13] video: Versatile Express display output driver
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1347977875-16855-1-git-send-email-pawel.moll@arm.com>

Versatile Express' DVI video output can be connected to one the three
sources - motherboard's CLCD controller or a video signal generated
by one of the daughterboards.

This driver configures the muxer FPGA so the output displays
content of one of the framebuffers in the system (0 by default,
can be changed by user writing to "fb" attribute of the muxfpga
device). The decision is based on an educated guess in case of
DT-less system or on the "arm,vexpress,site" property of the
display controller's DT node.

It will also set up the display formatter mode and keep it up
to date with mode changes requested by the user (eg. with fbset
tool).

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/video/Makefile       |    3 +
 drivers/video/vexpress-dvi.c |  208 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 211 insertions(+)
 create mode 100644 drivers/video/vexpress-dvi.c

Hi Florian,

Assuming it's not totally crap ;-) what would be you preference about
merging this patch? Would you take it through your tree?

Regards

Pawel

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ee8dafb..01d28d5 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -170,3 +170,6 @@ obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
 
 #video output switch sysfs driver
 obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
+
+# platform specific output drivers
+obj-$(CONFIG_VEXPRESS_CONFIG)	  += vexpress-dvi.o
diff --git a/drivers/video/vexpress-dvi.c b/drivers/video/vexpress-dvi.c
new file mode 100644
index 0000000..fc50fc6
--- /dev/null
+++ b/drivers/video/vexpress-dvi.c
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-dvi: " fmt
+
+#include <linux/fb.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/vexpress.h>
+
+
+static struct vexpress_config_func *vexpress_dvimode_func;
+
+static struct {
+	u32 xres, yres, mode;
+} vexpress_dvi_dvimodes[] = {
+	{ 640, 480, 0 }, /* VGA */
+	{ 800, 600, 1 }, /* SVGA */
+	{ 1024, 768, 2 }, /* XGA */
+	{ 1280, 1024, 3 }, /* SXGA */
+	{ 1600, 1200, 4 }, /* UXGA */
+	{ 1920, 1080, 5 }, /* HD1080 */
+};
+
+static void vexpress_dvi_mode_set(struct fb_info *info, u32 xres, u32 yres)
+{
+	int err = -ENOENT;
+	int i;
+
+	if (!vexpress_dvimode_func)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_dvi_dvimodes); i++) {
+		if (vexpress_dvi_dvimodes[i].xres == xres &&
+				vexpress_dvi_dvimodes[i].yres == yres) {
+			pr_debug("mode: %ux%u = %d\n", xres, yres,
+					vexpress_dvi_dvimodes[i].mode);
+			err = vexpress_config_write(vexpress_dvimode_func, 0,
+					vexpress_dvi_dvimodes[i].mode);
+			break;
+		}
+	}
+
+	if (err)
+		pr_warn("Failed to set %ux%u mode! (%d)\n", xres, yres, err);
+}
+
+
+static struct vexpress_config_func *vexpress_muxfpga_func;
+static int vexpress_dvi_fb = -1;
+
+static int vexpress_dvi_mux_set(struct fb_info *info)
+{
+	u32 site = vexpress_get_site_by_dev(info->device);
+	int err = vexpress_config_write(vexpress_muxfpga_func, 0, site);
+
+	if (!err) {
+		pr_debug("Selected MUXFPGA input %d (fb%d)\n", site,
+				info->node);
+		vexpress_dvi_fb = info->node;
+		vexpress_dvi_mode_set(info, info->var.xres,
+				info->var.yres);
+	} else {
+		pr_warn("Failed to select MUXFPGA input %d (fb%d)! (%d)\n",
+				site, info->node, err);
+	}
+
+	return err;
+}
+
+static int vexpress_dvi_fb_select(int fb)
+{
+	int err;
+	struct fb_info *info = registered_fb[fb];
+
+	if (!info || !lock_fb_info(info))
+		return -ENODEV;
+
+	err = vexpress_dvi_mux_set(info);
+
+	unlock_fb_info(info);
+
+	return err;
+}
+
+static ssize_t vexpress_dvi_fb_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", vexpress_dvi_fb);
+}
+
+static ssize_t vexpress_dvi_fb_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	long value;
+	int err = kstrtol(buf, 0, &value);
+
+	if (!err)
+		err = vexpress_dvi_fb_select(value);
+
+	return err ? err : count;
+}
+
+DEVICE_ATTR(fb, S_IRUGO | S_IWUSR, vexpress_dvi_fb_show,
+		vexpress_dvi_fb_store);
+
+
+static int vexpress_dvi_fb_event_notify(struct notifier_block *self,
+			      unsigned long action, void *data)
+{
+	struct fb_event *event = data;
+	struct fb_info *info = event->info;
+	struct fb_videomode *mode = event->data;
+
+	switch (action) {
+	case FB_EVENT_FB_REGISTERED:
+		if (vexpress_dvi_fb < 0)
+			vexpress_dvi_mux_set(info);
+		break;
+	case FB_EVENT_MODE_CHANGE:
+	case FB_EVENT_MODE_CHANGE_ALL:
+		if (info->node == vexpress_dvi_fb)
+			vexpress_dvi_mode_set(info, mode->xres, mode->yres);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block vexpress_dvi_fb_notifier = {
+	.notifier_call = vexpress_dvi_fb_event_notify,
+};
+
+
+enum vexpress_dvi_func { FUNC_MUXFPGA, FUNC_DVIMODE };
+
+static struct of_device_id vexpress_dvi_of_match[] = {
+	{
+		.compatible = "arm,vexpress-muxfpga",
+		.data = (void *)FUNC_MUXFPGA,
+	}, {
+		.compatible = "arm,vexpress-dvimode",
+		.data = (void *)FUNC_DVIMODE,
+	},
+	{}
+};
+
+static int vexpress_dvi_probe(struct platform_device *pdev)
+{
+	enum vexpress_dvi_func func;
+	const struct of_device_id *match =
+			of_match_device(vexpress_dvi_of_match, &pdev->dev);
+
+	if (match)
+		func = (enum vexpress_dvi_func)match->data;
+	else
+		func = pdev->id_entry->driver_data;
+
+	switch (func) {
+	case FUNC_MUXFPGA:
+		vexpress_muxfpga_func =
+				vexpress_config_func_get_by_dev(&pdev->dev);
+		device_create_file(&pdev->dev, &dev_attr_fb);
+		break;
+	case FUNC_DVIMODE:
+		vexpress_dvimode_func =
+				vexpress_config_func_get_by_dev(&pdev->dev);
+		break;
+	}
+
+	if (vexpress_muxfpga_func && vexpress_dvimode_func) {
+		fb_register_client(&vexpress_dvi_fb_notifier);
+		vexpress_dvi_fb_select(0);
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id vexpress_dvi_id_table[] = {
+	{ .name = "vexpress-muxfpga", .driver_data = FUNC_MUXFPGA, },
+	{ .name = "vexpress-dvimode", .driver_data = FUNC_DVIMODE, },
+	{}
+};
+
+static struct platform_driver vexpress_dvi_driver = {
+	.probe = vexpress_dvi_probe,
+	.driver = {
+		.name = "vexpress-dvi",
+		.of_match_table = vexpress_dvi_of_match,
+	},
+	.id_table = vexpress_dvi_id_table,
+};
+
+static int __init vexpress_dvi_init(void)
+{
+	return platform_driver_register(&vexpress_dvi_driver);
+}
+device_initcall(vexpress_dvi_init);
-- 
1.7.9.5



^ permalink raw reply related

* [PATCH 10/10] drivers/video/arcfb.c: fix error return code
From: Peter Senna Tschudin @ 2012-09-18 12:08 UTC (permalink / raw)
  To: jayalk
  Cc: FlorianSchandinat, linux-fbdev, linux-kernel, kernel-janitors,
	Peter Senna Tschudin
In-Reply-To: <1347970080-25175-1-git-send-email-peter.senna@gmail.com>

From: Peter Senna Tschudin <peter.senna@gmail.com>

Convert a nonnegative error return code to a negative one, as returned
elsewhere in the function.

A simplified version of the semantic match that finds this problem is as
follows: (http://coccinelle.lip6.fr/)

// <smpl>
(
if@p1 (\(ret < 0\|ret != 0\))
 { ... return ret; }
|
ret@p1 = 0
)
... when != ret = e1
    when != &ret
*if(...)
{
  ... when != ret = e2
      when forall
 return ret;
}
// </smpl>

Signed-off-by: Peter Senna Tschudin <peter.senna@gmail.com>
---
 drivers/video/arcfb.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index a1d58e9..4659d5d 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -552,6 +552,7 @@ static int __devinit arcfb_probe(struct platform_device *dev)
 				"arcfb", info)) {
 			printk(KERN_INFO
 				"arcfb: Failed req IRQ %d\n", par->irq);
+			retval = -EBUSY;
 			goto err1;
 		}
 	}
-- 
1.7.11.4


^ 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