Merge branch 'for-paul' of git://gitorious.org/linux-omap-dss2/linux

Conflicts:
	arch/arm/mach-omap2/board-overo.c

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index 38077a6..5b28ed0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4542,14 +4542,14 @@
 F:	sound/soc/omap/
 
 OMAP FRAMEBUFFER SUPPORT
-M:	Tomi Valkeinen <tomi.valkeinen@nokia.com>
+M:	Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:	linux-fbdev@vger.kernel.org
 L:	linux-omap@vger.kernel.org
 S:	Maintained
 F:	drivers/video/omap/
 
 OMAP DISPLAY SUBSYSTEM and FRAMEBUFFER SUPPORT (DSS2)
-M:	Tomi Valkeinen <tomi.valkeinen@nokia.com>
+M:	Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:	linux-omap@vger.kernel.org
 L:	linux-fbdev@vger.kernel.org
 S:	Maintained
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 019fb7c..076db52 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -193,6 +193,17 @@
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_OMAP_LCD_VGA=y
+CONFIG_OMAP2_DSS=m
+CONFIG_OMAP2_DSS_RFBI=y
+CONFIG_OMAP2_DSS_SDI=y
+CONFIG_OMAP2_DSS_DSI=y
+CONFIG_FB_OMAP2=m
+CONFIG_PANEL_GENERIC_DPI=m
+CONFIG_PANEL_SHARP_LS037V7DW01=m
+CONFIG_PANEL_NEC_NL8048HL11_01B=m
+CONFIG_PANEL_TAAL=m
+CONFIG_PANEL_TPO_TD043MTEA1=m
+CONFIG_PANEL_ACX565AKM=m
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_PLATFORM=y
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index c06eb42..9afd087 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -307,9 +307,6 @@
 	.default_device	= &sdp3430_lcd_device,
 };
 
-static struct regulator_consumer_supply sdp3430_vdda_dac_supply =
-	REGULATOR_SUPPLY("vdda_dac", "omapdss");
-
 static struct omap_board_config_kernel sdp3430_config[] __initdata = {
 };
 
@@ -398,12 +395,13 @@
 };
 
 static struct regulator_consumer_supply sdp3430_vdda_dac_supplies[] = {
-	REGULATOR_SUPPLY("vdda_dac", "omapdss"),
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc"),
 };
 
 /* VPLL2 for digital video outputs */
 static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = {
 	REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
 };
 
 static struct regulator_consumer_supply sdp3430_vmmc1_supplies[] = {
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 333ceb2..62c78de 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -36,6 +36,7 @@
 #include <plat/usb.h>
 #include <plat/mmc.h>
 #include <plat/omap4-keypad.h>
+#include <plat/display.h>
 
 #include "mux.h"
 #include "hsmmc.h"
@@ -47,6 +48,8 @@
 #define ETH_KS8851_QUART		138
 #define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO	184
 #define OMAP4_SFH7741_ENABLE_GPIO		188
+#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */
+#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
 
 static const int sdp4430_keymap[] = {
 	KEY(0, 0, KEY_E),
@@ -621,6 +624,76 @@
 	}
 }
 
+static void sdp4430_hdmi_mux_init(void)
+{
+	/* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
+	omap_mux_init_signal("hdmi_hpd",
+			OMAP_PIN_INPUT_PULLUP);
+	omap_mux_init_signal("hdmi_cec",
+			OMAP_PIN_INPUT_PULLUP);
+	/* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
+	omap_mux_init_signal("hdmi_ddc_scl",
+			OMAP_PIN_INPUT_PULLUP);
+	omap_mux_init_signal("hdmi_ddc_sda",
+			OMAP_PIN_INPUT_PULLUP);
+}
+
+static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev)
+{
+	int status;
+
+	status = gpio_request_one(HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH,
+							"hdmi_gpio_hpd");
+	if (status) {
+		pr_err("Cannot request GPIO %d\n", HDMI_GPIO_HPD);
+		return status;
+	}
+	status = gpio_request_one(HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH,
+							"hdmi_gpio_ls_oe");
+	if (status) {
+		pr_err("Cannot request GPIO %d\n", HDMI_GPIO_LS_OE);
+		goto error1;
+	}
+
+	return 0;
+
+error1:
+	gpio_free(HDMI_GPIO_HPD);
+
+	return status;
+}
+
+static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev)
+{
+	gpio_free(HDMI_GPIO_LS_OE);
+	gpio_free(HDMI_GPIO_HPD);
+}
+
+static struct omap_dss_device sdp4430_hdmi_device = {
+	.name = "hdmi",
+	.driver_name = "hdmi_panel",
+	.type = OMAP_DISPLAY_TYPE_HDMI,
+	.platform_enable = sdp4430_panel_enable_hdmi,
+	.platform_disable = sdp4430_panel_disable_hdmi,
+	.channel = OMAP_DSS_CHANNEL_DIGIT,
+};
+
+static struct omap_dss_device *sdp4430_dss_devices[] = {
+	&sdp4430_hdmi_device,
+};
+
+static struct omap_dss_board_info sdp4430_dss_data = {
+	.num_devices	= ARRAY_SIZE(sdp4430_dss_devices),
+	.devices	= sdp4430_dss_devices,
+	.default_device	= &sdp4430_hdmi_device,
+};
+
+void omap_4430sdp_display_init(void)
+{
+	sdp4430_hdmi_mux_init();
+	omap_display_init(&sdp4430_dss_data);
+}
+
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
 	OMAP4_MUX(USBB2_ULPITLL_CLK, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
@@ -729,6 +802,8 @@
 	status = omap4_keyboard_init(&sdp4430_keypad_data);
 	if (status)
 		pr_err("Keypad initialization failed: %d\n", status);
+
+	omap_4430sdp_display_init();
 }
 
 static void __init omap_4430sdp_map_io(void)
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index 7b56479..02a12b4 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -488,7 +488,7 @@
 };
 
 static struct regulator_consumer_supply cm_t35_vdac_supply =
-	REGULATOR_SUPPLY("vdda_dac", "omapdss");
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 static struct regulator_consumer_supply cm_t35_vdvi_supply =
 	REGULATOR_SUPPLY("vdvi", "omapdss");
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index aa27483..65f9fde 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -196,7 +196,7 @@
 };
 
 static struct regulator_consumer_supply devkit8000_vdda_dac_supply =
-	REGULATOR_SUPPLY("vdda_dac", "omapdss");
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 static uint32_t board_keymap[] = {
 	KEY(0, 0, KEY_1),
@@ -277,8 +277,10 @@
 	.setup		= devkit8000_twl_gpio_setup,
 };
 
-static struct regulator_consumer_supply devkit8000_vpll1_supply =
-	REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply devkit8000_vpll1_supplies[] = {
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 /* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
 static struct regulator_init_data devkit8000_vmmc1 = {
@@ -319,8 +321,8 @@
 		.valid_ops_mask		= REGULATOR_CHANGE_MODE
 					| REGULATOR_CHANGE_STATUS,
 	},
-	.num_consumer_supplies	= 1,
-	.consumer_supplies	= &devkit8000_vpll1_supply,
+	.num_consumer_supplies	= ARRAY_SIZE(devkit8000_vpll1_supplies),
+	.consumer_supplies	= devkit8000_vpll1_supplies,
 };
 
 /* VAUX4 for ads7846 and nubs */
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index d3199b4..5f8a2fd 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -485,8 +485,10 @@
 	.default_device	= &igep2_dvi_device,
 };
 
-static struct regulator_consumer_supply igep2_vpll2_supply =
-	REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply igep2_vpll2_supplies[] = {
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static struct regulator_init_data igep2_vpll2 = {
 	.constraints = {
@@ -499,8 +501,8 @@
 		.valid_ops_mask		= REGULATOR_CHANGE_MODE
 					| REGULATOR_CHANGE_STATUS,
 	},
-	.num_consumer_supplies	= 1,
-	.consumer_supplies	= &igep2_vpll2_supply,
+	.num_consumer_supplies	= ARRAY_SIZE(igep2_vpll2_supplies),
+	.consumer_supplies	= igep2_vpll2_supplies,
 };
 
 static void __init igep2_display_init(void)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 7640c05..33007fd 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -232,10 +232,12 @@
 };
 
 static struct regulator_consumer_supply beagle_vdac_supply =
-	REGULATOR_SUPPLY("vdda_dac", "omapdss");
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
-static struct regulator_consumer_supply beagle_vdvi_supply =
-	REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply beagle_vdvi_supplies[] = {
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static void __init beagle_display_init(void)
 {
@@ -422,8 +424,8 @@
 		.valid_ops_mask		= REGULATOR_CHANGE_MODE
 					| REGULATOR_CHANGE_STATUS,
 	},
-	.num_consumer_supplies	= 1,
-	.consumer_supplies	= &beagle_vdvi_supply,
+	.num_consumer_supplies	= ARRAY_SIZE(beagle_vdvi_supplies),
+	.consumer_supplies	= beagle_vdvi_supplies,
 };
 
 static struct twl4030_usb_data beagle_usb_data = {
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 0fa2c7b..5a1a916 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -542,7 +542,7 @@
 };
 
 static struct regulator_consumer_supply omap3_evm_vdda_dac_supply =
-	REGULATOR_SUPPLY("vdda_dac", "omapdss");
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 /* VDAC for DSS driving S-Video */
 static struct regulator_init_data omap3_evm_vdac = {
@@ -560,8 +560,10 @@
 };
 
 /* VPLL2 for digital video outputs */
-static struct regulator_consumer_supply omap3_evm_vpll2_supply =
-	REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply omap3_evm_vpll2_supplies[] = {
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static struct regulator_init_data omap3_evm_vpll2 = {
 	.constraints = {
@@ -573,8 +575,8 @@
 		.valid_ops_mask		= REGULATOR_CHANGE_MODE
 					| REGULATOR_CHANGE_STATUS,
 	},
-	.num_consumer_supplies	= 1,
-	.consumer_supplies	= &omap3_evm_vpll2_supply,
+	.num_consumer_supplies	= ARRAY_SIZE(omap3_evm_vpll2_supplies),
+	.consumer_supplies	= omap3_evm_vpll2_supplies,
 };
 
 /* ads7846 on SPI */
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index 2e5dc21..07dba88 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -342,11 +342,12 @@
 	REGULATOR_SUPPLY("vmmc", "omap_hsmmc.2");
 
 static struct regulator_consumer_supply pandora_vdda_dac_supply =
-	REGULATOR_SUPPLY("vdda_dac", "omapdss");
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 static struct regulator_consumer_supply pandora_vdds_supplies[] = {
 	REGULATOR_SUPPLY("vdds_sdi", "omapdss"),
 	REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
 };
 
 static struct regulator_consumer_supply pandora_vcc_lcd_supply =
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index 8ebdbc3..a6e0b91 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -439,7 +439,7 @@
 };
 
 static struct regulator_consumer_supply omap3_stalker_vdda_dac_supply =
-	REGULATOR_SUPPLY("vdda_dac", "omapdss");
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 /* VDAC for DSS driving S-Video */
 static struct regulator_init_data omap3_stalker_vdac = {
@@ -457,8 +457,10 @@
 };
 
 /* VPLL2 for digital video outputs */
-static struct regulator_consumer_supply omap3_stalker_vpll2_supply =
-	REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply omap3_stalker_vpll2_supplies[] = {
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static struct regulator_init_data omap3_stalker_vpll2 = {
 	.constraints		= {
@@ -471,8 +473,8 @@
 		.valid_ops_mask		= REGULATOR_CHANGE_MODE
 		| REGULATOR_CHANGE_STATUS,
 	},
-	.num_consumer_supplies	= 1,
-	.consumer_supplies	= &omap3_stalker_vpll2_supply,
+	.num_consumer_supplies	= ARRAY_SIZE(omap3_stalker_vpll2_supplies),
+	.consumer_supplies	= omap3_stalker_vpll2_supplies,
 };
 
 static struct twl4030_platform_data omap3stalker_twldata = {
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 0f4d8a7..209cffb 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -34,11 +34,13 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <plat/display.h>
 
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
+#include <plat/panel-generic-dpi.h>
 #include "timer-gp.h"
 
 #include "hsmmc.h"
@@ -49,6 +51,8 @@
 #define GPIO_HUB_NRESET		62
 #define GPIO_WIFI_PMENA		43
 #define GPIO_WIFI_IRQ		53
+#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */
+#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
 
 /* wl127x BT, FM, GPS connectivity chip */
 static int wl1271_gpios[] = {46, -1, -1};
@@ -433,6 +437,17 @@
 		.platform_data = &omap4_panda_twldata,
 	},
 };
+
+/*
+ * Display monitor features are burnt in their EEPROM as EDID data. The EEPROM
+ * is connected as I2C slave device, and can be accessed at address 0x50
+ */
+static struct i2c_board_info __initdata panda_i2c_eeprom[] = {
+	{
+		I2C_BOARD_INFO("eeprom", 0x50),
+	},
+};
+
 static int __init omap4_panda_i2c_init(void)
 {
 	/*
@@ -442,7 +457,12 @@
 	omap_register_i2c_bus(1, 400, omap4_panda_i2c_boardinfo,
 			ARRAY_SIZE(omap4_panda_i2c_boardinfo));
 	omap_register_i2c_bus(2, 400, NULL, 0);
-	omap_register_i2c_bus(3, 400, NULL, 0);
+	/*
+	 * Bus 3 is attached to the DVI port where devices like the pico DLP
+	 * projector don't work reliably with 400kHz
+	 */
+	omap_register_i2c_bus(3, 100, panda_i2c_eeprom,
+					ARRAY_SIZE(panda_i2c_eeprom));
 	omap_register_i2c_bus(4, 400, NULL, 0);
 	return 0;
 }
@@ -462,6 +482,64 @@
 	OMAP4_MUX(SDMMC5_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
 	OMAP4_MUX(SDMMC5_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
 	OMAP4_MUX(SDMMC5_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+	/* gpio 0 - TFP410 PD */
+	OMAP4_MUX(KPD_COL1, OMAP_PIN_OUTPUT | OMAP_MUX_MODE3),
+	/* dispc2_data23 */
+	OMAP4_MUX(USBB2_ULPITLL_STP, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data22 */
+	OMAP4_MUX(USBB2_ULPITLL_DIR, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data21 */
+	OMAP4_MUX(USBB2_ULPITLL_NXT, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data20 */
+	OMAP4_MUX(USBB2_ULPITLL_DAT0, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data19 */
+	OMAP4_MUX(USBB2_ULPITLL_DAT1, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data18 */
+	OMAP4_MUX(USBB2_ULPITLL_DAT2, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data15 */
+	OMAP4_MUX(USBB2_ULPITLL_DAT3, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data14 */
+	OMAP4_MUX(USBB2_ULPITLL_DAT4, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data13 */
+	OMAP4_MUX(USBB2_ULPITLL_DAT5, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data12 */
+	OMAP4_MUX(USBB2_ULPITLL_DAT6, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data11 */
+	OMAP4_MUX(USBB2_ULPITLL_DAT7, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data10 */
+	OMAP4_MUX(DPM_EMU3, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data9 */
+	OMAP4_MUX(DPM_EMU4, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data16 */
+	OMAP4_MUX(DPM_EMU5, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data17 */
+	OMAP4_MUX(DPM_EMU6, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_hsync */
+	OMAP4_MUX(DPM_EMU7, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_pclk */
+	OMAP4_MUX(DPM_EMU8, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_vsync */
+	OMAP4_MUX(DPM_EMU9, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_de */
+	OMAP4_MUX(DPM_EMU10, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data8 */
+	OMAP4_MUX(DPM_EMU11, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data7 */
+	OMAP4_MUX(DPM_EMU12, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data6 */
+	OMAP4_MUX(DPM_EMU13, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data5 */
+	OMAP4_MUX(DPM_EMU14, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data4 */
+	OMAP4_MUX(DPM_EMU15, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data3 */
+	OMAP4_MUX(DPM_EMU16, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data2 */
+	OMAP4_MUX(DPM_EMU17, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data1 */
+	OMAP4_MUX(DPM_EMU18, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+	/* dispc2_data0 */
+	OMAP4_MUX(DPM_EMU19, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
 
@@ -535,6 +613,128 @@
 }
 #endif
 
+/* Display DVI */
+#define PANDA_DVI_TFP410_POWER_DOWN_GPIO	0
+
+static int omap4_panda_enable_dvi(struct omap_dss_device *dssdev)
+{
+	gpio_set_value(dssdev->reset_gpio, 1);
+	return 0;
+}
+
+static void omap4_panda_disable_dvi(struct omap_dss_device *dssdev)
+{
+	gpio_set_value(dssdev->reset_gpio, 0);
+}
+
+/* Using generic display panel */
+static struct panel_generic_dpi_data omap4_dvi_panel = {
+	.name			= "generic",
+	.platform_enable	= omap4_panda_enable_dvi,
+	.platform_disable	= omap4_panda_disable_dvi,
+};
+
+struct omap_dss_device omap4_panda_dvi_device = {
+	.type			= OMAP_DISPLAY_TYPE_DPI,
+	.name			= "dvi",
+	.driver_name		= "generic_dpi_panel",
+	.data			= &omap4_dvi_panel,
+	.phy.dpi.data_lines	= 24,
+	.reset_gpio		= PANDA_DVI_TFP410_POWER_DOWN_GPIO,
+	.channel		= OMAP_DSS_CHANNEL_LCD2,
+};
+
+int __init omap4_panda_dvi_init(void)
+{
+	int r;
+
+	/* Requesting TFP410 DVI GPIO and disabling it, at bootup */
+	r = gpio_request_one(omap4_panda_dvi_device.reset_gpio,
+				GPIOF_OUT_INIT_LOW, "DVI PD");
+	if (r)
+		pr_err("Failed to get DVI powerdown GPIO\n");
+
+	return r;
+}
+
+
+static void omap4_panda_hdmi_mux_init(void)
+{
+	/* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
+	omap_mux_init_signal("hdmi_hpd",
+			OMAP_PIN_INPUT_PULLUP);
+	omap_mux_init_signal("hdmi_cec",
+			OMAP_PIN_INPUT_PULLUP);
+	/* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
+	omap_mux_init_signal("hdmi_ddc_scl",
+			OMAP_PIN_INPUT_PULLUP);
+	omap_mux_init_signal("hdmi_ddc_sda",
+			OMAP_PIN_INPUT_PULLUP);
+}
+
+static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev)
+{
+	int status;
+
+	status = gpio_request_one(HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH,
+							"hdmi_gpio_hpd");
+	if (status) {
+		pr_err("Cannot request GPIO %d\n", HDMI_GPIO_HPD);
+		return status;
+	}
+	status = gpio_request_one(HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH,
+							"hdmi_gpio_ls_oe");
+	if (status) {
+		pr_err("Cannot request GPIO %d\n", HDMI_GPIO_LS_OE);
+		goto error1;
+	}
+
+	return 0;
+
+error1:
+	gpio_free(HDMI_GPIO_HPD);
+
+	return status;
+}
+
+static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev)
+{
+	gpio_free(HDMI_GPIO_LS_OE);
+	gpio_free(HDMI_GPIO_HPD);
+}
+
+static struct omap_dss_device  omap4_panda_hdmi_device = {
+	.name = "hdmi",
+	.driver_name = "hdmi_panel",
+	.type = OMAP_DISPLAY_TYPE_HDMI,
+	.platform_enable = omap4_panda_panel_enable_hdmi,
+	.platform_disable = omap4_panda_panel_disable_hdmi,
+	.channel = OMAP_DSS_CHANNEL_DIGIT,
+};
+
+static struct omap_dss_device *omap4_panda_dss_devices[] = {
+	&omap4_panda_dvi_device,
+	&omap4_panda_hdmi_device,
+};
+
+static struct omap_dss_board_info omap4_panda_dss_data = {
+	.num_devices	= ARRAY_SIZE(omap4_panda_dss_devices),
+	.devices	= omap4_panda_dss_devices,
+	.default_device	= &omap4_panda_dvi_device,
+};
+
+void omap4_panda_display_init(void)
+{
+	int r;
+
+	r = omap4_panda_dvi_init();
+	if (r)
+		pr_err("error initializing panda DVI\n");
+
+	omap4_panda_hdmi_mux_init();
+	omap_display_init(&omap4_panda_dss_data);
+}
+
 static void __init omap4_panda_init(void)
 {
 	int package = OMAP_PACKAGE_CBS;
@@ -553,6 +753,7 @@
 	omap4_twl6030_hsmmc_init(mmc);
 	omap4_ehci_init();
 	usb_musb_init(&musb_board_data);
+	omap4_panda_display_init();
 }
 
 static void __init omap4_panda_map_io(void)
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index d096194..59ca333 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -28,6 +28,8 @@
 #include <linux/platform_device.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/spi/spi.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -41,10 +43,14 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
+#include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 #include <mach/gpio.h>
 #include <plat/gpmc.h>
 #include <mach/hardware.h>
 #include <plat/nand.h>
+#include <plat/mcspi.h>
+#include <plat/mux.h>
 #include <plat/usb.h>
 
 #include "mux.h"
@@ -68,8 +74,6 @@
 #if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
 	defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 
-#include <plat/mcspi.h>
-#include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 
 static struct omap2_mcspi_device_config ads7846_mcspi_config = {
@@ -94,16 +98,32 @@
 	.keep_vref_on		= 1,
 };
 
-static struct spi_board_info overo_spi_board_info[] __initdata = {
-	{
-		.modalias		= "ads7846",
-		.bus_num		= 1,
-		.chip_select		= 0,
-		.max_speed_hz		= 1500000,
-		.controller_data	= &ads7846_mcspi_config,
-		.irq			= OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
-		.platform_data		= &ads7846_config,
-	}
+/* fixed regulator for ads7846 */
+static struct regulator_consumer_supply ads7846_supply =
+	REGULATOR_SUPPLY("vcc", "spi1.0");
+
+static struct regulator_init_data vads7846_regulator = {
+	.constraints = {
+		.valid_ops_mask		= REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &ads7846_supply,
+};
+
+static struct fixed_voltage_config vads7846 = {
+	.supply_name		= "vads7846",
+	.microvolts		= 3300000, /* 3.3V */
+	.gpio			= -EINVAL,
+	.startup_delay		= 0,
+	.init_data		= &vads7846_regulator,
+};
+
+static struct platform_device vads7846_device = {
+	.name		= "reg-fixed-voltage",
+	.id		= 1,
+	.dev = {
+		.platform_data = &vads7846,
+	},
 };
 
 static void __init overo_ads7846_init(void)
@@ -116,8 +136,7 @@
 		return;
 	}
 
-	spi_register_board_info(overo_spi_board_info,
-			ARRAY_SIZE(overo_spi_board_info));
+	platform_device_register(&vads7846_device);
 }
 
 #else
@@ -233,6 +252,137 @@
 static inline void __init overo_init_smsc911x(void) { return; }
 #endif
 
+/* DSS */
+static int lcd_enabled;
+static int dvi_enabled;
+
+#define OVERO_GPIO_LCD_EN 144
+#define OVERO_GPIO_LCD_BL 145
+
+static void __init overo_display_init(void)
+{
+	if ((gpio_request(OVERO_GPIO_LCD_EN, "OVERO_GPIO_LCD_EN") == 0) &&
+	    (gpio_direction_output(OVERO_GPIO_LCD_EN, 1) == 0))
+		gpio_export(OVERO_GPIO_LCD_EN, 0);
+	else
+		printk(KERN_ERR "could not obtain gpio for "
+					"OVERO_GPIO_LCD_EN\n");
+
+	if ((gpio_request(OVERO_GPIO_LCD_BL, "OVERO_GPIO_LCD_BL") == 0) &&
+	    (gpio_direction_output(OVERO_GPIO_LCD_BL, 1) == 0))
+		gpio_export(OVERO_GPIO_LCD_BL, 0);
+	else
+		printk(KERN_ERR "could not obtain gpio for "
+					"OVERO_GPIO_LCD_BL\n");
+}
+
+static int overo_panel_enable_dvi(struct omap_dss_device *dssdev)
+{
+	if (lcd_enabled) {
+		printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
+		return -EINVAL;
+	}
+	dvi_enabled = 1;
+
+	return 0;
+}
+
+static void overo_panel_disable_dvi(struct omap_dss_device *dssdev)
+{
+	dvi_enabled = 0;
+}
+
+static struct panel_generic_dpi_data dvi_panel = {
+	.name			= "generic",
+	.platform_enable	= overo_panel_enable_dvi,
+	.platform_disable	= overo_panel_disable_dvi,
+};
+
+static struct omap_dss_device overo_dvi_device = {
+	.name			= "dvi",
+	.type			= OMAP_DISPLAY_TYPE_DPI,
+	.driver_name		= "generic_dpi_panel",
+	.data			= &dvi_panel,
+	.phy.dpi.data_lines	= 24,
+};
+
+static struct omap_dss_device overo_tv_device = {
+	.name = "tv",
+	.driver_name = "venc",
+	.type = OMAP_DISPLAY_TYPE_VENC,
+	.phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
+};
+
+static int overo_panel_enable_lcd(struct omap_dss_device *dssdev)
+{
+	if (dvi_enabled) {
+		printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
+		return -EINVAL;
+	}
+
+	gpio_set_value(OVERO_GPIO_LCD_EN, 1);
+	gpio_set_value(OVERO_GPIO_LCD_BL, 1);
+	lcd_enabled = 1;
+	return 0;
+}
+
+static void overo_panel_disable_lcd(struct omap_dss_device *dssdev)
+{
+	gpio_set_value(OVERO_GPIO_LCD_EN, 0);
+	gpio_set_value(OVERO_GPIO_LCD_BL, 0);
+	lcd_enabled = 0;
+}
+
+static struct panel_generic_dpi_data lcd43_panel = {
+	.name			= "samsung_lte430wq_f0c",
+	.platform_enable	= overo_panel_enable_lcd,
+	.platform_disable	= overo_panel_disable_lcd,
+};
+
+static struct omap_dss_device overo_lcd43_device = {
+	.name			= "lcd43",
+	.type			= OMAP_DISPLAY_TYPE_DPI,
+	.driver_name		= "generic_dpi_panel",
+	.data			= &lcd43_panel,
+	.phy.dpi.data_lines	= 24,
+};
+
+#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
+	defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
+static struct omap_dss_device overo_lcd35_device = {
+	.type			= OMAP_DISPLAY_TYPE_DPI,
+	.name			= "lcd35",
+	.driver_name		= "lgphilips_lb035q02_panel",
+	.phy.dpi.data_lines	= 24,
+	.platform_enable	= overo_panel_enable_lcd,
+	.platform_disable	= overo_panel_disable_lcd,
+};
+#endif
+
+static struct omap_dss_device *overo_dss_devices[] = {
+	&overo_dvi_device,
+	&overo_tv_device,
+#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
+	defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
+	&overo_lcd35_device,
+#endif
+	&overo_lcd43_device,
+};
+
+static struct omap_dss_board_info overo_dss_data = {
+	.num_devices	= ARRAY_SIZE(overo_dss_devices),
+	.devices	= overo_dss_devices,
+	.default_device	= &overo_dvi_device,
+};
+
+static struct regulator_consumer_supply overo_vdda_dac_supply =
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
+
+static struct regulator_consumer_supply overo_vdds_dsi_supply[] = {
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
+
 static struct mtd_partition overo_nand_partitions[] = {
 	{
 		.name           = "xloader",
@@ -323,6 +473,93 @@
 	.supply			= "vmmc",
 };
 
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led gpio_leds[] = {
+	{
+		.name			= "overo:red:gpio21",
+		.default_trigger	= "heartbeat",
+		.gpio			= 21,
+		.active_low		= true,
+	},
+	{
+		.name			= "overo:blue:gpio22",
+		.default_trigger	= "none",
+		.gpio			= 22,
+		.active_low		= true,
+	},
+	{
+		.name			= "overo:blue:COM",
+		.default_trigger	= "mmc0",
+		.gpio			= -EINVAL,	/* gets replaced */
+		.active_low		= true,
+	},
+};
+
+static struct gpio_led_platform_data gpio_leds_pdata = {
+	.leds		= gpio_leds,
+	.num_leds	= ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device gpio_leds_device = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &gpio_leds_pdata,
+	},
+};
+
+static void __init overo_init_led(void)
+{
+	platform_device_register(&gpio_leds_device);
+}
+
+#else
+static inline void __init overo_init_led(void) { return; }
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button gpio_buttons[] = {
+	{
+		.code			= BTN_0,
+		.gpio			= 23,
+		.desc			= "button0",
+		.wakeup			= 1,
+	},
+	{
+		.code			= BTN_1,
+		.gpio			= 14,
+		.desc			= "button1",
+		.wakeup			= 1,
+	},
+};
+
+static struct gpio_keys_platform_data gpio_keys_pdata = {
+	.buttons	= gpio_buttons,
+	.nbuttons	= ARRAY_SIZE(gpio_buttons),
+};
+
+static struct platform_device gpio_keys_device = {
+	.name	= "gpio-keys",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &gpio_keys_pdata,
+	},
+};
+
+static void __init overo_init_keys(void)
+{
+	platform_device_register(&gpio_keys_device);
+}
+
+#else
+static inline void __init overo_init_keys(void) { return; }
+#endif
+
 static int overo_twl_gpio_setup(struct device *dev,
 		unsigned gpio, unsigned ngpio)
 {
@@ -330,6 +567,11 @@
 
 	overo_vmmc1_supply.dev = mmc[0].dev;
 
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+	/* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
+	gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+#endif
+
 	return 0;
 }
 
@@ -337,6 +579,7 @@
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
+	.use_leds	= true,
 	.setup		= overo_twl_gpio_setup,
 };
 
@@ -358,6 +601,35 @@
 	.consumer_supplies	= &overo_vmmc1_supply,
 };
 
+/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */
+static struct regulator_init_data overo_vdac = {
+	.constraints = {
+		.min_uV			= 1800000,
+		.max_uV			= 1800000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &overo_vdda_dac_supply,
+};
+
+/* VPLL2 for digital video outputs */
+static struct regulator_init_data overo_vpll2 = {
+	.constraints = {
+		.name			= "VDVI",
+		.min_uV			= 1800000,
+		.max_uV			= 1800000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(overo_vdds_dsi_supply),
+	.consumer_supplies	= overo_vdds_dsi_supply,
+};
+
 static struct twl4030_codec_audio_data overo_audio_data;
 
 static struct twl4030_codec_data overo_codec_data = {
@@ -365,8 +637,6 @@
 	.audio = &overo_audio_data,
 };
 
-/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
-
 static struct twl4030_platform_data overo_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
@@ -374,6 +644,8 @@
 	.usb		= &overo_usb_data,
 	.codec		= &overo_codec_data,
 	.vmmc1		= &overo_vmmc1,
+	.vdac		= &overo_vdac,
+	.vpll2		= &overo_vpll2,
 };
 
 static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
@@ -394,18 +666,38 @@
 	return 0;
 }
 
-static struct platform_device overo_lcd_device = {
-	.name		= "overo_lcd",
-	.id		= -1,
+static struct spi_board_info overo_spi_board_info[] __initdata = {
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
+	defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+	{
+		.modalias		= "ads7846",
+		.bus_num		= 1,
+		.chip_select		= 0,
+		.max_speed_hz		= 1500000,
+		.controller_data	= &ads7846_mcspi_config,
+		.irq			= OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
+		.platform_data		= &ads7846_config,
+	},
+#endif
+#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
+	defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
+	{
+		.modalias		= "lgphilips_lb035q02_panel-spi",
+		.bus_num		= 1,
+		.chip_select		= 1,
+		.max_speed_hz		= 500000,
+		.mode			= SPI_MODE_3,
+	},
+#endif
 };
 
-static struct omap_lcd_config overo_lcd_config __initdata = {
-	.ctrl_name	= "internal",
-};
-
-static struct omap_board_config_kernel overo_config[] __initdata = {
-	{ OMAP_TAG_LCD,		&overo_lcd_config },
-};
+static int __init overo_spi_init(void)
+{
+	overo_ads7846_init();
+	spi_register_board_info(overo_spi_board_info,
+			ARRAY_SIZE(overo_spi_board_info));
+	return 0;
+}
 
 static void __init overo_init_early(void)
 {
@@ -414,15 +706,10 @@
 				  mt46h32m32lf6_sdrc_params);
 }
 
-static struct platform_device *overo_devices[] __initdata = {
-	&overo_lcd_device,
-};
-
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 	.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
 	.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
 	.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
-
 	.phy_reset  = true,
 	.reset_gpio_port[0]  = -EINVAL,
 	.reset_gpio_port[1]  = OVERO_GPIO_USBH_NRESET,
@@ -444,16 +731,18 @@
 static void __init overo_init(void)
 {
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-	omap_board_config = overo_config;
-	omap_board_config_size = ARRAY_SIZE(overo_config);
 	overo_i2c_init();
-	platform_add_devices(overo_devices, ARRAY_SIZE(overo_devices));
+	omap_display_init(&overo_dss_data);
 	omap_serial_init();
 	overo_flash_init();
 	usb_musb_init(&musb_board_data);
 	usbhs_init(&usbhs_bdata);
+	overo_spi_init();
 	overo_ads7846_init();
 	overo_init_smsc911x();
+	overo_display_init();
+	overo_init_led();
+	overo_init_keys();
 
 	/* Ensure SDRC pins are mux'd for self-refresh */
 	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 5f1900c..bbcb677 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -372,7 +372,7 @@
 };
 
 static struct regulator_consumer_supply rx51_vdac_supply[] = {
-	REGULATOR_SUPPLY("vdda_dac", "omapdss"),
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc"),
 };
 
 static struct regulator_init_data rx51_vaux1 = {
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index 448ab60..8dee754 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -226,11 +226,13 @@
 	{}      /* Terminator */
 };
 
-static struct regulator_consumer_supply zoom_vpll2_supply =
-	REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply zoom_vpll2_supplies[] = {
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+	REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static struct regulator_consumer_supply zoom_vdda_dac_supply =
-	REGULATOR_SUPPLY("vdda_dac", "omapdss");
+	REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 static struct regulator_init_data zoom_vpll2 = {
 	.constraints = {
@@ -241,8 +243,8 @@
 		.valid_ops_mask         = REGULATOR_CHANGE_MODE
 					| REGULATOR_CHANGE_STATUS,
 	},
-	.num_consumer_supplies		= 1,
-	.consumer_supplies		= &zoom_vpll2_supply,
+	.num_consumer_supplies		= ARRAY_SIZE(zoom_vpll2_supplies),
+	.consumer_supplies		= zoom_vpll2_supplies,
 };
 
 static struct regulator_init_data zoom_vdac = {
diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c
index b6f65d4..2926d02 100644
--- a/arch/arm/mach-omap2/clock2420_data.c
+++ b/arch/arm/mach-omap2/clock2420_data.c
@@ -1804,10 +1804,10 @@
 	CLK(NULL,	"gfx_2d_fck",	&gfx_2d_fck,	CK_242X),
 	CLK(NULL,	"gfx_ick",	&gfx_ick,	CK_242X),
 	/* DSS domain clocks */
-	CLK("omapdss",	"ick",		&dss_ick,	CK_242X),
-	CLK("omapdss",	"dss1_fck",	&dss1_fck,	CK_242X),
-	CLK("omapdss",	"dss2_fck",	&dss2_fck,	CK_242X),
-	CLK("omapdss",	"tv_fck",	&dss_54m_fck,	CK_242X),
+	CLK("omapdss_dss",	"ick",		&dss_ick,	CK_242X),
+	CLK("omapdss_dss",	"fck",		&dss1_fck,	CK_242X),
+	CLK("omapdss_dss",	"sys_clk",	&dss2_fck,	CK_242X),
+	CLK("omapdss_dss",	"tv_clk",	&dss_54m_fck,	CK_242X),
 	/* L3 domain clocks */
 	CLK(NULL,	"core_l3_ck",	&core_l3_ck,	CK_242X),
 	CLK(NULL,	"ssi_fck",	&ssi_ssr_sst_fck, CK_242X),
diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c
index bba0183..0c79d39 100644
--- a/arch/arm/mach-omap2/clock2430_data.c
+++ b/arch/arm/mach-omap2/clock2430_data.c
@@ -1894,10 +1894,10 @@
 	CLK(NULL,	"mdm_ick",	&mdm_ick,	CK_243X),
 	CLK(NULL,	"mdm_osc_ck",	&mdm_osc_ck,	CK_243X),
 	/* DSS domain clocks */
-	CLK("omapdss",	"ick",		&dss_ick,	CK_243X),
-	CLK("omapdss",	"dss1_fck",	&dss1_fck,	CK_243X),
-	CLK("omapdss",	"dss2_fck",	&dss2_fck,	CK_243X),
-	CLK("omapdss",	"tv_fck",	&dss_54m_fck,	CK_243X),
+	CLK("omapdss_dss",	"ick",		&dss_ick,	CK_243X),
+	CLK("omapdss_dss",	"fck",		&dss1_fck,	CK_243X),
+	CLK("omapdss_dss",	"sys_clk",	&dss2_fck,	CK_243X),
+	CLK("omapdss_dss",	"tv_clk",	&dss_54m_fck,	CK_243X),
 	/* L3 domain clocks */
 	CLK(NULL,	"core_l3_ck",	&core_l3_ck,	CK_243X),
 	CLK(NULL,	"ssi_fck",	&ssi_ssr_sst_fck, CK_243X),
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index fcb321a..75b119b 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -3356,13 +3356,13 @@
 	CLK("omap_rng",	"ick",		&rng_ick,	CK_34XX | CK_36XX),
 	CLK(NULL,	"sha11_ick",	&sha11_ick,	CK_34XX | CK_36XX),
 	CLK(NULL,	"des1_ick",	&des1_ick,	CK_34XX | CK_36XX),
-	CLK("omapdss",	"dss1_fck",	&dss1_alwon_fck_3430es1, CK_3430ES1),
-	CLK("omapdss",	"dss1_fck",	&dss1_alwon_fck_3430es2, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
-	CLK("omapdss",	"tv_fck",	&dss_tv_fck,	CK_3XXX),
-	CLK("omapdss",	"video_fck",	&dss_96m_fck,	CK_3XXX),
-	CLK("omapdss",	"dss2_fck",	&dss2_alwon_fck, CK_3XXX),
-	CLK("omapdss",	"ick",		&dss_ick_3430es1,	CK_3430ES1),
-	CLK("omapdss",	"ick",		&dss_ick_3430es2,	CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+	CLK("omapdss_dss",	"fck",		&dss1_alwon_fck_3430es1, CK_3430ES1),
+	CLK("omapdss_dss",	"fck",		&dss1_alwon_fck_3430es2, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+	CLK("omapdss_dss",	"tv_clk",	&dss_tv_fck,	CK_3XXX),
+	CLK("omapdss_dss",	"video_clk",	&dss_96m_fck,	CK_3XXX),
+	CLK("omapdss_dss",	"sys_clk",	&dss2_alwon_fck, CK_3XXX),
+	CLK("omapdss_dss",	"ick",		&dss_ick_3430es1,	CK_3430ES1),
+	CLK("omapdss_dss",	"ick",		&dss_ick_3430es2,	CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
 	CLK(NULL,	"cam_mclk",	&cam_mclk,	CK_34XX | CK_36XX),
 	CLK(NULL,	"cam_ick",	&cam_ick,	CK_34XX | CK_36XX),
 	CLK(NULL,	"csi2_96m_fck",	&csi2_96m_fck,	CK_34XX | CK_36XX),
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index d32ed97..276992d 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3114,11 +3114,16 @@
 	CLK(NULL,	"dmic_sync_mux_ck",		&dmic_sync_mux_ck,	CK_443X),
 	CLK(NULL,	"dmic_fck",			&dmic_fck,	CK_443X),
 	CLK(NULL,	"dsp_fck",			&dsp_fck,	CK_443X),
-	CLK(NULL,	"dss_sys_clk",			&dss_sys_clk,	CK_443X),
-	CLK(NULL,	"dss_tv_clk",			&dss_tv_clk,	CK_443X),
-	CLK(NULL,	"dss_dss_clk",			&dss_dss_clk,	CK_443X),
-	CLK(NULL,	"dss_48mhz_clk",		&dss_48mhz_clk,	CK_443X),
-	CLK(NULL,	"dss_fck",			&dss_fck,	CK_443X),
+	CLK("omapdss_dss",	"sys_clk",			&dss_sys_clk,	CK_443X),
+	CLK("omapdss_dss",	"tv_clk",			&dss_tv_clk,	CK_443X),
+	CLK("omapdss_dss",	"dss_clk",			&dss_dss_clk,	CK_443X),
+	CLK("omapdss_dss",	"video_clk",			&dss_48mhz_clk,	CK_443X),
+	CLK("omapdss_dss",	"fck",				&dss_fck,	CK_443X),
+	/*
+	 * On OMAP4, DSS ick is a dummy clock; this is needed for compatibility
+	 * with OMAP2/3.
+	 */
+	CLK("omapdss_dss",	"ick",				&dummy_ck,	CK_443X),
 	CLK(NULL,	"efuse_ctrl_cust_fck",		&efuse_ctrl_cust_fck,	CK_443X),
 	CLK(NULL,	"emif1_fck",			&emif1_fck,	CK_443X),
 	CLK(NULL,	"emif2_fck",			&emif2_fck,	CK_443X),
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index b18db84..256d23f 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -23,6 +23,8 @@
 #include <linux/err.h>
 
 #include <plat/display.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 static struct platform_device omap_display_device = {
 	.name          = "omapdss",
@@ -32,9 +34,87 @@
 	},
 };
 
+static struct omap_device_pm_latency omap_dss_latency[] = {
+	[0] = {
+		.deactivate_func        = omap_device_idle_hwmods,
+		.activate_func          = omap_device_enable_hwmods,
+		.flags			= OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
+};
+
+/* oh_core is used for getting opt-clocks */
+static struct omap_hwmod	*oh_core;
+
+static bool opt_clock_available(const char *clk_role)
+{
+	int i;
+
+	for (i = 0; i < oh_core->opt_clks_cnt; i++) {
+		if (!strcmp(oh_core->opt_clks[i].role, clk_role))
+			return true;
+	}
+	return false;
+}
+
 int __init omap_display_init(struct omap_dss_board_info *board_data)
 {
 	int r = 0;
+	struct omap_hwmod *oh;
+	struct omap_device *od;
+	int i;
+	struct omap_display_platform_data pdata;
+
+	/*
+	 * omap: valid DSS hwmod names
+	 * omap2,3,4: dss_core, dss_dispc, dss_rfbi, dss_venc
+	 * omap3,4: dss_dsi1
+	 * omap4: dss_dsi2, dss_hdmi
+	 */
+	char *oh_name[] = { "dss_core", "dss_dispc", "dss_rfbi", "dss_venc",
+		"dss_dsi1", "dss_dsi2", "dss_hdmi" };
+	char *dev_name[] = { "omapdss_dss", "omapdss_dispc", "omapdss_rfbi",
+		"omapdss_venc", "omapdss_dsi1", "omapdss_dsi2",
+		"omapdss_hdmi" };
+	int oh_count;
+
+	memset(&pdata, 0, sizeof(pdata));
+
+	if (cpu_is_omap24xx())
+		oh_count = ARRAY_SIZE(oh_name) - 3;
+		/* last 3 hwmod dev in oh_name are not available for omap2 */
+	else if (cpu_is_omap44xx())
+		oh_count = ARRAY_SIZE(oh_name);
+	else
+		oh_count = ARRAY_SIZE(oh_name) - 2;
+		/* last 2 hwmod dev in oh_name are not available for omap3 */
+
+	/* opt_clks are always associated with dss hwmod */
+	oh_core = omap_hwmod_lookup("dss_core");
+	if (!oh_core) {
+		pr_err("Could not look up dss_core.\n");
+		return -ENODEV;
+	}
+
+	pdata.board_data = board_data;
+	pdata.board_data->get_last_off_on_transaction_id = NULL;
+	pdata.opt_clock_available = opt_clock_available;
+
+	for (i = 0; i < oh_count; i++) {
+		oh = omap_hwmod_lookup(oh_name[i]);
+		if (!oh) {
+			pr_err("Could not look up %s\n", oh_name[i]);
+			return -ENODEV;
+		}
+
+		od = omap_device_build(dev_name[i], -1, oh, &pdata,
+				sizeof(struct omap_display_platform_data),
+				omap_dss_latency,
+				ARRAY_SIZE(omap_dss_latency), 0);
+
+		if (WARN((IS_ERR(od)), "Could not build omap_device for %s\n",
+				oh_name[i]))
+			return -ENODEV;
+	}
 	omap_display_device.dev.platform_data = board_data;
 
 	r = platform_device_register(&omap_display_device);
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index 6282346..8eb3ce1 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -1168,11 +1168,6 @@
 	.sysc = &omap2420_dss_sysc,
 };
 
-/* dss */
-static struct omap_hwmod_irq_info omap2420_dss_irqs[] = {
-	{ .irq = 25 },
-};
-
 static struct omap_hwmod_dma_info omap2420_dss_sdma_chs[] = {
 	{ .name = "dispc", .dma_req = 5 },
 };
@@ -1221,8 +1216,6 @@
 	.name		= "dss_core",
 	.class		= &omap2420_dss_hwmod_class,
 	.main_clk	= "dss1_fck", /* instead of dss_fck */
-	.mpu_irqs	= omap2420_dss_irqs,
-	.mpu_irqs_cnt	= ARRAY_SIZE(omap2420_dss_irqs),
 	.sdma_reqs	= omap2420_dss_sdma_chs,
 	.sdma_reqs_cnt	= ARRAY_SIZE(omap2420_dss_sdma_chs),
 	.prcm		= {
@@ -1265,6 +1258,10 @@
 	.sysc = &omap2420_dispc_sysc,
 };
 
+static struct omap_hwmod_irq_info omap2420_dispc_irqs[] = {
+	{ .irq = 25 },
+};
+
 static struct omap_hwmod_addr_space omap2420_dss_dispc_addrs[] = {
 	{
 		.pa_start	= 0x48050400,
@@ -1297,6 +1294,8 @@
 static struct omap_hwmod omap2420_dss_dispc_hwmod = {
 	.name		= "dss_dispc",
 	.class		= &omap2420_dispc_hwmod_class,
+	.mpu_irqs	= omap2420_dispc_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap2420_dispc_irqs),
 	.main_clk	= "dss1_fck",
 	.prcm		= {
 		.omap2 = {
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 0fdf2ca..a860fb5 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -1268,10 +1268,6 @@
 	.sysc = &omap2430_dss_sysc,
 };
 
-/* dss */
-static struct omap_hwmod_irq_info omap2430_dss_irqs[] = {
-	{ .irq = 25 },
-};
 static struct omap_hwmod_dma_info omap2430_dss_sdma_chs[] = {
 	{ .name = "dispc", .dma_req = 5 },
 };
@@ -1314,8 +1310,6 @@
 	.name		= "dss_core",
 	.class		= &omap2430_dss_hwmod_class,
 	.main_clk	= "dss1_fck", /* instead of dss_fck */
-	.mpu_irqs	= omap2430_dss_irqs,
-	.mpu_irqs_cnt	= ARRAY_SIZE(omap2430_dss_irqs),
 	.sdma_reqs	= omap2430_dss_sdma_chs,
 	.sdma_reqs_cnt	= ARRAY_SIZE(omap2430_dss_sdma_chs),
 	.prcm		= {
@@ -1358,6 +1352,10 @@
 	.sysc = &omap2430_dispc_sysc,
 };
 
+static struct omap_hwmod_irq_info omap2430_dispc_irqs[] = {
+	{ .irq = 25 },
+};
+
 static struct omap_hwmod_addr_space omap2430_dss_dispc_addrs[] = {
 	{
 		.pa_start	= 0x48050400,
@@ -1384,6 +1382,8 @@
 static struct omap_hwmod omap2430_dss_dispc_hwmod = {
 	.name		= "dss_dispc",
 	.class		= &omap2430_dispc_hwmod_class,
+	.mpu_irqs	= omap2430_dispc_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap2430_dispc_irqs),
 	.main_clk	= "dss1_fck",
 	.prcm		= {
 		.omap2 = {
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index c819c30..b98e2df 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -1480,11 +1480,6 @@
 	.sysc = &omap3xxx_dss_sysc,
 };
 
-/* dss */
-static struct omap_hwmod_irq_info omap3xxx_dss_irqs[] = {
-	{ .irq = 25 },
-};
-
 static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = {
 	{ .name = "dispc", .dma_req = 5 },
 	{ .name = "dsi1", .dma_req = 74 },
@@ -1548,7 +1543,7 @@
 
 static struct omap_hwmod_opt_clk dss_opt_clks[] = {
 	{ .role = "tv_clk", .clk = "dss_tv_fck" },
-	{ .role = "dssclk", .clk = "dss_96m_fck" },
+	{ .role = "video_clk", .clk = "dss_96m_fck" },
 	{ .role = "sys_clk", .clk = "dss2_alwon_fck" },
 };
 
@@ -1556,8 +1551,6 @@
 	.name		= "dss_core",
 	.class		= &omap3xxx_dss_hwmod_class,
 	.main_clk	= "dss1_alwon_fck", /* instead of dss_fck */
-	.mpu_irqs	= omap3xxx_dss_irqs,
-	.mpu_irqs_cnt	= ARRAY_SIZE(omap3xxx_dss_irqs),
 	.sdma_reqs	= omap3xxx_dss_sdma_chs,
 	.sdma_reqs_cnt	= ARRAY_SIZE(omap3xxx_dss_sdma_chs),
 
@@ -1584,8 +1577,6 @@
 	.name		= "dss_core",
 	.class		= &omap3xxx_dss_hwmod_class,
 	.main_clk	= "dss1_alwon_fck", /* instead of dss_fck */
-	.mpu_irqs	= omap3xxx_dss_irqs,
-	.mpu_irqs_cnt	= ARRAY_SIZE(omap3xxx_dss_irqs),
 	.sdma_reqs	= omap3xxx_dss_sdma_chs,
 	.sdma_reqs_cnt	= ARRAY_SIZE(omap3xxx_dss_sdma_chs),
 
@@ -1631,6 +1622,10 @@
 	.sysc = &omap3xxx_dispc_sysc,
 };
 
+static struct omap_hwmod_irq_info omap3xxx_dispc_irqs[] = {
+	{ .irq = 25 },
+};
+
 static struct omap_hwmod_addr_space omap3xxx_dss_dispc_addrs[] = {
 	{
 		.pa_start	= 0x48050400,
@@ -1664,6 +1659,8 @@
 static struct omap_hwmod omap3xxx_dss_dispc_hwmod = {
 	.name		= "dss_dispc",
 	.class		= &omap3xxx_dispc_hwmod_class,
+	.mpu_irqs	= omap3xxx_dispc_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap3xxx_dispc_irqs),
 	.main_clk	= "dss1_alwon_fck",
 	.prcm		= {
 		.omap2 = {
@@ -1689,6 +1686,10 @@
 	.name = "dsi",
 };
 
+static struct omap_hwmod_irq_info omap3xxx_dsi1_irqs[] = {
+	{ .irq = 25 },
+};
+
 /* dss_dsi1 */
 static struct omap_hwmod_addr_space omap3xxx_dss_dsi1_addrs[] = {
 	{
@@ -1722,6 +1723,8 @@
 static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = {
 	.name		= "dss_dsi1",
 	.class		= &omap3xxx_dsi_hwmod_class,
+	.mpu_irqs	= omap3xxx_dsi1_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap3xxx_dsi1_irqs),
 	.main_clk	= "dss1_alwon_fck",
 	.prcm		= {
 		.omap2 = {
diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h
index 0f140ec..5e04ddc 100644
--- a/arch/arm/plat-omap/include/plat/display.h
+++ b/arch/arm/plat-omap/include/plat/display.h
@@ -58,6 +58,7 @@
 	OMAP_DISPLAY_TYPE_SDI		= 1 << 2,
 	OMAP_DISPLAY_TYPE_DSI		= 1 << 3,
 	OMAP_DISPLAY_TYPE_VENC		= 1 << 4,
+	OMAP_DISPLAY_TYPE_HDMI		= 1 << 5,
 };
 
 enum omap_plane {
@@ -237,6 +238,13 @@
 }
 #endif
 
+struct omap_display_platform_data {
+	struct omap_dss_board_info *board_data;
+	/* TODO: Additional members to be added when PM is considered */
+
+	bool (*opt_clock_available)(const char *clk_role);
+};
+
 struct omap_video_timings {
 	/* Unit: pixels */
 	u16 x_res;
@@ -396,8 +404,8 @@
 			struct {
 				u16 regn;
 				u16 regm;
-				u16 regm3;
-				u16 regm4;
+				u16 regm_dispc;
+				u16 regm_dsi;
 
 				u16 lp_clk_div;
 
@@ -555,6 +563,9 @@
 		int channel,
 		u16 x, u16 y, u16 w, u16 h,
 		void (*callback)(int, void *), void *data);
+int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel);
+int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id);
+void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel);
 
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_dsi_display_disable(struct omap_dss_device *dssdev);
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index 083c8fe..15e7f19 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -5,13 +5,18 @@
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select TWL4030_CORE if MACH_OMAP_2430SDP
 	help
           Frame buffer driver for OMAP based boards.
 
 config FB_OMAP_LCD_VGA
         bool "Use LCD in VGA mode"
 	        depends on MACH_OMAP_3430SDP || MACH_OMAP_LDP
-
+		help
+		  Set LCD resolution as VGA (640 X 480).
+		  Default resolution without this option is QVGA(320 X 240).
+		  Please take a look at drivers/video/omap/lcd_ldp.c file
+		  for lcd driver code.
 choice
 	depends on FB_OMAP && MACH_OVERO
 	prompt "Screen resolution"
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index 940cab3..d18ad6b 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -9,6 +9,12 @@
 	  Supports LCD Panel used in TI SDP3430 and EVM boards,
 	  OMAP3517 EVM boards and CM-T35.
 
+config PANEL_LGPHILIPS_LB035Q02
+	tristate "LG.Philips LB035Q02 LCD Panel"
+	depends on OMAP2_DSS && SPI
+	help
+	  LCD Panel used on the Gumstix Overo Palo35
+
 config PANEL_SHARP_LS037V7DW01
         tristate "Sharp LS037V7DW01 LCD Panel"
         depends on OMAP2_DSS
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index 861f025..0f601ab3a 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o
+obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
 obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
 obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
 
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
index 07eb30e..4a9b9ff 100644
--- a/drivers/video/omap2/displays/panel-generic-dpi.c
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -156,6 +156,31 @@
 		.power_off_delay	= 0,
 		.name			= "toppoly_tdo35s",
 	},
+
+	/* Samsung LTE430WQ-F0C */
+	{
+		{
+			.x_res		= 480,
+			.y_res		= 272,
+
+			.pixel_clock	= 9200,
+
+			.hfp		= 8,
+			.hsw		= 41,
+			.hbp		= 45 - 41,
+
+			.vfp		= 4,
+			.vsw		= 10,
+			.vbp		= 12 - 10,
+		},
+		.acbi			= 0x0,
+		.acb			= 0x0,
+		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+						OMAP_DSS_LCD_IHS,
+		.power_on_delay		= 0,
+		.power_off_delay	= 0,
+		.name			= "samsung_lte430wq_f0c",
+	},
 };
 
 struct panel_drv_data {
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
new file mode 100644
index 0000000..271324d
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
@@ -0,0 +1,279 @@
+/*
+ * LCD panel driver for LG.Philips LB035Q02
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/mutex.h>
+
+#include <plat/display.h>
+
+struct lb035q02_data {
+	struct mutex lock;
+};
+
+static struct omap_video_timings lb035q02_timings = {
+	.x_res = 320,
+	.y_res = 240,
+
+	.pixel_clock	= 6500,
+
+	.hsw		= 2,
+	.hfp		= 20,
+	.hbp		= 68,
+
+	.vsw		= 2,
+	.vfp		= 4,
+	.vbp		= 18,
+};
+
+static int lb035q02_panel_power_on(struct omap_dss_device *dssdev)
+{
+	int r;
+
+	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+		return 0;
+
+	r = omapdss_dpi_display_enable(dssdev);
+	if (r)
+		goto err0;
+
+	if (dssdev->platform_enable) {
+		r = dssdev->platform_enable(dssdev);
+		if (r)
+			goto err1;
+	}
+
+	return 0;
+err1:
+	omapdss_dpi_display_disable(dssdev);
+err0:
+	return r;
+}
+
+static void lb035q02_panel_power_off(struct omap_dss_device *dssdev)
+{
+	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+		return;
+
+	if (dssdev->platform_disable)
+		dssdev->platform_disable(dssdev);
+
+	omapdss_dpi_display_disable(dssdev);
+}
+
+static int lb035q02_panel_probe(struct omap_dss_device *dssdev)
+{
+	struct lb035q02_data *ld;
+	int r;
+
+	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+		OMAP_DSS_LCD_IHS;
+	dssdev->panel.timings = lb035q02_timings;
+
+	ld = kzalloc(sizeof(*ld), GFP_KERNEL);
+	if (!ld) {
+		r = -ENOMEM;
+		goto err;
+	}
+	mutex_init(&ld->lock);
+	dev_set_drvdata(&dssdev->dev, ld);
+	return 0;
+err:
+	return r;
+}
+
+static void lb035q02_panel_remove(struct omap_dss_device *dssdev)
+{
+	struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+
+	kfree(ld);
+}
+
+static int lb035q02_panel_enable(struct omap_dss_device *dssdev)
+{
+	struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+	int r;
+
+	mutex_lock(&ld->lock);
+
+	r = lb035q02_panel_power_on(dssdev);
+	if (r)
+		goto err;
+	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+	mutex_unlock(&ld->lock);
+	return 0;
+err:
+	mutex_unlock(&ld->lock);
+	return r;
+}
+
+static void lb035q02_panel_disable(struct omap_dss_device *dssdev)
+{
+	struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&ld->lock);
+
+	lb035q02_panel_power_off(dssdev);
+	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+	mutex_unlock(&ld->lock);
+}
+
+static int lb035q02_panel_suspend(struct omap_dss_device *dssdev)
+{
+	struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+
+	mutex_lock(&ld->lock);
+
+	lb035q02_panel_power_off(dssdev);
+	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+	mutex_unlock(&ld->lock);
+	return 0;
+}
+
+static int lb035q02_panel_resume(struct omap_dss_device *dssdev)
+{
+	struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+	int r;
+
+	mutex_lock(&ld->lock);
+
+	r = lb035q02_panel_power_on(dssdev);
+	if (r)
+		goto err;
+	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+	mutex_unlock(&ld->lock);
+	return 0;
+err:
+	mutex_unlock(&ld->lock);
+	return r;
+}
+
+static struct omap_dss_driver lb035q02_driver = {
+	.probe		= lb035q02_panel_probe,
+	.remove		= lb035q02_panel_remove,
+
+	.enable		= lb035q02_panel_enable,
+	.disable	= lb035q02_panel_disable,
+	.suspend	= lb035q02_panel_suspend,
+	.resume		= lb035q02_panel_resume,
+
+	.driver         = {
+		.name   = "lgphilips_lb035q02_panel",
+		.owner  = THIS_MODULE,
+	},
+};
+
+static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val)
+{
+	struct spi_message msg;
+	struct spi_transfer index_xfer = {
+		.len		= 3,
+		.cs_change	= 1,
+	};
+	struct spi_transfer value_xfer = {
+		.len		= 3,
+	};
+	u8	buffer[16];
+
+	spi_message_init(&msg);
+
+	/* register index */
+	buffer[0] = 0x70;
+	buffer[1] = 0x00;
+	buffer[2] = reg & 0x7f;
+	index_xfer.tx_buf = buffer;
+	spi_message_add_tail(&index_xfer, &msg);
+
+	/* register value */
+	buffer[4] = 0x72;
+	buffer[5] = val >> 8;
+	buffer[6] = val;
+	value_xfer.tx_buf = buffer + 4;
+	spi_message_add_tail(&value_xfer, &msg);
+
+	return spi_sync(spi, &msg);
+}
+
+static void init_lb035q02_panel(struct spi_device *spi)
+{
+	/* Init sequence from page 28 of the lb035q02 spec */
+	lb035q02_write_reg(spi, 0x01, 0x6300);
+	lb035q02_write_reg(spi, 0x02, 0x0200);
+	lb035q02_write_reg(spi, 0x03, 0x0177);
+	lb035q02_write_reg(spi, 0x04, 0x04c7);
+	lb035q02_write_reg(spi, 0x05, 0xffc0);
+	lb035q02_write_reg(spi, 0x06, 0xe806);
+	lb035q02_write_reg(spi, 0x0a, 0x4008);
+	lb035q02_write_reg(spi, 0x0b, 0x0000);
+	lb035q02_write_reg(spi, 0x0d, 0x0030);
+	lb035q02_write_reg(spi, 0x0e, 0x2800);
+	lb035q02_write_reg(spi, 0x0f, 0x0000);
+	lb035q02_write_reg(spi, 0x16, 0x9f80);
+	lb035q02_write_reg(spi, 0x17, 0x0a0f);
+	lb035q02_write_reg(spi, 0x1e, 0x00c1);
+	lb035q02_write_reg(spi, 0x30, 0x0300);
+	lb035q02_write_reg(spi, 0x31, 0x0007);
+	lb035q02_write_reg(spi, 0x32, 0x0000);
+	lb035q02_write_reg(spi, 0x33, 0x0000);
+	lb035q02_write_reg(spi, 0x34, 0x0707);
+	lb035q02_write_reg(spi, 0x35, 0x0004);
+	lb035q02_write_reg(spi, 0x36, 0x0302);
+	lb035q02_write_reg(spi, 0x37, 0x0202);
+	lb035q02_write_reg(spi, 0x3a, 0x0a0d);
+	lb035q02_write_reg(spi, 0x3b, 0x0806);
+}
+
+static int __devinit lb035q02_panel_spi_probe(struct spi_device *spi)
+{
+	init_lb035q02_panel(spi);
+	return omap_dss_register_driver(&lb035q02_driver);
+}
+
+static int __devexit lb035q02_panel_spi_remove(struct spi_device *spi)
+{
+	omap_dss_unregister_driver(&lb035q02_driver);
+	return 0;
+}
+
+static struct spi_driver lb035q02_spi_driver = {
+	.driver		= {
+		.name	= "lgphilips_lb035q02_panel-spi",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= lb035q02_panel_spi_probe,
+	.remove		= __devexit_p(lb035q02_panel_spi_remove),
+};
+
+static int __init lb035q02_panel_drv_init(void)
+{
+	return spi_register_driver(&lb035q02_spi_driver);
+}
+
+static void __exit lb035q02_panel_drv_exit(void)
+{
+	spi_unregister_driver(&lb035q02_spi_driver);
+}
+
+module_init(lb035q02_panel_drv_init);
+module_exit(lb035q02_panel_drv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 61026f9..abdfdd8 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -218,6 +218,8 @@
 		u16 w;
 		u16 h;
 	} update_region;
+	int channel;
+
 	struct delayed_work te_timeout_work;
 
 	bool use_dsi_bl;
@@ -257,12 +259,12 @@
 	}
 }
 
-static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
+static int taal_dcs_read_1(struct taal_data *td, u8 dcs_cmd, u8 *data)
 {
 	int r;
 	u8 buf[1];
 
-	r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1);
+	r = dsi_vc_dcs_read(td->channel, dcs_cmd, buf, 1);
 
 	if (r < 0)
 		return r;
@@ -272,17 +274,17 @@
 	return 0;
 }
 
-static int taal_dcs_write_0(u8 dcs_cmd)
+static int taal_dcs_write_0(struct taal_data *td, u8 dcs_cmd)
 {
-	return dsi_vc_dcs_write(TCH, &dcs_cmd, 1);
+	return dsi_vc_dcs_write(td->channel, &dcs_cmd, 1);
 }
 
-static int taal_dcs_write_1(u8 dcs_cmd, u8 param)
+static int taal_dcs_write_1(struct taal_data *td, u8 dcs_cmd, u8 param)
 {
 	u8 buf[2];
 	buf[0] = dcs_cmd;
 	buf[1] = param;
-	return dsi_vc_dcs_write(TCH, buf, 2);
+	return dsi_vc_dcs_write(td->channel, buf, 2);
 }
 
 static int taal_sleep_in(struct taal_data *td)
@@ -294,7 +296,7 @@
 	hw_guard_wait(td);
 
 	cmd = DCS_SLEEP_IN;
-	r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1);
+	r = dsi_vc_dcs_write_nosync(td->channel, &cmd, 1);
 	if (r)
 		return r;
 
@@ -312,7 +314,7 @@
 
 	hw_guard_wait(td);
 
-	r = taal_dcs_write_0(DCS_SLEEP_OUT);
+	r = taal_dcs_write_0(td, DCS_SLEEP_OUT);
 	if (r)
 		return r;
 
@@ -324,30 +326,30 @@
 	return 0;
 }
 
-static int taal_get_id(u8 *id1, u8 *id2, u8 *id3)
+static int taal_get_id(struct taal_data *td, u8 *id1, u8 *id2, u8 *id3)
 {
 	int r;
 
-	r = taal_dcs_read_1(DCS_GET_ID1, id1);
+	r = taal_dcs_read_1(td, DCS_GET_ID1, id1);
 	if (r)
 		return r;
-	r = taal_dcs_read_1(DCS_GET_ID2, id2);
+	r = taal_dcs_read_1(td, DCS_GET_ID2, id2);
 	if (r)
 		return r;
-	r = taal_dcs_read_1(DCS_GET_ID3, id3);
+	r = taal_dcs_read_1(td, DCS_GET_ID3, id3);
 	if (r)
 		return r;
 
 	return 0;
 }
 
-static int taal_set_addr_mode(u8 rotate, bool mirror)
+static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror)
 {
 	int r;
 	u8 mode;
 	int b5, b6, b7;
 
-	r = taal_dcs_read_1(DCS_READ_MADCTL, &mode);
+	r = taal_dcs_read_1(td, DCS_READ_MADCTL, &mode);
 	if (r)
 		return r;
 
@@ -381,10 +383,11 @@
 	mode &= ~((1<<7) | (1<<6) | (1<<5));
 	mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
 
-	return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode);
+	return taal_dcs_write_1(td, DCS_MEM_ACC_CTRL, mode);
 }
 
-static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
+static int taal_set_update_window(struct taal_data *td,
+		u16 x, u16 y, u16 w, u16 h)
 {
 	int r;
 	u16 x1 = x;
@@ -399,7 +402,7 @@
 	buf[3] = (x2 >> 8) & 0xff;
 	buf[4] = (x2 >> 0) & 0xff;
 
-	r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
+	r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
 	if (r)
 		return r;
 
@@ -409,11 +412,11 @@
 	buf[3] = (y2 >> 8) & 0xff;
 	buf[4] = (y2 >> 0) & 0xff;
 
-	r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
+	r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
 	if (r)
 		return r;
 
-	dsi_vc_send_bta_sync(TCH);
+	dsi_vc_send_bta_sync(td->channel);
 
 	return r;
 }
@@ -439,7 +442,7 @@
 	if (td->use_dsi_bl) {
 		if (td->enabled) {
 			dsi_bus_lock();
-			r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
+			r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
 			dsi_bus_unlock();
 		} else {
 			r = 0;
@@ -502,7 +505,7 @@
 
 	if (td->enabled) {
 		dsi_bus_lock();
-		r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
+		r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
 		dsi_bus_unlock();
 	} else {
 		r = -ENODEV;
@@ -528,7 +531,7 @@
 
 	if (td->enabled) {
 		dsi_bus_lock();
-		r = taal_get_id(&id1, &id2, &id3);
+		r = taal_get_id(td, &id1, &id2, &id3);
 		dsi_bus_unlock();
 	} else {
 		r = -ENODEV;
@@ -590,7 +593,7 @@
 	if (td->enabled) {
 		dsi_bus_lock();
 		if (!td->cabc_broken)
-			taal_dcs_write_1(DCS_WRITE_CABC, i);
+			taal_dcs_write_1(td, DCS_WRITE_CABC, i);
 		dsi_bus_unlock();
 	}
 
@@ -774,14 +777,29 @@
 		dev_dbg(&dssdev->dev, "Using GPIO TE\n");
 	}
 
+	r = omap_dsi_request_vc(dssdev, &td->channel);
+	if (r) {
+		dev_err(&dssdev->dev, "failed to get virtual channel\n");
+		goto err_req_vc;
+	}
+
+	r = omap_dsi_set_vc_id(dssdev, td->channel, TCH);
+	if (r) {
+		dev_err(&dssdev->dev, "failed to set VC_ID\n");
+		goto err_vc_id;
+	}
+
 	r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
 	if (r) {
 		dev_err(&dssdev->dev, "failed to create sysfs files\n");
-		goto err_sysfs;
+		goto err_vc_id;
 	}
 
 	return 0;
-err_sysfs:
+
+err_vc_id:
+	omap_dsi_release_vc(dssdev, td->channel);
+err_req_vc:
 	if (panel_data->use_ext_te)
 		free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev);
 err_irq:
@@ -808,6 +826,7 @@
 	dev_dbg(&dssdev->dev, "remove\n");
 
 	sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
+	omap_dsi_release_vc(dssdev, td->channel);
 
 	if (panel_data->use_ext_te) {
 		int gpio = panel_data->ext_te_gpio;
@@ -846,13 +865,13 @@
 
 	taal_hw_reset(dssdev);
 
-	omapdss_dsi_vc_enable_hs(TCH, false);
+	omapdss_dsi_vc_enable_hs(td->channel, false);
 
 	r = taal_sleep_out(td);
 	if (r)
 		goto err;
 
-	r = taal_get_id(&id1, &id2, &id3);
+	r = taal_get_id(td, &id1, &id2, &id3);
 	if (r)
 		goto err;
 
@@ -861,30 +880,30 @@
 		(id2 == 0x00 || id2 == 0xff || id2 == 0x81))
 		td->cabc_broken = true;
 
-	r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
+	r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff);
 	if (r)
 		goto err;
 
-	r = taal_dcs_write_1(DCS_CTRL_DISPLAY,
+	r = taal_dcs_write_1(td, DCS_CTRL_DISPLAY,
 			(1<<2) | (1<<5));	/* BL | BCTRL */
 	if (r)
 		goto err;
 
-	r = taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
+	r = taal_dcs_write_1(td, DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
 	if (r)
 		goto err;
 
-	r = taal_set_addr_mode(td->rotate, td->mirror);
+	r = taal_set_addr_mode(td, td->rotate, td->mirror);
 	if (r)
 		goto err;
 
 	if (!td->cabc_broken) {
-		r = taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
+		r = taal_dcs_write_1(td, DCS_WRITE_CABC, td->cabc_mode);
 		if (r)
 			goto err;
 	}
 
-	r = taal_dcs_write_0(DCS_DISPLAY_ON);
+	r = taal_dcs_write_0(td, DCS_DISPLAY_ON);
 	if (r)
 		goto err;
 
@@ -903,7 +922,7 @@
 		td->intro_printed = true;
 	}
 
-	omapdss_dsi_vc_enable_hs(TCH, true);
+	omapdss_dsi_vc_enable_hs(td->channel, true);
 
 	return 0;
 err:
@@ -921,7 +940,7 @@
 	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
 	int r;
 
-	r = taal_dcs_write_0(DCS_DISPLAY_OFF);
+	r = taal_dcs_write_0(td, DCS_DISPLAY_OFF);
 	if (!r) {
 		r = taal_sleep_in(td);
 		/* HACK: wait a bit so that the message goes through */
@@ -1089,7 +1108,7 @@
 	if (old) {
 		cancel_delayed_work(&td->te_timeout_work);
 
-		r = omap_dsi_update(dssdev, TCH,
+		r = omap_dsi_update(dssdev, td->channel,
 				td->update_region.x,
 				td->update_region.y,
 				td->update_region.w,
@@ -1139,7 +1158,7 @@
 	if (r)
 		goto err;
 
-	r = taal_set_update_window(x, y, w, h);
+	r = taal_set_update_window(td, x, y, w, h);
 	if (r)
 		goto err;
 
@@ -1153,7 +1172,7 @@
 				msecs_to_jiffies(250));
 		atomic_set(&td->do_update, 1);
 	} else {
-		r = omap_dsi_update(dssdev, TCH, x, y, w, h,
+		r = omap_dsi_update(dssdev, td->channel, x, y, w, h,
 				taal_framedone_cb, dssdev);
 		if (r)
 			goto err;
@@ -1191,9 +1210,9 @@
 	int r;
 
 	if (enable)
-		r = taal_dcs_write_1(DCS_TEAR_ON, 0);
+		r = taal_dcs_write_1(td, DCS_TEAR_ON, 0);
 	else
-		r = taal_dcs_write_0(DCS_TEAR_OFF);
+		r = taal_dcs_write_0(td, DCS_TEAR_OFF);
 
 	if (!panel_data->use_ext_te)
 		omapdss_dsi_enable_te(dssdev, enable);
@@ -1263,7 +1282,7 @@
 	dsi_bus_lock();
 
 	if (td->enabled) {
-		r = taal_set_addr_mode(rotate, td->mirror);
+		r = taal_set_addr_mode(td, rotate, td->mirror);
 		if (r)
 			goto err;
 	}
@@ -1306,7 +1325,7 @@
 
 	dsi_bus_lock();
 	if (td->enabled) {
-		r = taal_set_addr_mode(td->rotate, enable);
+		r = taal_set_addr_mode(td, td->rotate, enable);
 		if (r)
 			goto err;
 	}
@@ -1350,13 +1369,13 @@
 
 	dsi_bus_lock();
 
-	r = taal_dcs_read_1(DCS_GET_ID1, &id1);
+	r = taal_dcs_read_1(td, DCS_GET_ID1, &id1);
 	if (r)
 		goto err2;
-	r = taal_dcs_read_1(DCS_GET_ID2, &id2);
+	r = taal_dcs_read_1(td, DCS_GET_ID2, &id2);
 	if (r)
 		goto err2;
-	r = taal_dcs_read_1(DCS_GET_ID3, &id3);
+	r = taal_dcs_read_1(td, DCS_GET_ID3, &id3);
 	if (r)
 		goto err2;
 
@@ -1404,9 +1423,9 @@
 	else
 		plen = 2;
 
-	taal_set_update_window(x, y, w, h);
+	taal_set_update_window(td, x, y, w, h);
 
-	r = dsi_vc_set_max_rx_packet_size(TCH, plen);
+	r = dsi_vc_set_max_rx_packet_size(td->channel, plen);
 	if (r)
 		goto err2;
 
@@ -1414,7 +1433,7 @@
 		u8 dcs_cmd = first ? 0x2e : 0x3e;
 		first = 0;
 
-		r = dsi_vc_dcs_read(TCH, dcs_cmd,
+		r = dsi_vc_dcs_read(td->channel, dcs_cmd,
 				buf + buf_used, size - buf_used);
 
 		if (r < 0) {
@@ -1440,7 +1459,7 @@
 	r = buf_used;
 
 err3:
-	dsi_vc_set_max_rx_packet_size(TCH, 1);
+	dsi_vc_set_max_rx_packet_size(td->channel, 1);
 err2:
 	dsi_bus_unlock();
 err1:
@@ -1466,7 +1485,7 @@
 
 	dsi_bus_lock();
 
-	r = taal_dcs_read_1(DCS_RDDSDR, &state1);
+	r = taal_dcs_read_1(td, DCS_RDDSDR, &state1);
 	if (r) {
 		dev_err(&dssdev->dev, "failed to read Taal status\n");
 		goto err;
@@ -1479,7 +1498,7 @@
 		goto err;
 	}
 
-	r = taal_dcs_read_1(DCS_RDDSDR, &state2);
+	r = taal_dcs_read_1(td, DCS_RDDSDR, &state2);
 	if (r) {
 		dev_err(&dssdev->dev, "failed to read Taal status\n");
 		goto err;
@@ -1495,7 +1514,7 @@
 	/* Self-diagnostics result is also shown on TE GPIO line. We need
 	 * to re-enable TE after self diagnostics */
 	if (td->te_enabled && panel_data->use_ext_te) {
-		r = taal_dcs_write_1(DCS_TEAR_ON, 0);
+		r = taal_dcs_write_1(td, DCS_TEAR_ON, 0);
 		if (r)
 			goto err;
 	}
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index 43b6440..bfc5da0 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -1,8 +1,8 @@
 menuconfig OMAP2_DSS
-        tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
-        depends on ARCH_OMAP2 || ARCH_OMAP3
+        tristate "OMAP2+ Display Subsystem support (EXPERIMENTAL)"
+        depends on ARCH_OMAP2PLUS
         help
-          OMAP2/3 Display Subsystem support.
+	  OMAP2+ Display Subsystem support.
 
 if OMAP2_DSS
 
@@ -60,6 +60,14 @@
 	help
 	  OMAP Video Encoder support for S-Video and composite TV-out.
 
+config OMAP4_DSS_HDMI
+	bool "HDMI support"
+	depends on ARCH_OMAP4
+        default y
+	help
+	  HDMI Interface. This adds the High Definition Multimedia Interface.
+	  See http://www.hdmi.org/ for HDMI specification.
+
 config OMAP2_DSS_SDI
 	bool "SDI support"
 	depends on ARCH_OMAP3
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index 7db17b5..10d9d3b 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -5,3 +5,5 @@
 omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
 omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
 omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
+omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \
+				    hdmi_omap4_panel.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 8e89f60..1aa2ed1 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -34,332 +34,26 @@
 #include <linux/regulator/consumer.h>
 
 #include <plat/display.h>
-#include <plat/clock.h>
 
 #include "dss.h"
 #include "dss_features.h"
 
 static struct {
 	struct platform_device *pdev;
-	int		ctx_id;
-
-	struct clk      *dss_ick;
-	struct clk	*dss1_fck;
-	struct clk	*dss2_fck;
-	struct clk      *dss_54m_fck;
-	struct clk	*dss_96m_fck;
-	unsigned	num_clks_enabled;
 
 	struct regulator *vdds_dsi_reg;
 	struct regulator *vdds_sdi_reg;
-	struct regulator *vdda_dac_reg;
 } core;
 
-static void dss_clk_enable_all_no_ctx(void);
-static void dss_clk_disable_all_no_ctx(void);
-static void dss_clk_enable_no_ctx(enum dss_clock clks);
-static void dss_clk_disable_no_ctx(enum dss_clock clks);
-
 static char *def_disp_name;
 module_param_named(def_disp, def_disp_name, charp, 0);
-MODULE_PARM_DESC(def_disp_name, "default display name");
+MODULE_PARM_DESC(def_disp, "default display name");
 
 #ifdef DEBUG
 unsigned int dss_debug;
 module_param_named(debug, dss_debug, bool, 0644);
 #endif
 
-/* CONTEXT */
-static int dss_get_ctx_id(void)
-{
-	struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
-	int r;
-
-	if (!pdata->get_last_off_on_transaction_id)
-		return 0;
-	r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
-	if (r < 0) {
-		dev_err(&core.pdev->dev, "getting transaction ID failed, "
-				"will force context restore\n");
-		r = -1;
-	}
-	return r;
-}
-
-int dss_need_ctx_restore(void)
-{
-	int id = dss_get_ctx_id();
-
-	if (id < 0 || id != core.ctx_id) {
-		DSSDBG("ctx id %d -> id %d\n",
-				core.ctx_id, id);
-		core.ctx_id = id;
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-static void save_all_ctx(void)
-{
-	DSSDBG("save context\n");
-
-	dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
-
-	dss_save_context();
-	dispc_save_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
-	dsi_save_context();
-#endif
-
-	dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
-}
-
-static void restore_all_ctx(void)
-{
-	DSSDBG("restore context\n");
-
-	dss_clk_enable_all_no_ctx();
-
-	dss_restore_context();
-	dispc_restore_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
-	dsi_restore_context();
-#endif
-
-	dss_clk_disable_all_no_ctx();
-}
-
-#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
-/* CLOCKS */
-static void core_dump_clocks(struct seq_file *s)
-{
-	int i;
-	struct clk *clocks[5] = {
-		core.dss_ick,
-		core.dss1_fck,
-		core.dss2_fck,
-		core.dss_54m_fck,
-		core.dss_96m_fck
-	};
-
-	seq_printf(s, "- CORE -\n");
-
-	seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
-
-	for (i = 0; i < 5; i++) {
-		if (!clocks[i])
-			continue;
-		seq_printf(s, "%-15s\t%lu\t%d\n",
-				clocks[i]->name,
-				clk_get_rate(clocks[i]),
-				clocks[i]->usecount);
-	}
-}
-#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
-
-static int dss_get_clock(struct clk **clock, const char *clk_name)
-{
-	struct clk *clk;
-
-	clk = clk_get(&core.pdev->dev, clk_name);
-
-	if (IS_ERR(clk)) {
-		DSSERR("can't get clock %s", clk_name);
-		return PTR_ERR(clk);
-	}
-
-	*clock = clk;
-
-	DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
-
-	return 0;
-}
-
-static int dss_get_clocks(void)
-{
-	int r;
-
-	core.dss_ick = NULL;
-	core.dss1_fck = NULL;
-	core.dss2_fck = NULL;
-	core.dss_54m_fck = NULL;
-	core.dss_96m_fck = NULL;
-
-	r = dss_get_clock(&core.dss_ick, "ick");
-	if (r)
-		goto err;
-
-	r = dss_get_clock(&core.dss1_fck, "dss1_fck");
-	if (r)
-		goto err;
-
-	r = dss_get_clock(&core.dss2_fck, "dss2_fck");
-	if (r)
-		goto err;
-
-	r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
-	if (r)
-		goto err;
-
-	r = dss_get_clock(&core.dss_96m_fck, "video_fck");
-	if (r)
-		goto err;
-
-	return 0;
-
-err:
-	if (core.dss_ick)
-		clk_put(core.dss_ick);
-	if (core.dss1_fck)
-		clk_put(core.dss1_fck);
-	if (core.dss2_fck)
-		clk_put(core.dss2_fck);
-	if (core.dss_54m_fck)
-		clk_put(core.dss_54m_fck);
-	if (core.dss_96m_fck)
-		clk_put(core.dss_96m_fck);
-
-	return r;
-}
-
-static void dss_put_clocks(void)
-{
-	if (core.dss_96m_fck)
-		clk_put(core.dss_96m_fck);
-	clk_put(core.dss_54m_fck);
-	clk_put(core.dss1_fck);
-	clk_put(core.dss2_fck);
-	clk_put(core.dss_ick);
-}
-
-unsigned long dss_clk_get_rate(enum dss_clock clk)
-{
-	switch (clk) {
-	case DSS_CLK_ICK:
-		return clk_get_rate(core.dss_ick);
-	case DSS_CLK_FCK1:
-		return clk_get_rate(core.dss1_fck);
-	case DSS_CLK_FCK2:
-		return clk_get_rate(core.dss2_fck);
-	case DSS_CLK_54M:
-		return clk_get_rate(core.dss_54m_fck);
-	case DSS_CLK_96M:
-		return clk_get_rate(core.dss_96m_fck);
-	}
-
-	BUG();
-	return 0;
-}
-
-static unsigned count_clk_bits(enum dss_clock clks)
-{
-	unsigned num_clks = 0;
-
-	if (clks & DSS_CLK_ICK)
-		++num_clks;
-	if (clks & DSS_CLK_FCK1)
-		++num_clks;
-	if (clks & DSS_CLK_FCK2)
-		++num_clks;
-	if (clks & DSS_CLK_54M)
-		++num_clks;
-	if (clks & DSS_CLK_96M)
-		++num_clks;
-
-	return num_clks;
-}
-
-static void dss_clk_enable_no_ctx(enum dss_clock clks)
-{
-	unsigned num_clks = count_clk_bits(clks);
-
-	if (clks & DSS_CLK_ICK)
-		clk_enable(core.dss_ick);
-	if (clks & DSS_CLK_FCK1)
-		clk_enable(core.dss1_fck);
-	if (clks & DSS_CLK_FCK2)
-		clk_enable(core.dss2_fck);
-	if (clks & DSS_CLK_54M)
-		clk_enable(core.dss_54m_fck);
-	if (clks & DSS_CLK_96M)
-		clk_enable(core.dss_96m_fck);
-
-	core.num_clks_enabled += num_clks;
-}
-
-void dss_clk_enable(enum dss_clock clks)
-{
-	bool check_ctx = core.num_clks_enabled == 0;
-
-	dss_clk_enable_no_ctx(clks);
-
-	if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
-		restore_all_ctx();
-}
-
-static void dss_clk_disable_no_ctx(enum dss_clock clks)
-{
-	unsigned num_clks = count_clk_bits(clks);
-
-	if (clks & DSS_CLK_ICK)
-		clk_disable(core.dss_ick);
-	if (clks & DSS_CLK_FCK1)
-		clk_disable(core.dss1_fck);
-	if (clks & DSS_CLK_FCK2)
-		clk_disable(core.dss2_fck);
-	if (clks & DSS_CLK_54M)
-		clk_disable(core.dss_54m_fck);
-	if (clks & DSS_CLK_96M)
-		clk_disable(core.dss_96m_fck);
-
-	core.num_clks_enabled -= num_clks;
-}
-
-void dss_clk_disable(enum dss_clock clks)
-{
-	if (cpu_is_omap34xx()) {
-		unsigned num_clks = count_clk_bits(clks);
-
-		BUG_ON(core.num_clks_enabled < num_clks);
-
-		if (core.num_clks_enabled == num_clks)
-			save_all_ctx();
-	}
-
-	dss_clk_disable_no_ctx(clks);
-}
-
-static void dss_clk_enable_all_no_ctx(void)
-{
-	enum dss_clock clks;
-
-	clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
-	if (cpu_is_omap34xx())
-		clks |= DSS_CLK_96M;
-	dss_clk_enable_no_ctx(clks);
-}
-
-static void dss_clk_disable_all_no_ctx(void)
-{
-	enum dss_clock clks;
-
-	clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
-	if (cpu_is_omap34xx())
-		clks |= DSS_CLK_96M;
-	dss_clk_disable_no_ctx(clks);
-}
-
-static void dss_clk_disable_all(void)
-{
-	enum dss_clock clks;
-
-	clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
-	if (cpu_is_omap34xx())
-		clks |= DSS_CLK_96M;
-	dss_clk_disable(clks);
-}
-
 /* REGULATORS */
 
 struct regulator *dss_get_vdds_dsi(void)
@@ -390,32 +84,7 @@
 	return reg;
 }
 
-struct regulator *dss_get_vdda_dac(void)
-{
-	struct regulator *reg;
-
-	if (core.vdda_dac_reg != NULL)
-		return core.vdda_dac_reg;
-
-	reg = regulator_get(&core.pdev->dev, "vdda_dac");
-	if (!IS_ERR(reg))
-		core.vdda_dac_reg = reg;
-
-	return reg;
-}
-
-/* DEBUGFS */
 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
-static void dss_debug_dump_clocks(struct seq_file *s)
-{
-	core_dump_clocks(s);
-	dss_dump_clocks(s);
-	dispc_dump_clocks(s);
-#ifdef CONFIG_OMAP2_DSS_DSI
-	dsi_dump_clocks(s);
-#endif
-}
-
 static int dss_debug_show(struct seq_file *s, void *unused)
 {
 	void (*func)(struct seq_file *) = s->private;
@@ -497,7 +166,6 @@
 static int omap_dss_probe(struct platform_device *pdev)
 {
 	struct omap_dss_board_info *pdata = pdev->dev.platform_data;
-	int skip_init = 0;
 	int r;
 	int i;
 
@@ -508,63 +176,43 @@
 	dss_init_overlay_managers(pdev);
 	dss_init_overlays(pdev);
 
-	r = dss_get_clocks();
-	if (r)
-		goto err_clocks;
-
-	dss_clk_enable_all_no_ctx();
-
-	core.ctx_id = dss_get_ctx_id();
-	DSSDBG("initial ctx id %u\n", core.ctx_id);
-
-#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
-	/* DISPC_CONTROL */
-	if (omap_readl(0x48050440) & 1)	/* LCD enabled? */
-		skip_init = 1;
-#endif
-
-	r = dss_init(skip_init);
+	r = dss_init_platform_driver();
 	if (r) {
-		DSSERR("Failed to initialize DSS\n");
+		DSSERR("Failed to initialize DSS platform driver\n");
 		goto err_dss;
 	}
 
-	r = rfbi_init();
+	/* keep clocks enabled to prevent context saves/restores during init */
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+
+	r = rfbi_init_platform_driver();
 	if (r) {
-		DSSERR("Failed to initialize rfbi\n");
+		DSSERR("Failed to initialize rfbi platform driver\n");
 		goto err_rfbi;
 	}
 
-	r = dpi_init(pdev);
+	r = dispc_init_platform_driver();
 	if (r) {
-		DSSERR("Failed to initialize dpi\n");
-		goto err_dpi;
-	}
-
-	r = dispc_init();
-	if (r) {
-		DSSERR("Failed to initialize dispc\n");
+		DSSERR("Failed to initialize dispc platform driver\n");
 		goto err_dispc;
 	}
 
-	r = venc_init(pdev);
+	r = venc_init_platform_driver();
 	if (r) {
-		DSSERR("Failed to initialize venc\n");
+		DSSERR("Failed to initialize venc platform driver\n");
 		goto err_venc;
 	}
 
-	if (cpu_is_omap34xx()) {
-		r = sdi_init(skip_init);
-		if (r) {
-			DSSERR("Failed to initialize SDI\n");
-			goto err_sdi;
-		}
+	r = dsi_init_platform_driver();
+	if (r) {
+		DSSERR("Failed to initialize DSI platform driver\n");
+		goto err_dsi;
+	}
 
-		r = dsi_init(pdev);
-		if (r) {
-			DSSERR("Failed to initialize DSI\n");
-			goto err_dsi;
-		}
+	r = hdmi_init_platform_driver();
+	if (r) {
+		DSSERR("Failed to initialize hdmi\n");
+		goto err_hdmi;
 	}
 
 	r = dss_initialize_debugfs();
@@ -589,32 +237,25 @@
 			pdata->default_device = dssdev;
 	}
 
-	dss_clk_disable_all();
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	return 0;
 
 err_register:
 	dss_uninitialize_debugfs();
 err_debugfs:
-	if (cpu_is_omap34xx())
-		dsi_exit();
+	hdmi_uninit_platform_driver();
+err_hdmi:
+	dsi_uninit_platform_driver();
 err_dsi:
-	if (cpu_is_omap34xx())
-		sdi_exit();
-err_sdi:
-	venc_exit();
+	venc_uninit_platform_driver();
 err_venc:
-	dispc_exit();
+	dispc_uninit_platform_driver();
 err_dispc:
-	dpi_exit();
-err_dpi:
-	rfbi_exit();
+	rfbi_uninit_platform_driver();
 err_rfbi:
-	dss_exit();
+	dss_uninit_platform_driver();
 err_dss:
-	dss_clk_disable_all_no_ctx();
-	dss_put_clocks();
-err_clocks:
 
 	return r;
 }
@@ -623,61 +264,15 @@
 {
 	struct omap_dss_board_info *pdata = pdev->dev.platform_data;
 	int i;
-	int c;
 
 	dss_uninitialize_debugfs();
 
-	venc_exit();
-	dispc_exit();
-	dpi_exit();
-	rfbi_exit();
-	if (cpu_is_omap34xx()) {
-		dsi_exit();
-		sdi_exit();
-	}
-
-	dss_exit();
-
-	/* these should be removed at some point */
-	c = core.dss_ick->usecount;
-	if (c > 0) {
-		DSSERR("warning: dss_ick usecount %d, disabling\n", c);
-		while (c-- > 0)
-			clk_disable(core.dss_ick);
-	}
-
-	c = core.dss1_fck->usecount;
-	if (c > 0) {
-		DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
-		while (c-- > 0)
-			clk_disable(core.dss1_fck);
-	}
-
-	c = core.dss2_fck->usecount;
-	if (c > 0) {
-		DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
-		while (c-- > 0)
-			clk_disable(core.dss2_fck);
-	}
-
-	c = core.dss_54m_fck->usecount;
-	if (c > 0) {
-		DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
-		while (c-- > 0)
-			clk_disable(core.dss_54m_fck);
-	}
-
-	if (core.dss_96m_fck) {
-		c = core.dss_96m_fck->usecount;
-		if (c > 0) {
-			DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
-					c);
-			while (c-- > 0)
-				clk_disable(core.dss_96m_fck);
-		}
-	}
-
-	dss_put_clocks();
+	venc_uninit_platform_driver();
+	dispc_uninit_platform_driver();
+	rfbi_uninit_platform_driver();
+	dsi_uninit_platform_driver();
+	hdmi_uninit_platform_driver();
+	dss_uninit_platform_driver();
 
 	dss_uninit_overlays(pdev);
 	dss_uninit_overlay_managers(pdev);
@@ -965,11 +560,6 @@
 		core.vdds_sdi_reg = NULL;
 	}
 
-	if (core.vdda_dac_reg != NULL) {
-		regulator_put(core.vdda_dac_reg);
-		core.vdda_dac_reg = NULL;
-	}
-
 	platform_driver_unregister(&omap_dss_driver);
 
 	omap_dss_bus_unregister();
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 9f8c69f..7804779 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/hardirq.h>
+#include <linux/interrupt.h>
 
 #include <plat/sram.h>
 #include <plat/clock.h>
@@ -42,8 +43,6 @@
 #include "dss_features.h"
 
 /* DISPC */
-#define DISPC_BASE			0x48050400
-
 #define DISPC_SZ_REGS			SZ_4K
 
 struct dispc_reg { u16 idx; };
@@ -74,7 +73,7 @@
 #define DISPC_TIMING_H(ch)		DISPC_REG(ch != 2 ? 0x0064 : 0x0400)
 #define DISPC_TIMING_V(ch)		DISPC_REG(ch != 2 ? 0x0068 : 0x0404)
 #define DISPC_POL_FREQ(ch)		DISPC_REG(ch != 2 ? 0x006C : 0x0408)
-#define DISPC_DIVISOR(ch)		DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
+#define DISPC_DIVISORo(ch)		DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
 #define DISPC_GLOBAL_ALPHA		DISPC_REG(0x0074)
 #define DISPC_SIZE_DIG			DISPC_REG(0x0078)
 #define DISPC_SIZE_LCD(ch)		DISPC_REG(ch != 2 ? 0x007C : 0x03CC)
@@ -129,6 +128,7 @@
 
 #define DISPC_VID_PRELOAD(n)		DISPC_REG(0x230 + (n)*0x04)
 
+#define DISPC_DIVISOR			DISPC_REG(0x0804)
 
 #define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
 					 DISPC_IRQ_OCP_ERR | \
@@ -178,7 +178,9 @@
 };
 
 static struct {
+	struct platform_device *pdev;
 	void __iomem    *base;
+	int irq;
 
 	u32	fifo_size[3];
 
@@ -230,7 +232,7 @@
 	SR(TIMING_H(0));
 	SR(TIMING_V(0));
 	SR(POL_FREQ(0));
-	SR(DIVISOR(0));
+	SR(DIVISORo(0));
 	SR(GLOBAL_ALPHA);
 	SR(SIZE_DIG);
 	SR(SIZE_LCD(0));
@@ -242,7 +244,7 @@
 		SR(TIMING_H(2));
 		SR(TIMING_V(2));
 		SR(POL_FREQ(2));
-		SR(DIVISOR(2));
+		SR(DIVISORo(2));
 		SR(CONFIG2);
 	}
 
@@ -373,6 +375,9 @@
 	SR(VID_FIR_COEF_V(1, 7));
 
 	SR(VID_PRELOAD(1));
+
+	if (dss_has_feature(FEAT_CORE_CLK_DIV))
+		SR(DIVISOR);
 }
 
 void dispc_restore_context(void)
@@ -389,7 +394,7 @@
 	RR(TIMING_H(0));
 	RR(TIMING_V(0));
 	RR(POL_FREQ(0));
-	RR(DIVISOR(0));
+	RR(DIVISORo(0));
 	RR(GLOBAL_ALPHA);
 	RR(SIZE_DIG);
 	RR(SIZE_LCD(0));
@@ -400,7 +405,7 @@
 		RR(TIMING_H(2));
 		RR(TIMING_V(2));
 		RR(POL_FREQ(2));
-		RR(DIVISOR(2));
+		RR(DIVISORo(2));
 		RR(CONFIG2);
 	}
 
@@ -532,6 +537,9 @@
 
 	RR(VID_PRELOAD(1));
 
+	if (dss_has_feature(FEAT_CORE_CLK_DIV))
+		RR(DIVISOR);
+
 	/* enable last, because LCD & DIGIT enable are here */
 	RR(CONTROL);
 	if (dss_has_feature(FEAT_MGR_LCD2))
@@ -552,9 +560,9 @@
 static inline void enable_clocks(bool enable)
 {
 	if (enable)
-		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 	else
-		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
 bool dispc_go_busy(enum omap_channel channel)
@@ -1000,6 +1008,20 @@
 	enable_clocks(0);
 }
 
+void dispc_enable_gamma_table(bool enable)
+{
+	/*
+	 * This is partially implemented to support only disabling of
+	 * the gamma table.
+	 */
+	if (enable) {
+		DSSWARN("Gamma table enabling for TV not yet supported");
+		return;
+	}
+
+	REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
+}
+
 static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
 {
 	u32 val;
@@ -1129,10 +1151,16 @@
 	u32 val;
 	const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
 				      DISPC_VID_ACCU0(1) };
+	u8 hor_start, hor_end, vert_start, vert_end;
 
 	BUG_ON(plane == OMAP_DSS_GFX);
 
-	val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
+	dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
+	dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
+
+	val = FLD_VAL(vaccu, vert_start, vert_end) |
+			FLD_VAL(haccu, hor_start, hor_end);
+
 	dispc_write_reg(ac0_reg[plane-1], val);
 }
 
@@ -1141,10 +1169,16 @@
 	u32 val;
 	const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
 				      DISPC_VID_ACCU1(1) };
+	u8 hor_start, hor_end, vert_start, vert_end;
 
 	BUG_ON(plane == OMAP_DSS_GFX);
 
-	val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
+	dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
+	dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
+
+	val = FLD_VAL(vaccu, vert_start, vert_end) |
+			FLD_VAL(haccu, hor_start, hor_end);
+
 	dispc_write_reg(ac1_reg[plane-1], val);
 }
 
@@ -1182,16 +1216,25 @@
 	_dispc_set_fir(plane, fir_hinc, fir_vinc);
 
 	l = dispc_read_reg(dispc_reg_att[plane]);
-	l &= ~((0x0f << 5) | (0x3 << 21));
 
+	/* RESIZEENABLE and VERTICALTAPS */
+	l &= ~((0x3 << 5) | (0x1 << 21));
 	l |= fir_hinc ? (1 << 5) : 0;
 	l |= fir_vinc ? (1 << 6) : 0;
-
-	l |= hscaleup ? 0 : (1 << 7);
-	l |= vscaleup ? 0 : (1 << 8);
-
 	l |= five_taps ? (1 << 21) : 0;
-	l |= five_taps ? (1 << 22) : 0;
+
+	/* VRESIZECONF and HRESIZECONF */
+	if (dss_has_feature(FEAT_RESIZECONF)) {
+		l &= ~(0x3 << 7);
+		l |= hscaleup ? 0 : (1 << 7);
+		l |= vscaleup ? 0 : (1 << 8);
+	}
+
+	/* LINEBUFFERSPLIT */
+	if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
+		l &= ~(0x1 << 22);
+		l |= five_taps ? (1 << 22) : 0;
+	}
 
 	dispc_write_reg(dispc_reg_att[plane], l);
 
@@ -1215,9 +1258,11 @@
 static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
 		bool mirroring, enum omap_color_mode color_mode)
 {
+	bool row_repeat = false;
+	int vidrot = 0;
+
 	if (color_mode == OMAP_DSS_COLOR_YUV2 ||
 			color_mode == OMAP_DSS_COLOR_UYVY) {
-		int vidrot = 0;
 
 		if (mirroring) {
 			switch (rotation) {
@@ -1251,16 +1296,15 @@
 			}
 		}
 
-		REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
-
 		if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
-			REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
+			row_repeat = true;
 		else
-			REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
-	} else {
-		REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
-		REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
+			row_repeat = false;
 	}
+
+	REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
+	if (dss_has_feature(FEAT_ROWREPEATENABLE))
+		REG_FLD_MOD(dispc_reg_att[plane], row_repeat ? 1 : 0, 18, 18);
 }
 
 static int color_mode_to_bpp(enum omap_color_mode color_mode)
@@ -2293,7 +2337,7 @@
 	BUG_ON(pck_div < 2);
 
 	enable_clocks(1);
-	dispc_write_reg(DISPC_DIVISOR(channel),
+	dispc_write_reg(DISPC_DIVISORo(channel),
 			FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
 	enable_clocks(0);
 }
@@ -2302,7 +2346,7 @@
 		int *pck_div)
 {
 	u32 l;
-	l = dispc_read_reg(DISPC_DIVISOR(channel));
+	l = dispc_read_reg(DISPC_DIVISORo(channel));
 	*lck_div = FLD_GET(l, 23, 16);
 	*pck_div = FLD_GET(l, 7, 0);
 }
@@ -2311,14 +2355,17 @@
 {
 	unsigned long r = 0;
 
-	if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK)
-		r = dss_clk_get_rate(DSS_CLK_FCK1);
-	else
-#ifdef CONFIG_OMAP2_DSS_DSI
-		r = dsi_get_dsi1_pll_rate();
-#else
-	BUG();
-#endif
+	switch (dss_get_dispc_clk_source()) {
+	case DSS_CLK_SRC_FCK:
+		r = dss_clk_get_rate(DSS_CLK_FCK);
+		break;
+	case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+		r = dsi_get_pll_hsdiv_dispc_rate();
+		break;
+	default:
+		BUG();
+	}
+
 	return r;
 }
 
@@ -2328,47 +2375,72 @@
 	unsigned long r;
 	u32 l;
 
-	l = dispc_read_reg(DISPC_DIVISOR(channel));
+	l = dispc_read_reg(DISPC_DIVISORo(channel));
 
 	lcd = FLD_GET(l, 23, 16);
 
-	r = dispc_fclk_rate();
+	switch (dss_get_lcd_clk_source(channel)) {
+	case DSS_CLK_SRC_FCK:
+		r = dss_clk_get_rate(DSS_CLK_FCK);
+		break;
+	case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+		r = dsi_get_pll_hsdiv_dispc_rate();
+		break;
+	default:
+		BUG();
+	}
 
 	return r / lcd;
 }
 
 unsigned long dispc_pclk_rate(enum omap_channel channel)
 {
-	int lcd, pcd;
+	int pcd;
 	unsigned long r;
 	u32 l;
 
-	l = dispc_read_reg(DISPC_DIVISOR(channel));
+	l = dispc_read_reg(DISPC_DIVISORo(channel));
 
-	lcd = FLD_GET(l, 23, 16);
 	pcd = FLD_GET(l, 7, 0);
 
-	r = dispc_fclk_rate();
+	r = dispc_lclk_rate(channel);
 
-	return r / lcd / pcd;
+	return r / pcd;
 }
 
 void dispc_dump_clocks(struct seq_file *s)
 {
 	int lcd, pcd;
+	u32 l;
+	enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
+	enum dss_clk_source lcd_clk_src;
 
 	enable_clocks(1);
 
 	seq_printf(s, "- DISPC -\n");
 
-	seq_printf(s, "dispc fclk source = %s\n",
-			dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
-			"dss1_alwon_fclk" : "dsi1_pll_fclk");
+	seq_printf(s, "dispc fclk source = %s (%s)\n",
+			dss_get_generic_clk_source_name(dispc_clk_src),
+			dss_feat_get_clk_source_name(dispc_clk_src));
 
 	seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
 
+	if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
+		seq_printf(s, "- DISPC-CORE-CLK -\n");
+		l = dispc_read_reg(DISPC_DIVISOR);
+		lcd = FLD_GET(l, 23, 16);
+
+		seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+				(dispc_fclk_rate()/lcd), lcd);
+	}
 	seq_printf(s, "- LCD1 -\n");
 
+	lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD);
+
+	seq_printf(s, "lcd1_clk source = %s (%s)\n",
+		dss_get_generic_clk_source_name(lcd_clk_src),
+		dss_feat_get_clk_source_name(lcd_clk_src));
+
 	dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
 
 	seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
@@ -2378,6 +2450,12 @@
 	if (dss_has_feature(FEAT_MGR_LCD2)) {
 		seq_printf(s, "- LCD2 -\n");
 
+		lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2);
+
+		seq_printf(s, "lcd2_clk source = %s (%s)\n",
+			dss_get_generic_clk_source_name(lcd_clk_src),
+			dss_feat_get_clk_source_name(lcd_clk_src));
+
 		dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
 
 		seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
@@ -2440,7 +2518,7 @@
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
 
-	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	DUMPREG(DISPC_REVISION);
 	DUMPREG(DISPC_SYSCONFIG);
@@ -2459,7 +2537,7 @@
 	DUMPREG(DISPC_TIMING_H(0));
 	DUMPREG(DISPC_TIMING_V(0));
 	DUMPREG(DISPC_POL_FREQ(0));
-	DUMPREG(DISPC_DIVISOR(0));
+	DUMPREG(DISPC_DIVISORo(0));
 	DUMPREG(DISPC_GLOBAL_ALPHA);
 	DUMPREG(DISPC_SIZE_DIG);
 	DUMPREG(DISPC_SIZE_LCD(0));
@@ -2471,7 +2549,7 @@
 		DUMPREG(DISPC_TIMING_H(2));
 		DUMPREG(DISPC_TIMING_V(2));
 		DUMPREG(DISPC_POL_FREQ(2));
-		DUMPREG(DISPC_DIVISOR(2));
+		DUMPREG(DISPC_DIVISORo(2));
 		DUMPREG(DISPC_SIZE_LCD(2));
 	}
 
@@ -2597,7 +2675,7 @@
 	DUMPREG(DISPC_VID_PRELOAD(0));
 	DUMPREG(DISPC_VID_PRELOAD(1));
 
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
@@ -2713,8 +2791,8 @@
 
 	fck = dispc_fclk_rate();
 
-	cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16);
-	cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0);
+	cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
+	cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
 
 	cinfo->lck = fck / cinfo->lck_div;
 	cinfo->pck = cinfo->lck / cinfo->pck_div;
@@ -2791,6 +2869,9 @@
 		break;
 	}
 
+	if (ret)
+		goto err;
+
 	_omap_dispc_set_irqs();
 
 	spin_unlock_irqrestore(&dispc.irq_lock, flags);
@@ -2866,10 +2947,10 @@
  * but we presume they are on because we got an IRQ. However,
  * an irq handler may turn the clocks off, so we may not have
  * clock later in the function. */
-void dispc_irq_handler(void)
+static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
 {
 	int i;
-	u32 irqstatus;
+	u32 irqstatus, irqenable;
 	u32 handledirqs = 0;
 	u32 unhandled_errors;
 	struct omap_dispc_isr_data *isr_data;
@@ -2878,6 +2959,13 @@
 	spin_lock(&dispc.irq_lock);
 
 	irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
+	irqenable = dispc_read_reg(DISPC_IRQENABLE);
+
+	/* IRQ is not for us */
+	if (!(irqstatus & irqenable)) {
+		spin_unlock(&dispc.irq_lock);
+		return IRQ_NONE;
+	}
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
 	spin_lock(&dispc.irq_stats_lock);
@@ -2929,6 +3017,8 @@
 	}
 
 	spin_unlock(&dispc.irq_lock);
+
+	return IRQ_HANDLED;
 }
 
 static void dispc_error_worker(struct work_struct *work)
@@ -3253,6 +3343,15 @@
 	l = FLD_MOD(l, 1, 0, 0);	/* AUTOIDLE */
 	dispc_write_reg(DISPC_SYSCONFIG, l);
 
+	/* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
+	if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
+		l = dispc_read_reg(DISPC_DIVISOR);
+		/* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
+		l = FLD_MOD(l, 1, 0, 0);
+		l = FLD_MOD(l, 1, 23, 16);
+		dispc_write_reg(DISPC_DIVISOR, l);
+	}
+
 	/* FUNCGATED */
 	if (dss_has_feature(FEAT_FUNCGATED))
 		REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
@@ -3269,47 +3368,6 @@
 	dispc_read_plane_fifo_sizes();
 }
 
-int dispc_init(void)
-{
-	u32 rev;
-
-	spin_lock_init(&dispc.irq_lock);
-
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-	spin_lock_init(&dispc.irq_stats_lock);
-	dispc.irq_stats.last_reset = jiffies;
-#endif
-
-	INIT_WORK(&dispc.error_work, dispc_error_worker);
-
-	dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
-	if (!dispc.base) {
-		DSSERR("can't ioremap DISPC\n");
-		return -ENOMEM;
-	}
-
-	enable_clocks(1);
-
-	_omap_dispc_initial_config();
-
-	_omap_dispc_initialize_irq();
-
-	dispc_save_context();
-
-	rev = dispc_read_reg(DISPC_REVISION);
-	printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
-	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
-
-	enable_clocks(0);
-
-	return 0;
-}
-
-void dispc_exit(void)
-{
-	iounmap(dispc.base);
-}
-
 int dispc_enable_plane(enum omap_plane plane, bool enable)
 {
 	DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
@@ -3359,3 +3417,94 @@
 
 	return r;
 }
+
+/* DISPC HW IP initialisation */
+static int omap_dispchw_probe(struct platform_device *pdev)
+{
+	u32 rev;
+	int r = 0;
+	struct resource *dispc_mem;
+
+	dispc.pdev = pdev;
+
+	spin_lock_init(&dispc.irq_lock);
+
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+	spin_lock_init(&dispc.irq_stats_lock);
+	dispc.irq_stats.last_reset = jiffies;
+#endif
+
+	INIT_WORK(&dispc.error_work, dispc_error_worker);
+
+	dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
+	if (!dispc_mem) {
+		DSSERR("can't get IORESOURCE_MEM DISPC\n");
+		r = -EINVAL;
+		goto fail0;
+	}
+	dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem));
+	if (!dispc.base) {
+		DSSERR("can't ioremap DISPC\n");
+		r = -ENOMEM;
+		goto fail0;
+	}
+	dispc.irq = platform_get_irq(dispc.pdev, 0);
+	if (dispc.irq < 0) {
+		DSSERR("platform_get_irq failed\n");
+		r = -ENODEV;
+		goto fail1;
+	}
+
+	r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED,
+		"OMAP DISPC", dispc.pdev);
+	if (r < 0) {
+		DSSERR("request_irq failed\n");
+		goto fail1;
+	}
+
+	enable_clocks(1);
+
+	_omap_dispc_initial_config();
+
+	_omap_dispc_initialize_irq();
+
+	dispc_save_context();
+
+	rev = dispc_read_reg(DISPC_REVISION);
+	dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
+	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+	enable_clocks(0);
+
+	return 0;
+fail1:
+	iounmap(dispc.base);
+fail0:
+	return r;
+}
+
+static int omap_dispchw_remove(struct platform_device *pdev)
+{
+	free_irq(dispc.irq, dispc.pdev);
+	iounmap(dispc.base);
+	return 0;
+}
+
+static struct platform_driver omap_dispchw_driver = {
+	.probe          = omap_dispchw_probe,
+	.remove         = omap_dispchw_remove,
+	.driver         = {
+		.name   = "omapdss_dispc",
+		.owner  = THIS_MODULE,
+	},
+};
+
+int dispc_init_platform_driver(void)
+{
+	return platform_driver_register(&omap_dispchw_driver);
+}
+
+void dispc_uninit_platform_driver(void)
+{
+	return platform_driver_unregister(&omap_dispchw_driver);
+}
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 22dd7a4..a85a6f3 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -25,14 +25,11 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/jiffies.h>
-#include <linux/list.h>
 #include <linux/platform_device.h>
 
 #include <plat/display.h>
 #include "dss.h"
 
-static LIST_HEAD(display_list);
-
 static ssize_t display_enabled_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -345,6 +342,7 @@
 			return 16;
 	case OMAP_DISPLAY_TYPE_VENC:
 	case OMAP_DISPLAY_TYPE_SDI:
+	case OMAP_DISPLAY_TYPE_HDMI:
 		return 24;
 	default:
 		BUG();
@@ -371,6 +369,7 @@
 	case OMAP_DISPLAY_TYPE_DPI:
 		bpp = dssdev->phy.dpi.data_lines;
 		break;
+	case OMAP_DISPLAY_TYPE_HDMI:
 	case OMAP_DISPLAY_TYPE_VENC:
 	case OMAP_DISPLAY_TYPE_SDI:
 		bpp = 24;
@@ -396,29 +395,6 @@
 	switch (dssdev->type) {
 #ifdef CONFIG_OMAP2_DSS_DPI
 	case OMAP_DISPLAY_TYPE_DPI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_RFBI
-	case OMAP_DISPLAY_TYPE_DBI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_SDI
-	case OMAP_DISPLAY_TYPE_SDI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_DSI
-	case OMAP_DISPLAY_TYPE_DSI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_VENC
-	case OMAP_DISPLAY_TYPE_VENC:
-#endif
-		break;
-	default:
-		DSSERR("Support for display '%s' not compiled in.\n",
-				dssdev->name);
-		return;
-	}
-
-	switch (dssdev->type) {
-#ifdef CONFIG_OMAP2_DSS_DPI
-	case OMAP_DISPLAY_TYPE_DPI:
 		r = dpi_init_display(dssdev);
 		break;
 #endif
@@ -442,8 +418,13 @@
 		r = dsi_init_display(dssdev);
 		break;
 #endif
+	case OMAP_DISPLAY_TYPE_HDMI:
+		r = hdmi_init_display(dssdev);
+		break;
 	default:
-		BUG();
+		DSSERR("Support for display '%s' not compiled in.\n",
+				dssdev->name);
+		return;
 	}
 
 	if (r) {
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 75fb0a5..2d3ca4c 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -57,13 +57,13 @@
 	if (r)
 		return r;
 
-	dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
+	dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
 
 	r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
 	if (r)
 		return r;
 
-	*fck = dsi_cinfo.dsi1_pll_fclk;
+	*fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
 	*lck_div = dispc_cinfo.lck_div;
 	*pck_div = dispc_cinfo.pck_div;
 
@@ -107,7 +107,7 @@
 	bool is_tft;
 	int r = 0;
 
-	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
 			dssdev->panel.acbi, dssdev->panel.acb);
@@ -137,7 +137,7 @@
 	dispc_set_lcd_timings(dssdev->manager->id, t);
 
 err0:
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 	return r;
 }
 
@@ -173,14 +173,14 @@
 			goto err1;
 	}
 
-	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	r = dpi_basic_init(dssdev);
 	if (r)
 		goto err2;
 
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-	dss_clk_enable(DSS_CLK_FCK2);
+	dss_clk_enable(DSS_CLK_SYSCK);
 	r = dsi_pll_init(dssdev, 0, 1);
 	if (r)
 		goto err3;
@@ -199,10 +199,10 @@
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
 	dsi_pll_uninit();
 err3:
-	dss_clk_disable(DSS_CLK_FCK2);
+	dss_clk_disable(DSS_CLK_SYSCK);
 #endif
 err2:
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 	if (cpu_is_omap34xx())
 		regulator_disable(dpi.vdds_dsi_reg);
 err1:
@@ -217,12 +217,12 @@
 	dssdev->manager->disable(dssdev->manager);
 
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-	dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+	dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
 	dsi_pll_uninit();
-	dss_clk_disable(DSS_CLK_FCK2);
+	dss_clk_disable(DSS_CLK_SYSCK);
 #endif
 
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	if (cpu_is_omap34xx())
 		regulator_disable(dpi.vdds_dsi_reg);
@@ -271,7 +271,7 @@
 		if (r)
 			return r;
 
-		fck = dsi_cinfo.dsi1_pll_fclk;
+		fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
 		lck_div = dispc_cinfo.lck_div;
 		pck_div = dispc_cinfo.pck_div;
 	}
@@ -303,19 +303,24 @@
 {
 	DSSDBG("init_display\n");
 
+	if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) {
+		struct regulator *vdds_dsi;
+
+		vdds_dsi = dss_get_vdds_dsi();
+
+		if (IS_ERR(vdds_dsi)) {
+			DSSERR("can't get VDDS_DSI regulator\n");
+			return PTR_ERR(vdds_dsi);
+		}
+
+		dpi.vdds_dsi_reg = vdds_dsi;
+	}
+
 	return 0;
 }
 
-int dpi_init(struct platform_device *pdev)
+int dpi_init(void)
 {
-	if (cpu_is_omap34xx()) {
-		dpi.vdds_dsi_reg = dss_get_vdds_dsi();
-		if (IS_ERR(dpi.vdds_dsi_reg)) {
-			DSSERR("can't get VDDS_DSI regulator\n");
-			return PTR_ERR(dpi.vdds_dsi_reg);
-		}
-	}
-
 	return 0;
 }
 
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index ddf3a05..0a7f1a4 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -38,12 +38,11 @@
 #include <plat/clock.h>
 
 #include "dss.h"
+#include "dss_features.h"
 
 /*#define VERBOSE_IRQ*/
 #define DSI_CATCH_MISSING_TE
 
-#define DSI_BASE		0x4804FC00
-
 struct dsi_reg { u16 idx; };
 
 #define DSI_REG(idx)		((const struct dsi_reg) { idx })
@@ -186,13 +185,15 @@
 #define DSI_DT_RX_SHORT_READ_1		0x21
 #define DSI_DT_RX_SHORT_READ_2		0x22
 
-#define FINT_MAX 2100000
-#define FINT_MIN 750000
-#define REGN_MAX (1 << 7)
-#define REGM_MAX ((1 << 11) - 1)
-#define REGM3_MAX (1 << 4)
-#define REGM4_MAX (1 << 4)
-#define LP_DIV_MAX ((1 << 13) - 1)
+typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
+
+#define DSI_MAX_NR_ISRS                2
+
+struct dsi_isr_data {
+	omap_dsi_isr_t	isr;
+	void		*arg;
+	u32		mask;
+};
 
 enum fifo_size {
 	DSI_FIFO_SIZE_0		= 0,
@@ -220,9 +221,17 @@
 	unsigned cio_irqs[32];
 };
 
+struct dsi_isr_tables {
+	struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
+	struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
+	struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
+};
+
 static struct
 {
+	struct platform_device *pdev;
 	void __iomem	*base;
+	int irq;
 
 	struct dsi_clock_info current_cinfo;
 
@@ -232,6 +241,7 @@
 		enum dsi_vc_mode mode;
 		struct omap_dss_device *dssdev;
 		enum fifo_size fifo_size;
+		int vc_id;
 	} vc[4];
 
 	struct mutex lock;
@@ -239,8 +249,10 @@
 
 	unsigned pll_locked;
 
-	struct completion bta_completion;
-	void (*bta_callback)(void);
+	spinlock_t irq_lock;
+	struct dsi_isr_tables isr_tables;
+	/* space for a copy used by the interrupt handler */
+	struct dsi_isr_tables isr_tables_copy;
 
 	int update_channel;
 	struct dsi_update_region update_region;
@@ -275,6 +287,11 @@
 	spinlock_t irq_stats_lock;
 	struct dsi_irq_stats irq_stats;
 #endif
+	/* DSI PLL Parameter Ranges */
+	unsigned long regm_max, regn_max;
+	unsigned long  regm_dispc_max, regm_dsi_max;
+	unsigned long  fint_min, fint_max;
+	unsigned long lpdiv_max;
 } dsi;
 
 #ifdef DEBUG
@@ -318,6 +335,11 @@
 	return dsi.bus_lock.count == 0;
 }
 
+static void dsi_completion_handler(void *data, u32 mask)
+{
+	complete((struct completion *)data);
+}
+
 static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
 		int value)
 {
@@ -387,6 +409,9 @@
 
 static void print_irq_status(u32 status)
 {
+	if (status == 0)
+		return;
+
 #ifndef VERBOSE_IRQ
 	if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
 		return;
@@ -422,6 +447,9 @@
 
 static void print_irq_status_vc(int channel, u32 status)
 {
+	if (status == 0)
+		return;
+
 #ifndef VERBOSE_IRQ
 	if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
 		return;
@@ -448,6 +476,9 @@
 
 static void print_irq_status_cio(u32 status)
 {
+	if (status == 0)
+		return;
+
 	printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
 
 #define PIS(x) \
@@ -478,22 +509,33 @@
 	printk("\n");
 }
 
-static int debug_irq;
-
-/* called from dss */
-void dsi_irq_handler(void)
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+static void dsi_collect_irq_stats(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
 {
-	u32 irqstatus, vcstatus, ciostatus;
 	int i;
 
-	irqstatus = dsi_read_reg(DSI_IRQSTATUS);
-
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
 	spin_lock(&dsi.irq_stats_lock);
+
 	dsi.irq_stats.irq_count++;
 	dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
+
+	for (i = 0; i < 4; ++i)
+		dss_collect_irq_stats(vcstatus[i], dsi.irq_stats.vc_irqs[i]);
+
+	dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
+
+	spin_unlock(&dsi.irq_stats_lock);
+}
+#else
+#define dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus)
 #endif
 
+static int debug_irq;
+
+static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+{
+	int i;
+
 	if (irqstatus & DSI_IRQ_ERROR_MASK) {
 		DSSERR("DSI error, irqstatus %x\n", irqstatus);
 		print_irq_status(irqstatus);
@@ -504,37 +546,88 @@
 		print_irq_status(irqstatus);
 	}
 
-#ifdef DSI_CATCH_MISSING_TE
-	if (irqstatus & DSI_IRQ_TE_TRIGGER)
-		del_timer(&dsi.te_timer);
-#endif
+	for (i = 0; i < 4; ++i) {
+		if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
+			DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
+				       i, vcstatus[i]);
+			print_irq_status_vc(i, vcstatus[i]);
+		} else if (debug_irq) {
+			print_irq_status_vc(i, vcstatus[i]);
+		}
+	}
+
+	if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
+		DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
+		print_irq_status_cio(ciostatus);
+	} else if (debug_irq) {
+		print_irq_status_cio(ciostatus);
+	}
+}
+
+static void dsi_call_isrs(struct dsi_isr_data *isr_array,
+		unsigned isr_array_size, u32 irqstatus)
+{
+	struct dsi_isr_data *isr_data;
+	int i;
+
+	for (i = 0; i < isr_array_size; i++) {
+		isr_data = &isr_array[i];
+		if (isr_data->isr && isr_data->mask & irqstatus)
+			isr_data->isr(isr_data->arg, irqstatus);
+	}
+}
+
+static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
+		u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+{
+	int i;
+
+	dsi_call_isrs(isr_tables->isr_table,
+			ARRAY_SIZE(isr_tables->isr_table),
+			irqstatus);
 
 	for (i = 0; i < 4; ++i) {
-		if ((irqstatus & (1<<i)) == 0)
+		if (vcstatus[i] == 0)
 			continue;
+		dsi_call_isrs(isr_tables->isr_table_vc[i],
+				ARRAY_SIZE(isr_tables->isr_table_vc[i]),
+				vcstatus[i]);
+	}
 
-		vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+	if (ciostatus != 0)
+		dsi_call_isrs(isr_tables->isr_table_cio,
+				ARRAY_SIZE(isr_tables->isr_table_cio),
+				ciostatus);
+}
 
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-		dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
-#endif
+static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
+{
+	u32 irqstatus, vcstatus[4], ciostatus;
+	int i;
 
-		if (vcstatus & DSI_VC_IRQ_BTA) {
-			complete(&dsi.bta_completion);
+	spin_lock(&dsi.irq_lock);
 
-			if (dsi.bta_callback)
-				dsi.bta_callback();
+	irqstatus = dsi_read_reg(DSI_IRQSTATUS);
+
+	/* IRQ is not for us */
+	if (!irqstatus) {
+		spin_unlock(&dsi.irq_lock);
+		return IRQ_NONE;
+	}
+
+	dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
+	/* flush posted write */
+	dsi_read_reg(DSI_IRQSTATUS);
+
+	for (i = 0; i < 4; ++i) {
+		if ((irqstatus & (1 << i)) == 0) {
+			vcstatus[i] = 0;
+			continue;
 		}
 
-		if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
-			DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
-				       i, vcstatus);
-			print_irq_status_vc(i, vcstatus);
-		} else if (debug_irq) {
-			print_irq_status_vc(i, vcstatus);
-		}
+		vcstatus[i] = dsi_read_reg(DSI_VC_IRQSTATUS(i));
 
-		dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
+		dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus[i]);
 		/* flush posted write */
 		dsi_read_reg(DSI_VC_IRQSTATUS(i));
 	}
@@ -542,68 +635,278 @@
 	if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
 		ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
 
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-		dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
-#endif
-
 		dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
 		/* flush posted write */
 		dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
-
-		if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
-			DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
-			print_irq_status_cio(ciostatus);
-		} else if (debug_irq) {
-			print_irq_status_cio(ciostatus);
-		}
+	} else {
+		ciostatus = 0;
 	}
 
-	dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
-	/* flush posted write */
-	dsi_read_reg(DSI_IRQSTATUS);
-
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-	spin_unlock(&dsi.irq_stats_lock);
+#ifdef DSI_CATCH_MISSING_TE
+	if (irqstatus & DSI_IRQ_TE_TRIGGER)
+		del_timer(&dsi.te_timer);
 #endif
+
+	/* make a copy and unlock, so that isrs can unregister
+	 * themselves */
+	memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables));
+
+	spin_unlock(&dsi.irq_lock);
+
+	dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus);
+
+	dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus);
+
+	dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus);
+
+	return IRQ_HANDLED;
 }
 
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array,
+		unsigned isr_array_size, u32 default_mask,
+		const struct dsi_reg enable_reg,
+		const struct dsi_reg status_reg)
+{
+	struct dsi_isr_data *isr_data;
+	u32 mask;
+	u32 old_mask;
+	int i;
+
+	mask = default_mask;
+
+	for (i = 0; i < isr_array_size; i++) {
+		isr_data = &isr_array[i];
+
+		if (isr_data->isr == NULL)
+			continue;
+
+		mask |= isr_data->mask;
+	}
+
+	old_mask = dsi_read_reg(enable_reg);
+	/* clear the irqstatus for newly enabled irqs */
+	dsi_write_reg(status_reg, (mask ^ old_mask) & mask);
+	dsi_write_reg(enable_reg, mask);
+
+	/* flush posted writes */
+	dsi_read_reg(enable_reg);
+	dsi_read_reg(status_reg);
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs(void)
+{
+	u32 mask = DSI_IRQ_ERROR_MASK;
+#ifdef DSI_CATCH_MISSING_TE
+	mask |= DSI_IRQ_TE_TRIGGER;
+#endif
+	_omap_dsi_configure_irqs(dsi.isr_tables.isr_table,
+			ARRAY_SIZE(dsi.isr_tables.isr_table), mask,
+			DSI_IRQENABLE, DSI_IRQSTATUS);
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_vc(int vc)
+{
+	_omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc],
+			ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]),
+			DSI_VC_IRQ_ERROR_MASK,
+			DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_cio(void)
+{
+	_omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio,
+			ARRAY_SIZE(dsi.isr_tables.isr_table_cio),
+			DSI_CIO_IRQ_ERROR_MASK,
+			DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
+}
 
 static void _dsi_initialize_irq(void)
 {
-	u32 l;
+	unsigned long flags;
+	int vc;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables));
+
+	_omap_dsi_set_irqs();
+	for (vc = 0; vc < 4; ++vc)
+		_omap_dsi_set_irqs_vc(vc);
+	_omap_dsi_set_irqs_cio();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+}
+
+static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+		struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+	struct dsi_isr_data *isr_data;
+	int free_idx;
 	int i;
 
-	/* disable all interrupts */
-	dsi_write_reg(DSI_IRQENABLE, 0);
-	for (i = 0; i < 4; ++i)
-		dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
-	dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
+	BUG_ON(isr == NULL);
 
-	/* clear interrupt status */
-	l = dsi_read_reg(DSI_IRQSTATUS);
-	dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
+	/* check for duplicate entry and find a free slot */
+	free_idx = -1;
+	for (i = 0; i < isr_array_size; i++) {
+		isr_data = &isr_array[i];
 
-	for (i = 0; i < 4; ++i) {
-		l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
-		dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
+		if (isr_data->isr == isr && isr_data->arg == arg &&
+				isr_data->mask == mask) {
+			return -EINVAL;
+		}
+
+		if (isr_data->isr == NULL && free_idx == -1)
+			free_idx = i;
 	}
 
-	l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
-	dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
+	if (free_idx == -1)
+		return -EBUSY;
 
-	/* enable error irqs */
-	l = DSI_IRQ_ERROR_MASK;
-#ifdef DSI_CATCH_MISSING_TE
-	l |= DSI_IRQ_TE_TRIGGER;
-#endif
-	dsi_write_reg(DSI_IRQENABLE, l);
+	isr_data = &isr_array[free_idx];
+	isr_data->isr = isr;
+	isr_data->arg = arg;
+	isr_data->mask = mask;
 
-	l = DSI_VC_IRQ_ERROR_MASK;
-	for (i = 0; i < 4; ++i)
-		dsi_write_reg(DSI_VC_IRQENABLE(i), l);
+	return 0;
+}
 
-	l = DSI_CIO_IRQ_ERROR_MASK;
-	dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l);
+static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+		struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+	struct dsi_isr_data *isr_data;
+	int i;
+
+	for (i = 0; i < isr_array_size; i++) {
+		isr_data = &isr_array[i];
+		if (isr_data->isr != isr || isr_data->arg != arg ||
+				isr_data->mask != mask)
+			continue;
+
+		isr_data->isr = NULL;
+		isr_data->arg = NULL;
+		isr_data->mask = 0;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table,
+			ARRAY_SIZE(dsi.isr_tables.isr_table));
+
+	if (r == 0)
+		_omap_dsi_set_irqs();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table,
+			ARRAY_SIZE(dsi.isr_tables.isr_table));
+
+	if (r == 0)
+		_omap_dsi_set_irqs();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
+		u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_register_isr(isr, arg, mask,
+			dsi.isr_tables.isr_table_vc[channel],
+			ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+
+	if (r == 0)
+		_omap_dsi_set_irqs_vc(channel);
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
+		u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_unregister_isr(isr, arg, mask,
+			dsi.isr_tables.isr_table_vc[channel],
+			ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+
+	if (r == 0)
+		_omap_dsi_set_irqs_vc(channel);
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
+			ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+
+	if (r == 0)
+		_omap_dsi_set_irqs_cio();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
+			ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+
+	if (r == 0)
+		_omap_dsi_set_irqs_cio();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
 }
 
 static u32 dsi_get_errors(void)
@@ -617,42 +920,22 @@
 	return e;
 }
 
-static void dsi_vc_enable_bta_irq(int channel)
-{
-	u32 l;
-
-	dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
-
-	l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
-	l |= DSI_VC_IRQ_BTA;
-	dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
-}
-
-static void dsi_vc_disable_bta_irq(int channel)
-{
-	u32 l;
-
-	l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
-	l &= ~DSI_VC_IRQ_BTA;
-	dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
-}
-
-/* DSI func clock. this could also be DSI2_PLL_FCLK */
+/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
 static inline void enable_clocks(bool enable)
 {
 	if (enable)
-		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 	else
-		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
 /* source clock for DSI PLL. this could also be PCLKFREE */
 static inline void dsi_enable_pll_clock(bool enable)
 {
 	if (enable)
-		dss_clk_enable(DSS_CLK_FCK2);
+		dss_clk_enable(DSS_CLK_SYSCK);
 	else
-		dss_clk_disable(DSS_CLK_FCK2);
+		dss_clk_disable(DSS_CLK_SYSCK);
 
 	if (enable && dsi.pll_locked) {
 		if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
@@ -707,14 +990,14 @@
 	return 0;
 }
 
-unsigned long dsi_get_dsi1_pll_rate(void)
+unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
 {
-	return dsi.current_cinfo.dsi1_pll_fclk;
+	return dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk;
 }
 
-static unsigned long dsi_get_dsi2_pll_rate(void)
+static unsigned long dsi_get_pll_hsdiv_dsi_rate(void)
 {
-	return dsi.current_cinfo.dsi2_pll_fclk;
+	return dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk;
 }
 
 static unsigned long dsi_get_txbyteclkhs(void)
@@ -726,12 +1009,12 @@
 {
 	unsigned long r;
 
-	if (dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) {
-		/* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */
-		r = dss_clk_get_rate(DSS_CLK_FCK1);
+	if (dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK) {
+		/* DSI FCLK source is DSS_CLK_FCK */
+		r = dss_clk_get_rate(DSS_CLK_FCK);
 	} else {
-		/* DSI FCLK source is DSI2_PLL_FCLK */
-		r = dsi_get_dsi2_pll_rate();
+		/* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
+		r = dsi_get_pll_hsdiv_dsi_rate();
 	}
 
 	return r;
@@ -745,7 +1028,7 @@
 
 	lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
 
-	if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX)
+	if (lp_clk_div == 0 || lp_clk_div > dsi.lpdiv_max)
 		return -EINVAL;
 
 	dsi_fclk = dsi_fclk_rate();
@@ -795,22 +1078,22 @@
 static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
 		struct dsi_clock_info *cinfo)
 {
-	if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
+	if (cinfo->regn == 0 || cinfo->regn > dsi.regn_max)
 		return -EINVAL;
 
-	if (cinfo->regm == 0 || cinfo->regm > REGM_MAX)
+	if (cinfo->regm == 0 || cinfo->regm > dsi.regm_max)
 		return -EINVAL;
 
-	if (cinfo->regm3 > REGM3_MAX)
+	if (cinfo->regm_dispc > dsi.regm_dispc_max)
 		return -EINVAL;
 
-	if (cinfo->regm4 > REGM4_MAX)
+	if (cinfo->regm_dsi > dsi.regm_dsi_max)
 		return -EINVAL;
 
-	if (cinfo->use_dss2_fck) {
-		cinfo->clkin = dss_clk_get_rate(DSS_CLK_FCK2);
+	if (cinfo->use_sys_clk) {
+		cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK);
 		/* XXX it is unclear if highfreq should be used
-		 * with DSS2_FCK source also */
+		 * with DSS_SYS_CLK source also */
 		cinfo->highfreq = 0;
 	} else {
 		cinfo->clkin = dispc_pclk_rate(dssdev->manager->id);
@@ -823,7 +1106,7 @@
 
 	cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
 
-	if (cinfo->fint > FINT_MAX || cinfo->fint < FINT_MIN)
+	if (cinfo->fint > dsi.fint_max || cinfo->fint < dsi.fint_min)
 		return -EINVAL;
 
 	cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
@@ -831,15 +1114,17 @@
 	if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
 		return -EINVAL;
 
-	if (cinfo->regm3 > 0)
-		cinfo->dsi1_pll_fclk = cinfo->clkin4ddr / cinfo->regm3;
+	if (cinfo->regm_dispc > 0)
+		cinfo->dsi_pll_hsdiv_dispc_clk =
+			cinfo->clkin4ddr / cinfo->regm_dispc;
 	else
-		cinfo->dsi1_pll_fclk = 0;
+		cinfo->dsi_pll_hsdiv_dispc_clk = 0;
 
-	if (cinfo->regm4 > 0)
-		cinfo->dsi2_pll_fclk = cinfo->clkin4ddr / cinfo->regm4;
+	if (cinfo->regm_dsi > 0)
+		cinfo->dsi_pll_hsdiv_dsi_clk =
+			cinfo->clkin4ddr / cinfo->regm_dsi;
 	else
-		cinfo->dsi2_pll_fclk = 0;
+		cinfo->dsi_pll_hsdiv_dsi_clk = 0;
 
 	return 0;
 }
@@ -852,23 +1137,25 @@
 	struct dispc_clock_info best_dispc;
 	int min_fck_per_pck;
 	int match = 0;
-	unsigned long dss_clk_fck2;
+	unsigned long dss_sys_clk, max_dss_fck;
 
-	dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
+	dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK);
+
+	max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 
 	if (req_pck == dsi.cache_req_pck &&
-			dsi.cache_cinfo.clkin == dss_clk_fck2) {
+			dsi.cache_cinfo.clkin == dss_sys_clk) {
 		DSSDBG("DSI clock info found from cache\n");
 		*dsi_cinfo = dsi.cache_cinfo;
-		dispc_find_clk_divs(is_tft, req_pck, dsi_cinfo->dsi1_pll_fclk,
-				dispc_cinfo);
+		dispc_find_clk_divs(is_tft, req_pck,
+			dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo);
 		return 0;
 	}
 
 	min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
 
 	if (min_fck_per_pck &&
-		req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
+		req_pck * min_fck_per_pck > max_dss_fck) {
 		DSSERR("Requested pixel clock not possible with the current "
 				"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
 				"the constraint off.\n");
@@ -882,24 +1169,24 @@
 	memset(&best_dispc, 0, sizeof(best_dispc));
 
 	memset(&cur, 0, sizeof(cur));
-	cur.clkin = dss_clk_fck2;
-	cur.use_dss2_fck = 1;
+	cur.clkin = dss_sys_clk;
+	cur.use_sys_clk = 1;
 	cur.highfreq = 0;
 
 	/* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
 	/* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
 	/* To reduce PLL lock time, keep Fint high (around 2 MHz) */
-	for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) {
+	for (cur.regn = 1; cur.regn < dsi.regn_max; ++cur.regn) {
 		if (cur.highfreq == 0)
 			cur.fint = cur.clkin / cur.regn;
 		else
 			cur.fint = cur.clkin / (2 * cur.regn);
 
-		if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
+		if (cur.fint > dsi.fint_max || cur.fint < dsi.fint_min)
 			continue;
 
 		/* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
-		for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) {
+		for (cur.regm = 1; cur.regm < dsi.regm_max; ++cur.regm) {
 			unsigned long a, b;
 
 			a = 2 * cur.regm * (cur.clkin/1000);
@@ -909,30 +1196,32 @@
 			if (cur.clkin4ddr > 1800 * 1000 * 1000)
 				break;
 
-			/* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3  < 173MHz */
-			for (cur.regm3 = 1; cur.regm3 < REGM3_MAX;
-					++cur.regm3) {
+			/* dsi_pll_hsdiv_dispc_clk(MHz) =
+			 * DSIPHY(MHz) / regm_dispc  < 173MHz/186Mhz */
+			for (cur.regm_dispc = 1; cur.regm_dispc < dsi.regm_dispc_max;
+					++cur.regm_dispc) {
 				struct dispc_clock_info cur_dispc;
-				cur.dsi1_pll_fclk = cur.clkin4ddr / cur.regm3;
+				cur.dsi_pll_hsdiv_dispc_clk =
+					cur.clkin4ddr / cur.regm_dispc;
 
 				/* this will narrow down the search a bit,
 				 * but still give pixclocks below what was
 				 * requested */
-				if (cur.dsi1_pll_fclk  < req_pck)
+				if (cur.dsi_pll_hsdiv_dispc_clk  < req_pck)
 					break;
 
-				if (cur.dsi1_pll_fclk > DISPC_MAX_FCK)
+				if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
 					continue;
 
 				if (min_fck_per_pck &&
-					cur.dsi1_pll_fclk <
+					cur.dsi_pll_hsdiv_dispc_clk <
 						req_pck * min_fck_per_pck)
 					continue;
 
 				match = 1;
 
 				dispc_find_clk_divs(is_tft, req_pck,
-						cur.dsi1_pll_fclk,
+						cur.dsi_pll_hsdiv_dispc_clk,
 						&cur_dispc);
 
 				if (abs(cur_dispc.pck - req_pck) <
@@ -961,9 +1250,9 @@
 		return -EINVAL;
 	}
 
-	/* DSI2_PLL_FCLK (regm4) is not used */
-	best.regm4 = 0;
-	best.dsi2_pll_fclk = 0;
+	/* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
+	best.regm_dsi = 0;
+	best.dsi_pll_hsdiv_dsi_clk = 0;
 
 	if (dsi_cinfo)
 		*dsi_cinfo = best;
@@ -982,23 +1271,27 @@
 	int r = 0;
 	u32 l;
 	int f;
+	u8 regn_start, regn_end, regm_start, regm_end;
+	u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
 
 	DSSDBGF();
 
 	dsi.current_cinfo.fint = cinfo->fint;
 	dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
-	dsi.current_cinfo.dsi1_pll_fclk = cinfo->dsi1_pll_fclk;
-	dsi.current_cinfo.dsi2_pll_fclk = cinfo->dsi2_pll_fclk;
+	dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk =
+			cinfo->dsi_pll_hsdiv_dispc_clk;
+	dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk =
+			cinfo->dsi_pll_hsdiv_dsi_clk;
 
 	dsi.current_cinfo.regn = cinfo->regn;
 	dsi.current_cinfo.regm = cinfo->regm;
-	dsi.current_cinfo.regm3 = cinfo->regm3;
-	dsi.current_cinfo.regm4 = cinfo->regm4;
+	dsi.current_cinfo.regm_dispc = cinfo->regm_dispc;
+	dsi.current_cinfo.regm_dsi = cinfo->regm_dsi;
 
 	DSSDBG("DSI Fint %ld\n", cinfo->fint);
 
 	DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
-			cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree",
+			cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree",
 			cinfo->clkin,
 			cinfo->highfreq);
 
@@ -1015,24 +1308,39 @@
 
 	DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
 
-	DSSDBG("regm3 = %d, dsi1_pll_fclk = %lu\n",
-			cinfo->regm3, cinfo->dsi1_pll_fclk);
-	DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n",
-			cinfo->regm4, cinfo->dsi2_pll_fclk);
+	DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
+		dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+		dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+		cinfo->dsi_pll_hsdiv_dispc_clk);
+	DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
+		dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+		dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+		cinfo->dsi_pll_hsdiv_dsi_clk);
+
+	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
+	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
+	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
+			&regm_dispc_end);
+	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
+			&regm_dsi_end);
 
 	REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
 
 	l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
 	l = FLD_MOD(l, 1, 0, 0);		/* DSI_PLL_STOPMODE */
-	l = FLD_MOD(l, cinfo->regn - 1, 7, 1);	/* DSI_PLL_REGN */
-	l = FLD_MOD(l, cinfo->regm, 18, 8);	/* DSI_PLL_REGM */
-	l = FLD_MOD(l, cinfo->regm3 > 0 ? cinfo->regm3 - 1 : 0,
-			22, 19);		/* DSI_CLOCK_DIV */
-	l = FLD_MOD(l, cinfo->regm4 > 0 ? cinfo->regm4 - 1 : 0,
-			26, 23);		/* DSIPROTO_CLOCK_DIV */
+	/* DSI_PLL_REGN */
+	l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
+	/* DSI_PLL_REGM */
+	l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
+	/* DSI_CLOCK_DIV */
+	l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
+			regm_dispc_start, regm_dispc_end);
+	/* DSIPROTO_CLOCK_DIV */
+	l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
+			regm_dsi_start, regm_dsi_end);
 	dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
 
-	BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000);
+	BUG_ON(cinfo->fint < dsi.fint_min || cinfo->fint > dsi.fint_max);
 	if (cinfo->fint < 1000000)
 		f = 0x3;
 	else if (cinfo->fint < 1250000)
@@ -1046,7 +1354,7 @@
 
 	l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
 	l = FLD_MOD(l, f, 4, 1);		/* DSI_PLL_FREQSEL */
-	l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1,
+	l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1,
 			11, 11);		/* DSI_PLL_CLKSEL */
 	l = FLD_MOD(l, cinfo->highfreq,
 			12, 12);		/* DSI_PLL_HIGHFREQ */
@@ -1101,6 +1409,26 @@
 
 	DSSDBG("PLL init\n");
 
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+	/*
+	 * HACK: this is just a quick hack to get the USE_DSI_PLL
+	 * option working. USE_DSI_PLL is itself a big hack, and
+	 * should be removed.
+	 */
+	if (dsi.vdds_dsi_reg == NULL) {
+		struct regulator *vdds_dsi;
+
+		vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+
+		if (IS_ERR(vdds_dsi)) {
+			DSSERR("can't get VDDS_DSI regulator\n");
+			return PTR_ERR(vdds_dsi);
+		}
+
+		dsi.vdds_dsi_reg = vdds_dsi;
+	}
+#endif
+
 	enable_clocks(1);
 	dsi_enable_pll_clock(1);
 
@@ -1162,6 +1490,10 @@
 {
 	int clksel;
 	struct dsi_clock_info *cinfo = &dsi.current_cinfo;
+	enum dss_clk_source dispc_clk_src, dsi_clk_src;
+
+	dispc_clk_src = dss_get_dispc_clk_source();
+	dsi_clk_src = dss_get_dsi_clk_source();
 
 	enable_clocks(1);
 
@@ -1171,30 +1503,34 @@
 
 	seq_printf(s,	"dsi pll source = %s\n",
 			clksel == 0 ?
-			"dss2_alwon_fclk" : "pclkfree");
+			"dss_sys_clk" : "pclkfree");
 
 	seq_printf(s,	"Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
 
 	seq_printf(s,	"CLKIN4DDR\t%-16luregm %u\n",
 			cinfo->clkin4ddr, cinfo->regm);
 
-	seq_printf(s,	"dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n",
-			cinfo->dsi1_pll_fclk,
-			cinfo->regm3,
-			dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+	seq_printf(s,	"%s (%s)\t%-16luregm_dispc %u\t(%s)\n",
+			dss_get_generic_clk_source_name(dispc_clk_src),
+			dss_feat_get_clk_source_name(dispc_clk_src),
+			cinfo->dsi_pll_hsdiv_dispc_clk,
+			cinfo->regm_dispc,
+			dispc_clk_src == DSS_CLK_SRC_FCK ?
 			"off" : "on");
 
-	seq_printf(s,	"dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n",
-			cinfo->dsi2_pll_fclk,
-			cinfo->regm4,
-			dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+	seq_printf(s,	"%s (%s)\t%-16luregm_dsi %u\t(%s)\n",
+			dss_get_generic_clk_source_name(dsi_clk_src),
+			dss_feat_get_clk_source_name(dsi_clk_src),
+			cinfo->dsi_pll_hsdiv_dsi_clk,
+			cinfo->regm_dsi,
+			dsi_clk_src == DSS_CLK_SRC_FCK ?
 			"off" : "on");
 
 	seq_printf(s,	"- DSI -\n");
 
-	seq_printf(s,	"dsi fclk source = %s\n",
-			dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
-			"dss1_alwon_fclk" : "dsi2_pll_fclk");
+	seq_printf(s,	"dsi fclk source = %s (%s)\n",
+			dss_get_generic_clk_source_name(dsi_clk_src),
+			dss_feat_get_clk_source_name(dsi_clk_src));
 
 	seq_printf(s,	"DSI_FCLK\t%lu\n", dsi_fclk_rate());
 
@@ -1306,7 +1642,7 @@
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
 
-	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	DUMPREG(DSI_REVISION);
 	DUMPREG(DSI_SYSCONFIG);
@@ -1378,7 +1714,7 @@
 	DUMPREG(DSI_PLL_CONFIGURATION1);
 	DUMPREG(DSI_PLL_CONFIGURATION2);
 
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
@@ -1622,20 +1958,6 @@
 	return _dsi_wait_reset();
 }
 
-static void dsi_reset_tx_fifo(int channel)
-{
-	u32 mask;
-	u32 l;
-
-	/* set fifosize of the channel to 0, then return the old size */
-	l = dsi_read_reg(DSI_TX_FIFO_VC_SIZE);
-
-	mask = FLD_MASK((8 * channel) + 7, (8 * channel) + 4);
-	dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l & ~mask);
-
-	dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l);
-}
-
 static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
 		enum fifo_size size3, enum fifo_size size4)
 {
@@ -1753,8 +2075,6 @@
 	r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
 
 	dsi_write_reg(DSI_VC_CTRL(channel), r);
-
-	dsi.vc[channel].mode = DSI_VC_MODE_L4;
 }
 
 static int dsi_vc_config_l4(int channel)
@@ -1922,33 +2242,44 @@
 
 int dsi_vc_send_bta_sync(int channel)
 {
+	DECLARE_COMPLETION_ONSTACK(completion);
 	int r = 0;
 	u32 err;
 
-	INIT_COMPLETION(dsi.bta_completion);
+	r = dsi_register_isr_vc(channel, dsi_completion_handler,
+			&completion, DSI_VC_IRQ_BTA);
+	if (r)
+		goto err0;
 
-	dsi_vc_enable_bta_irq(channel);
+	r = dsi_register_isr(dsi_completion_handler, &completion,
+			DSI_IRQ_ERROR_MASK);
+	if (r)
+		goto err1;
 
 	r = dsi_vc_send_bta(channel);
 	if (r)
-		goto err;
+		goto err2;
 
-	if (wait_for_completion_timeout(&dsi.bta_completion,
+	if (wait_for_completion_timeout(&completion,
 				msecs_to_jiffies(500)) == 0) {
 		DSSERR("Failed to receive BTA\n");
 		r = -EIO;
-		goto err;
+		goto err2;
 	}
 
 	err = dsi_get_errors();
 	if (err) {
 		DSSERR("Error while sending BTA: %x\n", err);
 		r = -EIO;
-		goto err;
+		goto err2;
 	}
-err:
-	dsi_vc_disable_bta_irq(channel);
-
+err2:
+	dsi_unregister_isr(dsi_completion_handler, &completion,
+			DSI_IRQ_ERROR_MASK);
+err1:
+	dsi_unregister_isr_vc(channel, dsi_completion_handler,
+			&completion, DSI_VC_IRQ_BTA);
+err0:
 	return r;
 }
 EXPORT_SYMBOL(dsi_vc_send_bta_sync);
@@ -1961,7 +2292,7 @@
 
 	WARN_ON(!dsi_bus_is_locked());
 
-	data_id = data_type | channel << 6;
+	data_id = data_type | dsi.vc[channel].vc_id << 6;
 
 	val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
 		FLD_VAL(ecc, 31, 24);
@@ -2064,7 +2395,7 @@
 		return -EINVAL;
 	}
 
-	data_id = data_type | channel << 6;
+	data_id = data_type | dsi.vc[channel].vc_id << 6;
 
 	r = (data_id << 0) | (data << 8) | (ecc << 24);
 
@@ -2762,19 +3093,20 @@
 }
 #endif
 
+static void dsi_framedone_bta_callback(void *data, u32 mask);
+
 static void dsi_handle_framedone(int error)
 {
 	const int channel = dsi.update_channel;
 
-	cancel_delayed_work(&dsi.framedone_timeout_work);
+	dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
+			NULL, DSI_VC_IRQ_BTA);
 
-	dsi_vc_disable_bta_irq(channel);
+	cancel_delayed_work(&dsi.framedone_timeout_work);
 
 	/* SIDLEMODE back to smart-idle */
 	dispc_enable_sidle();
 
-	dsi.bta_callback = NULL;
-
 	if (dsi.te_enabled) {
 		/* enable LP_RX_TO again after the TE */
 		REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
@@ -2808,7 +3140,7 @@
 	dsi_handle_framedone(-ETIMEDOUT);
 }
 
-static void dsi_framedone_bta_callback(void)
+static void dsi_framedone_bta_callback(void *data, u32 mask)
 {
 	dsi_handle_framedone(0);
 
@@ -2848,15 +3180,19 @@
 	 * asynchronously.
 	 * */
 
-	dsi.bta_callback = dsi_framedone_bta_callback;
-
-	barrier();
-
-	dsi_vc_enable_bta_irq(channel);
+	r = dsi_register_isr_vc(channel, dsi_framedone_bta_callback,
+			NULL, DSI_VC_IRQ_BTA);
+	if (r) {
+		DSSERR("Failed to register BTA ISR\n");
+		dsi_handle_framedone(-EIO);
+		return;
+	}
 
 	r = dsi_vc_send_bta(channel);
 	if (r) {
 		DSSERR("BTA after framedone failed\n");
+		dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
+				NULL, DSI_VC_IRQ_BTA);
 		dsi_handle_framedone(-EIO);
 	}
 }
@@ -2984,12 +3320,12 @@
 	struct dsi_clock_info cinfo;
 	int r;
 
-	/* we always use DSS2_FCK as input clock */
-	cinfo.use_dss2_fck = true;
+	/* we always use DSS_CLK_SYSCK as input clock */
+	cinfo.use_sys_clk = true;
 	cinfo.regn  = dssdev->phy.dsi.div.regn;
 	cinfo.regm  = dssdev->phy.dsi.div.regm;
-	cinfo.regm3 = dssdev->phy.dsi.div.regm3;
-	cinfo.regm4 = dssdev->phy.dsi.div.regm4;
+	cinfo.regm_dispc = dssdev->phy.dsi.div.regm_dispc;
+	cinfo.regm_dsi = dssdev->phy.dsi.div.regm_dsi;
 	r = dsi_calc_clock_rates(dssdev, &cinfo);
 	if (r) {
 		DSSERR("Failed to calc dsi clocks\n");
@@ -3011,7 +3347,7 @@
 	int r;
 	unsigned long long fck;
 
-	fck = dsi_get_dsi1_pll_rate();
+	fck = dsi_get_pll_hsdiv_dispc_rate();
 
 	dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div;
 	dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div;
@@ -3045,8 +3381,8 @@
 	if (r)
 		goto err1;
 
-	dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
-	dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK);
+	dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
+	dss_select_dsi_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI);
 
 	DSSDBG("PLL OK\n");
 
@@ -3082,8 +3418,8 @@
 err3:
 	dsi_complexio_uninit();
 err2:
-	dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
-	dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+	dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+	dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
 err1:
 	dsi_pll_uninit();
 err0:
@@ -3099,8 +3435,8 @@
 	dsi_vc_enable(2, 0);
 	dsi_vc_enable(3, 0);
 
-	dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
-	dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+	dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+	dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
 	dsi_complexio_uninit();
 	dsi_pll_uninit();
 }
@@ -3220,29 +3556,107 @@
 	dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
 		OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
 
-	dsi.vc[0].dssdev = dssdev;
-	dsi.vc[1].dssdev = dssdev;
+	if (dsi.vdds_dsi_reg == NULL) {
+		struct regulator *vdds_dsi;
+
+		vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+
+		if (IS_ERR(vdds_dsi)) {
+			DSSERR("can't get VDDS_DSI regulator\n");
+			return PTR_ERR(vdds_dsi);
+		}
+
+		dsi.vdds_dsi_reg = vdds_dsi;
+	}
 
 	return 0;
 }
 
-void dsi_wait_dsi1_pll_active(void)
+int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
+		if (!dsi.vc[i].dssdev) {
+			dsi.vc[i].dssdev = dssdev;
+			*channel = i;
+			return 0;
+		}
+	}
+
+	DSSERR("cannot get VC for display %s", dssdev->name);
+	return -ENOSPC;
+}
+EXPORT_SYMBOL(omap_dsi_request_vc);
+
+int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
+{
+	if (vc_id < 0 || vc_id > 3) {
+		DSSERR("VC ID out of range\n");
+		return -EINVAL;
+	}
+
+	if (channel < 0 || channel > 3) {
+		DSSERR("Virtual Channel out of range\n");
+		return -EINVAL;
+	}
+
+	if (dsi.vc[channel].dssdev != dssdev) {
+		DSSERR("Virtual Channel not allocated to display %s\n",
+			dssdev->name);
+		return -EINVAL;
+	}
+
+	dsi.vc[channel].vc_id = vc_id;
+
+	return 0;
+}
+EXPORT_SYMBOL(omap_dsi_set_vc_id);
+
+void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel)
+{
+	if ((channel >= 0 && channel <= 3) &&
+		dsi.vc[channel].dssdev == dssdev) {
+		dsi.vc[channel].dssdev = NULL;
+		dsi.vc[channel].vc_id = 0;
+	}
+}
+EXPORT_SYMBOL(omap_dsi_release_vc);
+
+void dsi_wait_pll_hsdiv_dispc_active(void)
 {
 	if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1)
-		DSSERR("DSI1 PLL clock not active\n");
+		DSSERR("%s (%s) not active\n",
+			dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+			dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
 }
 
-void dsi_wait_dsi2_pll_active(void)
+void dsi_wait_pll_hsdiv_dsi_active(void)
 {
 	if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1)
-		DSSERR("DSI2 PLL clock not active\n");
+		DSSERR("%s (%s) not active\n",
+			dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+			dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
 }
 
-int dsi_init(struct platform_device *pdev)
+static void dsi_calc_clock_param_ranges(void)
+{
+	dsi.regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
+	dsi.regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
+	dsi.regm_dispc_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
+	dsi.regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
+	dsi.fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
+	dsi.fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
+	dsi.lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
+}
+
+static int dsi_init(struct platform_device *pdev)
 {
 	u32 rev;
-	int r;
+	int r, i;
+	struct resource *dsi_mem;
 
+	spin_lock_init(&dsi.irq_lock);
 	spin_lock_init(&dsi.errors_lock);
 	dsi.errors = 0;
 
@@ -3251,8 +3665,6 @@
 	dsi.irq_stats.last_reset = jiffies;
 #endif
 
-	init_completion(&dsi.bta_completion);
-
 	mutex_init(&dsi.lock);
 	sema_init(&dsi.bus_lock, 1);
 
@@ -3268,24 +3680,45 @@
 	dsi.te_timer.function = dsi_te_timeout;
 	dsi.te_timer.data = 0;
 #endif
-	dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
+	dsi_mem = platform_get_resource(dsi.pdev, IORESOURCE_MEM, 0);
+	if (!dsi_mem) {
+		DSSERR("can't get IORESOURCE_MEM DSI\n");
+		r = -EINVAL;
+		goto err1;
+	}
+	dsi.base = ioremap(dsi_mem->start, resource_size(dsi_mem));
 	if (!dsi.base) {
 		DSSERR("can't ioremap DSI\n");
 		r = -ENOMEM;
 		goto err1;
 	}
-
-	dsi.vdds_dsi_reg = dss_get_vdds_dsi();
-	if (IS_ERR(dsi.vdds_dsi_reg)) {
-		DSSERR("can't get VDDS_DSI regulator\n");
-		r = PTR_ERR(dsi.vdds_dsi_reg);
+	dsi.irq	= platform_get_irq(dsi.pdev, 0);
+	if (dsi.irq < 0) {
+		DSSERR("platform_get_irq failed\n");
+		r = -ENODEV;
 		goto err2;
 	}
 
+	r = request_irq(dsi.irq, omap_dsi_irq_handler, IRQF_SHARED,
+		"OMAP DSI1", dsi.pdev);
+	if (r < 0) {
+		DSSERR("request_irq failed\n");
+		goto err2;
+	}
+
+	/* DSI VCs initialization */
+	for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
+		dsi.vc[i].mode = DSI_VC_MODE_L4;
+		dsi.vc[i].dssdev = NULL;
+		dsi.vc[i].vc_id = 0;
+	}
+
+	dsi_calc_clock_param_ranges();
+
 	enable_clocks(1);
 
 	rev = dsi_read_reg(DSI_REVISION);
-	printk(KERN_INFO "OMAP DSI rev %d.%d\n",
+	dev_dbg(&pdev->dev, "OMAP DSI rev %d.%d\n",
 	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
 	enable_clocks(0);
@@ -3298,8 +3731,14 @@
 	return r;
 }
 
-void dsi_exit(void)
+static void dsi_exit(void)
 {
+	if (dsi.vdds_dsi_reg != NULL) {
+		regulator_put(dsi.vdds_dsi_reg);
+		dsi.vdds_dsi_reg = NULL;
+	}
+
+	free_irq(dsi.irq, dsi.pdev);
 	iounmap(dsi.base);
 
 	destroy_workqueue(dsi.workqueue);
@@ -3307,3 +3746,41 @@
 	DSSDBG("omap_dsi_exit\n");
 }
 
+/* DSI1 HW IP initialisation */
+static int omap_dsi1hw_probe(struct platform_device *pdev)
+{
+	int r;
+	dsi.pdev = pdev;
+	r = dsi_init(pdev);
+	if (r) {
+		DSSERR("Failed to initialize DSI\n");
+		goto err_dsi;
+	}
+err_dsi:
+	return r;
+}
+
+static int omap_dsi1hw_remove(struct platform_device *pdev)
+{
+	dsi_exit();
+	return 0;
+}
+
+static struct platform_driver omap_dsi1hw_driver = {
+	.probe          = omap_dsi1hw_probe,
+	.remove         = omap_dsi1hw_remove,
+	.driver         = {
+		.name   = "omapdss_dsi1",
+		.owner  = THIS_MODULE,
+	},
+};
+
+int dsi_init_platform_driver(void)
+{
+	return platform_driver_register(&omap_dsi1hw_driver);
+}
+
+void dsi_uninit_platform_driver(void)
+{
+	return platform_driver_unregister(&omap_dsi1hw_driver);
+}
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 77c3621..3f1fee6 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -26,14 +26,13 @@
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/delay.h>
-#include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/clk.h>
 
 #include <plat/display.h>
+#include <plat/clock.h>
 #include "dss.h"
-
-#define DSS_BASE			0x48050000
+#include "dss_features.h"
 
 #define DSS_SZ_REGS			SZ_512
 
@@ -59,9 +58,17 @@
 	dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
 
 static struct {
+	struct platform_device *pdev;
 	void __iomem    *base;
+	int             ctx_id;
 
 	struct clk	*dpll4_m4_ck;
+	struct clk	*dss_ick;
+	struct clk	*dss_fck;
+	struct clk	*dss_sys_clk;
+	struct clk	*dss_tv_fck;
+	struct clk	*dss_video_fck;
+	unsigned	num_clks_enabled;
 
 	unsigned long	cache_req_pck;
 	unsigned long	cache_prate;
@@ -70,10 +77,22 @@
 
 	enum dss_clk_source dsi_clk_source;
 	enum dss_clk_source dispc_clk_source;
+	enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
 
 	u32		ctx[DSS_SZ_REGS / sizeof(u32)];
 } dss;
 
+static const char * const dss_generic_clk_source_names[] = {
+	[DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "DSI_PLL_HSDIV_DISPC",
+	[DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]		= "DSI_PLL_HSDIV_DSI",
+	[DSS_CLK_SRC_FCK]			= "DSS_FCK",
+};
+
+static void dss_clk_enable_all_no_ctx(void);
+static void dss_clk_disable_all_no_ctx(void);
+static void dss_clk_enable_no_ctx(enum dss_clock clks);
+static void dss_clk_disable_no_ctx(enum dss_clock clks);
+
 static int _omap_dss_wait_reset(void);
 
 static inline void dss_write_reg(const struct dss_reg idx, u32 val)
@@ -99,10 +118,11 @@
 	SR(SYSCONFIG);
 	SR(CONTROL);
 
-#ifdef CONFIG_OMAP2_DSS_SDI
-	SR(SDI_CONTROL);
-	SR(PLL_CONTROL);
-#endif
+	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+			OMAP_DISPLAY_TYPE_SDI) {
+		SR(SDI_CONTROL);
+		SR(PLL_CONTROL);
+	}
 }
 
 void dss_restore_context(void)
@@ -113,10 +133,11 @@
 	RR(SYSCONFIG);
 	RR(CONTROL);
 
-#ifdef CONFIG_OMAP2_DSS_SDI
-	RR(SDI_CONTROL);
-	RR(PLL_CONTROL);
-#endif
+	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+			OMAP_DISPLAY_TYPE_SDI) {
+		RR(SDI_CONTROL);
+		RR(PLL_CONTROL);
+	}
 }
 
 #undef SR
@@ -209,66 +230,96 @@
 	REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
 }
 
+const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src)
+{
+	return dss_generic_clk_source_names[clk_src];
+}
+
 void dss_dump_clocks(struct seq_file *s)
 {
 	unsigned long dpll4_ck_rate;
 	unsigned long dpll4_m4_ck_rate;
+	const char *fclk_name, *fclk_real_name;
+	unsigned long fclk_rate;
 
-	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
-	dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-	dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	seq_printf(s, "- DSS -\n");
 
-	seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
+	fclk_name = dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK);
+	fclk_real_name = dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK);
+	fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
 
-	if (cpu_is_omap3630())
-		seq_printf(s, "dss1_alwon_fclk = %lu / %lu  = %lu\n",
-			dpll4_ck_rate,
-			dpll4_ck_rate / dpll4_m4_ck_rate,
-			dss_clk_get_rate(DSS_CLK_FCK1));
-	else
-		seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
-			dpll4_ck_rate,
-			dpll4_ck_rate / dpll4_m4_ck_rate,
-			dss_clk_get_rate(DSS_CLK_FCK1));
+	if (dss.dpll4_m4_ck) {
+		dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
+		dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
 
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+		seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
+
+		if (cpu_is_omap3630() || cpu_is_omap44xx())
+			seq_printf(s, "%s (%s) = %lu / %lu  = %lu\n",
+					fclk_name, fclk_real_name,
+					dpll4_ck_rate,
+					dpll4_ck_rate / dpll4_m4_ck_rate,
+					fclk_rate);
+		else
+			seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
+					fclk_name, fclk_real_name,
+					dpll4_ck_rate,
+					dpll4_ck_rate / dpll4_m4_ck_rate,
+					fclk_rate);
+	} else {
+		seq_printf(s, "%s (%s) = %lu\n",
+				fclk_name, fclk_real_name,
+				fclk_rate);
+	}
+
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
 void dss_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
 
-	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	DUMPREG(DSS_REVISION);
 	DUMPREG(DSS_SYSCONFIG);
 	DUMPREG(DSS_SYSSTATUS);
 	DUMPREG(DSS_IRQSTATUS);
 	DUMPREG(DSS_CONTROL);
-	DUMPREG(DSS_SDI_CONTROL);
-	DUMPREG(DSS_PLL_CONTROL);
-	DUMPREG(DSS_SDI_STATUS);
 
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+			OMAP_DISPLAY_TYPE_SDI) {
+		DUMPREG(DSS_SDI_CONTROL);
+		DUMPREG(DSS_PLL_CONTROL);
+		DUMPREG(DSS_SDI_STATUS);
+	}
+
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
 void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
 {
 	int b;
+	u8 start, end;
 
-	BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK &&
-			clk_src != DSS_SRC_DSS1_ALWON_FCLK);
+	switch (clk_src) {
+	case DSS_CLK_SRC_FCK:
+		b = 0;
+		break;
+	case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+		b = 1;
+		dsi_wait_pll_hsdiv_dispc_active();
+		break;
+	default:
+		BUG();
+	}
 
-	b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
+	dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
 
-	if (clk_src == DSS_SRC_DSI1_PLL_FCLK)
-		dsi_wait_dsi1_pll_active();
-
-	REG_FLD_MOD(DSS_CONTROL, b, 0, 0);	/* DISPC_CLK_SWITCH */
+	REG_FLD_MOD(DSS_CONTROL, b, start, end);	/* DISPC_CLK_SWITCH */
 
 	dss.dispc_clk_source = clk_src;
 }
@@ -277,19 +328,51 @@
 {
 	int b;
 
-	BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK &&
-			clk_src != DSS_SRC_DSS1_ALWON_FCLK);
-
-	b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
-
-	if (clk_src == DSS_SRC_DSI2_PLL_FCLK)
-		dsi_wait_dsi2_pll_active();
+	switch (clk_src) {
+	case DSS_CLK_SRC_FCK:
+		b = 0;
+		break;
+	case DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+		b = 1;
+		dsi_wait_pll_hsdiv_dsi_active();
+		break;
+	default:
+		BUG();
+	}
 
 	REG_FLD_MOD(DSS_CONTROL, b, 1, 1);	/* DSI_CLK_SWITCH */
 
 	dss.dsi_clk_source = clk_src;
 }
 
+void dss_select_lcd_clk_source(enum omap_channel channel,
+		enum dss_clk_source clk_src)
+{
+	int b, ix, pos;
+
+	if (!dss_has_feature(FEAT_LCD_CLK_SRC))
+		return;
+
+	switch (clk_src) {
+	case DSS_CLK_SRC_FCK:
+		b = 0;
+		break;
+	case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
+		b = 1;
+		dsi_wait_pll_hsdiv_dispc_active();
+		break;
+	default:
+		BUG();
+	}
+
+	pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12;
+	REG_FLD_MOD(DSS_CONTROL, b, pos, pos);	/* LCDx_CLK_SWITCH */
+
+	ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+	dss.lcd_clk_source[ix] = clk_src;
+}
+
 enum dss_clk_source dss_get_dispc_clk_source(void)
 {
 	return dss.dispc_clk_source;
@@ -300,34 +383,52 @@
 	return dss.dsi_clk_source;
 }
 
+enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
+{
+	int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+	return dss.lcd_clk_source[ix];
+}
+
 /* calculate clock rates using dividers in cinfo */
 int dss_calc_clock_rates(struct dss_clock_info *cinfo)
 {
-	unsigned long prate;
+	if (dss.dpll4_m4_ck) {
+		unsigned long prate;
+		u16 fck_div_max = 16;
 
-	if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) ||
-						cinfo->fck_div == 0)
-		return -EINVAL;
+		if (cpu_is_omap3630() || cpu_is_omap44xx())
+			fck_div_max = 32;
 
-	prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
+		if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
+			return -EINVAL;
 
-	cinfo->fck = prate / cinfo->fck_div;
+		prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
+
+		cinfo->fck = prate / cinfo->fck_div;
+	} else {
+		if (cinfo->fck_div != 0)
+			return -EINVAL;
+		cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
+	}
 
 	return 0;
 }
 
 int dss_set_clock_div(struct dss_clock_info *cinfo)
 {
-	unsigned long prate;
-	int r;
+	if (dss.dpll4_m4_ck) {
+		unsigned long prate;
+		int r;
 
-	if (cpu_is_omap34xx()) {
 		prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
 		DSSDBG("dpll4_m4 = %ld\n", prate);
 
 		r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
 		if (r)
 			return r;
+	} else {
+		if (cinfo->fck_div != 0)
+			return -EINVAL;
 	}
 
 	DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
@@ -337,12 +438,14 @@
 
 int dss_get_clock_div(struct dss_clock_info *cinfo)
 {
-	cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
+	cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
 
-	if (cpu_is_omap34xx()) {
+	if (dss.dpll4_m4_ck) {
 		unsigned long prate;
+
 		prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-		if (cpu_is_omap3630())
+
+		if (cpu_is_omap3630() || cpu_is_omap44xx())
 			cinfo->fck_div = prate / (cinfo->fck);
 		else
 			cinfo->fck_div = prate / (cinfo->fck / 2);
@@ -355,7 +458,7 @@
 
 unsigned long dss_get_dpll4_rate(void)
 {
-	if (cpu_is_omap34xx())
+	if (dss.dpll4_m4_ck)
 		return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
 	else
 		return 0;
@@ -369,16 +472,18 @@
 	struct dss_clock_info best_dss;
 	struct dispc_clock_info best_dispc;
 
-	unsigned long fck;
+	unsigned long fck, max_dss_fck;
 
-	u16 fck_div;
+	u16 fck_div, fck_div_max = 16;
 
 	int match = 0;
 	int min_fck_per_pck;
 
 	prate = dss_get_dpll4_rate();
 
-	fck = dss_clk_get_rate(DSS_CLK_FCK1);
+	max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+	fck = dss_clk_get_rate(DSS_CLK_FCK);
 	if (req_pck == dss.cache_req_pck &&
 			((cpu_is_omap34xx() && prate == dss.cache_prate) ||
 			 dss.cache_dss_cinfo.fck == fck)) {
@@ -391,7 +496,7 @@
 	min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
 
 	if (min_fck_per_pck &&
-		req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
+		req_pck * min_fck_per_pck > max_dss_fck) {
 		DSSERR("Requested pixel clock not possible with the current "
 				"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
 				"the constraint off.\n");
@@ -402,10 +507,10 @@
 	memset(&best_dss, 0, sizeof(best_dss));
 	memset(&best_dispc, 0, sizeof(best_dispc));
 
-	if (cpu_is_omap24xx()) {
+	if (dss.dpll4_m4_ck == NULL) {
 		struct dispc_clock_info cur_dispc;
 		/* XXX can we change the clock on omap2? */
-		fck = dss_clk_get_rate(DSS_CLK_FCK1);
+		fck = dss_clk_get_rate(DSS_CLK_FCK);
 		fck_div = 1;
 
 		dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
@@ -417,17 +522,19 @@
 		best_dispc = cur_dispc;
 
 		goto found;
-	} else if (cpu_is_omap34xx()) {
-		for (fck_div = (cpu_is_omap3630() ? 32 : 16);
-					fck_div > 0; --fck_div) {
+	} else {
+		if (cpu_is_omap3630() || cpu_is_omap44xx())
+			fck_div_max = 32;
+
+		for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
 			struct dispc_clock_info cur_dispc;
 
-			if (cpu_is_omap3630())
+			if (fck_div_max == 32)
 				fck = prate / fck_div;
 			else
 				fck = prate / fck_div * 2;
 
-			if (fck > DISPC_MAX_FCK)
+			if (fck > max_dss_fck)
 				continue;
 
 			if (min_fck_per_pck &&
@@ -450,8 +557,6 @@
 					goto found;
 			}
 		}
-	} else {
-		BUG();
 	}
 
 found:
@@ -482,31 +587,6 @@
 	return 0;
 }
 
-
-
-static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
-{
-	dispc_irq_handler();
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
-{
-	u32 irqstatus;
-
-	irqstatus = dss_read_reg(DSS_IRQSTATUS);
-
-	if (irqstatus & (1<<0))	/* DISPC_IRQ */
-		dispc_irq_handler();
-#ifdef CONFIG_OMAP2_DSS_DSI
-	if (irqstatus & (1<<1))	/* DSI_IRQ */
-		dsi_irq_handler();
-#endif
-
-	return IRQ_HANDLED;
-}
-
 static int _omap_dss_wait_reset(void)
 {
 	int t = 0;
@@ -549,34 +629,45 @@
 	REG_FLD_MOD(DSS_CONTROL, enable, 5, 5);	/* DAC Power-Down Control */
 }
 
-int dss_init(bool skip_init)
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
+{
+	REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15);	/* VENC_HDMI_SWITCH */
+}
+
+static int dss_init(void)
 {
 	int r;
 	u32 rev;
+	struct resource *dss_mem;
+	struct clk *dpll4_m4_ck;
 
-	dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
+	dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
+	if (!dss_mem) {
+		DSSERR("can't get IORESOURCE_MEM DSS\n");
+		r = -EINVAL;
+		goto fail0;
+	}
+	dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
 	if (!dss.base) {
 		DSSERR("can't ioremap DSS\n");
 		r = -ENOMEM;
 		goto fail0;
 	}
 
-	if (!skip_init) {
-		/* disable LCD and DIGIT output. This seems to fix the synclost
-		 * problem that we get, if the bootloader starts the DSS and
-		 * the kernel resets it */
-		omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
+	/* disable LCD and DIGIT output. This seems to fix the synclost
+	 * problem that we get, if the bootloader starts the DSS and
+	 * the kernel resets it */
+	omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
 
-		/* We need to wait here a bit, otherwise we sometimes start to
-		 * get synclost errors, and after that only power cycle will
-		 * restore DSS functionality. I have no idea why this happens.
-		 * And we have to wait _before_ resetting the DSS, but after
-		 * enabling clocks.
-		 */
-		msleep(50);
+	/* We need to wait here a bit, otherwise we sometimes start to
+	 * get synclost errors, and after that only power cycle will
+	 * restore DSS functionality. I have no idea why this happens.
+	 * And we have to wait _before_ resetting the DSS, but after
+	 * enabling clocks.
+	 */
+	msleep(50);
 
-		_omap_dss_reset();
-	}
+	_omap_dss_reset();
 
 	/* autoidle */
 	REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
@@ -589,29 +680,30 @@
 	REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);	/* venc clock 4x enable */
 	REG_FLD_MOD(DSS_CONTROL, 0, 2, 2);	/* venc clock mode = normal */
 #endif
-
-	r = request_irq(INT_24XX_DSS_IRQ,
-			cpu_is_omap24xx()
-			? dss_irq_handler_omap2
-			: dss_irq_handler_omap3,
-			0, "OMAP DSS", NULL);
-
-	if (r < 0) {
-		DSSERR("omap2 dss: request_irq failed\n");
-		goto fail1;
-	}
-
 	if (cpu_is_omap34xx()) {
-		dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
-		if (IS_ERR(dss.dpll4_m4_ck)) {
+		dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
+		if (IS_ERR(dpll4_m4_ck)) {
 			DSSERR("Failed to get dpll4_m4_ck\n");
-			r = PTR_ERR(dss.dpll4_m4_ck);
-			goto fail2;
+			r = PTR_ERR(dpll4_m4_ck);
+			goto fail1;
 		}
+	} else if (cpu_is_omap44xx()) {
+		dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck");
+		if (IS_ERR(dpll4_m4_ck)) {
+			DSSERR("Failed to get dpll4_m4_ck\n");
+			r = PTR_ERR(dpll4_m4_ck);
+			goto fail1;
+		}
+	} else { /* omap24xx */
+		dpll4_m4_ck = NULL;
 	}
 
-	dss.dsi_clk_source = DSS_SRC_DSS1_ALWON_FCLK;
-	dss.dispc_clk_source = DSS_SRC_DSS1_ALWON_FCLK;
+	dss.dpll4_m4_ck = dpll4_m4_ck;
+
+	dss.dsi_clk_source = DSS_CLK_SRC_FCK;
+	dss.dispc_clk_source = DSS_CLK_SRC_FCK;
+	dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK;
+	dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK;
 
 	dss_save_context();
 
@@ -621,21 +713,416 @@
 
 	return 0;
 
-fail2:
-	free_irq(INT_24XX_DSS_IRQ, NULL);
 fail1:
 	iounmap(dss.base);
 fail0:
 	return r;
 }
 
-void dss_exit(void)
+static void dss_exit(void)
 {
-	if (cpu_is_omap34xx())
+	if (dss.dpll4_m4_ck)
 		clk_put(dss.dpll4_m4_ck);
 
-	free_irq(INT_24XX_DSS_IRQ, NULL);
-
 	iounmap(dss.base);
 }
 
+/* CONTEXT */
+static int dss_get_ctx_id(void)
+{
+	struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
+	int r;
+
+	if (!pdata->board_data->get_last_off_on_transaction_id)
+		return 0;
+	r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev);
+	if (r < 0) {
+		dev_err(&dss.pdev->dev, "getting transaction ID failed, "
+				"will force context restore\n");
+		r = -1;
+	}
+	return r;
+}
+
+int dss_need_ctx_restore(void)
+{
+	int id = dss_get_ctx_id();
+
+	if (id < 0 || id != dss.ctx_id) {
+		DSSDBG("ctx id %d -> id %d\n",
+				dss.ctx_id, id);
+		dss.ctx_id = id;
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+static void save_all_ctx(void)
+{
+	DSSDBG("save context\n");
+
+	dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
+
+	dss_save_context();
+	dispc_save_context();
+#ifdef CONFIG_OMAP2_DSS_DSI
+	dsi_save_context();
+#endif
+
+	dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
+}
+
+static void restore_all_ctx(void)
+{
+	DSSDBG("restore context\n");
+
+	dss_clk_enable_all_no_ctx();
+
+	dss_restore_context();
+	dispc_restore_context();
+#ifdef CONFIG_OMAP2_DSS_DSI
+	dsi_restore_context();
+#endif
+
+	dss_clk_disable_all_no_ctx();
+}
+
+static int dss_get_clock(struct clk **clock, const char *clk_name)
+{
+	struct clk *clk;
+
+	clk = clk_get(&dss.pdev->dev, clk_name);
+
+	if (IS_ERR(clk)) {
+		DSSERR("can't get clock %s", clk_name);
+		return PTR_ERR(clk);
+	}
+
+	*clock = clk;
+
+	DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
+
+	return 0;
+}
+
+static int dss_get_clocks(void)
+{
+	int r;
+	struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
+
+	dss.dss_ick = NULL;
+	dss.dss_fck = NULL;
+	dss.dss_sys_clk = NULL;
+	dss.dss_tv_fck = NULL;
+	dss.dss_video_fck = NULL;
+
+	r = dss_get_clock(&dss.dss_ick, "ick");
+	if (r)
+		goto err;
+
+	r = dss_get_clock(&dss.dss_fck, "fck");
+	if (r)
+		goto err;
+
+	if (!pdata->opt_clock_available) {
+		r = -ENODEV;
+		goto err;
+	}
+
+	if (pdata->opt_clock_available("sys_clk")) {
+		r = dss_get_clock(&dss.dss_sys_clk, "sys_clk");
+		if (r)
+			goto err;
+	}
+
+	if (pdata->opt_clock_available("tv_clk")) {
+		r = dss_get_clock(&dss.dss_tv_fck, "tv_clk");
+		if (r)
+			goto err;
+	}
+
+	if (pdata->opt_clock_available("video_clk")) {
+		r = dss_get_clock(&dss.dss_video_fck, "video_clk");
+		if (r)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	if (dss.dss_ick)
+		clk_put(dss.dss_ick);
+	if (dss.dss_fck)
+		clk_put(dss.dss_fck);
+	if (dss.dss_sys_clk)
+		clk_put(dss.dss_sys_clk);
+	if (dss.dss_tv_fck)
+		clk_put(dss.dss_tv_fck);
+	if (dss.dss_video_fck)
+		clk_put(dss.dss_video_fck);
+
+	return r;
+}
+
+static void dss_put_clocks(void)
+{
+	if (dss.dss_video_fck)
+		clk_put(dss.dss_video_fck);
+	if (dss.dss_tv_fck)
+		clk_put(dss.dss_tv_fck);
+	if (dss.dss_sys_clk)
+		clk_put(dss.dss_sys_clk);
+	clk_put(dss.dss_fck);
+	clk_put(dss.dss_ick);
+}
+
+unsigned long dss_clk_get_rate(enum dss_clock clk)
+{
+	switch (clk) {
+	case DSS_CLK_ICK:
+		return clk_get_rate(dss.dss_ick);
+	case DSS_CLK_FCK:
+		return clk_get_rate(dss.dss_fck);
+	case DSS_CLK_SYSCK:
+		return clk_get_rate(dss.dss_sys_clk);
+	case DSS_CLK_TVFCK:
+		return clk_get_rate(dss.dss_tv_fck);
+	case DSS_CLK_VIDFCK:
+		return clk_get_rate(dss.dss_video_fck);
+	}
+
+	BUG();
+	return 0;
+}
+
+static unsigned count_clk_bits(enum dss_clock clks)
+{
+	unsigned num_clks = 0;
+
+	if (clks & DSS_CLK_ICK)
+		++num_clks;
+	if (clks & DSS_CLK_FCK)
+		++num_clks;
+	if (clks & DSS_CLK_SYSCK)
+		++num_clks;
+	if (clks & DSS_CLK_TVFCK)
+		++num_clks;
+	if (clks & DSS_CLK_VIDFCK)
+		++num_clks;
+
+	return num_clks;
+}
+
+static void dss_clk_enable_no_ctx(enum dss_clock clks)
+{
+	unsigned num_clks = count_clk_bits(clks);
+
+	if (clks & DSS_CLK_ICK)
+		clk_enable(dss.dss_ick);
+	if (clks & DSS_CLK_FCK)
+		clk_enable(dss.dss_fck);
+	if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
+		clk_enable(dss.dss_sys_clk);
+	if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
+		clk_enable(dss.dss_tv_fck);
+	if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
+		clk_enable(dss.dss_video_fck);
+
+	dss.num_clks_enabled += num_clks;
+}
+
+void dss_clk_enable(enum dss_clock clks)
+{
+	bool check_ctx = dss.num_clks_enabled == 0;
+
+	dss_clk_enable_no_ctx(clks);
+
+	/*
+	 * HACK: On omap4 the registers may not be accessible right after
+	 * enabling the clocks. At some point this will be handled by
+	 * pm_runtime, but for the time begin this should make things work.
+	 */
+	if (cpu_is_omap44xx() && check_ctx)
+		udelay(10);
+
+	if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
+		restore_all_ctx();
+}
+
+static void dss_clk_disable_no_ctx(enum dss_clock clks)
+{
+	unsigned num_clks = count_clk_bits(clks);
+
+	if (clks & DSS_CLK_ICK)
+		clk_disable(dss.dss_ick);
+	if (clks & DSS_CLK_FCK)
+		clk_disable(dss.dss_fck);
+	if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
+		clk_disable(dss.dss_sys_clk);
+	if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
+		clk_disable(dss.dss_tv_fck);
+	if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
+		clk_disable(dss.dss_video_fck);
+
+	dss.num_clks_enabled -= num_clks;
+}
+
+void dss_clk_disable(enum dss_clock clks)
+{
+	if (cpu_is_omap34xx()) {
+		unsigned num_clks = count_clk_bits(clks);
+
+		BUG_ON(dss.num_clks_enabled < num_clks);
+
+		if (dss.num_clks_enabled == num_clks)
+			save_all_ctx();
+	}
+
+	dss_clk_disable_no_ctx(clks);
+}
+
+static void dss_clk_enable_all_no_ctx(void)
+{
+	enum dss_clock clks;
+
+	clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
+	if (cpu_is_omap34xx())
+		clks |= DSS_CLK_VIDFCK;
+	dss_clk_enable_no_ctx(clks);
+}
+
+static void dss_clk_disable_all_no_ctx(void)
+{
+	enum dss_clock clks;
+
+	clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
+	if (cpu_is_omap34xx())
+		clks |= DSS_CLK_VIDFCK;
+	dss_clk_disable_no_ctx(clks);
+}
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
+/* CLOCKS */
+static void core_dump_clocks(struct seq_file *s)
+{
+	int i;
+	struct clk *clocks[5] = {
+		dss.dss_ick,
+		dss.dss_fck,
+		dss.dss_sys_clk,
+		dss.dss_tv_fck,
+		dss.dss_video_fck
+	};
+
+	seq_printf(s, "- CORE -\n");
+
+	seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
+
+	for (i = 0; i < 5; i++) {
+		if (!clocks[i])
+			continue;
+		seq_printf(s, "%-15s\t%lu\t%d\n",
+				clocks[i]->name,
+				clk_get_rate(clocks[i]),
+				clocks[i]->usecount);
+	}
+}
+#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
+
+/* DEBUGFS */
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
+void dss_debug_dump_clocks(struct seq_file *s)
+{
+	core_dump_clocks(s);
+	dss_dump_clocks(s);
+	dispc_dump_clocks(s);
+#ifdef CONFIG_OMAP2_DSS_DSI
+	dsi_dump_clocks(s);
+#endif
+}
+#endif
+
+
+/* DSS HW IP initialisation */
+static int omap_dsshw_probe(struct platform_device *pdev)
+{
+	int r;
+
+	dss.pdev = pdev;
+
+	r = dss_get_clocks();
+	if (r)
+		goto err_clocks;
+
+	dss_clk_enable_all_no_ctx();
+
+	dss.ctx_id = dss_get_ctx_id();
+	DSSDBG("initial ctx id %u\n", dss.ctx_id);
+
+	r = dss_init();
+	if (r) {
+		DSSERR("Failed to initialize DSS\n");
+		goto err_dss;
+	}
+
+	r = dpi_init();
+	if (r) {
+		DSSERR("Failed to initialize DPI\n");
+		goto err_dpi;
+	}
+
+	r = sdi_init();
+	if (r) {
+		DSSERR("Failed to initialize SDI\n");
+		goto err_sdi;
+	}
+
+	dss_clk_disable_all_no_ctx();
+	return 0;
+err_sdi:
+	dpi_exit();
+err_dpi:
+	dss_exit();
+err_dss:
+	dss_clk_disable_all_no_ctx();
+	dss_put_clocks();
+err_clocks:
+	return r;
+}
+
+static int omap_dsshw_remove(struct platform_device *pdev)
+{
+
+	dss_exit();
+
+	/*
+	 * As part of hwmod changes, DSS is not the only controller of dss
+	 * clocks; hwmod framework itself will also enable clocks during hwmod
+	 * init for dss, and autoidle is set in h/w for DSS. Hence, there's no
+	 * need to disable clocks if their usecounts > 1.
+	 */
+	WARN_ON(dss.num_clks_enabled > 0);
+
+	dss_put_clocks();
+	return 0;
+}
+
+static struct platform_driver omap_dsshw_driver = {
+	.probe          = omap_dsshw_probe,
+	.remove         = omap_dsshw_remove,
+	.driver         = {
+		.name   = "omapdss_dss",
+		.owner  = THIS_MODULE,
+	},
+};
+
+int dss_init_platform_driver(void)
+{
+	return platform_driver_register(&omap_dsshw_driver);
+}
+
+void dss_uninit_platform_driver(void)
+{
+	return platform_driver_unregister(&omap_dsshw_driver);
+}
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index b394951..c2f582b 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -97,8 +97,6 @@
 #define FLD_MOD(orig, val, start, end) \
 	(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
 
-#define DISPC_MAX_FCK 173000000
-
 enum omap_burst_size {
 	OMAP_DSS_BURST_4x32 = 0,
 	OMAP_DSS_BURST_8x32 = 1,
@@ -112,17 +110,25 @@
 };
 
 enum dss_clock {
-	DSS_CLK_ICK	= 1 << 0,
-	DSS_CLK_FCK1	= 1 << 1,
-	DSS_CLK_FCK2	= 1 << 2,
-	DSS_CLK_54M	= 1 << 3,
-	DSS_CLK_96M	= 1 << 4,
+	DSS_CLK_ICK	= 1 << 0,	/* DSS_L3_ICLK and DSS_L4_ICLK */
+	DSS_CLK_FCK	= 1 << 1,	/* DSS1_ALWON_FCLK */
+	DSS_CLK_SYSCK	= 1 << 2,	/* DSS2_ALWON_FCLK */
+	DSS_CLK_TVFCK	= 1 << 3,	/* DSS_TV_FCLK */
+	DSS_CLK_VIDFCK	= 1 << 4,	/* DSS_96M_FCLK*/
 };
 
 enum dss_clk_source {
-	DSS_SRC_DSI1_PLL_FCLK,
-	DSS_SRC_DSI2_PLL_FCLK,
-	DSS_SRC_DSS1_ALWON_FCLK,
+	DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC,	/* OMAP3: DSI1_PLL_FCLK
+						 * OMAP4: PLL1_CLK1 */
+	DSS_CLK_SRC_DSI_PLL_HSDIV_DSI,		/* OMAP3: DSI2_PLL_FCLK
+						 * OMAP4: PLL1_CLK2 */
+	DSS_CLK_SRC_FCK,			/* OMAP2/3: DSS1_ALWON_FCLK
+						 * OMAP4: DSS_FCLK */
+};
+
+enum dss_hdmi_venc_clk_source_select {
+	DSS_VENC_TV_CLK = 0,
+	DSS_HDMI_M_PCLK = 1,
 };
 
 struct dss_clock_info {
@@ -148,36 +154,42 @@
 	unsigned long fint;
 	unsigned long clkin4ddr;
 	unsigned long clkin;
-	unsigned long dsi1_pll_fclk;
-	unsigned long dsi2_pll_fclk;
-
+	unsigned long dsi_pll_hsdiv_dispc_clk;	/* OMAP3: DSI1_PLL_CLK
+						 * OMAP4: PLLx_CLK1 */
+	unsigned long dsi_pll_hsdiv_dsi_clk;	/* OMAP3: DSI2_PLL_CLK
+						 * OMAP4: PLLx_CLK2 */
 	unsigned long lp_clk;
 
 	/* dividers */
 	u16 regn;
 	u16 regm;
-	u16 regm3;
-	u16 regm4;
-
+	u16 regm_dispc;	/* OMAP3: REGM3
+			 * OMAP4: REGM4 */
+	u16 regm_dsi;	/* OMAP3: REGM4
+			 * OMAP4: REGM5 */
 	u16 lp_clk_div;
 
 	u8 highfreq;
-	bool use_dss2_fck;
+	bool use_sys_clk;
+};
+
+/* HDMI PLL structure */
+struct hdmi_pll_info {
+	u16 regn;
+	u16 regm;
+	u32 regmf;
+	u16 regm2;
+	u16 regsd;
+	u16 dcofreq;
 };
 
 struct seq_file;
 struct platform_device;
 
 /* core */
-void dss_clk_enable(enum dss_clock clks);
-void dss_clk_disable(enum dss_clock clks);
-unsigned long dss_clk_get_rate(enum dss_clock clk);
-int dss_need_ctx_restore(void);
-void dss_dump_clocks(struct seq_file *s);
 struct bus_type *dss_get_bus(void);
 struct regulator *dss_get_vdds_dsi(void);
 struct regulator *dss_get_vdds_sdi(void);
-struct regulator *dss_get_vdda_dac(void);
 
 /* display */
 int dss_suspend_all_devices(void);
@@ -214,13 +226,23 @@
 void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
 
 /* DSS */
-int dss_init(bool skip_init);
-void dss_exit(void);
+int dss_init_platform_driver(void);
+void dss_uninit_platform_driver(void);
 
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
 void dss_save_context(void);
 void dss_restore_context(void);
+void dss_clk_enable(enum dss_clock clks);
+void dss_clk_disable(enum dss_clock clks);
+unsigned long dss_clk_get_rate(enum dss_clock clk);
+int dss_need_ctx_restore(void);
+const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src);
+void dss_dump_clocks(struct seq_file *s);
 
 void dss_dump_regs(struct seq_file *s);
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
+void dss_debug_dump_clocks(struct seq_file *s);
+#endif
 
 void dss_sdi_init(u8 datapairs);
 int dss_sdi_enable(void);
@@ -228,8 +250,11 @@
 
 void dss_select_dispc_clk_source(enum dss_clk_source clk_src);
 void dss_select_dsi_clk_source(enum dss_clk_source clk_src);
+void dss_select_lcd_clk_source(enum omap_channel channel,
+		enum dss_clk_source clk_src);
 enum dss_clk_source dss_get_dispc_clk_source(void);
 enum dss_clk_source dss_get_dsi_clk_source(void);
+enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
 
 void dss_set_venc_output(enum omap_dss_venc_type type);
 void dss_set_dac_pwrdn_bgz(bool enable);
@@ -244,11 +269,11 @@
 
 /* SDI */
 #ifdef CONFIG_OMAP2_DSS_SDI
-int sdi_init(bool skip_init);
+int sdi_init(void);
 void sdi_exit(void);
 int sdi_init_display(struct omap_dss_device *display);
 #else
-static inline int sdi_init(bool skip_init)
+static inline int sdi_init(void)
 {
 	return 0;
 }
@@ -259,8 +284,8 @@
 
 /* DSI */
 #ifdef CONFIG_OMAP2_DSS_DSI
-int dsi_init(struct platform_device *pdev);
-void dsi_exit(void);
+int dsi_init_platform_driver(void);
+void dsi_uninit_platform_driver(void);
 
 void dsi_dump_clocks(struct seq_file *s);
 void dsi_dump_irqs(struct seq_file *s);
@@ -271,7 +296,7 @@
 
 int dsi_init_display(struct omap_dss_device *display);
 void dsi_irq_handler(void);
-unsigned long dsi_get_dsi1_pll_rate(void);
+unsigned long dsi_get_pll_hsdiv_dispc_rate(void);
 int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
 int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
 		struct dsi_clock_info *cinfo,
@@ -282,31 +307,36 @@
 void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
 		u32 fifo_size, enum omap_burst_size *burst_size,
 		u32 *fifo_low, u32 *fifo_high);
-void dsi_wait_dsi1_pll_active(void);
-void dsi_wait_dsi2_pll_active(void);
+void dsi_wait_pll_hsdiv_dispc_active(void);
+void dsi_wait_pll_hsdiv_dsi_active(void);
 #else
-static inline int dsi_init(struct platform_device *pdev)
+static inline int dsi_init_platform_driver(void)
 {
 	return 0;
 }
-static inline void dsi_exit(void)
+static inline void dsi_uninit_platform_driver(void)
 {
 }
-static inline void dsi_wait_dsi1_pll_active(void)
+static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
+{
+	WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
+	return 0;
+}
+static inline void dsi_wait_pll_hsdiv_dispc_active(void)
 {
 }
-static inline void dsi_wait_dsi2_pll_active(void)
+static inline void dsi_wait_pll_hsdiv_dsi_active(void)
 {
 }
 #endif
 
 /* DPI */
 #ifdef CONFIG_OMAP2_DSS_DPI
-int dpi_init(struct platform_device *pdev);
+int dpi_init(void);
 void dpi_exit(void);
 int dpi_init_display(struct omap_dss_device *dssdev);
 #else
-static inline int dpi_init(struct platform_device *pdev)
+static inline int dpi_init(void)
 {
 	return 0;
 }
@@ -316,8 +346,8 @@
 #endif
 
 /* DISPC */
-int dispc_init(void);
-void dispc_exit(void);
+int dispc_init_platform_driver(void);
+void dispc_uninit_platform_driver(void);
 void dispc_dump_clocks(struct seq_file *s);
 void dispc_dump_irqs(struct seq_file *s);
 void dispc_dump_regs(struct seq_file *s);
@@ -350,6 +380,7 @@
 void dispc_set_channel_out(enum omap_plane plane,
 		enum omap_channel channel_out);
 
+void dispc_enable_gamma_table(bool enable);
 int dispc_setup_plane(enum omap_plane plane,
 		      u32 paddr, u16 screen_width,
 		      u16 pos_x, u16 pos_y,
@@ -409,24 +440,50 @@
 
 /* VENC */
 #ifdef CONFIG_OMAP2_DSS_VENC
-int venc_init(struct platform_device *pdev);
-void venc_exit(void);
+int venc_init_platform_driver(void);
+void venc_uninit_platform_driver(void);
 void venc_dump_regs(struct seq_file *s);
 int venc_init_display(struct omap_dss_device *display);
 #else
-static inline int venc_init(struct platform_device *pdev)
+static inline int venc_init_platform_driver(void)
 {
 	return 0;
 }
-static inline void venc_exit(void)
+static inline void venc_uninit_platform_driver(void)
 {
 }
 #endif
 
+/* HDMI */
+#ifdef CONFIG_OMAP4_DSS_HDMI
+int hdmi_init_platform_driver(void);
+void hdmi_uninit_platform_driver(void);
+int hdmi_init_display(struct omap_dss_device *dssdev);
+#else
+static inline int hdmi_init_display(struct omap_dss_device *dssdev)
+{
+	return 0;
+}
+static inline int hdmi_init_platform_driver(void)
+{
+	return 0;
+}
+static inline void hdmi_uninit_platform_driver(void)
+{
+}
+#endif
+int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev);
+int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
+					struct omap_video_timings *timings);
+int hdmi_panel_init(void);
+void hdmi_panel_exit(void);
+
 /* RFBI */
 #ifdef CONFIG_OMAP2_DSS_RFBI
-int rfbi_init(void);
-void rfbi_exit(void);
+int rfbi_init_platform_driver(void);
+void rfbi_uninit_platform_driver(void);
 void rfbi_dump_regs(struct seq_file *s);
 
 int rfbi_configure(int rfbi_module, int bpp, int lines);
@@ -437,11 +494,11 @@
 unsigned long rfbi_get_max_tx_rate(void);
 int rfbi_init_display(struct omap_dss_device *display);
 #else
-static inline int rfbi_init(void)
+static inline int rfbi_init_platform_driver(void)
 {
 	return 0;
 }
-static inline void rfbi_exit(void)
+static inline void rfbi_uninit_platform_driver(void)
 {
 }
 #endif
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index cf3ef69..aa16222 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -25,14 +25,18 @@
 #include <plat/display.h>
 #include <plat/cpu.h>
 
+#include "dss.h"
 #include "dss_features.h"
 
 /* Defines a generic omap register field */
 struct dss_reg_field {
-	enum dss_feat_reg_field id;
 	u8 start, end;
 };
 
+struct dss_param_range {
+	int min, max;
+};
+
 struct omap_dss_features {
 	const struct dss_reg_field *reg_fields;
 	const int num_reg_fields;
@@ -43,29 +47,68 @@
 	const int num_ovls;
 	const enum omap_display_type *supported_displays;
 	const enum omap_color_mode *supported_color_modes;
+	const char * const *clksrc_names;
+	const struct dss_param_range *dss_params;
 };
 
 /* This struct is assigned to one of the below during initialization */
 static struct omap_dss_features *omap_current_dss_features;
 
 static const struct dss_reg_field omap2_dss_reg_fields[] = {
-	{ FEAT_REG_FIRHINC, 11, 0 },
-	{ FEAT_REG_FIRVINC, 27, 16 },
-	{ FEAT_REG_FIFOLOWTHRESHOLD, 8, 0 },
-	{ FEAT_REG_FIFOHIGHTHRESHOLD, 24, 16 },
-	{ FEAT_REG_FIFOSIZE, 8, 0 },
+	[FEAT_REG_FIRHINC]			= { 11, 0 },
+	[FEAT_REG_FIRVINC]			= { 27, 16 },
+	[FEAT_REG_FIFOLOWTHRESHOLD]		= { 8, 0 },
+	[FEAT_REG_FIFOHIGHTHRESHOLD]		= { 24, 16 },
+	[FEAT_REG_FIFOSIZE]			= { 8, 0 },
+	[FEAT_REG_HORIZONTALACCU]		= { 9, 0 },
+	[FEAT_REG_VERTICALACCU]			= { 25, 16 },
+	[FEAT_REG_DISPC_CLK_SWITCH]		= { 0, 0 },
+	[FEAT_REG_DSIPLL_REGN]			= { 0, 0 },
+	[FEAT_REG_DSIPLL_REGM]			= { 0, 0 },
+	[FEAT_REG_DSIPLL_REGM_DISPC]		= { 0, 0 },
+	[FEAT_REG_DSIPLL_REGM_DSI]		= { 0, 0 },
 };
 
 static const struct dss_reg_field omap3_dss_reg_fields[] = {
-	{ FEAT_REG_FIRHINC, 12, 0 },
-	{ FEAT_REG_FIRVINC, 28, 16 },
-	{ FEAT_REG_FIFOLOWTHRESHOLD, 11, 0 },
-	{ FEAT_REG_FIFOHIGHTHRESHOLD, 27, 16 },
-	{ FEAT_REG_FIFOSIZE, 10, 0 },
+	[FEAT_REG_FIRHINC]			= { 12, 0 },
+	[FEAT_REG_FIRVINC]			= { 28, 16 },
+	[FEAT_REG_FIFOLOWTHRESHOLD]		= { 11, 0 },
+	[FEAT_REG_FIFOHIGHTHRESHOLD]		= { 27, 16 },
+	[FEAT_REG_FIFOSIZE]			= { 10, 0 },
+	[FEAT_REG_HORIZONTALACCU]		= { 9, 0 },
+	[FEAT_REG_VERTICALACCU]			= { 25, 16 },
+	[FEAT_REG_DISPC_CLK_SWITCH]		= { 0, 0 },
+	[FEAT_REG_DSIPLL_REGN]			= { 7, 1 },
+	[FEAT_REG_DSIPLL_REGM]			= { 18, 8 },
+	[FEAT_REG_DSIPLL_REGM_DISPC]		= { 22, 19 },
+	[FEAT_REG_DSIPLL_REGM_DSI]		= { 26, 23 },
+};
+
+static const struct dss_reg_field omap4_dss_reg_fields[] = {
+	[FEAT_REG_FIRHINC]			= { 12, 0 },
+	[FEAT_REG_FIRVINC]			= { 28, 16 },
+	[FEAT_REG_FIFOLOWTHRESHOLD]		= { 15, 0 },
+	[FEAT_REG_FIFOHIGHTHRESHOLD]		= { 31, 16 },
+	[FEAT_REG_FIFOSIZE]			= { 15, 0 },
+	[FEAT_REG_HORIZONTALACCU]		= { 10, 0 },
+	[FEAT_REG_VERTICALACCU]			= { 26, 16 },
+	[FEAT_REG_DISPC_CLK_SWITCH]		= { 9, 8 },
+	[FEAT_REG_DSIPLL_REGN]			= { 8, 1 },
+	[FEAT_REG_DSIPLL_REGM]			= { 20, 9 },
+	[FEAT_REG_DSIPLL_REGM_DISPC]		= { 25, 21 },
+	[FEAT_REG_DSIPLL_REGM_DSI]		= { 30, 26 },
 };
 
 static const enum omap_display_type omap2_dss_supported_displays[] = {
 	/* OMAP_DSS_CHANNEL_LCD */
+	OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
+
+	/* OMAP_DSS_CHANNEL_DIGIT */
+	OMAP_DISPLAY_TYPE_VENC,
+};
+
+static const enum omap_display_type omap3430_dss_supported_displays[] = {
+	/* OMAP_DSS_CHANNEL_LCD */
 	OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
 	OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
 
@@ -73,10 +116,10 @@
 	OMAP_DISPLAY_TYPE_VENC,
 };
 
-static const enum omap_display_type omap3_dss_supported_displays[] = {
+static const enum omap_display_type omap3630_dss_supported_displays[] = {
 	/* OMAP_DSS_CHANNEL_LCD */
 	OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
-	OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
+	OMAP_DISPLAY_TYPE_DSI,
 
 	/* OMAP_DSS_CHANNEL_DIGIT */
 	OMAP_DISPLAY_TYPE_VENC,
@@ -87,7 +130,7 @@
 	OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
 
 	/* OMAP_DSS_CHANNEL_DIGIT */
-	OMAP_DISPLAY_TYPE_VENC,
+	OMAP_DISPLAY_TYPE_VENC | OMAP_DISPLAY_TYPE_HDMI,
 
 	/* OMAP_DSS_CHANNEL_LCD2 */
 	OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
@@ -134,6 +177,54 @@
 	OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
 };
 
+static const char * const omap2_dss_clk_source_names[] = {
+	[DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "N/A",
+	[DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]		= "N/A",
+	[DSS_CLK_SRC_FCK]			= "DSS_FCLK1",
+};
+
+static const char * const omap3_dss_clk_source_names[] = {
+	[DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "DSI1_PLL_FCLK",
+	[DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]		= "DSI2_PLL_FCLK",
+	[DSS_CLK_SRC_FCK]			= "DSS1_ALWON_FCLK",
+};
+
+static const char * const omap4_dss_clk_source_names[] = {
+	[DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "PLL1_CLK1",
+	[DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]		= "PLL1_CLK2",
+	[DSS_CLK_SRC_FCK]			= "DSS_FCLK",
+};
+
+static const struct dss_param_range omap2_dss_param_range[] = {
+	[FEAT_PARAM_DSS_FCK]			= { 0, 173000000 },
+	[FEAT_PARAM_DSIPLL_REGN]		= { 0, 0 },
+	[FEAT_PARAM_DSIPLL_REGM]		= { 0, 0 },
+	[FEAT_PARAM_DSIPLL_REGM_DISPC]		= { 0, 0 },
+	[FEAT_PARAM_DSIPLL_REGM_DSI]		= { 0, 0 },
+	[FEAT_PARAM_DSIPLL_FINT]		= { 0, 0 },
+	[FEAT_PARAM_DSIPLL_LPDIV]		= { 0, 0 },
+};
+
+static const struct dss_param_range omap3_dss_param_range[] = {
+	[FEAT_PARAM_DSS_FCK]			= { 0, 173000000 },
+	[FEAT_PARAM_DSIPLL_REGN]		= { 0, (1 << 7) - 1 },
+	[FEAT_PARAM_DSIPLL_REGM]		= { 0, (1 << 11) - 1 },
+	[FEAT_PARAM_DSIPLL_REGM_DISPC]		= { 0, (1 << 4) - 1 },
+	[FEAT_PARAM_DSIPLL_REGM_DSI]		= { 0, (1 << 4) - 1 },
+	[FEAT_PARAM_DSIPLL_FINT]		= { 750000, 2100000 },
+	[FEAT_PARAM_DSIPLL_LPDIV]		= { 1, (1 << 13) - 1},
+};
+
+static const struct dss_param_range omap4_dss_param_range[] = {
+	[FEAT_PARAM_DSS_FCK]			= { 0, 186000000 },
+	[FEAT_PARAM_DSIPLL_REGN]		= { 0, (1 << 8) - 1 },
+	[FEAT_PARAM_DSIPLL_REGM]		= { 0, (1 << 12) - 1 },
+	[FEAT_PARAM_DSIPLL_REGM_DISPC]		= { 0, (1 << 5) - 1 },
+	[FEAT_PARAM_DSIPLL_REGM_DSI]		= { 0, (1 << 5) - 1 },
+	[FEAT_PARAM_DSIPLL_FINT]		= { 500000, 2500000 },
+	[FEAT_PARAM_DSIPLL_LPDIV]		= { 0, (1 << 13) - 1 },
+};
+
 /* OMAP2 DSS Features */
 static struct omap_dss_features omap2_dss_features = {
 	.reg_fields = omap2_dss_reg_fields,
@@ -141,12 +232,15 @@
 
 	.has_feature	=
 		FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL |
-		FEAT_PCKFREEENABLE | FEAT_FUNCGATED,
+		FEAT_PCKFREEENABLE | FEAT_FUNCGATED |
+		FEAT_ROWREPEATENABLE | FEAT_RESIZECONF,
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
 	.supported_displays = omap2_dss_supported_displays,
 	.supported_color_modes = omap2_dss_supported_color_modes,
+	.clksrc_names = omap2_dss_clk_source_names,
+	.dss_params = omap2_dss_param_range,
 };
 
 /* OMAP3 DSS Features */
@@ -157,12 +251,15 @@
 	.has_feature	=
 		FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
 		FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
-		FEAT_FUNCGATED,
+		FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
+		FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF,
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
-	.supported_displays = omap3_dss_supported_displays,
+	.supported_displays = omap3430_dss_supported_displays,
 	.supported_color_modes = omap3_dss_supported_color_modes,
+	.clksrc_names = omap3_dss_clk_source_names,
+	.dss_params = omap3_dss_param_range,
 };
 
 static struct omap_dss_features omap3630_dss_features = {
@@ -172,27 +269,34 @@
 	.has_feature    =
 		FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
 		FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
-		FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED,
+		FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
+		FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
+		FEAT_RESIZECONF,
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
-	.supported_displays = omap3_dss_supported_displays,
+	.supported_displays = omap3630_dss_supported_displays,
 	.supported_color_modes = omap3_dss_supported_color_modes,
+	.clksrc_names = omap3_dss_clk_source_names,
+	.dss_params = omap3_dss_param_range,
 };
 
 /* OMAP4 DSS Features */
 static struct omap_dss_features omap4_dss_features = {
-	.reg_fields = omap3_dss_reg_fields,
-	.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+	.reg_fields = omap4_dss_reg_fields,
+	.num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
 
 	.has_feature	=
 		FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
-		FEAT_MGR_LCD2,
+		FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
+		FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC,
 
 	.num_mgrs = 3,
 	.num_ovls = 3,
 	.supported_displays = omap4_dss_supported_displays,
 	.supported_color_modes = omap3_dss_supported_color_modes,
+	.clksrc_names = omap4_dss_clk_source_names,
+	.dss_params = omap4_dss_param_range,
 };
 
 /* Functions returning values related to a DSS feature */
@@ -206,6 +310,16 @@
 	return omap_current_dss_features->num_ovls;
 }
 
+unsigned long dss_feat_get_param_min(enum dss_range_param param)
+{
+	return omap_current_dss_features->dss_params[param].min;
+}
+
+unsigned long dss_feat_get_param_max(enum dss_range_param param)
+{
+	return omap_current_dss_features->dss_params[param].max;
+}
+
 enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel)
 {
 	return omap_current_dss_features->supported_displays[channel];
@@ -223,6 +337,11 @@
 			color_mode;
 }
 
+const char *dss_feat_get_clk_source_name(enum dss_clk_source id)
+{
+	return omap_current_dss_features->clksrc_names[id];
+}
+
 /* DSS has_feature check */
 bool dss_has_feature(enum dss_feat_id id)
 {
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index b9c70be..12e9c4e 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -22,6 +22,7 @@
 
 #define MAX_DSS_MANAGERS	3
 #define MAX_DSS_OVERLAYS	3
+#define MAX_DSS_LCD_MANAGERS	2
 
 /* DSS has feature id */
 enum dss_feat_id {
@@ -33,6 +34,12 @@
 	FEAT_PCKFREEENABLE	= 1 << 5,
 	FEAT_FUNCGATED		= 1 << 6,
 	FEAT_MGR_LCD2		= 1 << 7,
+	FEAT_LINEBUFFERSPLIT	= 1 << 8,
+	FEAT_ROWREPEATENABLE	= 1 << 9,
+	FEAT_RESIZECONF		= 1 << 10,
+	/* Independent core clk divider */
+	FEAT_CORE_CLK_DIV	= 1 << 11,
+	FEAT_LCD_CLK_SRC	= 1 << 12,
 };
 
 /* DSS register field id */
@@ -42,15 +49,35 @@
 	FEAT_REG_FIFOHIGHTHRESHOLD,
 	FEAT_REG_FIFOLOWTHRESHOLD,
 	FEAT_REG_FIFOSIZE,
+	FEAT_REG_HORIZONTALACCU,
+	FEAT_REG_VERTICALACCU,
+	FEAT_REG_DISPC_CLK_SWITCH,
+	FEAT_REG_DSIPLL_REGN,
+	FEAT_REG_DSIPLL_REGM,
+	FEAT_REG_DSIPLL_REGM_DISPC,
+	FEAT_REG_DSIPLL_REGM_DSI,
+};
+
+enum dss_range_param {
+	FEAT_PARAM_DSS_FCK,
+	FEAT_PARAM_DSIPLL_REGN,
+	FEAT_PARAM_DSIPLL_REGM,
+	FEAT_PARAM_DSIPLL_REGM_DISPC,
+	FEAT_PARAM_DSIPLL_REGM_DSI,
+	FEAT_PARAM_DSIPLL_FINT,
+	FEAT_PARAM_DSIPLL_LPDIV,
 };
 
 /* DSS Feature Functions */
 int dss_feat_get_num_mgrs(void);
 int dss_feat_get_num_ovls(void);
+unsigned long dss_feat_get_param_min(enum dss_range_param param);
+unsigned long dss_feat_get_param_max(enum dss_range_param param);
 enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
 enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
 bool dss_feat_color_mode_supported(enum omap_plane plane,
 		enum omap_color_mode color_mode);
+const char *dss_feat_get_clk_source_name(enum dss_clk_source id);
 
 bool dss_has_feature(enum dss_feat_id id);
 void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
new file mode 100644
index 0000000..0d44f07
--- /dev/null
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -0,0 +1,1332 @@
+/*
+ * hdmi.c
+ *
+ * HDMI interface DSS driver setting for TI's OMAP4 family of processor.
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors: Yong Zhi
+ *	Mythri pk <mythripk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "HDMI"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <plat/display.h>
+
+#include "dss.h"
+#include "hdmi.h"
+
+static struct {
+	struct mutex lock;
+	struct omap_display_platform_data *pdata;
+	struct platform_device *pdev;
+	void __iomem *base_wp;	/* HDMI wrapper */
+	int code;
+	int mode;
+	u8 edid[HDMI_EDID_MAX_LENGTH];
+	u8 edid_set;
+	bool custom_set;
+	struct hdmi_config cfg;
+} hdmi;
+
+/*
+ * Logic for the below structure :
+ * user enters the CEA or VESA timings by specifying the HDMI/DVI code.
+ * There is a correspondence between CEA/VESA timing and code, please
+ * refer to section 6.3 in HDMI 1.3 specification for timing code.
+ *
+ * In the below structure, cea_vesa_timings corresponds to all OMAP4
+ * supported CEA and VESA timing values.code_cea corresponds to the CEA
+ * code, It is used to get the timing from cea_vesa_timing array.Similarly
+ * with code_vesa. Code_index is used for back mapping, that is once EDID
+ * is read from the TV, EDID is parsed to find the timing values and then
+ * map it to corresponding CEA or VESA index.
+ */
+
+static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = {
+	{ {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0},
+	{ {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1},
+	{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1},
+	{ {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0},
+	{ {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0},
+	{ {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0},
+	{ {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0},
+	{ {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1},
+	{ {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1},
+	{ {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1},
+	{ {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0},
+	{ {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0},
+	{ {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1},
+	{ {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0},
+	{ {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1},
+	/* VESA From Here */
+	{ {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0},
+	{ {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1},
+	{ {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1},
+	{ {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0},
+	{ {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0},
+	{ {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1},
+	{ {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1},
+	{ {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1},
+	{ {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0},
+	{ {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0},
+	{ {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0},
+	{ {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0},
+	{ {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1},
+	{ {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1},
+	{ {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1},
+	{ {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1},
+	{ {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1},
+	{ {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1},
+	{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}
+};
+
+/*
+ * This is a static mapping array which maps the timing values
+ * with corresponding CEA / VESA code
+ */
+static const int code_index[OMAP_HDMI_TIMINGS_NB] = {
+	1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32,
+	/* <--15 CEA 17--> vesa*/
+	4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A,
+	0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B
+};
+
+/*
+ * This is reverse static mapping which maps the CEA / VESA code
+ * to the corresponding timing values
+ */
+static const int code_cea[39] = {
+	-1,  0,  3,  3,  2,  8,  5,  5, -1, -1,
+	-1, -1, -1, -1, -1, -1,  9, 10, 10,  1,
+	7,   6,  6, -1, -1, -1, -1, -1, -1, 11,
+	11, 12, 14, -1, -1, 13, 13,  4,  4
+};
+
+static const int code_vesa[85] = {
+	-1, -1, -1, -1, 15, -1, -1, -1, -1, 16,
+	-1, -1, -1, -1, 17, -1, 23, -1, -1, -1,
+	-1, -1, 29, 18, -1, -1, -1, 32, 19, -1,
+	-1, -1, 21, -1, -1, 22, -1, -1, -1, 20,
+	-1, 30, 24, -1, -1, -1, -1, 25, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, 31, 26, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, 27, 28, -1, 33};
+
+static const u8 edid_header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0};
+
+static inline void hdmi_write_reg(const struct hdmi_reg idx, u32 val)
+{
+	__raw_writel(val, hdmi.base_wp + idx.idx);
+}
+
+static inline u32 hdmi_read_reg(const struct hdmi_reg idx)
+{
+	return __raw_readl(hdmi.base_wp + idx.idx);
+}
+
+static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
+				int b2, int b1, u32 val)
+{
+	u32 t = 0;
+	while (val != REG_GET(idx, b2, b1)) {
+		udelay(1);
+		if (t++ > 10000)
+			return !val;
+	}
+	return val;
+}
+
+int hdmi_init_display(struct omap_dss_device *dssdev)
+{
+	DSSDBG("init_display\n");
+
+	return 0;
+}
+
+static int hdmi_pll_init(enum hdmi_clk_refsel refsel, int dcofreq,
+		struct hdmi_pll_info *fmt, u16 sd)
+{
+	u32 r;
+
+	/* PLL start always use manual mode */
+	REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
+
+	r = hdmi_read_reg(PLLCTRL_CFG1);
+	r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
+	r = FLD_MOD(r, fmt->regn, 8, 1);  /* CFG1_PLL_REGN */
+
+	hdmi_write_reg(PLLCTRL_CFG1, r);
+
+	r = hdmi_read_reg(PLLCTRL_CFG2);
+
+	r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
+	r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
+	r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
+
+	if (dcofreq) {
+		/* divider programming for frequency beyond 1000Mhz */
+		REG_FLD_MOD(PLLCTRL_CFG3, sd, 17, 10);
+		r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
+	} else {
+		r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
+	}
+
+	hdmi_write_reg(PLLCTRL_CFG2, r);
+
+	r = hdmi_read_reg(PLLCTRL_CFG4);
+	r = FLD_MOD(r, fmt->regm2, 24, 18);
+	r = FLD_MOD(r, fmt->regmf, 17, 0);
+
+	hdmi_write_reg(PLLCTRL_CFG4, r);
+
+	/* go now */
+	REG_FLD_MOD(PLLCTRL_PLL_GO, 0x1, 0, 0);
+
+	/* wait for bit change */
+	if (hdmi_wait_for_bit_change(PLLCTRL_PLL_GO, 0, 0, 1) != 1) {
+		DSSERR("PLL GO bit not set\n");
+		return -ETIMEDOUT;
+	}
+
+	/* Wait till the lock bit is set in PLL status */
+	if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
+		DSSWARN("cannot lock PLL\n");
+		DSSWARN("CFG1 0x%x\n",
+			hdmi_read_reg(PLLCTRL_CFG1));
+		DSSWARN("CFG2 0x%x\n",
+			hdmi_read_reg(PLLCTRL_CFG2));
+		DSSWARN("CFG4 0x%x\n",
+			hdmi_read_reg(PLLCTRL_CFG4));
+		return -ETIMEDOUT;
+	}
+
+	DSSDBG("PLL locked!\n");
+
+	return 0;
+}
+
+/* PHY_PWR_CMD */
+static int hdmi_set_phy_pwr(enum hdmi_phy_pwr val)
+{
+	/* Command for power control of HDMI PHY */
+	REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 7, 6);
+
+	/* Status of the power control of HDMI PHY */
+	if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 5, 4, val) != val) {
+		DSSERR("Failed to set PHY power mode to %d\n", val);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+/* PLL_PWR_CMD */
+static int hdmi_set_pll_pwr(enum hdmi_pll_pwr val)
+{
+	/* Command for power control of HDMI PLL */
+	REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 3, 2);
+
+	/* wait till PHY_PWR_STATUS is set */
+	if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 1, 0, val) != val) {
+		DSSERR("Failed to set PHY_PWR_STATUS\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int hdmi_pll_reset(void)
+{
+	/* SYSRESET  controlled by power FSM */
+	REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
+
+	/* READ 0x0 reset is in progress */
+	if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) {
+		DSSERR("Failed to sysreset PLL\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int hdmi_phy_init(void)
+{
+	u16 r = 0;
+
+	r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_LDOON);
+	if (r)
+		return r;
+
+	r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON);
+	if (r)
+		return r;
+
+	/*
+	 * Read address 0 in order to get the SCP reset done completed
+	 * Dummy access performed to make sure reset is done
+	 */
+	hdmi_read_reg(HDMI_TXPHY_TX_CTRL);
+
+	/*
+	 * Write to phy address 0 to configure the clock
+	 * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
+	 */
+	REG_FLD_MOD(HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);
+
+	/* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
+	hdmi_write_reg(HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
+
+	/* Setup max LDO voltage */
+	REG_FLD_MOD(HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
+
+	/* Write to phy address 3 to change the polarity control */
+	REG_FLD_MOD(HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
+
+	return 0;
+}
+
+static int hdmi_wait_softreset(void)
+{
+	/* reset W1 */
+	REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0);
+
+	/* wait till SOFTRESET == 0 */
+	if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) {
+		DSSERR("sysconfig reset failed\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int hdmi_pll_program(struct hdmi_pll_info *fmt)
+{
+	u16 r = 0;
+	enum hdmi_clk_refsel refsel;
+
+	/* wait for wrapper reset */
+	r = hdmi_wait_softreset();
+	if (r)
+		return r;
+
+	r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
+	if (r)
+		return r;
+
+	r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
+	if (r)
+		return r;
+
+	r = hdmi_pll_reset();
+	if (r)
+		return r;
+
+	refsel = HDMI_REFSEL_SYSCLK;
+
+	r = hdmi_pll_init(refsel, fmt->dcofreq, fmt, fmt->regsd);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+static void hdmi_phy_off(void)
+{
+	hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF);
+}
+
+static int hdmi_core_ddc_edid(u8 *pedid, int ext)
+{
+	u32 i, j;
+	char checksum = 0;
+	u32 offset = 0;
+
+	/* Turn on CLK for DDC */
+	REG_FLD_MOD(HDMI_CORE_AV_DPD, 0x7, 2, 0);
+
+	/*
+	 * SW HACK : Without the Delay DDC(i2c bus) reads 0 values /
+	 * right shifted values( The behavior is not consistent and seen only
+	 * with some TV's)
+	 */
+	usleep_range(800, 1000);
+
+	if (!ext) {
+		/* Clk SCL Devices */
+		REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0xA, 3, 0);
+
+		/* HDMI_CORE_DDC_STATUS_IN_PROG */
+		if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS,
+						4, 4, 0) != 0) {
+			DSSERR("Failed to program DDC\n");
+			return -ETIMEDOUT;
+		}
+
+		/* Clear FIFO */
+		REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x9, 3, 0);
+
+		/* HDMI_CORE_DDC_STATUS_IN_PROG */
+		if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS,
+						4, 4, 0) != 0) {
+			DSSERR("Failed to program DDC\n");
+			return -ETIMEDOUT;
+		}
+
+	} else {
+		if (ext % 2 != 0)
+			offset = 0x80;
+	}
+
+	/* Load Segment Address Register */
+	REG_FLD_MOD(HDMI_CORE_DDC_SEGM, ext/2, 7, 0);
+
+	/* Load Slave Address Register */
+	REG_FLD_MOD(HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
+
+	/* Load Offset Address Register */
+	REG_FLD_MOD(HDMI_CORE_DDC_OFFSET, offset, 7, 0);
+
+	/* Load Byte Count */
+	REG_FLD_MOD(HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
+	REG_FLD_MOD(HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
+
+	/* Set DDC_CMD */
+	if (ext)
+		REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x4, 3, 0);
+	else
+		REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x2, 3, 0);
+
+	/* HDMI_CORE_DDC_STATUS_BUS_LOW */
+	if (REG_GET(HDMI_CORE_DDC_STATUS, 6, 6) == 1) {
+		DSSWARN("I2C Bus Low?\n");
+		return -EIO;
+	}
+	/* HDMI_CORE_DDC_STATUS_NO_ACK */
+	if (REG_GET(HDMI_CORE_DDC_STATUS, 5, 5) == 1) {
+		DSSWARN("I2C No Ack\n");
+		return -EIO;
+	}
+
+	i = ext * 128;
+	j = 0;
+	while (((REG_GET(HDMI_CORE_DDC_STATUS, 4, 4) == 1) ||
+			(REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0)) &&
+			j < 128) {
+
+		if (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0) {
+			/* FIFO not empty */
+			pedid[i++] = REG_GET(HDMI_CORE_DDC_DATA, 7, 0);
+			j++;
+		}
+	}
+
+	for (j = 0; j < 128; j++)
+		checksum += pedid[j];
+
+	if (checksum != 0) {
+		DSSERR("E-EDID checksum failed!!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int read_edid(u8 *pedid, u16 max_length)
+{
+	int r = 0, n = 0, i = 0;
+	int max_ext_blocks = (max_length / 128) - 1;
+
+	r = hdmi_core_ddc_edid(pedid, 0);
+	if (r) {
+		return r;
+	} else {
+		n = pedid[0x7e];
+
+		/*
+		 * README: need to comply with max_length set by the caller.
+		 * Better implementation should be to allocate necessary
+		 * memory to store EDID according to nb_block field found
+		 * in first block
+		 */
+		if (n > max_ext_blocks)
+			n = max_ext_blocks;
+
+		for (i = 1; i <= n; i++) {
+			r = hdmi_core_ddc_edid(pedid, i);
+			if (r)
+				return r;
+		}
+	}
+	return 0;
+}
+
+static int get_timings_index(void)
+{
+	int code;
+
+	if (hdmi.mode == 0)
+		code = code_vesa[hdmi.code];
+	else
+		code = code_cea[hdmi.code];
+
+	if (code == -1)	{
+		/* HDMI code 4 corresponds to 640 * 480 VGA */
+		hdmi.code = 4;
+		/* DVI mode 1 corresponds to HDMI 0 to DVI */
+		hdmi.mode = HDMI_DVI;
+
+		code = code_vesa[hdmi.code];
+	}
+	return code;
+}
+
+static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
+{
+	int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0;
+	int timing_vsync = 0, timing_hsync = 0;
+	struct omap_video_timings temp;
+	struct hdmi_cm cm = {-1};
+	DSSDBG("hdmi_get_code\n");
+
+	for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) {
+		temp = cea_vesa_timings[i].timings;
+		if ((temp.pixel_clock == timing->pixel_clock) &&
+			(temp.x_res == timing->x_res) &&
+			(temp.y_res == timing->y_res)) {
+
+			temp_hsync = temp.hfp + temp.hsw + temp.hbp;
+			timing_hsync = timing->hfp + timing->hsw + timing->hbp;
+			temp_vsync = temp.vfp + temp.vsw + temp.vbp;
+			timing_vsync = timing->vfp + timing->vsw + timing->vbp;
+
+			DSSDBG("temp_hsync = %d , temp_vsync = %d"
+				"timing_hsync = %d, timing_vsync = %d\n",
+				temp_hsync, temp_hsync,
+				timing_hsync, timing_vsync);
+
+			if ((temp_hsync == timing_hsync) &&
+					(temp_vsync == timing_vsync)) {
+				code = i;
+				cm.code = code_index[i];
+				if (code < 14)
+					cm.mode = HDMI_HDMI;
+				else
+					cm.mode = HDMI_DVI;
+				DSSDBG("Hdmi_code = %d mode = %d\n",
+					 cm.code, cm.mode);
+				break;
+			 }
+		}
+	}
+
+	return cm;
+}
+
+static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid ,
+		struct omap_video_timings *timings)
+{
+	/* X and Y resolution */
+	timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) |
+			 edid[current_descriptor_addrs + 2]);
+	timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) |
+			 edid[current_descriptor_addrs + 5]);
+
+	timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) |
+				edid[current_descriptor_addrs]);
+
+	timings->pixel_clock = 10 * timings->pixel_clock;
+
+	/* HORIZONTAL FRONT PORCH */
+	timings->hfp = edid[current_descriptor_addrs + 8] |
+			((edid[current_descriptor_addrs + 11] & 0xc0) << 2);
+	/* HORIZONTAL SYNC WIDTH */
+	timings->hsw = edid[current_descriptor_addrs + 9] |
+			((edid[current_descriptor_addrs + 11] & 0x30) << 4);
+	/* HORIZONTAL BACK PORCH */
+	timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8) |
+			edid[current_descriptor_addrs + 3]) -
+			(timings->hfp + timings->hsw);
+	/* VERTICAL FRONT PORCH */
+	timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4) |
+			((edid[current_descriptor_addrs + 11] & 0x0f) << 2);
+	/* VERTICAL SYNC WIDTH */
+	timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F) |
+			((edid[current_descriptor_addrs + 11] & 0x03) << 4);
+	/* VERTICAL BACK PORCH */
+	timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8) |
+			edid[current_descriptor_addrs + 6]) -
+			(timings->vfp + timings->vsw);
+
+}
+
+/* Description : This function gets the resolution information from EDID */
+static void get_edid_timing_data(u8 *edid)
+{
+	u8 count;
+	u16 current_descriptor_addrs;
+	struct hdmi_cm cm;
+	struct omap_video_timings edid_timings;
+
+	/* seach block 0, there are 4 DTDs arranged in priority order */
+	for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
+		current_descriptor_addrs =
+			EDID_DESCRIPTOR_BLOCK0_ADDRESS +
+			count * EDID_TIMING_DESCRIPTOR_SIZE;
+		get_horz_vert_timing_info(current_descriptor_addrs,
+				edid, &edid_timings);
+		cm = hdmi_get_code(&edid_timings);
+		DSSDBG("Block0[%d] value matches code = %d , mode = %d\n",
+			count, cm.code, cm.mode);
+		if (cm.code == -1) {
+			continue;
+		} else {
+			hdmi.code = cm.code;
+			hdmi.mode = cm.mode;
+			DSSDBG("code = %d , mode = %d\n",
+				hdmi.code, hdmi.mode);
+			return;
+		}
+	}
+	if (edid[0x7e] != 0x00) {
+		for (count = 0; count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
+			count++) {
+			current_descriptor_addrs =
+			EDID_DESCRIPTOR_BLOCK1_ADDRESS +
+			count * EDID_TIMING_DESCRIPTOR_SIZE;
+			get_horz_vert_timing_info(current_descriptor_addrs,
+						edid, &edid_timings);
+			cm = hdmi_get_code(&edid_timings);
+			DSSDBG("Block1[%d] value matches code = %d, mode = %d",
+				count, cm.code, cm.mode);
+			if (cm.code == -1) {
+				continue;
+			} else {
+				hdmi.code = cm.code;
+				hdmi.mode = cm.mode;
+				DSSDBG("code = %d , mode = %d\n",
+					hdmi.code, hdmi.mode);
+				return;
+			}
+		}
+	}
+
+	DSSINFO("no valid timing found , falling back to VGA\n");
+	hdmi.code = 4; /* setting default value of 640 480 VGA */
+	hdmi.mode = HDMI_DVI;
+}
+
+static void hdmi_read_edid(struct omap_video_timings *dp)
+{
+	int ret = 0, code;
+
+	memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH);
+
+	if (!hdmi.edid_set)
+		ret = read_edid(hdmi.edid, HDMI_EDID_MAX_LENGTH);
+
+	if (!ret) {
+		if (!memcmp(hdmi.edid, edid_header, sizeof(edid_header))) {
+			/* search for timings of default resolution */
+			get_edid_timing_data(hdmi.edid);
+			hdmi.edid_set = true;
+		}
+	} else {
+		DSSWARN("failed to read E-EDID\n");
+	}
+
+	if (!hdmi.edid_set) {
+		DSSINFO("fallback to VGA\n");
+		hdmi.code = 4; /* setting default value of 640 480 VGA */
+		hdmi.mode = HDMI_DVI;
+	}
+
+	code = get_timings_index();
+
+	*dp = cea_vesa_timings[code].timings;
+}
+
+static void hdmi_core_init(struct hdmi_core_video_config *video_cfg,
+			struct hdmi_core_infoframe_avi *avi_cfg,
+			struct hdmi_core_packet_enable_repeat *repeat_cfg)
+{
+	DSSDBG("Enter hdmi_core_init\n");
+
+	/* video core */
+	video_cfg->ip_bus_width = HDMI_INPUT_8BIT;
+	video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT;
+	video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE;
+	video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE;
+	video_cfg->hdmi_dvi = HDMI_DVI;
+	video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK;
+
+	/* info frame */
+	avi_cfg->db1_format = 0;
+	avi_cfg->db1_active_info = 0;
+	avi_cfg->db1_bar_info_dv = 0;
+	avi_cfg->db1_scan_info = 0;
+	avi_cfg->db2_colorimetry = 0;
+	avi_cfg->db2_aspect_ratio = 0;
+	avi_cfg->db2_active_fmt_ar = 0;
+	avi_cfg->db3_itc = 0;
+	avi_cfg->db3_ec = 0;
+	avi_cfg->db3_q_range = 0;
+	avi_cfg->db3_nup_scaling = 0;
+	avi_cfg->db4_videocode = 0;
+	avi_cfg->db5_pixel_repeat = 0;
+	avi_cfg->db6_7_line_eoftop = 0 ;
+	avi_cfg->db8_9_line_sofbottom = 0;
+	avi_cfg->db10_11_pixel_eofleft = 0;
+	avi_cfg->db12_13_pixel_sofright = 0;
+
+	/* packet enable and repeat */
+	repeat_cfg->audio_pkt = 0;
+	repeat_cfg->audio_pkt_repeat = 0;
+	repeat_cfg->avi_infoframe = 0;
+	repeat_cfg->avi_infoframe_repeat = 0;
+	repeat_cfg->gen_cntrl_pkt = 0;
+	repeat_cfg->gen_cntrl_pkt_repeat = 0;
+	repeat_cfg->generic_pkt = 0;
+	repeat_cfg->generic_pkt_repeat = 0;
+}
+
+static void hdmi_core_powerdown_disable(void)
+{
+	DSSDBG("Enter hdmi_core_powerdown_disable\n");
+	REG_FLD_MOD(HDMI_CORE_CTRL1, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_release(void)
+{
+	DSSDBG("Enter hdmi_core_swreset_release\n");
+	REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_assert(void)
+{
+	DSSDBG("Enter hdmi_core_swreset_assert\n");
+	REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x1, 0, 0);
+}
+
+/* DSS_HDMI_CORE_VIDEO_CONFIG */
+static void hdmi_core_video_config(struct hdmi_core_video_config *cfg)
+{
+	u32 r = 0;
+
+	/* sys_ctrl1 default configuration not tunable */
+	r = hdmi_read_reg(HDMI_CORE_CTRL1);
+	r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5);
+	r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4);
+	r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2);
+	r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1);
+	hdmi_write_reg(HDMI_CORE_CTRL1, r);
+
+	REG_FLD_MOD(HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6);
+
+	/* Vid_Mode */
+	r = hdmi_read_reg(HDMI_CORE_SYS_VID_MODE);
+
+	/* dither truncation configuration */
+	if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) {
+		r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6);
+		r = FLD_MOD(r, 1, 5, 5);
+	} else {
+		r = FLD_MOD(r, cfg->op_dither_truc, 7, 6);
+		r = FLD_MOD(r, 0, 5, 5);
+	}
+	hdmi_write_reg(HDMI_CORE_SYS_VID_MODE, r);
+
+	/* HDMI_Ctrl */
+	r = hdmi_read_reg(HDMI_CORE_AV_HDMI_CTRL);
+	r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6);
+	r = FLD_MOD(r, cfg->pkt_mode, 5, 3);
+	r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0);
+	hdmi_write_reg(HDMI_CORE_AV_HDMI_CTRL, r);
+
+	/* TMDS_CTRL */
+	REG_FLD_MOD(HDMI_CORE_SYS_TMDS_CTRL,
+		cfg->tclk_sel_clkmult, 6, 5);
+}
+
+static void hdmi_core_aux_infoframe_avi_config(
+		struct hdmi_core_infoframe_avi info_avi)
+{
+	u32 val;
+	char sum = 0, checksum = 0;
+
+	sum += 0x82 + 0x002 + 0x00D;
+	hdmi_write_reg(HDMI_CORE_AV_AVI_TYPE, 0x082);
+	hdmi_write_reg(HDMI_CORE_AV_AVI_VERS, 0x002);
+	hdmi_write_reg(HDMI_CORE_AV_AVI_LEN, 0x00D);
+
+	val = (info_avi.db1_format << 5) |
+		(info_avi.db1_active_info << 4) |
+		(info_avi.db1_bar_info_dv << 2) |
+		(info_avi.db1_scan_info);
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(0), val);
+	sum += val;
+
+	val = (info_avi.db2_colorimetry << 6) |
+		(info_avi.db2_aspect_ratio << 4) |
+		(info_avi.db2_active_fmt_ar);
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(1), val);
+	sum += val;
+
+	val = (info_avi.db3_itc << 7) |
+		(info_avi.db3_ec << 4) |
+		(info_avi.db3_q_range << 2) |
+		(info_avi.db3_nup_scaling);
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(2), val);
+	sum += val;
+
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(3), info_avi.db4_videocode);
+	sum += info_avi.db4_videocode;
+
+	val = info_avi.db5_pixel_repeat;
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(4), val);
+	sum += val;
+
+	val = info_avi.db6_7_line_eoftop & 0x00FF;
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(5), val);
+	sum += val;
+
+	val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF);
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(6), val);
+	sum += val;
+
+	val = info_avi.db8_9_line_sofbottom & 0x00FF;
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(7), val);
+	sum += val;
+
+	val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF);
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(8), val);
+	sum += val;
+
+	val = info_avi.db10_11_pixel_eofleft & 0x00FF;
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(9), val);
+	sum += val;
+
+	val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF);
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(10), val);
+	sum += val;
+
+	val = info_avi.db12_13_pixel_sofright & 0x00FF;
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(11), val);
+	sum += val;
+
+	val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF);
+	hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(12), val);
+	sum += val;
+
+	checksum = 0x100 - sum;
+	hdmi_write_reg(HDMI_CORE_AV_AVI_CHSUM, checksum);
+}
+
+static void hdmi_core_av_packet_config(
+		struct hdmi_core_packet_enable_repeat repeat_cfg)
+{
+	/* enable/repeat the infoframe */
+	hdmi_write_reg(HDMI_CORE_AV_PB_CTRL1,
+		(repeat_cfg.audio_pkt << 5) |
+		(repeat_cfg.audio_pkt_repeat << 4) |
+		(repeat_cfg.avi_infoframe << 1) |
+		(repeat_cfg.avi_infoframe_repeat));
+
+	/* enable/repeat the packet */
+	hdmi_write_reg(HDMI_CORE_AV_PB_CTRL2,
+		(repeat_cfg.gen_cntrl_pkt << 3) |
+		(repeat_cfg.gen_cntrl_pkt_repeat << 2) |
+		(repeat_cfg.generic_pkt << 1) |
+		(repeat_cfg.generic_pkt_repeat));
+}
+
+static void hdmi_wp_init(struct omap_video_timings *timings,
+			struct hdmi_video_format *video_fmt,
+			struct hdmi_video_interface *video_int)
+{
+	DSSDBG("Enter hdmi_wp_init\n");
+
+	timings->hbp = 0;
+	timings->hfp = 0;
+	timings->hsw = 0;
+	timings->vbp = 0;
+	timings->vfp = 0;
+	timings->vsw = 0;
+
+	video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
+	video_fmt->y_res = 0;
+	video_fmt->x_res = 0;
+
+	video_int->vsp = 0;
+	video_int->hsp = 0;
+
+	video_int->interlacing = 0;
+	video_int->tm = 0; /* HDMI_TIMING_SLAVE */
+
+}
+
+static void hdmi_wp_video_start(bool start)
+{
+	REG_FLD_MOD(HDMI_WP_VIDEO_CFG, start, 31, 31);
+}
+
+static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt,
+	struct omap_video_timings *timings, struct hdmi_config *param)
+{
+	DSSDBG("Enter hdmi_wp_video_init_format\n");
+
+	video_fmt->y_res = param->timings.timings.y_res;
+	video_fmt->x_res = param->timings.timings.x_res;
+
+	timings->hbp = param->timings.timings.hbp;
+	timings->hfp = param->timings.timings.hfp;
+	timings->hsw = param->timings.timings.hsw;
+	timings->vbp = param->timings.timings.vbp;
+	timings->vfp = param->timings.timings.vfp;
+	timings->vsw = param->timings.timings.vsw;
+}
+
+static void hdmi_wp_video_config_format(
+		struct hdmi_video_format *video_fmt)
+{
+	u32 l = 0;
+
+	REG_FLD_MOD(HDMI_WP_VIDEO_CFG, video_fmt->packing_mode, 10, 8);
+
+	l |= FLD_VAL(video_fmt->y_res, 31, 16);
+	l |= FLD_VAL(video_fmt->x_res, 15, 0);
+	hdmi_write_reg(HDMI_WP_VIDEO_SIZE, l);
+}
+
+static void hdmi_wp_video_config_interface(
+		struct hdmi_video_interface *video_int)
+{
+	u32 r;
+	DSSDBG("Enter hdmi_wp_video_config_interface\n");
+
+	r = hdmi_read_reg(HDMI_WP_VIDEO_CFG);
+	r = FLD_MOD(r, video_int->vsp, 7, 7);
+	r = FLD_MOD(r, video_int->hsp, 6, 6);
+	r = FLD_MOD(r, video_int->interlacing, 3, 3);
+	r = FLD_MOD(r, video_int->tm, 1, 0);
+	hdmi_write_reg(HDMI_WP_VIDEO_CFG, r);
+}
+
+static void hdmi_wp_video_config_timing(
+		struct omap_video_timings *timings)
+{
+	u32 timing_h = 0;
+	u32 timing_v = 0;
+
+	DSSDBG("Enter hdmi_wp_video_config_timing\n");
+
+	timing_h |= FLD_VAL(timings->hbp, 31, 20);
+	timing_h |= FLD_VAL(timings->hfp, 19, 8);
+	timing_h |= FLD_VAL(timings->hsw, 7, 0);
+	hdmi_write_reg(HDMI_WP_VIDEO_TIMING_H, timing_h);
+
+	timing_v |= FLD_VAL(timings->vbp, 31, 20);
+	timing_v |= FLD_VAL(timings->vfp, 19, 8);
+	timing_v |= FLD_VAL(timings->vsw, 7, 0);
+	hdmi_write_reg(HDMI_WP_VIDEO_TIMING_V, timing_v);
+}
+
+static void hdmi_basic_configure(struct hdmi_config *cfg)
+{
+	/* HDMI */
+	struct omap_video_timings video_timing;
+	struct hdmi_video_format video_format;
+	struct hdmi_video_interface video_interface;
+	/* HDMI core */
+	struct hdmi_core_infoframe_avi avi_cfg;
+	struct hdmi_core_video_config v_core_cfg;
+	struct hdmi_core_packet_enable_repeat repeat_cfg;
+
+	hdmi_wp_init(&video_timing, &video_format,
+		&video_interface);
+
+	hdmi_core_init(&v_core_cfg,
+		&avi_cfg,
+		&repeat_cfg);
+
+	hdmi_wp_video_init_format(&video_format,
+			&video_timing, cfg);
+
+	hdmi_wp_video_config_timing(&video_timing);
+
+	/* video config */
+	video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
+
+	hdmi_wp_video_config_format(&video_format);
+
+	video_interface.vsp = cfg->timings.vsync_pol;
+	video_interface.hsp = cfg->timings.hsync_pol;
+	video_interface.interlacing = cfg->interlace;
+	video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */
+
+	hdmi_wp_video_config_interface(&video_interface);
+
+	/*
+	 * configure core video part
+	 * set software reset in the core
+	 */
+	hdmi_core_swreset_assert();
+
+	/* power down off */
+	hdmi_core_powerdown_disable();
+
+	v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL;
+	v_core_cfg.hdmi_dvi = cfg->cm.mode;
+
+	hdmi_core_video_config(&v_core_cfg);
+
+	/* release software reset in the core */
+	hdmi_core_swreset_release();
+
+	/*
+	 * configure packet
+	 * info frame video see doc CEA861-D page 65
+	 */
+	avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB;
+	avi_cfg.db1_active_info =
+		HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF;
+	avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO;
+	avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0;
+	avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO;
+	avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO;
+	avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME;
+	avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO;
+	avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601;
+	avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT;
+	avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO;
+	avi_cfg.db4_videocode = cfg->cm.code;
+	avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO;
+	avi_cfg.db6_7_line_eoftop = 0;
+	avi_cfg.db8_9_line_sofbottom = 0;
+	avi_cfg.db10_11_pixel_eofleft = 0;
+	avi_cfg.db12_13_pixel_sofright = 0;
+
+	hdmi_core_aux_infoframe_avi_config(avi_cfg);
+
+	/* enable/repeat the infoframe */
+	repeat_cfg.avi_infoframe = HDMI_PACKETENABLE;
+	repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON;
+	/* wakeup */
+	repeat_cfg.audio_pkt = HDMI_PACKETENABLE;
+	repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON;
+	hdmi_core_av_packet_config(repeat_cfg);
+}
+
+static void update_hdmi_timings(struct hdmi_config *cfg,
+		struct omap_video_timings *timings, int code)
+{
+	cfg->timings.timings.x_res = timings->x_res;
+	cfg->timings.timings.y_res = timings->y_res;
+	cfg->timings.timings.hbp = timings->hbp;
+	cfg->timings.timings.hfp = timings->hfp;
+	cfg->timings.timings.hsw = timings->hsw;
+	cfg->timings.timings.vbp = timings->vbp;
+	cfg->timings.timings.vfp = timings->vfp;
+	cfg->timings.timings.vsw = timings->vsw;
+	cfg->timings.timings.pixel_clock = timings->pixel_clock;
+	cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol;
+	cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol;
+}
+
+static void hdmi_compute_pll(unsigned long clkin, int phy,
+	int n, struct hdmi_pll_info *pi)
+{
+	unsigned long refclk;
+	u32 mf;
+
+	/*
+	 * Input clock is predivided by N + 1
+	 * out put of which is reference clk
+	 */
+	refclk = clkin / (n + 1);
+	pi->regn = n;
+
+	/*
+	 * multiplier is pixel_clk/ref_clk
+	 * Multiplying by 100 to avoid fractional part removal
+	 */
+	pi->regm = (phy * 100/(refclk))/100;
+	pi->regm2 = 1;
+
+	/*
+	 * fractional multiplier is remainder of the difference between
+	 * multiplier and actual phy(required pixel clock thus should be
+	 * multiplied by 2^18(262144) divided by the reference clock
+	 */
+	mf = (phy - pi->regm * refclk) * 262144;
+	pi->regmf = mf/(refclk);
+
+	/*
+	 * Dcofreq should be set to 1 if required pixel clock
+	 * is greater than 1000MHz
+	 */
+	pi->dcofreq = phy > 1000 * 100;
+	pi->regsd = ((pi->regm * clkin / 10) / ((n + 1) * 250) + 5) / 10;
+
+	DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
+	DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
+}
+
+static void hdmi_enable_clocks(int enable)
+{
+	if (enable)
+		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK |
+				DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
+	else
+		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK |
+				DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
+}
+
+static int hdmi_power_on(struct omap_dss_device *dssdev)
+{
+	int r, code = 0;
+	struct hdmi_pll_info pll_data;
+	struct omap_video_timings *p;
+	int clkin, n, phy;
+
+	hdmi_enable_clocks(1);
+
+	dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
+
+	p = &dssdev->panel.timings;
+
+	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n",
+		dssdev->panel.timings.x_res,
+		dssdev->panel.timings.y_res);
+
+	if (!hdmi.custom_set) {
+		DSSDBG("Read EDID as no EDID is not set on poweron\n");
+		hdmi_read_edid(p);
+	}
+	code = get_timings_index();
+	dssdev->panel.timings = cea_vesa_timings[code].timings;
+	update_hdmi_timings(&hdmi.cfg, p, code);
+
+	clkin = 3840; /* 38.4 MHz */
+	n = 15; /* this is a constant for our math */
+	phy = p->pixel_clock;
+
+	hdmi_compute_pll(clkin, phy, n, &pll_data);
+
+	hdmi_wp_video_start(0);
+
+	/* config the PLL and PHY first */
+	r = hdmi_pll_program(&pll_data);
+	if (r) {
+		DSSDBG("Failed to lock PLL\n");
+		goto err;
+	}
+
+	r = hdmi_phy_init();
+	if (r) {
+		DSSDBG("Failed to start PHY\n");
+		goto err;
+	}
+
+	hdmi.cfg.cm.mode = hdmi.mode;
+	hdmi.cfg.cm.code = hdmi.code;
+	hdmi_basic_configure(&hdmi.cfg);
+
+	/* Make selection of HDMI in DSS */
+	dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
+
+	/* Select the dispc clock source as PRCM clock, to ensure that it is not
+	 * DSI PLL source as the clock selected by DSI PLL might not be
+	 * sufficient for the resolution selected / that can be changed
+	 * dynamically by user. This can be moved to single location , say
+	 * Boardfile.
+	 */
+	dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+
+	/* bypass TV gamma table */
+	dispc_enable_gamma_table(0);
+
+	/* tv size */
+	dispc_set_digit_size(dssdev->panel.timings.x_res,
+			dssdev->panel.timings.y_res);
+
+	dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 1);
+
+	hdmi_wp_video_start(1);
+
+	return 0;
+err:
+	hdmi_enable_clocks(0);
+	return -EIO;
+}
+
+static void hdmi_power_off(struct omap_dss_device *dssdev)
+{
+	dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
+
+	hdmi_wp_video_start(0);
+	hdmi_phy_off();
+	hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
+	hdmi_enable_clocks(0);
+
+	hdmi.edid_set = 0;
+}
+
+int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
+					struct omap_video_timings *timings)
+{
+	struct hdmi_cm cm;
+
+	cm = hdmi_get_code(timings);
+	if (cm.code == -1) {
+		DSSERR("Invalid timing entered\n");
+		return -EINVAL;
+	}
+
+	return 0;
+
+}
+
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
+{
+	struct hdmi_cm cm;
+
+	hdmi.custom_set = 1;
+	cm = hdmi_get_code(&dssdev->panel.timings);
+	hdmi.code = cm.code;
+	hdmi.mode = cm.mode;
+	omapdss_hdmi_display_enable(dssdev);
+	hdmi.custom_set = 0;
+}
+
+int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
+{
+	int r = 0;
+
+	DSSDBG("ENTER hdmi_display_enable\n");
+
+	mutex_lock(&hdmi.lock);
+
+	r = omap_dss_start_device(dssdev);
+	if (r) {
+		DSSERR("failed to start device\n");
+		goto err0;
+	}
+
+	if (dssdev->platform_enable) {
+		r = dssdev->platform_enable(dssdev);
+		if (r) {
+			DSSERR("failed to enable GPIO's\n");
+			goto err1;
+		}
+	}
+
+	r = hdmi_power_on(dssdev);
+	if (r) {
+		DSSERR("failed to power on device\n");
+		goto err2;
+	}
+
+	mutex_unlock(&hdmi.lock);
+	return 0;
+
+err2:
+	if (dssdev->platform_disable)
+		dssdev->platform_disable(dssdev);
+err1:
+	omap_dss_stop_device(dssdev);
+err0:
+	mutex_unlock(&hdmi.lock);
+	return r;
+}
+
+void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
+{
+	DSSDBG("Enter hdmi_display_disable\n");
+
+	mutex_lock(&hdmi.lock);
+
+	hdmi_power_off(dssdev);
+
+	if (dssdev->platform_disable)
+		dssdev->platform_disable(dssdev);
+
+	omap_dss_stop_device(dssdev);
+
+	mutex_unlock(&hdmi.lock);
+}
+
+/* HDMI HW IP initialisation */
+static int omapdss_hdmihw_probe(struct platform_device *pdev)
+{
+	struct resource *hdmi_mem;
+
+	hdmi.pdata = pdev->dev.platform_data;
+	hdmi.pdev = pdev;
+
+	mutex_init(&hdmi.lock);
+
+	hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
+	if (!hdmi_mem) {
+		DSSERR("can't get IORESOURCE_MEM HDMI\n");
+		return -EINVAL;
+	}
+
+	/* Base address taken from platform */
+	hdmi.base_wp = ioremap(hdmi_mem->start, resource_size(hdmi_mem));
+	if (!hdmi.base_wp) {
+		DSSERR("can't ioremap WP\n");
+		return -ENOMEM;
+	}
+
+	hdmi_panel_init();
+
+	return 0;
+}
+
+static int omapdss_hdmihw_remove(struct platform_device *pdev)
+{
+	hdmi_panel_exit();
+
+	iounmap(hdmi.base_wp);
+
+	return 0;
+}
+
+static struct platform_driver omapdss_hdmihw_driver = {
+	.probe          = omapdss_hdmihw_probe,
+	.remove         = omapdss_hdmihw_remove,
+	.driver         = {
+		.name   = "omapdss_hdmi",
+		.owner  = THIS_MODULE,
+	},
+};
+
+int hdmi_init_platform_driver(void)
+{
+	return platform_driver_register(&omapdss_hdmihw_driver);
+}
+
+void hdmi_uninit_platform_driver(void)
+{
+	return platform_driver_unregister(&omapdss_hdmihw_driver);
+}
diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/hdmi.h
new file mode 100644
index 0000000..9887ab9
--- /dev/null
+++ b/drivers/video/omap2/dss/hdmi.h
@@ -0,0 +1,415 @@
+/*
+ * hdmi.h
+ *
+ * HDMI driver definition for TI OMAP4 processors.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _OMAP4_DSS_HDMI_H_
+#define _OMAP4_DSS_HDMI_H_
+
+#include <linux/string.h>
+#include <plat/display.h>
+
+#define HDMI_WP		0x0
+#define HDMI_CORE_SYS		0x400
+#define HDMI_CORE_AV		0x900
+#define HDMI_PLLCTRL		0x200
+#define HDMI_PHY		0x300
+
+struct hdmi_reg { u16 idx; };
+
+#define HDMI_REG(idx)			((const struct hdmi_reg) { idx })
+
+/* HDMI Wrapper */
+#define HDMI_WP_REG(idx)			HDMI_REG(HDMI_WP + idx)
+
+#define HDMI_WP_REVISION			HDMI_WP_REG(0x0)
+#define HDMI_WP_SYSCONFIG			HDMI_WP_REG(0x10)
+#define HDMI_WP_IRQSTATUS_RAW			HDMI_WP_REG(0x24)
+#define HDMI_WP_IRQSTATUS			HDMI_WP_REG(0x28)
+#define HDMI_WP_PWR_CTRL			HDMI_WP_REG(0x40)
+#define HDMI_WP_IRQENABLE_SET			HDMI_WP_REG(0x2C)
+#define HDMI_WP_VIDEO_CFG			HDMI_WP_REG(0x50)
+#define HDMI_WP_VIDEO_SIZE			HDMI_WP_REG(0x60)
+#define HDMI_WP_VIDEO_TIMING_H			HDMI_WP_REG(0x68)
+#define HDMI_WP_VIDEO_TIMING_V			HDMI_WP_REG(0x6C)
+#define HDMI_WP_WP_CLK				HDMI_WP_REG(0x70)
+
+/* HDMI IP Core System */
+#define HDMI_CORE_SYS_REG(idx)			HDMI_REG(HDMI_CORE_SYS + idx)
+
+#define HDMI_CORE_SYS_VND_IDL			HDMI_CORE_SYS_REG(0x0)
+#define HDMI_CORE_SYS_DEV_IDL			HDMI_CORE_SYS_REG(0x8)
+#define HDMI_CORE_SYS_DEV_IDH			HDMI_CORE_SYS_REG(0xC)
+#define HDMI_CORE_SYS_DEV_REV			HDMI_CORE_SYS_REG(0x10)
+#define HDMI_CORE_SYS_SRST			HDMI_CORE_SYS_REG(0x14)
+#define HDMI_CORE_CTRL1			HDMI_CORE_SYS_REG(0x20)
+#define HDMI_CORE_SYS_SYS_STAT			HDMI_CORE_SYS_REG(0x24)
+#define HDMI_CORE_SYS_VID_ACEN			HDMI_CORE_SYS_REG(0x124)
+#define HDMI_CORE_SYS_VID_MODE			HDMI_CORE_SYS_REG(0x128)
+#define HDMI_CORE_SYS_INTR_STATE		HDMI_CORE_SYS_REG(0x1C0)
+#define HDMI_CORE_SYS_INTR1			HDMI_CORE_SYS_REG(0x1C4)
+#define HDMI_CORE_SYS_INTR2			HDMI_CORE_SYS_REG(0x1C8)
+#define HDMI_CORE_SYS_INTR3			HDMI_CORE_SYS_REG(0x1CC)
+#define HDMI_CORE_SYS_INTR4			HDMI_CORE_SYS_REG(0x1D0)
+#define HDMI_CORE_SYS_UMASK1			HDMI_CORE_SYS_REG(0x1D4)
+#define HDMI_CORE_SYS_TMDS_CTRL		HDMI_CORE_SYS_REG(0x208)
+#define HDMI_CORE_SYS_DE_DLY			HDMI_CORE_SYS_REG(0xC8)
+#define HDMI_CORE_SYS_DE_CTRL			HDMI_CORE_SYS_REG(0xCC)
+#define HDMI_CORE_SYS_DE_TOP			HDMI_CORE_SYS_REG(0xD0)
+#define HDMI_CORE_SYS_DE_CNTL			HDMI_CORE_SYS_REG(0xD8)
+#define HDMI_CORE_SYS_DE_CNTH			HDMI_CORE_SYS_REG(0xDC)
+#define HDMI_CORE_SYS_DE_LINL			HDMI_CORE_SYS_REG(0xE0)
+#define HDMI_CORE_SYS_DE_LINH_1		HDMI_CORE_SYS_REG(0xE4)
+#define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC	0x1
+#define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC	0x1
+#define HDMI_CORE_CTRL1_BSEL_24BITBUS		0x1
+#define HDMI_CORE_CTRL1_EDGE_RISINGEDGE	0x1
+
+/* HDMI DDC E-DID */
+#define HDMI_CORE_DDC_CMD			HDMI_CORE_SYS_REG(0x3CC)
+#define HDMI_CORE_DDC_STATUS			HDMI_CORE_SYS_REG(0x3C8)
+#define HDMI_CORE_DDC_ADDR			HDMI_CORE_SYS_REG(0x3B4)
+#define HDMI_CORE_DDC_OFFSET			HDMI_CORE_SYS_REG(0x3BC)
+#define HDMI_CORE_DDC_COUNT1			HDMI_CORE_SYS_REG(0x3C0)
+#define HDMI_CORE_DDC_COUNT2			HDMI_CORE_SYS_REG(0x3C4)
+#define HDMI_CORE_DDC_DATA			HDMI_CORE_SYS_REG(0x3D0)
+#define HDMI_CORE_DDC_SEGM			HDMI_CORE_SYS_REG(0x3B8)
+
+/* HDMI IP Core Audio Video */
+#define HDMI_CORE_AV_REG(idx)			HDMI_REG(HDMI_CORE_AV + idx)
+
+#define HDMI_CORE_AV_HDMI_CTRL			HDMI_CORE_AV_REG(0xBC)
+#define HDMI_CORE_AV_DPD			HDMI_CORE_AV_REG(0xF4)
+#define HDMI_CORE_AV_PB_CTRL1			HDMI_CORE_AV_REG(0xF8)
+#define HDMI_CORE_AV_PB_CTRL2			HDMI_CORE_AV_REG(0xFC)
+#define HDMI_CORE_AV_AVI_TYPE			HDMI_CORE_AV_REG(0x100)
+#define HDMI_CORE_AV_AVI_VERS			HDMI_CORE_AV_REG(0x104)
+#define HDMI_CORE_AV_AVI_LEN			HDMI_CORE_AV_REG(0x108)
+#define HDMI_CORE_AV_AVI_CHSUM			HDMI_CORE_AV_REG(0x10C)
+#define HDMI_CORE_AV_AVI_DBYTE(n)		HDMI_CORE_AV_REG(n * 4 + 0x110)
+#define HDMI_CORE_AV_AVI_DBYTE_NELEMS		HDMI_CORE_AV_REG(15)
+#define HDMI_CORE_AV_SPD_DBYTE			HDMI_CORE_AV_REG(0x190)
+#define HDMI_CORE_AV_SPD_DBYTE_NELEMS		HDMI_CORE_AV_REG(27)
+#define HDMI_CORE_AV_MPEG_DBYTE		HDMI_CORE_AV_REG(0x290)
+#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS		HDMI_CORE_AV_REG(27)
+#define HDMI_CORE_AV_GEN_DBYTE			HDMI_CORE_AV_REG(0x300)
+#define HDMI_CORE_AV_GEN_DBYTE_NELEMS		HDMI_CORE_AV_REG(31)
+#define HDMI_CORE_AV_GEN2_DBYTE		HDMI_CORE_AV_REG(0x380)
+#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS		HDMI_CORE_AV_REG(31)
+#define HDMI_CORE_AV_ACR_CTRL			HDMI_CORE_AV_REG(0x4)
+#define HDMI_CORE_AV_FREQ_SVAL			HDMI_CORE_AV_REG(0x8)
+#define HDMI_CORE_AV_N_SVAL1			HDMI_CORE_AV_REG(0xC)
+#define HDMI_CORE_AV_N_SVAL2			HDMI_CORE_AV_REG(0x10)
+#define HDMI_CORE_AV_N_SVAL3			HDMI_CORE_AV_REG(0x14)
+#define HDMI_CORE_AV_CTS_SVAL1			HDMI_CORE_AV_REG(0x18)
+#define HDMI_CORE_AV_CTS_SVAL2			HDMI_CORE_AV_REG(0x1C)
+#define HDMI_CORE_AV_CTS_SVAL3			HDMI_CORE_AV_REG(0x20)
+#define HDMI_CORE_AV_CTS_HVAL1			HDMI_CORE_AV_REG(0x24)
+#define HDMI_CORE_AV_CTS_HVAL2			HDMI_CORE_AV_REG(0x28)
+#define HDMI_CORE_AV_CTS_HVAL3			HDMI_CORE_AV_REG(0x2C)
+#define HDMI_CORE_AV_AUD_MODE			HDMI_CORE_AV_REG(0x50)
+#define HDMI_CORE_AV_SPDIF_CTRL		HDMI_CORE_AV_REG(0x54)
+#define HDMI_CORE_AV_HW_SPDIF_FS		HDMI_CORE_AV_REG(0x60)
+#define HDMI_CORE_AV_SWAP_I2S			HDMI_CORE_AV_REG(0x64)
+#define HDMI_CORE_AV_SPDIF_ERTH		HDMI_CORE_AV_REG(0x6C)
+#define HDMI_CORE_AV_I2S_IN_MAP		HDMI_CORE_AV_REG(0x70)
+#define HDMI_CORE_AV_I2S_IN_CTRL		HDMI_CORE_AV_REG(0x74)
+#define HDMI_CORE_AV_I2S_CHST0			HDMI_CORE_AV_REG(0x78)
+#define HDMI_CORE_AV_I2S_CHST1			HDMI_CORE_AV_REG(0x7C)
+#define HDMI_CORE_AV_I2S_CHST2			HDMI_CORE_AV_REG(0x80)
+#define HDMI_CORE_AV_I2S_CHST4			HDMI_CORE_AV_REG(0x84)
+#define HDMI_CORE_AV_I2S_CHST5			HDMI_CORE_AV_REG(0x88)
+#define HDMI_CORE_AV_ASRC			HDMI_CORE_AV_REG(0x8C)
+#define HDMI_CORE_AV_I2S_IN_LEN		HDMI_CORE_AV_REG(0x90)
+#define HDMI_CORE_AV_HDMI_CTRL			HDMI_CORE_AV_REG(0xBC)
+#define HDMI_CORE_AV_AUDO_TXSTAT		HDMI_CORE_AV_REG(0xC0)
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1		HDMI_CORE_AV_REG(0xCC)
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2		HDMI_CORE_AV_REG(0xD0)
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3		HDMI_CORE_AV_REG(0xD4)
+#define HDMI_CORE_AV_TEST_TXCTRL		HDMI_CORE_AV_REG(0xF0)
+#define HDMI_CORE_AV_DPD			HDMI_CORE_AV_REG(0xF4)
+#define HDMI_CORE_AV_PB_CTRL1			HDMI_CORE_AV_REG(0xF8)
+#define HDMI_CORE_AV_PB_CTRL2			HDMI_CORE_AV_REG(0xFC)
+#define HDMI_CORE_AV_AVI_TYPE			HDMI_CORE_AV_REG(0x100)
+#define HDMI_CORE_AV_AVI_VERS			HDMI_CORE_AV_REG(0x104)
+#define HDMI_CORE_AV_AVI_LEN			HDMI_CORE_AV_REG(0x108)
+#define HDMI_CORE_AV_AVI_CHSUM			HDMI_CORE_AV_REG(0x10C)
+#define HDMI_CORE_AV_SPD_TYPE			HDMI_CORE_AV_REG(0x180)
+#define HDMI_CORE_AV_SPD_VERS			HDMI_CORE_AV_REG(0x184)
+#define HDMI_CORE_AV_SPD_LEN			HDMI_CORE_AV_REG(0x188)
+#define HDMI_CORE_AV_SPD_CHSUM			HDMI_CORE_AV_REG(0x18C)
+#define HDMI_CORE_AV_MPEG_TYPE			HDMI_CORE_AV_REG(0x280)
+#define HDMI_CORE_AV_MPEG_VERS			HDMI_CORE_AV_REG(0x284)
+#define HDMI_CORE_AV_MPEG_LEN			HDMI_CORE_AV_REG(0x288)
+#define HDMI_CORE_AV_MPEG_CHSUM		HDMI_CORE_AV_REG(0x28C)
+#define HDMI_CORE_AV_CP_BYTE1			HDMI_CORE_AV_REG(0x37C)
+#define HDMI_CORE_AV_CEC_ADDR_ID		HDMI_CORE_AV_REG(0x3FC)
+#define HDMI_CORE_AV_SPD_DBYTE_ELSIZE		0x4
+#define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE		0x4
+#define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE		0x4
+#define HDMI_CORE_AV_GEN_DBYTE_ELSIZE		0x4
+
+/* PLL */
+#define HDMI_PLL_REG(idx)			HDMI_REG(HDMI_PLLCTRL + idx)
+
+#define PLLCTRL_PLL_CONTROL			HDMI_PLL_REG(0x0)
+#define PLLCTRL_PLL_STATUS			HDMI_PLL_REG(0x4)
+#define PLLCTRL_PLL_GO				HDMI_PLL_REG(0x8)
+#define PLLCTRL_CFG1				HDMI_PLL_REG(0xC)
+#define PLLCTRL_CFG2				HDMI_PLL_REG(0x10)
+#define PLLCTRL_CFG3				HDMI_PLL_REG(0x14)
+#define PLLCTRL_CFG4				HDMI_PLL_REG(0x20)
+
+/* HDMI PHY */
+#define HDMI_PHY_REG(idx)			HDMI_REG(HDMI_PHY + idx)
+
+#define HDMI_TXPHY_TX_CTRL			HDMI_PHY_REG(0x0)
+#define HDMI_TXPHY_DIGITAL_CTRL		HDMI_PHY_REG(0x4)
+#define HDMI_TXPHY_POWER_CTRL			HDMI_PHY_REG(0x8)
+#define HDMI_TXPHY_PAD_CFG_CTRL		HDMI_PHY_REG(0xC)
+
+/* HDMI EDID Length  */
+#define HDMI_EDID_MAX_LENGTH			256
+#define EDID_TIMING_DESCRIPTOR_SIZE		0x12
+#define EDID_DESCRIPTOR_BLOCK0_ADDRESS		0x36
+#define EDID_DESCRIPTOR_BLOCK1_ADDRESS		0x80
+#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR	4
+#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR	4
+
+#define OMAP_HDMI_TIMINGS_NB			34
+
+#define REG_FLD_MOD(idx, val, start, end) \
+	hdmi_write_reg(idx, FLD_MOD(hdmi_read_reg(idx), val, start, end))
+#define REG_GET(idx, start, end) \
+	FLD_GET(hdmi_read_reg(idx), start, end)
+
+/* HDMI timing structure */
+struct hdmi_timings {
+	struct omap_video_timings timings;
+	int vsync_pol;
+	int hsync_pol;
+};
+
+enum hdmi_phy_pwr {
+	HDMI_PHYPWRCMD_OFF = 0,
+	HDMI_PHYPWRCMD_LDOON = 1,
+	HDMI_PHYPWRCMD_TXON = 2
+};
+
+enum hdmi_pll_pwr {
+	HDMI_PLLPWRCMD_ALLOFF = 0,
+	HDMI_PLLPWRCMD_PLLONLY = 1,
+	HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2,
+	HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3
+};
+
+enum hdmi_clk_refsel {
+	HDMI_REFSEL_PCLK = 0,
+	HDMI_REFSEL_REF1 = 1,
+	HDMI_REFSEL_REF2 = 2,
+	HDMI_REFSEL_SYSCLK = 3
+};
+
+enum hdmi_core_inputbus_width {
+	HDMI_INPUT_8BIT = 0,
+	HDMI_INPUT_10BIT = 1,
+	HDMI_INPUT_12BIT = 2
+};
+
+enum hdmi_core_dither_trunc {
+	HDMI_OUTPUTTRUNCATION_8BIT = 0,
+	HDMI_OUTPUTTRUNCATION_10BIT = 1,
+	HDMI_OUTPUTTRUNCATION_12BIT = 2,
+	HDMI_OUTPUTDITHER_8BIT = 3,
+	HDMI_OUTPUTDITHER_10BIT = 4,
+	HDMI_OUTPUTDITHER_12BIT = 5
+};
+
+enum hdmi_core_deepcolor_ed {
+	HDMI_DEEPCOLORPACKECTDISABLE = 0,
+	HDMI_DEEPCOLORPACKECTENABLE = 1
+};
+
+enum hdmi_core_packet_mode {
+	HDMI_PACKETMODERESERVEDVALUE = 0,
+	HDMI_PACKETMODE24BITPERPIXEL = 4,
+	HDMI_PACKETMODE30BITPERPIXEL = 5,
+	HDMI_PACKETMODE36BITPERPIXEL = 6,
+	HDMI_PACKETMODE48BITPERPIXEL = 7
+};
+
+enum hdmi_core_hdmi_dvi {
+	HDMI_DVI = 0,
+	HDMI_HDMI = 1
+};
+
+enum hdmi_core_tclkselclkmult {
+	HDMI_FPLL05IDCK = 0,
+	HDMI_FPLL10IDCK = 1,
+	HDMI_FPLL20IDCK = 2,
+	HDMI_FPLL40IDCK = 3
+};
+
+enum hdmi_core_packet_ctrl {
+	HDMI_PACKETENABLE = 1,
+	HDMI_PACKETDISABLE = 0,
+	HDMI_PACKETREPEATON = 1,
+	HDMI_PACKETREPEATOFF = 0
+};
+
+/* INFOFRAME_AVI_ definitions */
+enum hdmi_core_infoframe {
+	HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
+	HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
+	HDMI_INFOFRAME_AVI_DB1Y_YUV444 = 2,
+	HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF = 0,
+	HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_ON =  1,
+	HDMI_INFOFRAME_AVI_DB1B_NO = 0,
+	HDMI_INFOFRAME_AVI_DB1B_VERT = 1,
+	HDMI_INFOFRAME_AVI_DB1B_HORI = 2,
+	HDMI_INFOFRAME_AVI_DB1B_VERTHORI = 3,
+	HDMI_INFOFRAME_AVI_DB1S_0 = 0,
+	HDMI_INFOFRAME_AVI_DB1S_1 = 1,
+	HDMI_INFOFRAME_AVI_DB1S_2 = 2,
+	HDMI_INFOFRAME_AVI_DB2C_NO = 0,
+	HDMI_INFOFRAME_AVI_DB2C_ITU601 = 1,
+	HDMI_INFOFRAME_AVI_DB2C_ITU709 = 2,
+	HDMI_INFOFRAME_AVI_DB2C_EC_EXTENDED = 3,
+	HDMI_INFOFRAME_AVI_DB2M_NO = 0,
+	HDMI_INFOFRAME_AVI_DB2M_43 = 1,
+	HDMI_INFOFRAME_AVI_DB2M_169 = 2,
+	HDMI_INFOFRAME_AVI_DB2R_SAME = 8,
+	HDMI_INFOFRAME_AVI_DB2R_43 = 9,
+	HDMI_INFOFRAME_AVI_DB2R_169 = 10,
+	HDMI_INFOFRAME_AVI_DB2R_149 = 11,
+	HDMI_INFOFRAME_AVI_DB3ITC_NO = 0,
+	HDMI_INFOFRAME_AVI_DB3ITC_YES = 1,
+	HDMI_INFOFRAME_AVI_DB3EC_XVYUV601 = 0,
+	HDMI_INFOFRAME_AVI_DB3EC_XVYUV709 = 1,
+	HDMI_INFOFRAME_AVI_DB3Q_DEFAULT = 0,
+	HDMI_INFOFRAME_AVI_DB3Q_LR = 1,
+	HDMI_INFOFRAME_AVI_DB3Q_FR = 2,
+	HDMI_INFOFRAME_AVI_DB3SC_NO = 0,
+	HDMI_INFOFRAME_AVI_DB3SC_HORI = 1,
+	HDMI_INFOFRAME_AVI_DB3SC_VERT = 2,
+	HDMI_INFOFRAME_AVI_DB3SC_HORIVERT = 3,
+	HDMI_INFOFRAME_AVI_DB5PR_NO = 0,
+	HDMI_INFOFRAME_AVI_DB5PR_2 = 1,
+	HDMI_INFOFRAME_AVI_DB5PR_3 = 2,
+	HDMI_INFOFRAME_AVI_DB5PR_4 = 3,
+	HDMI_INFOFRAME_AVI_DB5PR_5 = 4,
+	HDMI_INFOFRAME_AVI_DB5PR_6 = 5,
+	HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
+	HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
+	HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
+	HDMI_INFOFRAME_AVI_DB5PR_10 = 9
+};
+
+enum hdmi_packing_mode {
+	HDMI_PACK_10b_RGB_YUV444 = 0,
+	HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
+	HDMI_PACK_20b_YUV422 = 2,
+	HDMI_PACK_ALREADYPACKED = 7
+};
+
+struct hdmi_core_video_config {
+	enum hdmi_core_inputbus_width	ip_bus_width;
+	enum hdmi_core_dither_trunc	op_dither_truc;
+	enum hdmi_core_deepcolor_ed	deep_color_pkt;
+	enum hdmi_core_packet_mode	pkt_mode;
+	enum hdmi_core_hdmi_dvi		hdmi_dvi;
+	enum hdmi_core_tclkselclkmult	tclk_sel_clkmult;
+};
+
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_avi {
+	u8	db1_format;
+		/* Y0, Y1 rgb,yCbCr */
+	u8	db1_active_info;
+		/* A0  Active information Present */
+	u8	db1_bar_info_dv;
+		/* B0, B1 Bar info data valid */
+	u8	db1_scan_info;
+		/* S0, S1 scan information */
+	u8	db2_colorimetry;
+		/* C0, C1 colorimetry */
+	u8	db2_aspect_ratio;
+		/* M0, M1 Aspect ratio (4:3, 16:9) */
+	u8	db2_active_fmt_ar;
+		/* R0...R3 Active format aspect ratio */
+	u8	db3_itc;
+		/* ITC IT content. */
+	u8	db3_ec;
+		/* EC0, EC1, EC2 Extended colorimetry */
+	u8	db3_q_range;
+		/* Q1, Q0 Quantization range */
+	u8	db3_nup_scaling;
+		/* SC1, SC0 Non-uniform picture scaling */
+	u8	db4_videocode;
+		/* VIC0..6 Video format identification */
+	u8	db5_pixel_repeat;
+		/* PR0..PR3 Pixel repetition factor */
+	u16	db6_7_line_eoftop;
+		/* Line number end of top bar */
+	u16	db8_9_line_sofbottom;
+		/* Line number start of bottom bar */
+	u16	db10_11_pixel_eofleft;
+		/* Pixel number end of left bar */
+	u16	db12_13_pixel_sofright;
+		/* Pixel number start of right bar */
+};
+
+struct hdmi_core_packet_enable_repeat {
+	u32	audio_pkt;
+	u32	audio_pkt_repeat;
+	u32	avi_infoframe;
+	u32	avi_infoframe_repeat;
+	u32	gen_cntrl_pkt;
+	u32	gen_cntrl_pkt_repeat;
+	u32	generic_pkt;
+	u32	generic_pkt_repeat;
+};
+
+struct hdmi_video_format {
+	enum hdmi_packing_mode	packing_mode;
+	u32			y_res;	/* Line per panel */
+	u32			x_res;	/* pixel per line */
+};
+
+struct hdmi_video_interface {
+	int	vsp;	/* Vsync polarity */
+	int	hsp;	/* Hsync polarity */
+	int	interlacing;
+	int	tm;	/* Timing mode */
+};
+
+struct hdmi_cm {
+	int	code;
+	int	mode;
+};
+
+struct hdmi_config {
+	struct hdmi_timings timings;
+	u16	interlace;
+	struct hdmi_cm cm;
+};
+
+#endif
diff --git a/drivers/video/omap2/dss/hdmi_omap4_panel.c b/drivers/video/omap2/dss/hdmi_omap4_panel.c
new file mode 100644
index 0000000..ffb5de9
--- /dev/null
+++ b/drivers/video/omap2/dss/hdmi_omap4_panel.c
@@ -0,0 +1,222 @@
+/*
+ * hdmi_omap4_panel.c
+ *
+ * HDMI library support functions for TI OMAP4 processors.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors:	Mythri P k <mythripk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <plat/display.h>
+
+#include "dss.h"
+
+static struct {
+	struct mutex hdmi_lock;
+} hdmi;
+
+
+static int hdmi_panel_probe(struct omap_dss_device *dssdev)
+{
+	DSSDBG("ENTER hdmi_panel_probe\n");
+
+	dssdev->panel.config = OMAP_DSS_LCD_TFT |
+			OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS;
+
+	/*
+	 * Initialize the timings to 640 * 480
+	 * This is only for framebuffer update not for TV timing setting
+	 * Setting TV timing will be done only on enable
+	 */
+	dssdev->panel.timings.x_res = 640;
+	dssdev->panel.timings.y_res = 480;
+
+	DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
+		dssdev->panel.timings.x_res,
+		dssdev->panel.timings.y_res);
+	return 0;
+}
+
+static void hdmi_panel_remove(struct omap_dss_device *dssdev)
+{
+
+}
+
+static int hdmi_panel_enable(struct omap_dss_device *dssdev)
+{
+	int r = 0;
+	DSSDBG("ENTER hdmi_panel_enable\n");
+
+	mutex_lock(&hdmi.hdmi_lock);
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+		r = -EINVAL;
+		goto err;
+	}
+
+	r = omapdss_hdmi_display_enable(dssdev);
+	if (r) {
+		DSSERR("failed to power on\n");
+		goto err;
+	}
+
+	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+err:
+	mutex_unlock(&hdmi.hdmi_lock);
+
+	return r;
+}
+
+static void hdmi_panel_disable(struct omap_dss_device *dssdev)
+{
+	mutex_lock(&hdmi.hdmi_lock);
+
+	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+		omapdss_hdmi_display_disable(dssdev);
+
+	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+	mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
+{
+	int r = 0;
+
+	mutex_lock(&hdmi.hdmi_lock);
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+		r = -EINVAL;
+		goto err;
+	}
+
+	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+	omapdss_hdmi_display_disable(dssdev);
+
+err:
+	mutex_unlock(&hdmi.hdmi_lock);
+
+	return r;
+}
+
+static int hdmi_panel_resume(struct omap_dss_device *dssdev)
+{
+	int r = 0;
+
+	mutex_lock(&hdmi.hdmi_lock);
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
+		r = -EINVAL;
+		goto err;
+	}
+
+	r = omapdss_hdmi_display_enable(dssdev);
+	if (r) {
+		DSSERR("failed to power on\n");
+		goto err;
+	}
+
+	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+err:
+	mutex_unlock(&hdmi.hdmi_lock);
+
+	return r;
+}
+
+static void hdmi_get_timings(struct omap_dss_device *dssdev,
+			struct omap_video_timings *timings)
+{
+	mutex_lock(&hdmi.hdmi_lock);
+
+	*timings = dssdev->panel.timings;
+
+	mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static void hdmi_set_timings(struct omap_dss_device *dssdev,
+			struct omap_video_timings *timings)
+{
+	DSSDBG("hdmi_set_timings\n");
+
+	mutex_lock(&hdmi.hdmi_lock);
+
+	dssdev->panel.timings = *timings;
+
+	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+		/* turn the hdmi off and on to get new timings to use */
+		omapdss_hdmi_display_disable(dssdev);
+		omapdss_hdmi_display_set_timing(dssdev);
+	}
+
+	mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static int hdmi_check_timings(struct omap_dss_device *dssdev,
+			struct omap_video_timings *timings)
+{
+	int r = 0;
+
+	DSSDBG("hdmi_check_timings\n");
+
+	mutex_lock(&hdmi.hdmi_lock);
+
+	r = omapdss_hdmi_display_check_timing(dssdev, timings);
+	if (r) {
+		DSSERR("Timing cannot be applied\n");
+		goto err;
+	}
+err:
+	mutex_unlock(&hdmi.hdmi_lock);
+	return r;
+}
+
+static struct omap_dss_driver hdmi_driver = {
+	.probe		= hdmi_panel_probe,
+	.remove		= hdmi_panel_remove,
+	.enable		= hdmi_panel_enable,
+	.disable	= hdmi_panel_disable,
+	.suspend	= hdmi_panel_suspend,
+	.resume		= hdmi_panel_resume,
+	.get_timings	= hdmi_get_timings,
+	.set_timings	= hdmi_set_timings,
+	.check_timings	= hdmi_check_timings,
+	.driver			= {
+		.name   = "hdmi_panel",
+		.owner  = THIS_MODULE,
+	},
+};
+
+int hdmi_panel_init(void)
+{
+	mutex_init(&hdmi.hdmi_lock);
+
+	omap_dss_register_driver(&hdmi_driver);
+
+	return 0;
+}
+
+void hdmi_panel_exit(void)
+{
+	omap_dss_unregister_driver(&hdmi_driver);
+
+}
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 172d4e6..bcd37ec 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -515,6 +515,8 @@
 
 	if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
 		irq = DISPC_IRQ_EVSYNC_ODD;
+	} else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) {
+		irq = DISPC_IRQ_EVSYNC_EVEN;
 	} else {
 		if (mgr->id == OMAP_DSS_CHANNEL_LCD)
 			irq = DISPC_IRQ_VSYNC;
@@ -536,7 +538,8 @@
 	if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 		return 0;
 
-	if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+	if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+			|| dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
 		irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
 	} else {
 		if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
@@ -613,7 +616,8 @@
 	if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 		return 0;
 
-	if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+	if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+			|| dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
 		irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
 	} else {
 		if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
@@ -1377,6 +1381,7 @@
 		case OMAP_DISPLAY_TYPE_DBI:
 		case OMAP_DISPLAY_TYPE_SDI:
 		case OMAP_DISPLAY_TYPE_VENC:
+		case OMAP_DISPLAY_TYPE_HDMI:
 			default_get_overlay_fifo_thresholds(ovl->id, size,
 					&oc->burst_size, &oc->fifo_low,
 					&oc->fifo_high);
@@ -1394,7 +1399,7 @@
 	}
 
 	r = 0;
-	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 	if (!dss_cache.irq_enabled) {
 		u32 mask;
 
@@ -1407,7 +1412,7 @@
 		dss_cache.irq_enabled = true;
 	}
 	configure_dispc();
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	spin_unlock_irqrestore(&dss_cache.lock, flags);
 
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index 456efef..f1aca6d 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -490,7 +490,7 @@
 
 	ovl->manager = mgr;
 
-	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 	/* XXX: on manual update display, in auto update mode, a bug happens
 	 * here. When an overlay is first enabled on LCD, then it's disabled,
 	 * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
@@ -499,7 +499,7 @@
 	 * but I don't understand how or why. */
 	msleep(40);
 	dispc_set_channel_out(ovl->id, mgr->id);
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	return 0;
 }
@@ -679,7 +679,8 @@
 			lcd2_mgr->set_device(lcd2_mgr, dssdev);
 			mgr = lcd2_mgr;
 		}
-	} else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
+	} 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);
@@ -688,7 +689,8 @@
 		}
 	}
 
-	if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+	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);
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 10a2ffe..5ea17f4 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -36,8 +36,6 @@
 #include <plat/display.h>
 #include "dss.h"
 
-#define RFBI_BASE               0x48050800
-
 struct rfbi_reg { u16 idx; };
 
 #define RFBI_REG(idx)		((const struct rfbi_reg) { idx })
@@ -100,6 +98,7 @@
 static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
 
 static struct {
+	struct platform_device *pdev;
 	void __iomem	*base;
 
 	unsigned long	l4_khz;
@@ -142,9 +141,9 @@
 static void rfbi_enable_clocks(bool enable)
 {
 	if (enable)
-		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 	else
-		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
 void omap_rfbi_write_command(const void *buf, u32 len)
@@ -497,7 +496,7 @@
 	};
 
 	l4_rate = rfbi.l4_khz / 1000;
-	dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000;
+	dss1_rate = dss_clk_get_rate(DSS_CLK_FCK) / 1000000;
 
 	for (i = 0; i < ARRAY_SIZE(ftab); i++) {
 		/* Use a window instead of an exact match, to account
@@ -922,7 +921,7 @@
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
 
-	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	DUMPREG(RFBI_REVISION);
 	DUMPREG(RFBI_SYSCONFIG);
@@ -953,54 +952,10 @@
 	DUMPREG(RFBI_VSYNC_WIDTH);
 	DUMPREG(RFBI_HSYNC_WIDTH);
 
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
-int rfbi_init(void)
-{
-	u32 rev;
-	u32 l;
-
-	spin_lock_init(&rfbi.cmd_lock);
-
-	init_completion(&rfbi.cmd_done);
-	atomic_set(&rfbi.cmd_fifo_full, 0);
-	atomic_set(&rfbi.cmd_pending, 0);
-
-	rfbi.base = ioremap(RFBI_BASE, SZ_256);
-	if (!rfbi.base) {
-		DSSERR("can't ioremap RFBI\n");
-		return -ENOMEM;
-	}
-
-	rfbi_enable_clocks(1);
-
-	msleep(10);
-
-	rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
-
-	/* Enable autoidle and smart-idle */
-	l = rfbi_read_reg(RFBI_SYSCONFIG);
-	l |= (1 << 0) | (2 << 3);
-	rfbi_write_reg(RFBI_SYSCONFIG, l);
-
-	rev = rfbi_read_reg(RFBI_REVISION);
-	printk(KERN_INFO "OMAP RFBI rev %d.%d\n",
-	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
-
-	rfbi_enable_clocks(0);
-
-	return 0;
-}
-
-void rfbi_exit(void)
-{
-	DSSDBG("rfbi_exit\n");
-
-	iounmap(rfbi.base);
-}
-
 int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
 	int r;
@@ -1056,3 +1011,74 @@
 	dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
 	return 0;
 }
+
+/* RFBI HW IP initialisation */
+static int omap_rfbihw_probe(struct platform_device *pdev)
+{
+	u32 rev;
+	u32 l;
+	struct resource *rfbi_mem;
+
+	rfbi.pdev = pdev;
+
+	spin_lock_init(&rfbi.cmd_lock);
+
+	init_completion(&rfbi.cmd_done);
+	atomic_set(&rfbi.cmd_fifo_full, 0);
+	atomic_set(&rfbi.cmd_pending, 0);
+
+	rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
+	if (!rfbi_mem) {
+		DSSERR("can't get IORESOURCE_MEM RFBI\n");
+		return -EINVAL;
+	}
+	rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
+	if (!rfbi.base) {
+		DSSERR("can't ioremap RFBI\n");
+		return -ENOMEM;
+	}
+
+	rfbi_enable_clocks(1);
+
+	msleep(10);
+
+	rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
+
+	/* Enable autoidle and smart-idle */
+	l = rfbi_read_reg(RFBI_SYSCONFIG);
+	l |= (1 << 0) | (2 << 3);
+	rfbi_write_reg(RFBI_SYSCONFIG, l);
+
+	rev = rfbi_read_reg(RFBI_REVISION);
+	dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
+	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+	rfbi_enable_clocks(0);
+
+	return 0;
+}
+
+static int omap_rfbihw_remove(struct platform_device *pdev)
+{
+	iounmap(rfbi.base);
+	return 0;
+}
+
+static struct platform_driver omap_rfbihw_driver = {
+	.probe          = omap_rfbihw_probe,
+	.remove         = omap_rfbihw_remove,
+	.driver         = {
+		.name   = "omapdss_rfbi",
+		.owner  = THIS_MODULE,
+	},
+};
+
+int rfbi_init_platform_driver(void)
+{
+	return platform_driver_register(&omap_rfbihw_driver);
+}
+
+void rfbi_uninit_platform_driver(void)
+{
+	return platform_driver_unregister(&omap_rfbihw_driver);
+}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index b64adf7..54a53e6 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -30,7 +30,6 @@
 #include "dss.h"
 
 static struct {
-	bool skip_init;
 	bool update_enabled;
 	struct regulator *vdds_sdi_reg;
 } sdi;
@@ -68,9 +67,7 @@
 	if (r)
 		goto err1;
 
-	/* In case of skip_init sdi_init has already enabled the clocks */
-	if (!sdi.skip_init)
-		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	sdi_basic_init(dssdev);
 
@@ -80,14 +77,8 @@
 	dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
 			dssdev->panel.acbi, dssdev->panel.acb);
 
-	if (!sdi.skip_init) {
-		r = dss_calc_clock_div(1, t->pixel_clock * 1000,
-				&dss_cinfo, &dispc_cinfo);
-	} else {
-		r = dss_get_clock_div(&dss_cinfo);
-		r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo);
-	}
-
+	r = dss_calc_clock_div(1, t->pixel_clock * 1000,
+			&dss_cinfo, &dispc_cinfo);
 	if (r)
 		goto err2;
 
@@ -116,21 +107,17 @@
 	if (r)
 		goto err2;
 
-	if (!sdi.skip_init) {
-		dss_sdi_init(dssdev->phy.sdi.datapairs);
-		r = dss_sdi_enable();
-		if (r)
-			goto err1;
-		mdelay(2);
-	}
+	dss_sdi_init(dssdev->phy.sdi.datapairs);
+	r = dss_sdi_enable();
+	if (r)
+		goto err1;
+	mdelay(2);
 
 	dssdev->manager->enable(dssdev->manager);
 
-	sdi.skip_init = 0;
-
 	return 0;
 err2:
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 	regulator_disable(sdi.vdds_sdi_reg);
 err1:
 	omap_dss_stop_device(dssdev);
@@ -145,7 +132,7 @@
 
 	dss_sdi_disable();
 
-	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
 	regulator_disable(sdi.vdds_sdi_reg);
 
@@ -157,25 +144,24 @@
 {
 	DSSDBG("SDI init\n");
 
+	if (sdi.vdds_sdi_reg == NULL) {
+		struct regulator *vdds_sdi;
+
+		vdds_sdi = dss_get_vdds_sdi();
+
+		if (IS_ERR(vdds_sdi)) {
+			DSSERR("can't get VDDS_SDI regulator\n");
+			return PTR_ERR(vdds_sdi);
+		}
+
+		sdi.vdds_sdi_reg = vdds_sdi;
+	}
+
 	return 0;
 }
 
-int sdi_init(bool skip_init)
+int sdi_init(void)
 {
-	/* we store this for first display enable, then clear it */
-	sdi.skip_init = skip_init;
-
-	sdi.vdds_sdi_reg = dss_get_vdds_sdi();
-	if (IS_ERR(sdi.vdds_sdi_reg)) {
-		DSSERR("can't get VDDS_SDI regulator\n");
-		return PTR_ERR(sdi.vdds_sdi_reg);
-	}
-	/*
-	 * Enable clocks already here, otherwise there would be a toggle
-	 * of them until sdi_display_enable is called.
-	 */
-	if (skip_init)
-		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
 	return 0;
 }
 
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index eff3505..8e35a5b 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -39,8 +39,6 @@
 
 #include "dss.h"
 
-#define VENC_BASE	0x48050C00
-
 /* Venc registers */
 #define VENC_REV_ID				0x00
 #define VENC_STATUS				0x04
@@ -289,6 +287,7 @@
 EXPORT_SYMBOL(omap_dss_ntsc_timings);
 
 static struct {
+	struct platform_device *pdev;
 	void __iomem *base;
 	struct mutex venc_lock;
 	u32 wss_data;
@@ -381,11 +380,11 @@
 static void venc_enable_clocks(int enable)
 {
 	if (enable)
-		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
-				DSS_CLK_96M);
+		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
+				DSS_CLK_VIDFCK);
 	else
-		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
-				DSS_CLK_96M);
+		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
+				DSS_CLK_VIDFCK);
 }
 
 static const struct venc_config *venc_timings_to_config(
@@ -641,50 +640,23 @@
 };
 /* driver end */
 
-
-
-int venc_init(struct platform_device *pdev)
-{
-	u8 rev_id;
-
-	mutex_init(&venc.venc_lock);
-
-	venc.wss_data = 0;
-
-	venc.base = ioremap(VENC_BASE, SZ_1K);
-	if (!venc.base) {
-		DSSERR("can't ioremap VENC\n");
-		return -ENOMEM;
-	}
-
-	venc.vdda_dac_reg = dss_get_vdda_dac();
-	if (IS_ERR(venc.vdda_dac_reg)) {
-		iounmap(venc.base);
-		DSSERR("can't get VDDA_DAC regulator\n");
-		return PTR_ERR(venc.vdda_dac_reg);
-	}
-
-	venc_enable_clocks(1);
-
-	rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
-	printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
-
-	venc_enable_clocks(0);
-
-	return omap_dss_register_driver(&venc_driver);
-}
-
-void venc_exit(void)
-{
-	omap_dss_unregister_driver(&venc_driver);
-
-	iounmap(venc.base);
-}
-
 int venc_init_display(struct omap_dss_device *dssdev)
 {
 	DSSDBG("init_display\n");
 
+	if (venc.vdda_dac_reg == NULL) {
+		struct regulator *vdda_dac;
+
+		vdda_dac = regulator_get(&venc.pdev->dev, "vdda_dac");
+
+		if (IS_ERR(vdda_dac)) {
+			DSSERR("can't get VDDA_DAC regulator\n");
+			return PTR_ERR(vdda_dac);
+		}
+
+		venc.vdda_dac_reg = vdda_dac;
+	}
+
 	return 0;
 }
 
@@ -740,3 +712,73 @@
 
 #undef DUMPREG
 }
+
+/* VENC HW IP initialisation */
+static int omap_venchw_probe(struct platform_device *pdev)
+{
+	u8 rev_id;
+	struct resource *venc_mem;
+
+	venc.pdev = pdev;
+
+	mutex_init(&venc.venc_lock);
+
+	venc.wss_data = 0;
+
+	venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
+	if (!venc_mem) {
+		DSSERR("can't get IORESOURCE_MEM VENC\n");
+		return -EINVAL;
+	}
+	venc.base = ioremap(venc_mem->start, resource_size(venc_mem));
+	if (!venc.base) {
+		DSSERR("can't ioremap VENC\n");
+		return -ENOMEM;
+	}
+
+	venc_enable_clocks(1);
+
+	rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
+	dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
+
+	venc_enable_clocks(0);
+
+	return omap_dss_register_driver(&venc_driver);
+}
+
+static int omap_venchw_remove(struct platform_device *pdev)
+{
+	if (venc.vdda_dac_reg != NULL) {
+		regulator_put(venc.vdda_dac_reg);
+		venc.vdda_dac_reg = NULL;
+	}
+	omap_dss_unregister_driver(&venc_driver);
+
+	iounmap(venc.base);
+	return 0;
+}
+
+static struct platform_driver omap_venchw_driver = {
+	.probe          = omap_venchw_probe,
+	.remove         = omap_venchw_remove,
+	.driver         = {
+		.name   = "omapdss_venc",
+		.owner  = THIS_MODULE,
+	},
+};
+
+int venc_init_platform_driver(void)
+{
+	if (cpu_is_omap44xx())
+		return 0;
+
+	return platform_driver_register(&omap_venchw_driver);
+}
+
+void venc_uninit_platform_driver(void)
+{
+	if (cpu_is_omap44xx())
+		return;
+
+	return platform_driver_unregister(&omap_venchw_driver);
+}
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index 65149b2..aa33386 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -1,5 +1,5 @@
 menuconfig FB_OMAP2
-        tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
+        tristate "OMAP2+ frame buffer support (EXPERIMENTAL)"
         depends on FB && OMAP2_DSS
 
 	select OMAP2_VRAM
@@ -8,10 +8,10 @@
         select FB_CFB_COPYAREA
         select FB_CFB_IMAGEBLIT
         help
-          Frame buffer driver for OMAP2/3 based boards.
+	  Frame buffer driver for OMAP2+ based boards.
 
 config FB_OMAP2_DEBUG_SUPPORT
-	bool "Debug support for OMAP2/3 FB"
+        bool "Debug support for OMAP2+ FB"
 	default y
 	depends on FB_OMAP2
 	help
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 4fdab8e..505ec66 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -2090,7 +2090,7 @@
 {
 	int r;
 	u8 bpp;
-	struct omap_video_timings timings;
+	struct omap_video_timings timings, temp_timings;
 
 	r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
 	if (r)
@@ -2100,14 +2100,23 @@
 	fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp;
 	++fbdev->num_bpp_overrides;
 
-	if (!display->driver->check_timings || !display->driver->set_timings)
-		return -EINVAL;
+	if (display->driver->check_timings) {
+		r = display->driver->check_timings(display, &timings);
+		if (r)
+			return r;
+	} else {
+		/* If check_timings is not present compare xres and yres */
+		if (display->driver->get_timings) {
+			display->driver->get_timings(display, &temp_timings);
 
-	r = display->driver->check_timings(display, &timings);
-	if (r)
-		return r;
+			if (temp_timings.x_res != timings.x_res ||
+				temp_timings.y_res != timings.y_res)
+				return -EINVAL;
+		}
+	}
 
-	display->driver->set_timings(display, &timings);
+	if (display->driver->set_timings)
+			display->driver->set_timings(display, &timings);
 
 	return 0;
 }