Browse Source

Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6: (126 commits)
  sh_mobile_meram: Safely disable MERAM operation when not initialized
  video: mb862xxfb: add support for L1 displaying
  video: mb862xx: add support for controller's I2C bus adapter
  video: mb862xxfb: relocate register space to get contiguous vram
  video: mb862xxfb: use pre-initialized configuration for PCI GDCs
  video: mb862xxfb: correct fix.smem_len field initialization
  video: s3c-fb: correct transparency checking in 32bpp
  video: s3c-fb: add gpio setup function to resume function
  fbdev/amifb: Remove superfluous alignment of frame buffer memory
  fbdev/amifb: Do not call panic() if there's not enough Chip RAM
  fbdev/amifb: Correct check for video memory size
  video: mb862xxfb: Require either FB_MB862XX_PCI_GDC or FB_MB862XX_LIME
  video: s3c-fb: add window variant information for S5P
  video: s3c-fb: add additional validate bpps
  video: s3c-fb: correct window osd size offset values
  udlfb: include prefetch.h explicitly
  drivers/video/s3c2410fb.c: Convert release_resource to release_mem_region
  drivers/video/sm501fb.c: Convert release_resource to release_mem_region
  drivers/video: Convert release_resource to release_mem_region
  video, udlfb: Fix two build warnings about 'ignoring return value'
  ...
Linus Torvalds 14 years ago
parent
commit
0f1493a601
82 changed files with 5100 additions and 1444 deletions
  1. 2 2
      arch/arm/mach-omap2/board-3430sdp.c
  2. 10 1
      arch/arm/mach-omap2/board-4430sdp.c
  3. 2 2
      arch/arm/mach-omap2/board-am3517evm.c
  4. 2 2
      arch/arm/mach-omap2/board-cm-t35.c
  5. 2 2
      arch/arm/mach-omap2/board-devkit8000.c
  6. 2 2
      arch/arm/mach-omap2/board-igep0020.c
  7. 2 2
      arch/arm/mach-omap2/board-omap3beagle.c
  8. 2 2
      arch/arm/mach-omap2/board-omap3evm.c
  9. 1 1
      arch/arm/mach-omap2/board-omap3pandora.c
  10. 2 2
      arch/arm/mach-omap2/board-omap3stalker.c
  11. 2 2
      arch/arm/mach-omap2/board-omap4panda.c
  12. 2 2
      arch/arm/mach-omap2/board-overo.c
  13. 1 1
      arch/arm/mach-omap2/board-rx51-video.c
  14. 1 1
      arch/arm/mach-omap2/board-zoom-display.c
  15. 50 27
      arch/arm/mach-omap2/display.c
  16. 1 1
      arch/arm/mach-omap2/include/mach/board-zoom.h
  17. 1 1
      drivers/media/video/omap/omap_vout.c
  18. 1 1
      drivers/media/video/omap/omap_voutdef.h
  19. 38 4
      drivers/video/Kconfig
  20. 1 0
      drivers/video/Makefile
  21. 16 11
      drivers/video/amifb.c
  22. 2 2
      drivers/video/da8xx-fb.c
  23. 2 2
      drivers/video/efifb.c
  24. 4 1
      drivers/video/mb862xx/Makefile
  25. 177 0
      drivers/video/mb862xx/mb862xx-i2c.c
  26. 54 4
      drivers/video/mb862xx/mb862xx_reg.h
  27. 36 0
      drivers/video/mb862xx/mb862xxfb.h
  28. 145 7
      drivers/video/mb862xx/mb862xxfbdrv.c
  29. 2 2
      drivers/video/omap/dispc.c
  30. 1 1
      drivers/video/omap/omapfb_main.c
  31. 1 1
      drivers/video/omap/rfbi.c
  32. 2 2
      drivers/video/omap2/Makefile
  33. 5 4
      drivers/video/omap2/displays/Kconfig
  34. 1 1
      drivers/video/omap2/displays/panel-acx565akm.c
  35. 54 3
      drivers/video/omap2/displays/panel-generic-dpi.c
  36. 1 1
      drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
  37. 1 1
      drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
  38. 3 3
      drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
  39. 446 90
      drivers/video/omap2/displays/panel-taal.c
  40. 6 4
      drivers/video/omap2/displays/panel-tpo-td043mtea1.c
  41. 24 9
      drivers/video/omap2/dss/Kconfig
  42. 8 7
      drivers/video/omap2/dss/core.c
  43. 442 455
      drivers/video/omap2/dss/dispc.c
  44. 691 0
      drivers/video/omap2/dss/dispc.h
  45. 30 16
      drivers/video/omap2/dss/display.c
  46. 68 45
      drivers/video/omap2/dss/dpi.c
  47. 347 176
      drivers/video/omap2/dss/dsi.c
  48. 82 36
      drivers/video/omap2/dss/dss.c
  49. 61 37
      drivers/video/omap2/dss/dss.h
  50. 84 21
      drivers/video/omap2/dss/dss_features.c
  51. 25 14
      drivers/video/omap2/dss/dss_features.h
  52. 446 15
      drivers/video/omap2/dss/hdmi.c
  53. 219 3
      drivers/video/omap2/dss/hdmi.h
  54. 1 1
      drivers/video/omap2/dss/hdmi_omap4_panel.c
  55. 12 2
      drivers/video/omap2/dss/manager.c
  56. 31 12
      drivers/video/omap2/dss/overlay.c
  57. 30 146
      drivers/video/omap2/dss/rfbi.c
  58. 1 1
      drivers/video/omap2/dss/sdi.c
  59. 16 7
      drivers/video/omap2/dss/venc.c
  60. 11 3
      drivers/video/omap2/omapfb/omapfb-ioctl.c
  61. 131 100
      drivers/video/omap2/omapfb/omapfb-main.c
  62. 15 8
      drivers/video/omap2/omapfb/omapfb-sysfs.c
  63. 5 3
      drivers/video/omap2/omapfb/omapfb.h
  64. 95 26
      drivers/video/s3c-fb.c
  65. 3 5
      drivers/video/s3c2410fb.c
  66. 202 7
      drivers/video/s3fb.c
  67. 2 0
      drivers/video/savage/savagefb-i2c.c
  68. 5 3
      drivers/video/savage/savagefb.h
  69. 10 5
      drivers/video/savage/savagefb_driver.c
  70. 2 4
      drivers/video/sh7760fb.c
  71. 8 2
      drivers/video/sh_mobile_hdmi.c
  72. 106 20
      drivers/video/sh_mobile_lcdcfb.c
  73. 1 0
      drivers/video/sh_mobile_lcdcfb.h
  74. 567 0
      drivers/video/sh_mobile_meram.c
  75. 41 0
      drivers/video/sh_mobile_meram.h
  76. 12 12
      drivers/video/sm501fb.c
  77. 17 3
      drivers/video/udlfb.c
  78. 4 4
      include/video/omap-panel-generic-dpi.h
  79. 8 6
      include/video/omap-panel-nokia-dsi.h
  80. 82 32
      include/video/omapdss.h
  81. 3 0
      include/video/sh_mobile_lcdc.h
  82. 68 0
      include/video/sh_mobile_meram.h

+ 2 - 2
arch/arm/mach-omap2/board-3430sdp.c

@@ -37,8 +37,8 @@
 #include <plat/common.h>
 #include <plat/dma.h>
 #include <plat/gpmc.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include <plat/gpmc-smc91x.h>
 

+ 10 - 1
arch/arm/mach-omap2/board-4430sdp.c

@@ -36,7 +36,7 @@
 #include <plat/usb.h>
 #include <plat/mmc.h>
 #include <plat/omap4-keypad.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "mux.h"
 #include "hsmmc.h"
@@ -680,6 +680,15 @@ static struct omap_dss_device sdp4430_hdmi_device = {
 	.name = "hdmi",
 	.driver_name = "hdmi_panel",
 	.type = OMAP_DISPLAY_TYPE_HDMI,
+	.clocks	= {
+		.dispc	= {
+			.dispc_fclk_src	= OMAP_DSS_CLK_SRC_FCK,
+		},
+		.hdmi	= {
+			.regn	= 15,
+			.regm2	= 1,
+		},
+	},
 	.platform_enable = sdp4430_panel_enable_hdmi,
 	.platform_disable = sdp4430_panel_disable_hdmi,
 	.channel = OMAP_DSS_CHANNEL_DIGIT,

+ 2 - 2
arch/arm/mach-omap2/board-am3517evm.c

@@ -34,8 +34,8 @@
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include "mux.h"
 #include "control.h"

+ 2 - 2
arch/arm/mach-omap2/board-cm-t35.c

@@ -45,8 +45,8 @@
 #include <plat/nand.h>
 #include <plat/gpmc.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/mcspi.h>
 
 #include <mach/hardware.h>

+ 2 - 2
arch/arm/mach-omap2/board-devkit8000.c

@@ -45,8 +45,8 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>

+ 2 - 2
arch/arm/mach-omap2/board-igep0020.c

@@ -31,8 +31,8 @@
 #include <plat/common.h>
 #include <plat/gpmc.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/onenand.h>
 
 #include "mux.h"

+ 2 - 2
arch/arm/mach-omap2/board-omap3beagle.c

@@ -41,8 +41,8 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>

+ 2 - 2
arch/arm/mach-omap2/board-omap3evm.c

@@ -44,8 +44,8 @@
 #include <plat/usb.h>
 #include <plat/common.h>
 #include <plat/mcspi.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"

+ 1 - 1
arch/arm/mach-omap2/board-omap3pandora.c

@@ -46,7 +46,7 @@
 #include <mach/hardware.h>
 #include <plat/mcspi.h>
 #include <plat/usb.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/nand.h>
 
 #include "mux.h"

+ 2 - 2
arch/arm/mach-omap2/board-omap3stalker.c

@@ -39,8 +39,8 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>

+ 2 - 2
arch/arm/mach-omap2/board-omap4panda.c

@@ -34,13 +34,13 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omap-panel-generic-dpi.h>
 #include "timer-gp.h"
 
 #include "hsmmc.h"

+ 2 - 2
arch/arm/mach-omap2/board-overo.c

@@ -43,8 +43,8 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <mach/gpio.h>
 #include <plat/gpmc.h>
 #include <mach/hardware.h>

+ 1 - 1
arch/arm/mach-omap2/board-rx51-video.c

@@ -15,7 +15,7 @@
 #include <linux/spi/spi.h>
 #include <linux/mm.h>
 #include <asm/mach-types.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vram.h>
 #include <plat/mcspi.h>
 

+ 1 - 1
arch/arm/mach-omap2/board-zoom-display.c

@@ -15,7 +15,7 @@
 #include <linux/i2c/twl.h>
 #include <linux/spi/spi.h>
 #include <plat/mcspi.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define LCD_PANEL_RESET_GPIO_PROD	96
 #define LCD_PANEL_RESET_GPIO_PILOT	55

+ 50 - 27
arch/arm/mach-omap2/display.c

@@ -22,7 +22,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
 
@@ -56,37 +56,58 @@ static bool opt_clock_available(const char *clk_role)
 	return false;
 }
 
+struct omap_dss_hwmod_data {
+	const char *oh_name;
+	const char *dev_name;
+	const int id;
+};
+
+static const struct omap_dss_hwmod_data omap2_dss_hwmod_data[] __initdata = {
+	{ "dss_core", "omapdss_dss", -1 },
+	{ "dss_dispc", "omapdss_dispc", -1 },
+	{ "dss_rfbi", "omapdss_rfbi", -1 },
+	{ "dss_venc", "omapdss_venc", -1 },
+};
+
+static const struct omap_dss_hwmod_data omap3_dss_hwmod_data[] __initdata = {
+	{ "dss_core", "omapdss_dss", -1 },
+	{ "dss_dispc", "omapdss_dispc", -1 },
+	{ "dss_rfbi", "omapdss_rfbi", -1 },
+	{ "dss_venc", "omapdss_venc", -1 },
+	{ "dss_dsi1", "omapdss_dsi1", -1 },
+};
+
+static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = {
+	{ "dss_core", "omapdss_dss", -1 },
+	{ "dss_dispc", "omapdss_dispc", -1 },
+	{ "dss_rfbi", "omapdss_rfbi", -1 },
+	{ "dss_venc", "omapdss_venc", -1 },
+	{ "dss_dsi1", "omapdss_dsi1", -1 },
+	{ "dss_dsi2", "omapdss_dsi2", -1 },
+	{ "dss_hdmi", "omapdss_hdmi", -1 },
+};
+
 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;
+	int i, oh_count;
 	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;
+	const struct omap_dss_hwmod_data *curr_dss_hwmod;
 
 	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 */
+	if (cpu_is_omap24xx()) {
+		curr_dss_hwmod = omap2_dss_hwmod_data;
+		oh_count = ARRAY_SIZE(omap2_dss_hwmod_data);
+	} else if (cpu_is_omap34xx()) {
+		curr_dss_hwmod = omap3_dss_hwmod_data;
+		oh_count = ARRAY_SIZE(omap3_dss_hwmod_data);
+	} else {
+		curr_dss_hwmod = omap4_dss_hwmod_data;
+		oh_count = ARRAY_SIZE(omap4_dss_hwmod_data);
+	}
 
 	/* opt_clks are always associated with dss hwmod */
 	oh_core = omap_hwmod_lookup("dss_core");
@@ -100,19 +121,21 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
 	pdata.opt_clock_available = opt_clock_available;
 
 	for (i = 0; i < oh_count; i++) {
-		oh = omap_hwmod_lookup(oh_name[i]);
+		oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
 		if (!oh) {
-			pr_err("Could not look up %s\n", oh_name[i]);
+			pr_err("Could not look up %s\n",
+				curr_dss_hwmod[i].oh_name);
 			return -ENODEV;
 		}
 
-		od = omap_device_build(dev_name[i], -1, oh, &pdata,
+		od = omap_device_build(curr_dss_hwmod[i].dev_name,
+				curr_dss_hwmod[i].id, 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]))
+				curr_dss_hwmod[i].oh_name))
 			return -ENODEV;
 	}
 	omap_display_device.dev.platform_data = board_data;

+ 1 - 1
arch/arm/mach-omap2/include/mach/board-zoom.h

@@ -1,7 +1,7 @@
 /*
  * Defines for zoom boards
  */
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define ZOOM_NAND_CS    0
 

+ 1 - 1
drivers/media/video/omap/omap_vout.c

@@ -47,7 +47,7 @@
 #include <plat/dma.h>
 #include <plat/vram.h>
 #include <plat/vrfb.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "omap_voutlib.h"
 #include "omap_voutdef.h"

+ 1 - 1
drivers/media/video/omap/omap_voutdef.h

@@ -11,7 +11,7 @@
 #ifndef OMAP_VOUTDEF_H
 #define OMAP_VOUTDEF_H
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define YUYV_BPP        2
 #define RGB565_BPP      2

+ 38 - 4
drivers/video/Kconfig

@@ -1460,6 +1460,14 @@ config FB_S3
 	---help---
 	  Driver for graphics boards with S3 Trio / S3 Virge chip.
 
+config FB_S3_DDC
+	bool "DDC for S3 support"
+	depends on FB_S3
+	select FB_DDC
+	default y
+	help
+	  Say Y here if you want DDC support for your S3 graphics card.
+
 config FB_SAVAGE
 	tristate "S3 Savage support"
 	depends on FB && PCI && EXPERIMENTAL
@@ -1983,6 +1991,18 @@ config FB_SH_MOBILE_HDMI
 	---help---
 	  Driver for the on-chip SH-Mobile HDMI controller.
 
+config FB_SH_MOBILE_MERAM
+	tristate "SuperH Mobile MERAM read ahead support for LCDC"
+	depends on FB_SH_MOBILE_LCDC
+	default y
+	---help---
+	  Enable MERAM support for the SH-Mobile LCD controller.
+
+	  This will allow for caching of the framebuffer to provide more
+	  reliable access under heavy main memory bus traffic situations.
+	  Up to 4 memory channels can be configured, allowing 4 RGB or
+	  2 YCbCr framebuffers to be configured.
+
 config FB_TMIO
 	tristate "Toshiba Mobile IO FrameBuffer support"
 	depends on FB && MFD_CORE
@@ -2246,29 +2266,43 @@ config FB_METRONOME
 config FB_MB862XX
 	tristate "Fujitsu MB862xx GDC support"
 	depends on FB
+	depends on PCI || (OF && PPC)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	---help---
 	  Frame buffer driver for Fujitsu Carmine/Coral-P(A)/Lime controllers.
 
+choice
+	prompt "GDC variant"
+	depends on FB_MB862XX
+
 config FB_MB862XX_PCI_GDC
 	bool "Carmine/Coral-P(A) GDC"
-	depends on PCI && FB_MB862XX
+	depends on PCI
 	---help---
 	  This enables framebuffer support for Fujitsu Carmine/Coral-P(A)
 	  PCI graphics controller devices.
 
 config FB_MB862XX_LIME
 	bool "Lime GDC"
-	depends on FB_MB862XX
-	depends on OF && !FB_MB862XX_PCI_GDC
-	depends on PPC
+	depends on OF && PPC
 	select FB_FOREIGN_ENDIAN
 	select FB_LITTLE_ENDIAN
 	---help---
 	  Framebuffer support for Fujitsu Lime GDC on host CPU bus.
 
+endchoice
+
+config FB_MB862XX_I2C
+	bool "Support I2C bus on MB862XX GDC"
+	depends on FB_MB862XX && I2C
+	default y
+	help
+	  Selecting this option adds Coral-P(A)/Lime GDC I2C bus adapter
+	  driver to support accessing I2C devices on controller's I2C bus.
+	  These are usually some video decoder chips.
+
 config FB_EP93XX
 	tristate "EP93XX frame buffer support"
 	depends on FB && ARCH_EP93XX

+ 1 - 0
drivers/video/Makefile

@@ -130,6 +130,7 @@ obj-$(CONFIG_FB_UDL)		  += udlfb.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 obj-$(CONFIG_SH_MIPI_DSI)	  += sh_mipi_dsi.o
 obj-$(CONFIG_FB_SH_MOBILE_HDMI)	  += sh_mobile_hdmi.o
+obj-$(CONFIG_FB_SH_MOBILE_MERAM)  += sh_mobile_meram.o
 obj-$(CONFIG_FB_SH_MOBILE_LCDC)	  += sh_mobile_lcdcfb.o
 obj-$(CONFIG_FB_OMAP)             += omap/
 obj-y                             += omap2/

+ 16 - 11
drivers/video/amifb.c

@@ -2224,22 +2224,23 @@ static int amifb_ioctl(struct fb_info *info,
 	 * Allocate, Clear and Align a Block of Chip Memory
 	 */
 
-static u_long unaligned_chipptr = 0;
+static void *aligned_chipptr;
 
 static inline u_long __init chipalloc(u_long size)
 {
-	size += PAGE_SIZE-1;
-	if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size,
-							   "amifb [RAM]")))
-		panic("No Chip RAM for frame buffer");
-	memset((void *)unaligned_chipptr, 0, size);
-	return PAGE_ALIGN(unaligned_chipptr);
+	aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]");
+	if (!aligned_chipptr) {
+		pr_err("amifb: No Chip RAM for frame buffer");
+		return 0;
+	}
+	memset(aligned_chipptr, 0, size);
+	return (u_long)aligned_chipptr;
 }
 
 static inline void chipfree(void)
 {
-	if (unaligned_chipptr)
-		amiga_chip_free((void *)unaligned_chipptr);
+	if (aligned_chipptr)
+		amiga_chip_free(aligned_chipptr);
 }
 
 
@@ -2295,7 +2296,7 @@ default_chipset:
 			    defmode = amiga_vblank == 50 ? DEFMODE_PAL
 							 : DEFMODE_NTSC;
 			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-			    VIDEOMEMSIZE_ECS_1M)
+			    VIDEOMEMSIZE_ECS_2M)
 				fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
 			else
 				fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
@@ -2312,7 +2313,7 @@ default_chipset:
 			maxfmode = TAG_FMODE_4;
 			defmode = DEFMODE_AGA;
 			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-			    VIDEOMEMSIZE_AGA_1M)
+			    VIDEOMEMSIZE_AGA_2M)
 				fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
 			else
 				fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
@@ -2385,6 +2386,10 @@ default_chipset:
 	                    DUMMYSPRITEMEMSIZE+
 	                    COPINITSIZE+
 	                    4*COPLISTSIZE);
+	if (!chipptr) {
+		err = -ENOMEM;
+		goto amifb_error;
+	}
 
 	assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
 	assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);

+ 2 - 2
drivers/video/da8xx-fb.c

@@ -899,7 +899,7 @@ static struct fb_ops da8xx_fb_ops = {
 	.fb_blank = cfb_blank,
 };
 
-static int __init fb_probe(struct platform_device *device)
+static int __devinit fb_probe(struct platform_device *device)
 {
 	struct da8xx_lcdc_platform_data *fb_pdata =
 						device->dev.platform_data;
@@ -1165,7 +1165,7 @@ static int fb_resume(struct platform_device *dev)
 
 static struct platform_driver da8xx_fb_driver = {
 	.probe = fb_probe,
-	.remove = fb_remove,
+	.remove = __devexit_p(fb_remove),
 	.suspend = fb_suspend,
 	.resume = fb_resume,
 	.driver = {

+ 2 - 2
drivers/video/efifb.c

@@ -242,9 +242,9 @@ static int set_system(const struct dmi_system_id *id)
 		return 0;
 	}
 
-	printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
+	printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
 			 "(%dx%d, stride %d)\n", id->ident,
-			 (void *)screen_info.lfb_base, screen_info.lfb_width,
+			 screen_info.lfb_base, screen_info.lfb_width,
 			 screen_info.lfb_height, screen_info.lfb_linelength);
 
 

+ 4 - 1
drivers/video/mb862xx/Makefile

@@ -2,4 +2,7 @@
 # Makefile for the MB862xx framebuffer driver
 #
 
-obj-$(CONFIG_FB_MB862XX)	:= mb862xxfb.o mb862xxfb_accel.o
+obj-$(CONFIG_FB_MB862XX) += mb862xxfb.o
+
+mb862xxfb-y := mb862xxfbdrv.o mb862xxfb_accel.o
+mb862xxfb-$(CONFIG_FB_MB862XX_I2C) += mb862xx-i2c.o

+ 177 - 0
drivers/video/mb862xx/mb862xx-i2c.c

@@ -0,0 +1,177 @@
+/*
+ * Coral-P(A)/Lime I2C adapter driver
+ *
+ * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/fb.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+
+#include "mb862xxfb.h"
+#include "mb862xx_reg.h"
+
+static int mb862xx_i2c_wait_event(struct i2c_adapter *adap)
+{
+	struct mb862xxfb_par *par = adap->algo_data;
+	u32 reg;
+
+	do {
+		udelay(1);
+		reg = inreg(i2c, GC_I2C_BCR);
+		if (reg & (I2C_INT | I2C_BER))
+			break;
+	} while (1);
+
+	return (reg & I2C_BER) ? 0 : 1;
+}
+
+static int mb862xx_i2c_do_address(struct i2c_adapter *adap, int addr)
+{
+	struct mb862xxfb_par *par = adap->algo_data;
+
+	outreg(i2c, GC_I2C_DAR, addr);
+	outreg(i2c, GC_I2C_CCR, I2C_CLOCK_AND_ENABLE);
+	outreg(i2c, GC_I2C_BCR, par->i2c_rs ? I2C_REPEATED_START : I2C_START);
+	if (!mb862xx_i2c_wait_event(adap))
+		return -EIO;
+	par->i2c_rs = !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);
+	return par->i2c_rs;
+}
+
+static int mb862xx_i2c_write_byte(struct i2c_adapter *adap, u8 byte)
+{
+	struct mb862xxfb_par *par = adap->algo_data;
+
+	outreg(i2c, GC_I2C_DAR, byte);
+	outreg(i2c, GC_I2C_BCR, I2C_START);
+	if (!mb862xx_i2c_wait_event(adap))
+		return -EIO;
+	return !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);
+}
+
+static int mb862xx_i2c_read_byte(struct i2c_adapter *adap, u8 *byte, int last)
+{
+	struct mb862xxfb_par *par = adap->algo_data;
+
+	outreg(i2c, GC_I2C_BCR, I2C_START | (last ? 0 : I2C_ACK));
+	if (!mb862xx_i2c_wait_event(adap))
+		return 0;
+	*byte = inreg(i2c, GC_I2C_DAR);
+	return 1;
+}
+
+void mb862xx_i2c_stop(struct i2c_adapter *adap)
+{
+	struct mb862xxfb_par *par = adap->algo_data;
+
+	outreg(i2c, GC_I2C_BCR, I2C_STOP);
+	outreg(i2c, GC_I2C_CCR, I2C_DISABLE);
+	par->i2c_rs = 0;
+}
+
+static int mb862xx_i2c_read(struct i2c_adapter *adap, struct i2c_msg *m)
+{
+	int i, ret = 0;
+	int last = m->len - 1;
+
+	for (i = 0; i < m->len; i++) {
+		if (!mb862xx_i2c_read_byte(adap, &m->buf[i], i == last)) {
+			ret = -EIO;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int mb862xx_i2c_write(struct i2c_adapter *adap, struct i2c_msg *m)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < m->len; i++) {
+		if (!mb862xx_i2c_write_byte(adap, m->buf[i])) {
+			ret = -EIO;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int mb862xx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+			int num)
+{
+	struct mb862xxfb_par *par = adap->algo_data;
+	struct i2c_msg *m;
+	int addr;
+	int i = 0, err = 0;
+
+	dev_dbg(par->dev, "%s: %d msgs\n", __func__, num);
+
+	for (i = 0; i < num; i++) {
+		m = &msgs[i];
+		if (!m->len) {
+			dev_dbg(par->dev, "%s: null msgs\n", __func__);
+			continue;
+		}
+		addr = m->addr;
+		if (m->flags & I2C_M_RD)
+			addr |= 1;
+
+		err = mb862xx_i2c_do_address(adap, addr);
+		if (err < 0)
+			break;
+		if (m->flags & I2C_M_RD)
+			err = mb862xx_i2c_read(adap, m);
+		else
+			err = mb862xx_i2c_write(adap, m);
+	}
+
+	if (i)
+		mb862xx_i2c_stop(adap);
+
+	return (err < 0) ? err : i;
+}
+
+static u32 mb862xx_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static const struct i2c_algorithm mb862xx_algo = {
+	.master_xfer	= mb862xx_xfer,
+	.functionality	= mb862xx_func,
+};
+
+static struct i2c_adapter mb862xx_i2c_adapter = {
+	.name		= "MB862xx I2C adapter",
+	.algo		= &mb862xx_algo,
+	.owner		= THIS_MODULE,
+};
+
+int mb862xx_i2c_init(struct mb862xxfb_par *par)
+{
+	int ret;
+
+	mb862xx_i2c_adapter.algo_data = par;
+	par->adap = &mb862xx_i2c_adapter;
+
+	ret = i2c_add_adapter(par->adap);
+	if (ret < 0) {
+		dev_err(par->dev, "failed to add %s\n",
+			mb862xx_i2c_adapter.name);
+	}
+	return ret;
+}
+
+void mb862xx_i2c_exit(struct mb862xxfb_par *par)
+{
+	if (par->adap) {
+		i2c_del_adapter(par->adap);
+		par->adap = NULL;
+	}
+}

+ 54 - 4
drivers/video/mb862xx/mb862xx_reg.h

@@ -5,11 +5,8 @@
 #ifndef _MB862XX_REG_H
 #define _MB862XX_REG_H
 
-#ifdef MB862XX_MMIO_BOTTOM
-#define MB862XX_MMIO_BASE	0x03fc0000
-#else
 #define MB862XX_MMIO_BASE	0x01fc0000
-#endif
+#define MB862XX_MMIO_HIGH_BASE	0x03fc0000
 #define MB862XX_I2C_BASE	0x0000c000
 #define MB862XX_DISP_BASE	0x00010000
 #define MB862XX_CAP_BASE	0x00018000
@@ -23,6 +20,7 @@
 #define GC_IMASK		0x00000024
 #define GC_SRST			0x0000002c
 #define GC_CCF			0x00000038
+#define GC_RSW			0x0000005c
 #define GC_CID			0x000000f0
 #define GC_REVISION		0x00000084
 
@@ -53,10 +51,16 @@
 #define GC_L0OA0		0x00000024
 #define GC_L0DA0		0x00000028
 #define GC_L0DY_L0DX		0x0000002c
+#define GC_L1M			0x00000030
+#define GC_L1DA			0x00000034
 #define GC_DCM1			0x00000100
 #define GC_L0EM			0x00000110
 #define GC_L0WY_L0WX		0x00000114
 #define GC_L0WH_L0WW		0x00000118
+#define GC_L1EM			0x00000120
+#define GC_L1WY_L1WX		0x00000124
+#define GC_L1WH_L1WW		0x00000128
+#define GC_DLS			0x00000180
 #define GC_DCM2			0x00000104
 #define GC_DCM3			0x00000108
 #define GC_CPM_CUTC		0x000000a0
@@ -68,6 +72,11 @@
 
 #define GC_CPM_CEN0		0x00100000
 #define GC_CPM_CEN1		0x00200000
+#define GC_DCM1_DEN		0x80000000
+#define GC_DCM1_L1E		0x00020000
+#define GC_L1M_16		0x80000000
+#define GC_L1M_YC		0x40000000
+#define GC_L1M_CS		0x20000000
 
 #define GC_DCM01_ESY		0x00000004
 #define GC_DCM01_SC		0x00003f00
@@ -79,9 +88,50 @@
 #define GC_L0M_L0C_16		0x80000000
 #define GC_L0EM_L0EC_24		0x40000000
 #define GC_L0M_L0W_UNIT		64
+#define GC_L1EM_DM		0x02000000
 
 #define GC_DISP_REFCLK_400	400
 
+/* I2C */
+#define GC_I2C_BSR		0x00000000	/* BSR */
+#define GC_I2C_BCR		0x00000004	/* BCR */
+#define GC_I2C_CCR		0x00000008	/* CCR */
+#define GC_I2C_ADR		0x0000000C	/* ADR */
+#define GC_I2C_DAR		0x00000010	/* DAR */
+
+#define I2C_DISABLE		0x00000000
+#define I2C_STOP		0x00000000
+#define I2C_START		0x00000010
+#define I2C_REPEATED_START	0x00000030
+#define I2C_CLOCK_AND_ENABLE	0x0000003f
+#define I2C_READY		0x01
+#define I2C_INT			0x01
+#define I2C_INTE		0x02
+#define I2C_ACK			0x08
+#define I2C_BER			0x80
+#define I2C_BEIE		0x40
+#define I2C_TRX			0x80
+#define I2C_LRB			0x10
+
+/* Capture registers and bits */
+#define GC_CAP_VCM		0x00000000
+#define GC_CAP_CSC		0x00000004
+#define GC_CAP_VCS		0x00000008
+#define GC_CAP_CBM		0x00000010
+#define GC_CAP_CBOA		0x00000014
+#define GC_CAP_CBLA		0x00000018
+#define GC_CAP_IMG_START	0x0000001C
+#define GC_CAP_IMG_END		0x00000020
+#define GC_CAP_CMSS		0x00000048
+#define GC_CAP_CMDS		0x0000004C
+
+#define GC_VCM_VIE		0x80000000
+#define GC_VCM_CM		0x03000000
+#define GC_VCM_VS_PAL		0x00000002
+#define GC_CBM_OO		0x80000000
+#define GC_CBM_HRV		0x00000010
+#define GC_CBM_CBST		0x00000001
+
 /* Carmine specific */
 #define MB86297_DRAW_BASE		0x00020000
 #define MB86297_DISP0_BASE		0x00100000

+ 36 - 0
drivers/video/mb862xx/mb862xxfb.h

@@ -1,6 +1,26 @@
 #ifndef __MB862XX_H__
 #define __MB862XX_H__
 
+struct mb862xx_l1_cfg {
+	unsigned short sx;
+	unsigned short sy;
+	unsigned short sw;
+	unsigned short sh;
+	unsigned short dx;
+	unsigned short dy;
+	unsigned short dw;
+	unsigned short dh;
+	int mirror;
+};
+
+#define MB862XX_BASE		'M'
+#define MB862XX_L1_GET_CFG	_IOR(MB862XX_BASE, 0, struct mb862xx_l1_cfg*)
+#define MB862XX_L1_SET_CFG	_IOW(MB862XX_BASE, 1, struct mb862xx_l1_cfg*)
+#define MB862XX_L1_ENABLE	_IOW(MB862XX_BASE, 2, int)
+#define MB862XX_L1_CAP_CTL	_IOW(MB862XX_BASE, 3, int)
+
+#ifdef __KERNEL__
+
 #define PCI_VENDOR_ID_FUJITSU_LIMITED	0x10cf
 #define PCI_DEVICE_ID_FUJITSU_CORALP	0x2019
 #define PCI_DEVICE_ID_FUJITSU_CORALPA	0x201e
@@ -38,6 +58,8 @@ struct mb862xxfb_par {
 	void __iomem		*mmio_base;	/* remapped registers */
 	size_t			mapped_vram;	/* length of remapped vram */
 	size_t			mmio_len;	/* length of register region */
+	unsigned long		cap_buf;	/* capture buffers offset */
+	size_t			cap_len;	/* length of capture buffers */
 
 	void __iomem		*host;		/* relocatable reg. bases */
 	void __iomem		*i2c;
@@ -57,11 +79,23 @@ struct mb862xxfb_par {
 	unsigned int		refclk;		/* disp. reference clock */
 	struct mb862xx_gc_mode	*gc_mode;	/* GDC mode init data */
 	int			pre_init;	/* don't init display if 1 */
+	struct i2c_adapter	*adap;		/* GDC I2C bus adapter */
+	int			i2c_rs;
+
+	struct mb862xx_l1_cfg	l1_cfg;
+	int			l1_stride;
 
 	u32			pseudo_palette[16];
 };
 
 extern void mb862xxfb_init_accel(struct fb_info *info, int xres);
+#ifdef CONFIG_FB_MB862XX_I2C
+extern int mb862xx_i2c_init(struct mb862xxfb_par *par);
+extern void mb862xx_i2c_exit(struct mb862xxfb_par *par);
+#else
+static inline int mb862xx_i2c_init(struct mb862xxfb_par *par) { return 0; }
+static inline void mb862xx_i2c_exit(struct mb862xxfb_par *par) { }
+#endif
 
 #if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC)
 #error	"Select Lime GDC or CoralP/Carmine support, but not both together"
@@ -82,4 +116,6 @@ extern void mb862xxfb_init_accel(struct fb_info *info, int xres);
 
 #define pack(a, b)	(((a) << 16) | (b))
 
+#endif /* __KERNEL__ */
+
 #endif

+ 145 - 7
drivers/video/mb862xx/mb862xxfb.c → drivers/video/mb862xx/mb862xxfbdrv.c

@@ -27,7 +27,7 @@
 
 #define NR_PALETTE		256
 #define MB862XX_MEM_SIZE	0x1000000
-#define CORALP_MEM_SIZE		0x4000000
+#define CORALP_MEM_SIZE		0x2000000
 #define CARMINE_MEM_SIZE	0x8000000
 #define DRV_NAME		"mb862xxfb"
 
@@ -309,6 +309,97 @@ static int mb862xxfb_blank(int mode, struct fb_info *fbi)
 	return 0;
 }
 
+static int mb862xxfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+			   unsigned long arg)
+{
+	struct mb862xxfb_par *par = fbi->par;
+	struct mb862xx_l1_cfg *l1_cfg = &par->l1_cfg;
+	void __user *argp = (void __user *)arg;
+	int *enable;
+	u32 l1em = 0;
+
+	switch (cmd) {
+	case MB862XX_L1_GET_CFG:
+		if (copy_to_user(argp, l1_cfg, sizeof(*l1_cfg)))
+			return -EFAULT;
+		break;
+	case MB862XX_L1_SET_CFG:
+		if (copy_from_user(l1_cfg, argp, sizeof(*l1_cfg)))
+			return -EFAULT;
+		if ((l1_cfg->sw >= l1_cfg->dw) && (l1_cfg->sh >= l1_cfg->dh)) {
+			/* downscaling */
+			outreg(cap, GC_CAP_CSC,
+				pack((l1_cfg->sh << 11) / l1_cfg->dh,
+				     (l1_cfg->sw << 11) / l1_cfg->dw));
+			l1em = inreg(disp, GC_L1EM);
+			l1em &= ~GC_L1EM_DM;
+		} else if ((l1_cfg->sw <= l1_cfg->dw) &&
+			   (l1_cfg->sh <= l1_cfg->dh)) {
+			/* upscaling */
+			outreg(cap, GC_CAP_CSC,
+				pack((l1_cfg->sh << 11) / l1_cfg->dh,
+				     (l1_cfg->sw << 11) / l1_cfg->dw));
+			outreg(cap, GC_CAP_CMSS,
+				pack(l1_cfg->sw >> 1, l1_cfg->sh));
+			outreg(cap, GC_CAP_CMDS,
+				pack(l1_cfg->dw >> 1, l1_cfg->dh));
+			l1em = inreg(disp, GC_L1EM);
+			l1em |= GC_L1EM_DM;
+		}
+
+		if (l1_cfg->mirror) {
+			outreg(cap, GC_CAP_CBM,
+				inreg(cap, GC_CAP_CBM) | GC_CBM_HRV);
+			l1em |= l1_cfg->dw * 2 - 8;
+		} else {
+			outreg(cap, GC_CAP_CBM,
+				inreg(cap, GC_CAP_CBM) & ~GC_CBM_HRV);
+			l1em &= 0xffff0000;
+		}
+		outreg(disp, GC_L1EM, l1em);
+		break;
+	case MB862XX_L1_ENABLE:
+		enable = (int *)arg;
+		if (*enable) {
+			outreg(disp, GC_L1DA, par->cap_buf);
+			outreg(cap, GC_CAP_IMG_START,
+				pack(l1_cfg->sy >> 1, l1_cfg->sx));
+			outreg(cap, GC_CAP_IMG_END,
+				pack(l1_cfg->sh, l1_cfg->sw));
+			outreg(disp, GC_L1M, GC_L1M_16 | GC_L1M_YC | GC_L1M_CS |
+					     (par->l1_stride << 16));
+			outreg(disp, GC_L1WY_L1WX,
+				pack(l1_cfg->dy, l1_cfg->dx));
+			outreg(disp, GC_L1WH_L1WW,
+				pack(l1_cfg->dh - 1, l1_cfg->dw));
+			outreg(disp, GC_DLS, 1);
+			outreg(cap, GC_CAP_VCM,
+				GC_VCM_VIE | GC_VCM_CM | GC_VCM_VS_PAL);
+			outreg(disp, GC_DCM1, inreg(disp, GC_DCM1) |
+					      GC_DCM1_DEN | GC_DCM1_L1E);
+		} else {
+			outreg(cap, GC_CAP_VCM,
+				inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE);
+			outreg(disp, GC_DCM1,
+				inreg(disp, GC_DCM1) & ~GC_DCM1_L1E);
+		}
+		break;
+	case MB862XX_L1_CAP_CTL:
+		enable = (int *)arg;
+		if (*enable) {
+			outreg(cap, GC_CAP_VCM,
+				inreg(cap, GC_CAP_VCM) | GC_VCM_VIE);
+		} else {
+			outreg(cap, GC_CAP_VCM,
+				inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 /* framebuffer ops */
 static struct fb_ops mb862xxfb_ops = {
 	.owner		= THIS_MODULE,
@@ -320,6 +411,7 @@ static struct fb_ops mb862xxfb_ops = {
 	.fb_fillrect	= cfb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
 	.fb_imageblit	= cfb_imageblit,
+	.fb_ioctl	= mb862xxfb_ioctl,
 };
 
 /* initialize fb_info data */
@@ -328,6 +420,7 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
 	struct mb862xxfb_par *par = fbi->par;
 	struct mb862xx_gc_mode *mode = par->gc_mode;
 	unsigned long reg;
+	int stride;
 
 	fbi->fbops = &mb862xxfb_ops;
 	fbi->pseudo_palette = par->pseudo_palette;
@@ -336,7 +429,6 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
 
 	strcpy(fbi->fix.id, DRV_NAME);
 	fbi->fix.smem_start = (unsigned long)par->fb_base_phys;
-	fbi->fix.smem_len = par->mapped_vram;
 	fbi->fix.mmio_start = (unsigned long)par->mmio_base_phys;
 	fbi->fix.mmio_len = par->mmio_len;
 	fbi->fix.accel = FB_ACCEL_NONE;
@@ -420,6 +512,28 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
 			 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
 	fbi->fix.line_length = (fbi->var.xres_virtual *
 				fbi->var.bits_per_pixel) / 8;
+	fbi->fix.smem_len = fbi->fix.line_length * fbi->var.yres_virtual;
+
+	/*
+	 * reserve space for capture buffers and two cursors
+	 * at the end of vram: 720x576 * 2 * 2.2 + 64x64 * 16.
+	 */
+	par->cap_buf = par->mapped_vram - 0x1bd800 - 0x10000;
+	par->cap_len = 0x1bd800;
+	par->l1_cfg.sx = 0;
+	par->l1_cfg.sy = 0;
+	par->l1_cfg.sw = 720;
+	par->l1_cfg.sh = 576;
+	par->l1_cfg.dx = 0;
+	par->l1_cfg.dy = 0;
+	par->l1_cfg.dw = 720;
+	par->l1_cfg.dh = 576;
+	stride = par->l1_cfg.sw * (fbi->var.bits_per_pixel / 8);
+	par->l1_stride = stride / 64 + ((stride % 64) ? 1 : 0);
+	outreg(cap, GC_CAP_CBM, GC_CBM_OO | GC_CBM_CBST |
+				(par->l1_stride << 16));
+	outreg(cap, GC_CAP_CBOA, par->cap_buf);
+	outreg(cap, GC_CAP_CBLA, par->cap_buf + par->cap_len);
 	return 0;
 }
 
@@ -742,22 +856,38 @@ static int coralp_init(struct mb862xxfb_par *par)
 
 	par->refclk = GC_DISP_REFCLK_400;
 
+	if (par->mapped_vram >= 0x2000000) {
+		/* relocate gdc registers space */
+		writel(1, par->fb_base + MB862XX_MMIO_BASE + GC_RSW);
+		udelay(1); /* wait at least 20 bus cycles */
+	}
+
 	ver = inreg(host, GC_CID);
 	cn = (ver & GC_CID_CNAME_MSK) >> 8;
 	ver = ver & GC_CID_VERSION_MSK;
 	if (cn == 3) {
+		unsigned long reg;
+
 		dev_info(par->dev, "Fujitsu Coral-%s GDC Rev.%d found\n",\
 			 (ver == 6) ? "P" : (ver == 8) ? "PA" : "?",
 			 par->pdev->revision);
-		outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133);
-		udelay(200);
-		outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL);
-		udelay(10);
+		reg = inreg(disp, GC_DCM1);
+		if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E)
+			par->pre_init = 1;
+
+		if (!par->pre_init) {
+			outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133);
+			udelay(200);
+			outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL);
+			udelay(10);
+		}
 		/* Clear interrupt status */
 		outreg(host, GC_IST, 0);
 	} else {
 		return -ENODEV;
 	}
+
+	mb862xx_i2c_init(par);
 	return 0;
 }
 
@@ -899,7 +1029,13 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
 	case PCI_DEVICE_ID_FUJITSU_CORALPA:
 		par->fb_base_phys = pci_resource_start(par->pdev, 0);
 		par->mapped_vram = CORALP_MEM_SIZE;
-		par->mmio_base_phys = par->fb_base_phys + MB862XX_MMIO_BASE;
+		if (par->mapped_vram >= 0x2000000) {
+			par->mmio_base_phys = par->fb_base_phys +
+					      MB862XX_MMIO_HIGH_BASE;
+		} else {
+			par->mmio_base_phys = par->fb_base_phys +
+					      MB862XX_MMIO_BASE;
+		}
 		par->mmio_len = MB862XX_MMIO_SIZE;
 		par->type = BT_CORALP;
 		break;
@@ -1009,6 +1145,8 @@ static void __devexit mb862xx_pci_remove(struct pci_dev *pdev)
 		outreg(host, GC_IMASK, 0);
 	}
 
+	mb862xx_i2c_exit(par);
+
 	device_remove_file(&pdev->dev, &dev_attr_dispregs);
 
 	pci_set_drvdata(pdev, NULL);

+ 2 - 2
drivers/video/omap/dispc.c

@@ -922,14 +922,14 @@ static int get_dss_clocks(void)
 		return PTR_ERR(dispc.dss_ick);
 	}
 
-	dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck");
+	dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "fck");
 	if (IS_ERR(dispc.dss1_fck)) {
 		dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
 		clk_put(dispc.dss_ick);
 		return PTR_ERR(dispc.dss1_fck);
 	}
 
-	dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_fck");
+	dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_clk");
 	if (IS_ERR(dispc.dss_54m_fck)) {
 		dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
 		clk_put(dispc.dss_ick);

+ 1 - 1
drivers/video/omap/omapfb_main.c

@@ -90,7 +90,7 @@ static void omapdss_release(struct device *dev)
 
 /* dummy device for clocks */
 static struct platform_device omapdss_device = {
-	.name		= "omapdss",
+	.name		= "omapdss_dss",
 	.id		= -1,
 	.dev            = {
 		.release = omapdss_release,

+ 1 - 1
drivers/video/omap/rfbi.c

@@ -90,7 +90,7 @@ static int rfbi_get_clocks(void)
 		return PTR_ERR(rfbi.dss_ick);
 	}
 
-	rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "dss1_fck");
+	rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "fck");
 	if (IS_ERR(rfbi.dss1_fck)) {
 		dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n");
 		clk_put(rfbi.dss_ick);

+ 2 - 2
drivers/video/omap2/Makefile

@@ -1,6 +1,6 @@
 obj-$(CONFIG_OMAP2_VRAM) += vram.o
 obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
 
-obj-y += dss/
-obj-y += omapfb/
+obj-$(CONFIG_OMAP2_DSS) += dss/
+obj-$(CONFIG_FB_OMAP2) += omapfb/
 obj-y += displays/

+ 5 - 4
drivers/video/omap2/displays/Kconfig

@@ -3,6 +3,7 @@ menu "OMAP2/3 Display Device Drivers"
 
 config PANEL_GENERIC_DPI
         tristate "Generic DPI Panel"
+	depends on OMAP2_DSS_DPI
         help
 	  Generic DPI panel driver.
 	  Supports DVI output for Beagle and OMAP3 SDP.
@@ -11,20 +12,20 @@ config PANEL_GENERIC_DPI
 
 config PANEL_LGPHILIPS_LB035Q02
 	tristate "LG.Philips LB035Q02 LCD Panel"
-	depends on OMAP2_DSS && SPI
+	depends on OMAP2_DSS_DPI && SPI
 	help
 	  LCD Panel used on the Gumstix Overo Palo35
 
 config PANEL_SHARP_LS037V7DW01
         tristate "Sharp LS037V7DW01 LCD Panel"
-        depends on OMAP2_DSS
+        depends on OMAP2_DSS_DPI
         select BACKLIGHT_CLASS_DEVICE
         help
           LCD Panel used in TI's SDP3430 and EVM boards
 
 config PANEL_NEC_NL8048HL11_01B
 	tristate "NEC NL8048HL11-01B Panel"
-	depends on OMAP2_DSS
+	depends on OMAP2_DSS_DPI
 	help
 		This NEC NL8048HL11-01B panel is TFT LCD
 		used in the Zoom2/3/3630 sdp boards.
@@ -37,7 +38,7 @@ config PANEL_TAAL
 
 config PANEL_TPO_TD043MTEA1
         tristate "TPO TD043MTEA1 LCD Panel"
-        depends on OMAP2_DSS && SPI
+        depends on OMAP2_DSS_DPI && SPI
         help
           LCD Panel used in OMAP3 Pandora
 

+ 1 - 1
drivers/video/omap2/displays/panel-acx565akm.c

@@ -30,7 +30,7 @@
 #include <linux/backlight.h>
 #include <linux/fb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define MIPID_CMD_READ_DISP_ID		0x04
 #define MIPID_CMD_READ_RED		0x06

+ 54 - 3
drivers/video/omap2/displays/panel-generic-dpi.c

@@ -33,8 +33,9 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <video/omapdss.h>
 
-#include <plat/panel-generic-dpi.h>
+#include <video/omap-panel-generic-dpi.h>
 
 struct panel_config {
 	struct omap_video_timings timings;
@@ -181,6 +182,56 @@ static struct panel_config generic_dpi_panels[] = {
 		.power_off_delay	= 0,
 		.name			= "samsung_lte430wq_f0c",
 	},
+
+	/* Seiko 70WVW1TZ3Z3 */
+	{
+		{
+			.x_res		= 800,
+			.y_res		= 480,
+
+			.pixel_clock	= 33000,
+
+			.hsw		= 128,
+			.hfp		= 10,
+			.hbp		= 10,
+
+			.vsw		= 2,
+			.vfp		= 4,
+			.vbp		= 11,
+		},
+		.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			= "seiko_70wvw1tz3",
+	},
+
+	/* Powertip PH480272T */
+	{
+		{
+			.x_res		= 480,
+			.y_res		= 272,
+
+			.pixel_clock	= 9000,
+
+			.hsw		= 40,
+			.hfp		= 2,
+			.hbp		= 2,
+
+			.vsw		= 10,
+			.vfp		= 2,
+			.vbp		= 2,
+		},
+		.acbi			= 0x0,
+		.acb			= 0x0,
+		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+					  OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
+		.power_on_delay		= 0,
+		.power_off_delay	= 0,
+		.name			= "powertip_ph480272t",
+	},
 };
 
 struct panel_drv_data {
@@ -285,7 +336,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
 	return 0;
 }
 
-static void generic_dpi_panel_remove(struct omap_dss_device *dssdev)
+static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 
@@ -358,7 +409,7 @@ static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
 
 static struct omap_dss_driver dpi_driver = {
 	.probe		= generic_dpi_panel_probe,
-	.remove		= generic_dpi_panel_remove,
+	.remove		= __exit_p(generic_dpi_panel_remove),
 
 	.enable		= generic_dpi_panel_enable,
 	.disable	= generic_dpi_panel_disable,

+ 1 - 1
drivers/video/omap2/displays/panel-lgphilips-lb035q02.c

@@ -21,7 +21,7 @@
 #include <linux/spi/spi.h>
 #include <linux/mutex.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 struct lb035q02_data {
 	struct mutex lock;

+ 1 - 1
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c

@@ -22,7 +22,7 @@
 #include <linux/backlight.h>
 #include <linux/fb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define LCD_XRES		800
 #define LCD_YRES		480

+ 3 - 3
drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c

@@ -25,7 +25,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 struct sharp_data {
 	struct backlight_device *bl;
@@ -120,7 +120,7 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
 	return 0;
 }
 
-static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
+static void __exit sharp_ls_panel_remove(struct omap_dss_device *dssdev)
 {
 	struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
 	struct backlight_device *bl = sd->bl;
@@ -205,7 +205,7 @@ static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
 
 static struct omap_dss_driver sharp_ls_driver = {
 	.probe		= sharp_ls_panel_probe,
-	.remove		= sharp_ls_panel_remove,
+	.remove		= __exit_p(sharp_ls_panel_remove),
 
 	.enable		= sharp_ls_panel_enable,
 	.disable	= sharp_ls_panel_disable,

+ 446 - 90
drivers/video/omap2/displays/panel-taal.c

@@ -33,8 +33,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/mutex.h>
 
-#include <plat/display.h>
-#include <plat/nokia-dsi-panel.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-nokia-dsi.h>
 
 /* DSI Virtual channel. Hardcoded for now. */
 #define TCH 0
@@ -63,12 +63,12 @@
 #define DCS_GET_ID2		0xdb
 #define DCS_GET_ID3		0xdc
 
-#define TAAL_ESD_CHECK_PERIOD	msecs_to_jiffies(5000)
-
 static irqreturn_t taal_te_isr(int irq, void *data);
 static void taal_te_timeout_work_callback(struct work_struct *work);
 static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
 
+static int taal_panel_reset(struct omap_dss_device *dssdev);
+
 struct panel_regulator {
 	struct regulator *regulator;
 	const char *name;
@@ -229,8 +229,14 @@ struct taal_data {
 
 	bool intro_printed;
 
-	struct workqueue_struct *esd_wq;
+	struct workqueue_struct *workqueue;
+
 	struct delayed_work esd_work;
+	unsigned esd_interval;
+
+	bool ulps_enabled;
+	unsigned ulps_timeout;
+	struct delayed_work ulps_work;
 
 	struct panel_config *panel_config;
 };
@@ -242,6 +248,7 @@ static inline struct nokia_dsi_panel_data
 }
 
 static void taal_esd_work(struct work_struct *work);
+static void taal_ulps_work(struct work_struct *work);
 
 static void hw_guard_start(struct taal_data *td, int guard_msec)
 {
@@ -264,7 +271,7 @@ 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(td->channel, dcs_cmd, buf, 1);
+	r = dsi_vc_dcs_read(td->dssdev, td->channel, dcs_cmd, buf, 1);
 
 	if (r < 0)
 		return r;
@@ -276,7 +283,7 @@ static int taal_dcs_read_1(struct taal_data *td, u8 dcs_cmd, u8 *data)
 
 static int taal_dcs_write_0(struct taal_data *td, u8 dcs_cmd)
 {
-	return dsi_vc_dcs_write(td->channel, &dcs_cmd, 1);
+	return dsi_vc_dcs_write(td->dssdev, td->channel, &dcs_cmd, 1);
 }
 
 static int taal_dcs_write_1(struct taal_data *td, u8 dcs_cmd, u8 param)
@@ -284,7 +291,7 @@ 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(td->channel, buf, 2);
+	return dsi_vc_dcs_write(td->dssdev, td->channel, buf, 2);
 }
 
 static int taal_sleep_in(struct taal_data *td)
@@ -296,7 +303,7 @@ static int taal_sleep_in(struct taal_data *td)
 	hw_guard_wait(td);
 
 	cmd = DCS_SLEEP_IN;
-	r = dsi_vc_dcs_write_nosync(td->channel, &cmd, 1);
+	r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, &cmd, 1);
 	if (r)
 		return r;
 
@@ -402,7 +409,7 @@ static int taal_set_update_window(struct taal_data *td,
 	buf[3] = (x2 >> 8) & 0xff;
 	buf[4] = (x2 >> 0) & 0xff;
 
-	r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
+	r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, buf, sizeof(buf));
 	if (r)
 		return r;
 
@@ -412,15 +419,132 @@ static int taal_set_update_window(struct taal_data *td,
 	buf[3] = (y2 >> 8) & 0xff;
 	buf[4] = (y2 >> 0) & 0xff;
 
-	r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
+	r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, buf, sizeof(buf));
 	if (r)
 		return r;
 
-	dsi_vc_send_bta_sync(td->channel);
+	dsi_vc_send_bta_sync(td->dssdev, td->channel);
 
 	return r;
 }
 
+static void taal_queue_esd_work(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	if (td->esd_interval > 0)
+		queue_delayed_work(td->workqueue, &td->esd_work,
+				msecs_to_jiffies(td->esd_interval));
+}
+
+static void taal_cancel_esd_work(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	cancel_delayed_work(&td->esd_work);
+}
+
+static void taal_queue_ulps_work(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	if (td->ulps_timeout > 0)
+		queue_delayed_work(td->workqueue, &td->ulps_work,
+				msecs_to_jiffies(td->ulps_timeout));
+}
+
+static void taal_cancel_ulps_work(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	cancel_delayed_work(&td->ulps_work);
+}
+
+static int taal_enter_ulps(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+	int r;
+
+	if (td->ulps_enabled)
+		return 0;
+
+	taal_cancel_ulps_work(dssdev);
+
+	r = _taal_enable_te(dssdev, false);
+	if (r)
+		goto err;
+
+	disable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+	omapdss_dsi_display_disable(dssdev, false, true);
+
+	td->ulps_enabled = true;
+
+	return 0;
+
+err:
+	dev_err(&dssdev->dev, "enter ULPS failed");
+	taal_panel_reset(dssdev);
+
+	td->ulps_enabled = false;
+
+	taal_queue_ulps_work(dssdev);
+
+	return r;
+}
+
+static int taal_exit_ulps(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+	int r;
+
+	if (!td->ulps_enabled)
+		return 0;
+
+	r = omapdss_dsi_display_enable(dssdev);
+	if (r)
+		goto err;
+
+	omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
+
+	r = _taal_enable_te(dssdev, true);
+	if (r)
+		goto err;
+
+	enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+	taal_queue_ulps_work(dssdev);
+
+	td->ulps_enabled = false;
+
+	return 0;
+
+err:
+	dev_err(&dssdev->dev, "exit ULPS failed");
+	r = taal_panel_reset(dssdev);
+
+	enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+	td->ulps_enabled = false;
+
+	taal_queue_ulps_work(dssdev);
+
+	return r;
+}
+
+static int taal_wake_up(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	if (td->ulps_enabled)
+		return taal_exit_ulps(dssdev);
+
+	taal_cancel_ulps_work(dssdev);
+	taal_queue_ulps_work(dssdev);
+	return 0;
+}
+
 static int taal_bl_update_status(struct backlight_device *dev)
 {
 	struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
@@ -441,9 +565,13 @@ static int taal_bl_update_status(struct backlight_device *dev)
 
 	if (td->use_dsi_bl) {
 		if (td->enabled) {
-			dsi_bus_lock();
-			r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
-			dsi_bus_unlock();
+			dsi_bus_lock(dssdev);
+
+			r = taal_wake_up(dssdev);
+			if (!r)
+				r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
+
+			dsi_bus_unlock(dssdev);
 		} else {
 			r = 0;
 		}
@@ -504,9 +632,13 @@ static ssize_t taal_num_errors_show(struct device *dev,
 	mutex_lock(&td->lock);
 
 	if (td->enabled) {
-		dsi_bus_lock();
-		r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
-		dsi_bus_unlock();
+		dsi_bus_lock(dssdev);
+
+		r = taal_wake_up(dssdev);
+		if (!r)
+			r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
+
+		dsi_bus_unlock(dssdev);
 	} else {
 		r = -ENODEV;
 	}
@@ -530,9 +662,13 @@ static ssize_t taal_hw_revision_show(struct device *dev,
 	mutex_lock(&td->lock);
 
 	if (td->enabled) {
-		dsi_bus_lock();
-		r = taal_get_id(td, &id1, &id2, &id3);
-		dsi_bus_unlock();
+		dsi_bus_lock(dssdev);
+
+		r = taal_wake_up(dssdev);
+		if (!r)
+			r = taal_get_id(td, &id1, &id2, &id3);
+
+		dsi_bus_unlock(dssdev);
 	} else {
 		r = -ENODEV;
 	}
@@ -579,6 +715,7 @@ static ssize_t store_cabc_mode(struct device *dev,
 	struct omap_dss_device *dssdev = to_dss_device(dev);
 	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
 	int i;
+	int r;
 
 	for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
 		if (sysfs_streq(cabc_modes[i], buf))
@@ -591,10 +728,19 @@ static ssize_t store_cabc_mode(struct device *dev,
 	mutex_lock(&td->lock);
 
 	if (td->enabled) {
-		dsi_bus_lock();
-		if (!td->cabc_broken)
-			taal_dcs_write_1(td, DCS_WRITE_CABC, i);
-		dsi_bus_unlock();
+		dsi_bus_lock(dssdev);
+
+		if (!td->cabc_broken) {
+			r = taal_wake_up(dssdev);
+			if (r)
+				goto err;
+
+			r = taal_dcs_write_1(td, DCS_WRITE_CABC, i);
+			if (r)
+				goto err;
+		}
+
+		dsi_bus_unlock(dssdev);
 	}
 
 	td->cabc_mode = i;
@@ -602,6 +748,10 @@ static ssize_t store_cabc_mode(struct device *dev,
 	mutex_unlock(&td->lock);
 
 	return count;
+err:
+	dsi_bus_unlock(dssdev);
+	mutex_unlock(&td->lock);
+	return r;
 }
 
 static ssize_t show_cabc_available_modes(struct device *dev,
@@ -620,18 +770,161 @@ static ssize_t show_cabc_available_modes(struct device *dev,
 	return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
 }
 
+static ssize_t taal_store_esd_interval(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	unsigned long t;
+	int r;
+
+	r = strict_strtoul(buf, 10, &t);
+	if (r)
+		return r;
+
+	mutex_lock(&td->lock);
+	taal_cancel_esd_work(dssdev);
+	td->esd_interval = t;
+	if (td->enabled)
+		taal_queue_esd_work(dssdev);
+	mutex_unlock(&td->lock);
+
+	return count;
+}
+
+static ssize_t taal_show_esd_interval(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned t;
+
+	mutex_lock(&td->lock);
+	t = td->esd_interval;
+	mutex_unlock(&td->lock);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t taal_store_ulps(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned long t;
+	int r;
+
+	r = strict_strtoul(buf, 10, &t);
+	if (r)
+		return r;
+
+	mutex_lock(&td->lock);
+
+	if (td->enabled) {
+		dsi_bus_lock(dssdev);
+
+		if (t)
+			r = taal_enter_ulps(dssdev);
+		else
+			r = taal_wake_up(dssdev);
+
+		dsi_bus_unlock(dssdev);
+	}
+
+	mutex_unlock(&td->lock);
+
+	if (r)
+		return r;
+
+	return count;
+}
+
+static ssize_t taal_show_ulps(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned t;
+
+	mutex_lock(&td->lock);
+	t = td->ulps_enabled;
+	mutex_unlock(&td->lock);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t taal_store_ulps_timeout(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned long t;
+	int r;
+
+	r = strict_strtoul(buf, 10, &t);
+	if (r)
+		return r;
+
+	mutex_lock(&td->lock);
+	td->ulps_timeout = t;
+
+	if (td->enabled) {
+		/* taal_wake_up will restart the timer */
+		dsi_bus_lock(dssdev);
+		r = taal_wake_up(dssdev);
+		dsi_bus_unlock(dssdev);
+	}
+
+	mutex_unlock(&td->lock);
+
+	if (r)
+		return r;
+
+	return count;
+}
+
+static ssize_t taal_show_ulps_timeout(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned t;
+
+	mutex_lock(&td->lock);
+	t = td->ulps_timeout;
+	mutex_unlock(&td->lock);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
 static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
 static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
 static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
 		show_cabc_mode, store_cabc_mode);
 static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
 		show_cabc_available_modes, NULL);
+static DEVICE_ATTR(esd_interval, S_IRUGO | S_IWUSR,
+		taal_show_esd_interval, taal_store_esd_interval);
+static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
+		taal_show_ulps, taal_store_ulps);
+static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,
+		taal_show_ulps_timeout, taal_store_ulps_timeout);
 
 static struct attribute *taal_attrs[] = {
 	&dev_attr_num_dsi_errors.attr,
 	&dev_attr_hw_revision.attr,
 	&dev_attr_cabc_mode.attr,
 	&dev_attr_cabc_available_modes.attr,
+	&dev_attr_esd_interval.attr,
+	&dev_attr_ulps.attr,
+	&dev_attr_ulps_timeout.attr,
 	NULL,
 };
 
@@ -700,6 +993,9 @@ static int taal_probe(struct omap_dss_device *dssdev)
 	}
 	td->dssdev = dssdev;
 	td->panel_config = panel_config;
+	td->esd_interval = panel_data->esd_interval;
+	td->ulps_enabled = false;
+	td->ulps_timeout = panel_data->ulps_timeout;
 
 	mutex_init(&td->lock);
 
@@ -710,13 +1006,14 @@ static int taal_probe(struct omap_dss_device *dssdev)
 	if (r)
 		goto err_reg;
 
-	td->esd_wq = create_singlethread_workqueue("taal_esd");
-	if (td->esd_wq == NULL) {
+	td->workqueue = create_singlethread_workqueue("taal_esd");
+	if (td->workqueue == NULL) {
 		dev_err(&dssdev->dev, "can't create ESD workqueue\n");
 		r = -ENOMEM;
 		goto err_wq;
 	}
 	INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
+	INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work);
 
 	dev_set_drvdata(&dssdev->dev, td);
 
@@ -734,8 +1031,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
 		props.max_brightness = 127;
 
 	props.type = BACKLIGHT_RAW;
-	bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
-					  &taal_bl_ops, &props);
+	bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev,
+					dssdev, &taal_bl_ops, &props);
 	if (IS_ERR(bldev)) {
 		r = PTR_ERR(bldev);
 		goto err_bl;
@@ -810,7 +1107,7 @@ err_irq:
 err_gpio:
 	backlight_device_unregister(bldev);
 err_bl:
-	destroy_workqueue(td->esd_wq);
+	destroy_workqueue(td->workqueue);
 err_wq:
 	free_regulators(panel_config->regulators, panel_config->num_regulators);
 err_reg:
@@ -819,7 +1116,7 @@ err:
 	return r;
 }
 
-static void taal_remove(struct omap_dss_device *dssdev)
+static void __exit taal_remove(struct omap_dss_device *dssdev)
 {
 	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
 	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
@@ -841,8 +1138,9 @@ static void taal_remove(struct omap_dss_device *dssdev)
 	taal_bl_update_status(bldev);
 	backlight_device_unregister(bldev);
 
-	cancel_delayed_work(&td->esd_work);
-	destroy_workqueue(td->esd_wq);
+	taal_cancel_ulps_work(dssdev);
+	taal_cancel_esd_work(dssdev);
+	destroy_workqueue(td->workqueue);
 
 	/* reset, to be sure that the panel is in a valid state */
 	taal_hw_reset(dssdev);
@@ -867,7 +1165,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
 
 	taal_hw_reset(dssdev);
 
-	omapdss_dsi_vc_enable_hs(td->channel, false);
+	omapdss_dsi_vc_enable_hs(dssdev, td->channel, false);
 
 	r = taal_sleep_out(td);
 	if (r)
@@ -924,7 +1222,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
 		td->intro_printed = true;
 	}
 
-	omapdss_dsi_vc_enable_hs(td->channel, true);
+	omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
 
 	return 0;
 err:
@@ -932,7 +1230,7 @@ err:
 
 	taal_hw_reset(dssdev);
 
-	omapdss_dsi_display_disable(dssdev);
+	omapdss_dsi_display_disable(dssdev, true, false);
 err0:
 	return r;
 }
@@ -955,15 +1253,23 @@ static void taal_power_off(struct omap_dss_device *dssdev)
 		taal_hw_reset(dssdev);
 	}
 
-	omapdss_dsi_display_disable(dssdev);
+	omapdss_dsi_display_disable(dssdev, true, false);
 
 	td->enabled = 0;
 }
 
+static int taal_panel_reset(struct omap_dss_device *dssdev)
+{
+	dev_err(&dssdev->dev, "performing LCD reset\n");
+
+	taal_power_off(dssdev);
+	taal_hw_reset(dssdev);
+	return taal_power_on(dssdev);
+}
+
 static int taal_enable(struct omap_dss_device *dssdev)
 {
 	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
 	int r;
 
 	dev_dbg(&dssdev->dev, "enable\n");
@@ -975,18 +1281,16 @@ static int taal_enable(struct omap_dss_device *dssdev)
 		goto err;
 	}
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
 
 	r = taal_power_on(dssdev);
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 
 	if (r)
 		goto err;
 
-	if (panel_data->use_esd_check)
-		queue_delayed_work(td->esd_wq, &td->esd_work,
-				TAAL_ESD_CHECK_PERIOD);
+	taal_queue_esd_work(dssdev);
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
@@ -1007,14 +1311,17 @@ static void taal_disable(struct omap_dss_device *dssdev)
 
 	mutex_lock(&td->lock);
 
-	cancel_delayed_work(&td->esd_work);
+	taal_cancel_ulps_work(dssdev);
+	taal_cancel_esd_work(dssdev);
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
 
-	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+		taal_wake_up(dssdev);
 		taal_power_off(dssdev);
+	}
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 
@@ -1035,13 +1342,16 @@ static int taal_suspend(struct omap_dss_device *dssdev)
 		goto err;
 	}
 
-	cancel_delayed_work(&td->esd_work);
+	taal_cancel_ulps_work(dssdev);
+	taal_cancel_esd_work(dssdev);
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
 
-	taal_power_off(dssdev);
+	r = taal_wake_up(dssdev);
+	if (!r)
+		taal_power_off(dssdev);
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 
 	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
 
@@ -1056,7 +1366,6 @@ err:
 static int taal_resume(struct omap_dss_device *dssdev)
 {
 	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
 	int r;
 
 	dev_dbg(&dssdev->dev, "resume\n");
@@ -1068,19 +1377,17 @@ static int taal_resume(struct omap_dss_device *dssdev)
 		goto err;
 	}
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
 
 	r = taal_power_on(dssdev);
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 
 	if (r) {
 		dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 	} else {
 		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-		if (panel_data->use_esd_check)
-			queue_delayed_work(td->esd_wq, &td->esd_work,
-					TAAL_ESD_CHECK_PERIOD);
+		taal_queue_esd_work(dssdev);
 	}
 
 	mutex_unlock(&td->lock);
@@ -1095,7 +1402,7 @@ static void taal_framedone_cb(int err, void *data)
 {
 	struct omap_dss_device *dssdev = data;
 	dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 }
 
 static irqreturn_t taal_te_isr(int irq, void *data)
@@ -1123,7 +1430,7 @@ static irqreturn_t taal_te_isr(int irq, void *data)
 	return IRQ_HANDLED;
 err:
 	dev_err(&dssdev->dev, "start update failed\n");
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 	return IRQ_HANDLED;
 }
 
@@ -1136,7 +1443,7 @@ static void taal_te_timeout_work_callback(struct work_struct *work)
 	dev_err(&dssdev->dev, "TE not received for 250ms!\n");
 
 	atomic_set(&td->do_update, 0);
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 }
 
 static int taal_update(struct omap_dss_device *dssdev,
@@ -1149,7 +1456,11 @@ static int taal_update(struct omap_dss_device *dssdev,
 	dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
 
 	mutex_lock(&td->lock);
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
+
+	r = taal_wake_up(dssdev);
+	if (r)
+		goto err;
 
 	if (!td->enabled) {
 		r = 0;
@@ -1184,7 +1495,7 @@ static int taal_update(struct omap_dss_device *dssdev,
 	mutex_unlock(&td->lock);
 	return 0;
 err:
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 	mutex_unlock(&td->lock);
 	return r;
 }
@@ -1196,8 +1507,8 @@ static int taal_sync(struct omap_dss_device *dssdev)
 	dev_dbg(&dssdev->dev, "sync\n");
 
 	mutex_lock(&td->lock);
-	dsi_bus_lock();
-	dsi_bus_unlock();
+	dsi_bus_lock(dssdev);
+	dsi_bus_unlock(dssdev);
 	mutex_unlock(&td->lock);
 
 	dev_dbg(&dssdev->dev, "sync done\n");
@@ -1235,9 +1546,13 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
 	if (td->te_enabled == enable)
 		goto end;
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
 
 	if (td->enabled) {
+		r = taal_wake_up(dssdev);
+		if (r)
+			goto err;
+
 		r = _taal_enable_te(dssdev, enable);
 		if (r)
 			goto err;
@@ -1245,13 +1560,13 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
 
 	td->te_enabled = enable;
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 end:
 	mutex_unlock(&td->lock);
 
 	return 0;
 err:
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 	mutex_unlock(&td->lock);
 
 	return r;
@@ -1281,9 +1596,13 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
 	if (td->rotate == rotate)
 		goto end;
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
 
 	if (td->enabled) {
+		r = taal_wake_up(dssdev);
+		if (r)
+			goto err;
+
 		r = taal_set_addr_mode(td, rotate, td->mirror);
 		if (r)
 			goto err;
@@ -1291,12 +1610,12 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
 
 	td->rotate = rotate;
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 end:
 	mutex_unlock(&td->lock);
 	return 0;
 err:
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 	mutex_unlock(&td->lock);
 	return r;
 }
@@ -1325,8 +1644,12 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
 	if (td->mirror == enable)
 		goto end;
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
 	if (td->enabled) {
+		r = taal_wake_up(dssdev);
+		if (r)
+			goto err;
+
 		r = taal_set_addr_mode(td, td->rotate, enable);
 		if (r)
 			goto err;
@@ -1334,12 +1657,12 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
 
 	td->mirror = enable;
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 end:
 	mutex_unlock(&td->lock);
 	return 0;
 err:
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 	mutex_unlock(&td->lock);
 	return r;
 }
@@ -1369,7 +1692,11 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
 		goto err1;
 	}
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
+
+	r = taal_wake_up(dssdev);
+	if (r)
+		goto err2;
 
 	r = taal_dcs_read_1(td, DCS_GET_ID1, &id1);
 	if (r)
@@ -1381,11 +1708,11 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
 	if (r)
 		goto err2;
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 	mutex_unlock(&td->lock);
 	return 0;
 err2:
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 err1:
 	mutex_unlock(&td->lock);
 	return r;
@@ -1415,7 +1742,11 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
 			dssdev->panel.timings.x_res *
 			dssdev->panel.timings.y_res * 3);
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
+
+	r = taal_wake_up(dssdev);
+	if (r)
+		goto err2;
 
 	/* plen 1 or 2 goes into short packet. until checksum error is fixed,
 	 * use short packets. plen 32 works, but bigger packets seem to cause
@@ -1427,7 +1758,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
 
 	taal_set_update_window(td, x, y, w, h);
 
-	r = dsi_vc_set_max_rx_packet_size(td->channel, plen);
+	r = dsi_vc_set_max_rx_packet_size(dssdev, td->channel, plen);
 	if (r)
 		goto err2;
 
@@ -1435,7 +1766,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
 		u8 dcs_cmd = first ? 0x2e : 0x3e;
 		first = 0;
 
-		r = dsi_vc_dcs_read(td->channel, dcs_cmd,
+		r = dsi_vc_dcs_read(dssdev, td->channel, dcs_cmd,
 				buf + buf_used, size - buf_used);
 
 		if (r < 0) {
@@ -1461,14 +1792,35 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
 	r = buf_used;
 
 err3:
-	dsi_vc_set_max_rx_packet_size(td->channel, 1);
+	dsi_vc_set_max_rx_packet_size(dssdev, td->channel, 1);
 err2:
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 err1:
 	mutex_unlock(&td->lock);
 	return r;
 }
 
+static void taal_ulps_work(struct work_struct *work)
+{
+	struct taal_data *td = container_of(work, struct taal_data,
+			ulps_work.work);
+	struct omap_dss_device *dssdev = td->dssdev;
+
+	mutex_lock(&td->lock);
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !td->enabled) {
+		mutex_unlock(&td->lock);
+		return;
+	}
+
+	dsi_bus_lock(dssdev);
+
+	taal_enter_ulps(dssdev);
+
+	dsi_bus_unlock(dssdev);
+	mutex_unlock(&td->lock);
+}
+
 static void taal_esd_work(struct work_struct *work)
 {
 	struct taal_data *td = container_of(work, struct taal_data,
@@ -1485,7 +1837,13 @@ static void taal_esd_work(struct work_struct *work)
 		return;
 	}
 
-	dsi_bus_lock();
+	dsi_bus_lock(dssdev);
+
+	r = taal_wake_up(dssdev);
+	if (r) {
+		dev_err(&dssdev->dev, "failed to exit ULPS\n");
+		goto err;
+	}
 
 	r = taal_dcs_read_1(td, DCS_RDDSDR, &state1);
 	if (r) {
@@ -1521,22 +1879,20 @@ static void taal_esd_work(struct work_struct *work)
 			goto err;
 	}
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 
-	queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+	taal_queue_esd_work(dssdev);
 
 	mutex_unlock(&td->lock);
 	return;
 err:
 	dev_err(&dssdev->dev, "performing LCD reset\n");
 
-	taal_power_off(dssdev);
-	taal_hw_reset(dssdev);
-	taal_power_on(dssdev);
+	taal_panel_reset(dssdev);
 
-	dsi_bus_unlock();
+	dsi_bus_unlock(dssdev);
 
-	queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+	taal_queue_esd_work(dssdev);
 
 	mutex_unlock(&td->lock);
 }
@@ -1557,7 +1913,7 @@ static enum omap_dss_update_mode taal_get_update_mode(
 
 static struct omap_dss_driver taal_driver = {
 	.probe		= taal_probe,
-	.remove		= taal_remove,
+	.remove		= __exit_p(taal_remove),
 
 	.enable		= taal_enable,
 	.disable	= taal_disable,

+ 6 - 4
drivers/video/omap2/displays/panel-tpo-td043mtea1.c

@@ -17,7 +17,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define TPO_R02_MODE(x)		((x) & 7)
 #define TPO_R02_MODE_800x480	7
@@ -144,13 +144,15 @@ static ssize_t tpo_td043_vmirror_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
-	long val;
+	int val;
 	int ret;
 
-	ret = strict_strtol(buf, 0, &val);
+	ret = kstrtoint(buf, 0, &val);
 	if (ret < 0)
 		return ret;
 
+	val = !!val;
+
 	ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val);
 	if (ret < 0)
 		return ret;
@@ -175,7 +177,7 @@ static ssize_t tpo_td043_mode_store(struct device *dev,
 	long val;
 	int ret;
 
-	ret = strict_strtol(buf, 0, &val);
+	ret = kstrtol(buf, 0, &val);
 	if (ret != 0 || val & ~7)
 		return -EINVAL;
 

+ 24 - 9
drivers/video/omap2/dss/Kconfig

@@ -80,7 +80,7 @@ config OMAP2_DSS_SDI
 
 config OMAP2_DSS_DSI
 	bool "DSI support"
-	depends on ARCH_OMAP3
+	depends on ARCH_OMAP3 || ARCH_OMAP4
         default n
 	help
 	  MIPI DSI (Display Serial Interface) support.
@@ -90,14 +90,6 @@ config OMAP2_DSS_DSI
 
 	  See http://www.mipi.org/ for DSI spesifications.
 
-config OMAP2_DSS_USE_DSI_PLL
-	bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
-	default n
-	depends on OMAP2_DSS_DSI
-	help
-	  Use DSI PLL to generate pixel clock.  Currently only for DPI output.
-	  DSI PLL can be used to generate higher and more precise pixel clocks.
-
 config OMAP2_DSS_FAKE_VSYNC
 	bool "Fake VSYNC irq from manual update displays"
 	default n
@@ -125,4 +117,27 @@ config OMAP2_DSS_MIN_FCK_PER_PCK
 	  Max FCK is 173MHz, so this doesn't work if your PCK
 	  is very high.
 
+config OMAP2_DSS_SLEEP_BEFORE_RESET
+	bool "Sleep 50ms before DSS reset"
+	default y
+	help
+	  For some unknown reason we may get SYNC_LOST errors from the display
+	  subsystem at initialization time if we don't sleep before resetting
+	  the DSS. See the source (dss.c) for more comments.
+
+	  However, 50ms is quite long time to sleep, and with some
+	  configurations the SYNC_LOST may never happen, so the sleep can
+	  be disabled here.
+
+config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
+	bool "Sleep 20ms after VENC reset"
+	default y
+	help
+	  There is a 20ms sleep after VENC reset which seemed to fix the
+	  reset. The reason for the bug is unclear, and it's also unclear
+	  on what platforms this happens.
+
+	  This option enables the sleep, and is enabled by default. You can
+	  disable the sleep if it doesn't cause problems on your platform.
+
 endif

+ 8 - 7
drivers/video/omap2/dss/core.c

@@ -33,7 +33,7 @@
 #include <linux/device.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "dss.h"
 #include "dss_features.h"
@@ -54,6 +54,9 @@ unsigned int dss_debug;
 module_param_named(debug, dss_debug, bool, 0644);
 #endif
 
+static int omap_dss_register_device(struct omap_dss_device *);
+static void omap_dss_unregister_device(struct omap_dss_device *);
+
 /* REGULATORS */
 
 struct regulator *dss_get_vdds_dsi(void)
@@ -124,8 +127,7 @@ static int dss_initialize_debugfs(void)
 #endif
 
 #if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS)
-	debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir,
-			&dsi_dump_irqs, &dss_debug_fops);
+	dsi_create_debugfs_files_irq(dss_debugfs_dir, &dss_debug_fops);
 #endif
 
 	debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
@@ -137,8 +139,7 @@ static int dss_initialize_debugfs(void)
 			&rfbi_dump_regs, &dss_debug_fops);
 #endif
 #ifdef CONFIG_OMAP2_DSS_DSI
-	debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
-			&dsi_dump_regs, &dss_debug_fops);
+	dsi_create_debugfs_files_reg(dss_debugfs_dir, &dss_debug_fops);
 #endif
 #ifdef CONFIG_OMAP2_DSS_VENC
 	debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
@@ -480,7 +481,7 @@ static void omap_dss_dev_release(struct device *dev)
 	reset_device(dev, 0);
 }
 
-int omap_dss_register_device(struct omap_dss_device *dssdev)
+static int omap_dss_register_device(struct omap_dss_device *dssdev)
 {
 	static int dev_num;
 
@@ -494,7 +495,7 @@ int omap_dss_register_device(struct omap_dss_device *dssdev)
 	return device_register(&dssdev->dev);
 }
 
-void omap_dss_unregister_device(struct omap_dss_device *dssdev)
+static void omap_dss_unregister_device(struct omap_dss_device *dssdev)
 {
 	device_unregister(&dssdev->dev);
 }

File diff suppressed because it is too large
+ 442 - 455
drivers/video/omap2/dss/dispc.c


+ 691 - 0
drivers/video/omap2/dss/dispc.h

@@ -0,0 +1,691 @@
+/*
+ * linux/drivers/video/omap2/dss/dispc.h
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Archit Taneja <archit@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 __OMAP2_DISPC_REG_H
+#define __OMAP2_DISPC_REG_H
+
+/* DISPC common registers */
+#define DISPC_REVISION			0x0000
+#define DISPC_SYSCONFIG			0x0010
+#define DISPC_SYSSTATUS			0x0014
+#define DISPC_IRQSTATUS			0x0018
+#define DISPC_IRQENABLE			0x001C
+#define DISPC_CONTROL			0x0040
+#define DISPC_CONFIG			0x0044
+#define DISPC_CAPABLE			0x0048
+#define DISPC_LINE_STATUS		0x005C
+#define DISPC_LINE_NUMBER		0x0060
+#define DISPC_GLOBAL_ALPHA		0x0074
+#define DISPC_CONTROL2			0x0238
+#define DISPC_CONFIG2			0x0620
+#define DISPC_DIVISOR			0x0804
+
+/* DISPC overlay registers */
+#define DISPC_OVL_BA0(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_BA0_OFFSET(n))
+#define DISPC_OVL_BA1(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_BA1_OFFSET(n))
+#define DISPC_OVL_BA0_UV(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_BA0_UV_OFFSET(n))
+#define DISPC_OVL_BA1_UV(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_BA1_UV_OFFSET(n))
+#define DISPC_OVL_POSITION(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_POS_OFFSET(n))
+#define DISPC_OVL_SIZE(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_SIZE_OFFSET(n))
+#define DISPC_OVL_ATTRIBUTES(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_ATTR_OFFSET(n))
+#define DISPC_OVL_ATTRIBUTES2(n)	(DISPC_OVL_BASE(n) + \
+					DISPC_ATTR2_OFFSET(n))
+#define DISPC_OVL_FIFO_THRESHOLD(n)	(DISPC_OVL_BASE(n) + \
+					DISPC_FIFO_THRESH_OFFSET(n))
+#define DISPC_OVL_FIFO_SIZE_STATUS(n)	(DISPC_OVL_BASE(n) + \
+					DISPC_FIFO_SIZE_STATUS_OFFSET(n))
+#define DISPC_OVL_ROW_INC(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_ROW_INC_OFFSET(n))
+#define DISPC_OVL_PIXEL_INC(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_PIX_INC_OFFSET(n))
+#define DISPC_OVL_WINDOW_SKIP(n)	(DISPC_OVL_BASE(n) + \
+					DISPC_WINDOW_SKIP_OFFSET(n))
+#define DISPC_OVL_TABLE_BA(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_TABLE_BA_OFFSET(n))
+#define DISPC_OVL_FIR(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_FIR_OFFSET(n))
+#define DISPC_OVL_FIR2(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_FIR2_OFFSET(n))
+#define DISPC_OVL_PICTURE_SIZE(n)	(DISPC_OVL_BASE(n) + \
+					DISPC_PIC_SIZE_OFFSET(n))
+#define DISPC_OVL_ACCU0(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_ACCU0_OFFSET(n))
+#define DISPC_OVL_ACCU1(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_ACCU1_OFFSET(n))
+#define DISPC_OVL_ACCU2_0(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_ACCU2_0_OFFSET(n))
+#define DISPC_OVL_ACCU2_1(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_ACCU2_1_OFFSET(n))
+#define DISPC_OVL_FIR_COEF_H(n, i)	(DISPC_OVL_BASE(n) + \
+					DISPC_FIR_COEF_H_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_HV(n, i)	(DISPC_OVL_BASE(n) + \
+					DISPC_FIR_COEF_HV_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_H2(n, i)	(DISPC_OVL_BASE(n) + \
+					DISPC_FIR_COEF_H2_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_HV2(n, i)	(DISPC_OVL_BASE(n) + \
+					DISPC_FIR_COEF_HV2_OFFSET(n, i))
+#define DISPC_OVL_CONV_COEF(n, i)	(DISPC_OVL_BASE(n) + \
+					DISPC_CONV_COEF_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_V(n, i)	(DISPC_OVL_BASE(n) + \
+					DISPC_FIR_COEF_V_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_V2(n, i)	(DISPC_OVL_BASE(n) + \
+					DISPC_FIR_COEF_V2_OFFSET(n, i))
+#define DISPC_OVL_PRELOAD(n)		(DISPC_OVL_BASE(n) + \
+					DISPC_PRELOAD_OFFSET(n))
+
+/* DISPC manager/channel specific registers */
+static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x004C;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		return 0x0050;
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x03AC;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x0054;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		return 0x0058;
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x03B0;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_TIMING_H(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x0064;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x0400;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_TIMING_V(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x0068;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x0404;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_POL_FREQ(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x006C;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x0408;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_DIVISORo(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x0070;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x040C;
+	default:
+		BUG();
+	}
+}
+
+/* Named as DISPC_SIZE_LCD, DISPC_SIZE_DIGIT and DISPC_SIZE_LCD2 in TRM */
+static inline u16 DISPC_SIZE_MGR(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x007C;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		return 0x0078;
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x03CC;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x01D4;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x03C0;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x01D8;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x03C4;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x01DC;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x03C8;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x0220;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x03BC;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x0224;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x03B8;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel)
+{
+	switch (channel) {
+	case OMAP_DSS_CHANNEL_LCD:
+		return 0x0228;
+	case OMAP_DSS_CHANNEL_DIGIT:
+		BUG();
+	case OMAP_DSS_CHANNEL_LCD2:
+		return 0x03B4;
+	default:
+		BUG();
+	}
+}
+
+/* DISPC overlay register base addresses */
+static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		return 0x0080;
+	case OMAP_DSS_VIDEO1:
+		return 0x00BC;
+	case OMAP_DSS_VIDEO2:
+		return 0x014C;
+	default:
+		BUG();
+	}
+}
+
+/* DISPC overlay register offsets */
+static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0000;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0004;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x0544;
+	case OMAP_DSS_VIDEO2:
+		return 0x04BC;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x0548;
+	case OMAP_DSS_VIDEO2:
+		return 0x04C0;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0008;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x000C;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		return 0x0020;
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0010;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x0568;
+	case OMAP_DSS_VIDEO2:
+		return 0x04DC;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		return 0x0024;
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0014;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		return 0x0028;
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0018;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		return 0x002C;
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x001C;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		return 0x0030;
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0020;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		return 0x0034;
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		BUG();
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		return 0x0038;
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		BUG();
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0024;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x0580;
+	case OMAP_DSS_VIDEO2:
+		return 0x055C;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0028;
+	default:
+		BUG();
+	}
+}
+
+
+static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x002C;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x0584;
+	case OMAP_DSS_VIDEO2:
+		return 0x0560;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0030;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x0588;
+	case OMAP_DSS_VIDEO2:
+		return 0x0564;
+	default:
+		BUG();
+	}
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0034 + i * 0x8;
+	default:
+		BUG();
+	}
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x058C + i * 0x8;
+	case OMAP_DSS_VIDEO2:
+		return 0x0568 + i * 0x8;
+	default:
+		BUG();
+	}
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0038 + i * 0x8;
+	default:
+		BUG();
+	}
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x0590 + i * 8;
+	case OMAP_DSS_VIDEO2:
+		return 0x056C + i * 0x8;
+	default:
+		BUG();
+	}
+}
+
+/* coef index i = {0, 1, 2, 3, 4,} */
+static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+	case OMAP_DSS_VIDEO2:
+		return 0x0074 + i * 0x4;
+	default:
+		BUG();
+	}
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x0124 + i * 0x4;
+	case OMAP_DSS_VIDEO2:
+		return 0x00B4 + i * 0x4;
+	default:
+		BUG();
+	}
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		BUG();
+	case OMAP_DSS_VIDEO1:
+		return 0x05CC + i * 0x4;
+	case OMAP_DSS_VIDEO2:
+		return 0x05A8 + i * 0x4;
+	default:
+		BUG();
+	}
+}
+
+static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
+{
+	switch (plane) {
+	case OMAP_DSS_GFX:
+		return 0x01AC;
+	case OMAP_DSS_VIDEO1:
+		return 0x0174;
+	case OMAP_DSS_VIDEO2:
+		return 0x00E8;
+	default:
+		BUG();
+	}
+}
+#endif

+ 30 - 16
drivers/video/omap2/dss/display.c

@@ -27,7 +27,7 @@
 #include <linux/jiffies.h>
 #include <linux/platform_device.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include "dss.h"
 
 static ssize_t display_enabled_show(struct device *dev,
@@ -44,9 +44,13 @@ static ssize_t display_enabled_store(struct device *dev,
 		const char *buf, size_t size)
 {
 	struct omap_dss_device *dssdev = to_dss_device(dev);
-	bool enabled, r;
+	int r, enabled;
 
-	enabled = simple_strtoul(buf, NULL, 10);
+	r = kstrtoint(buf, 0, &enabled);
+	if (r)
+		return r;
+
+	enabled = !!enabled;
 
 	if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
 		if (enabled) {
@@ -82,7 +86,9 @@ static ssize_t display_upd_mode_store(struct device *dev,
 	if (!dssdev->driver->set_update_mode)
 		return -EINVAL;
 
-	val = simple_strtoul(buf, NULL, 10);
+	r = kstrtoint(buf, 0, &val);
+	if (r)
+		return r;
 
 	switch (val) {
 	case OMAP_DSS_UPDATE_DISABLED:
@@ -114,13 +120,16 @@ static ssize_t display_tear_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t size)
 {
 	struct omap_dss_device *dssdev = to_dss_device(dev);
-	unsigned long te;
-	int r;
+	int te, r;
 
 	if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
 		return -ENOENT;
 
-	te = simple_strtoul(buf, NULL, 0);
+	r = kstrtoint(buf, 0, &te);
+	if (r)
+		return r;
+
+	te = !!te;
 
 	r = dssdev->driver->enable_te(dssdev, te);
 	if (r)
@@ -196,13 +205,14 @@ static ssize_t display_rotate_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t size)
 {
 	struct omap_dss_device *dssdev = to_dss_device(dev);
-	unsigned long rot;
-	int r;
+	int rot, r;
 
 	if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
 		return -ENOENT;
 
-	rot = simple_strtoul(buf, NULL, 0);
+	r = kstrtoint(buf, 0, &rot);
+	if (r)
+		return r;
 
 	r = dssdev->driver->set_rotate(dssdev, rot);
 	if (r)
@@ -226,13 +236,16 @@ static ssize_t display_mirror_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t size)
 {
 	struct omap_dss_device *dssdev = to_dss_device(dev);
-	unsigned long mirror;
-	int r;
+	int mirror, r;
 
 	if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
 		return -ENOENT;
 
-	mirror = simple_strtoul(buf, NULL, 0);
+	r = kstrtoint(buf, 0, &mirror);
+	if (r)
+		return r;
+
+	mirror = !!mirror;
 
 	r = dssdev->driver->set_mirror(dssdev, mirror);
 	if (r)
@@ -259,14 +272,15 @@ static ssize_t display_wss_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t size)
 {
 	struct omap_dss_device *dssdev = to_dss_device(dev);
-	unsigned long wss;
+	u32 wss;
 	int r;
 
 	if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
 		return -ENOENT;
 
-	if (strict_strtoul(buf, 0, &wss))
-		return -EINVAL;
+	r = kstrtou32(buf, 0, &wss);
+	if (r)
+		return r;
 
 	if (wss > 0xfffff)
 		return -EINVAL;

+ 68 - 45
drivers/video/omap2/dss/dpi.c

@@ -30,16 +30,40 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
 
 static struct {
 	struct regulator *vdds_dsi_reg;
+	struct platform_device *dsidev;
 } dpi;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
+{
+	int dsi_module;
+
+	dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1;
+
+	return dsi_get_dsidev_from_id(dsi_module);
+}
+
+static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)
+{
+	if (dssdev->clocks.dispc.dispc_fclk_src ==
+			OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
+			dssdev->clocks.dispc.dispc_fclk_src ==
+			OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC ||
+			dssdev->clocks.dispc.channel.lcd_clk_src ==
+			OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
+			dssdev->clocks.dispc.channel.lcd_clk_src ==
+			OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC)
+		return true;
+	else
+		return false;
+}
+
 static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
 		unsigned long pck_req, unsigned long *fck, int *lck_div,
 		int *pck_div)
@@ -48,16 +72,16 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
 	struct dispc_clock_info dispc_cinfo;
 	int r;
 
-	r = dsi_pll_calc_clock_div_pck(is_tft, pck_req, &dsi_cinfo,
-			&dispc_cinfo);
+	r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft, pck_req,
+			&dsi_cinfo, &dispc_cinfo);
 	if (r)
 		return r;
 
-	r = dsi_pll_set_clock_div(&dsi_cinfo);
+	r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
 	if (r)
 		return r;
 
-	dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
+	dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
 
 	r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
 	if (r)
@@ -69,7 +93,7 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
 
 	return 0;
 }
-#else
+
 static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,
 		unsigned long pck_req, unsigned long *fck, int *lck_div,
 		int *pck_div)
@@ -96,13 +120,12 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,
 
 	return 0;
 }
-#endif
 
 static int dpi_set_mode(struct omap_dss_device *dssdev)
 {
 	struct omap_video_timings *t = &dssdev->panel.timings;
-	int lck_div, pck_div;
-	unsigned long fck;
+	int lck_div = 0, pck_div = 0;
+	unsigned long fck = 0;
 	unsigned long pck;
 	bool is_tft;
 	int r = 0;
@@ -114,13 +137,12 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
 
 	is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-	r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
-			&lck_div, &pck_div);
-#else
-	r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
-			&lck_div, &pck_div);
-#endif
+	if (dpi_use_dsi_pll(dssdev))
+		r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000,
+				&fck, &lck_div, &pck_div);
+	else
+		r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000,
+				&fck, &lck_div, &pck_div);
 	if (r)
 		goto err0;
 
@@ -179,12 +201,13 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 	if (r)
 		goto err2;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-	dss_clk_enable(DSS_CLK_SYSCK);
-	r = dsi_pll_init(dssdev, 0, 1);
-	if (r)
-		goto err3;
-#endif
+	if (dpi_use_dsi_pll(dssdev)) {
+		dss_clk_enable(DSS_CLK_SYSCK);
+		r = dsi_pll_init(dpi.dsidev, 0, 1);
+		if (r)
+			goto err3;
+	}
+
 	r = dpi_set_mode(dssdev);
 	if (r)
 		goto err4;
@@ -196,11 +219,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 	return 0;
 
 err4:
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-	dsi_pll_uninit();
+	if (dpi_use_dsi_pll(dssdev))
+		dsi_pll_uninit(dpi.dsidev, true);
 err3:
-	dss_clk_disable(DSS_CLK_SYSCK);
-#endif
+	if (dpi_use_dsi_pll(dssdev))
+		dss_clk_disable(DSS_CLK_SYSCK);
 err2:
 	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 	if (cpu_is_omap34xx())
@@ -216,11 +239,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
 {
 	dssdev->manager->disable(dssdev->manager);
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-	dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
-	dsi_pll_uninit();
-	dss_clk_disable(DSS_CLK_SYSCK);
-#endif
+	if (dpi_use_dsi_pll(dssdev)) {
+		dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
+		dsi_pll_uninit(dpi.dsidev, true);
+		dss_clk_disable(DSS_CLK_SYSCK);
+	}
 
 	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
@@ -251,6 +274,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
 	int lck_div, pck_div;
 	unsigned long fck;
 	unsigned long pck;
+	struct dispc_clock_info dispc_cinfo;
 
 	if (!dispc_lcd_timings_ok(timings))
 		return -EINVAL;
@@ -260,11 +284,9 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
 
 	is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-	{
+	if (dpi_use_dsi_pll(dssdev)) {
 		struct dsi_clock_info dsi_cinfo;
-		struct dispc_clock_info dispc_cinfo;
-		r = dsi_pll_calc_clock_div_pck(is_tft,
+		r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft,
 				timings->pixel_clock * 1000,
 				&dsi_cinfo, &dispc_cinfo);
 
@@ -272,13 +294,8 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
 			return r;
 
 		fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
-		lck_div = dispc_cinfo.lck_div;
-		pck_div = dispc_cinfo.pck_div;
-	}
-#else
-	{
+	} else {
 		struct dss_clock_info dss_cinfo;
-		struct dispc_clock_info dispc_cinfo;
 		r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000,
 				&dss_cinfo, &dispc_cinfo);
 
@@ -286,10 +303,10 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
 			return r;
 
 		fck = dss_cinfo.fck;
-		lck_div = dispc_cinfo.lck_div;
-		pck_div = dispc_cinfo.pck_div;
 	}
-#endif
+
+	lck_div = dispc_cinfo.lck_div;
+	pck_div = dispc_cinfo.pck_div;
 
 	pck = fck / lck_div / pck_div / 1000;
 
@@ -316,6 +333,12 @@ int dpi_init_display(struct omap_dss_device *dssdev)
 		dpi.vdds_dsi_reg = vdds_dsi;
 	}
 
+	if (dpi_use_dsi_pll(dssdev)) {
+		enum omap_dss_clk_source dispc_fclk_src =
+			dssdev->clocks.dispc.dispc_fclk_src;
+		dpi.dsidev = dpi_get_dsidev(dispc_fclk_src);
+	}
+
 	return 0;
 }
 

File diff suppressed because it is too large
+ 347 - 176
drivers/video/omap2/dss/dsi.c


+ 82 - 36
drivers/video/omap2/dss/dss.c

@@ -29,7 +29,7 @@
 #include <linux/seq_file.h>
 #include <linux/clk.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/clock.h>
 #include "dss.h"
 #include "dss_features.h"
@@ -45,7 +45,6 @@ struct dss_reg {
 #define DSS_REVISION			DSS_REG(0x0000)
 #define DSS_SYSCONFIG			DSS_REG(0x0010)
 #define DSS_SYSSTATUS			DSS_REG(0x0014)
-#define DSS_IRQSTATUS			DSS_REG(0x0018)
 #define DSS_CONTROL			DSS_REG(0x0040)
 #define DSS_SDI_CONTROL			DSS_REG(0x0044)
 #define DSS_PLL_CONTROL			DSS_REG(0x0048)
@@ -75,17 +74,17 @@ static struct {
 	struct dss_clock_info cache_dss_cinfo;
 	struct dispc_clock_info cache_dispc_cinfo;
 
-	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];
+	enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
+	enum omap_dss_clk_source dispc_clk_source;
+	enum omap_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",
+	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "DSI_PLL_HSDIV_DISPC",
+	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]	= "DSI_PLL_HSDIV_DSI",
+	[OMAP_DSS_CLK_SRC_FCK]			= "DSS_FCK",
 };
 
 static void dss_clk_enable_all_no_ctx(void);
@@ -230,7 +229,7 @@ void dss_sdi_disable(void)
 	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)
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
 {
 	return dss_generic_clk_source_names[clk_src];
 }
@@ -246,8 +245,8 @@ void dss_dump_clocks(struct seq_file *s)
 
 	seq_printf(s, "- DSS -\n");
 
-	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_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
+	fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
 	fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
 
 	if (dss.dpll4_m4_ck) {
@@ -286,7 +285,6 @@ void dss_dump_regs(struct seq_file *s)
 	DUMPREG(DSS_REVISION);
 	DUMPREG(DSS_SYSCONFIG);
 	DUMPREG(DSS_SYSSTATUS);
-	DUMPREG(DSS_IRQSTATUS);
 	DUMPREG(DSS_CONTROL);
 
 	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
@@ -300,18 +298,25 @@ void dss_dump_regs(struct seq_file *s)
 #undef DUMPREG
 }
 
-void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
+void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
 {
+	struct platform_device *dsidev;
 	int b;
 	u8 start, end;
 
 	switch (clk_src) {
-	case DSS_CLK_SRC_FCK:
+	case OMAP_DSS_CLK_SRC_FCK:
 		b = 0;
 		break;
-	case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
 		b = 1;
-		dsi_wait_pll_hsdiv_dispc_active();
+		dsidev = dsi_get_dsidev_from_id(0);
+		dsi_wait_pll_hsdiv_dispc_active(dsidev);
+		break;
+	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+		b = 2;
+		dsidev = dsi_get_dsidev_from_id(1);
+		dsi_wait_pll_hsdiv_dispc_active(dsidev);
 		break;
 	default:
 		BUG();
@@ -324,17 +329,27 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
 	dss.dispc_clk_source = clk_src;
 }
 
-void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
+void dss_select_dsi_clk_source(int dsi_module,
+		enum omap_dss_clk_source clk_src)
 {
+	struct platform_device *dsidev;
 	int b;
 
 	switch (clk_src) {
-	case DSS_CLK_SRC_FCK:
+	case OMAP_DSS_CLK_SRC_FCK:
 		b = 0;
 		break;
-	case DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+		BUG_ON(dsi_module != 0);
+		b = 1;
+		dsidev = dsi_get_dsidev_from_id(0);
+		dsi_wait_pll_hsdiv_dsi_active(dsidev);
+		break;
+	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
+		BUG_ON(dsi_module != 1);
 		b = 1;
-		dsi_wait_pll_hsdiv_dsi_active();
+		dsidev = dsi_get_dsidev_from_id(1);
+		dsi_wait_pll_hsdiv_dsi_active(dsidev);
 		break;
 	default:
 		BUG();
@@ -342,25 +357,33 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
 
 	REG_FLD_MOD(DSS_CONTROL, b, 1, 1);	/* DSI_CLK_SWITCH */
 
-	dss.dsi_clk_source = clk_src;
+	dss.dsi_clk_source[dsi_module] = clk_src;
 }
 
 void dss_select_lcd_clk_source(enum omap_channel channel,
-		enum dss_clk_source clk_src)
+		enum omap_dss_clk_source clk_src)
 {
+	struct platform_device *dsidev;
 	int b, ix, pos;
 
 	if (!dss_has_feature(FEAT_LCD_CLK_SRC))
 		return;
 
 	switch (clk_src) {
-	case DSS_CLK_SRC_FCK:
+	case OMAP_DSS_CLK_SRC_FCK:
 		b = 0;
 		break;
-	case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
 		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
 		b = 1;
-		dsi_wait_pll_hsdiv_dispc_active();
+		dsidev = dsi_get_dsidev_from_id(0);
+		dsi_wait_pll_hsdiv_dispc_active(dsidev);
+		break;
+	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2);
+		b = 1;
+		dsidev = dsi_get_dsidev_from_id(1);
+		dsi_wait_pll_hsdiv_dispc_active(dsidev);
 		break;
 	default:
 		BUG();
@@ -373,20 +396,26 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
 	dss.lcd_clk_source[ix] = clk_src;
 }
 
-enum dss_clk_source dss_get_dispc_clk_source(void)
+enum omap_dss_clk_source dss_get_dispc_clk_source(void)
 {
 	return dss.dispc_clk_source;
 }
 
-enum dss_clk_source dss_get_dsi_clk_source(void)
+enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
 {
-	return dss.dsi_clk_source;
+	return dss.dsi_clk_source[dsi_module];
 }
 
-enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
+enum omap_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];
+	if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
+		int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+		return dss.lcd_clk_source[ix];
+	} else {
+		/* LCD_CLK source is the same as DISPC_FCLK source for
+		 * OMAP2 and OMAP3 */
+		return dss.dispc_clk_source;
+	}
 }
 
 /* calculate clock rates using dividers in cinfo */
@@ -659,13 +688,18 @@ static int dss_init(void)
 	 * the kernel resets it */
 	omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
 
+#ifdef CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET
 	/* 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.
+	 *
+	 * This bug was at least present on OMAP3430. It's unknown
+	 * if it happens on OMAP2 or OMAP3630.
 	 */
 	msleep(50);
+#endif
 
 	_omap_dss_reset();
 
@@ -700,10 +734,11 @@ static int dss_init(void)
 
 	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.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+	dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
+	dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
+	dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+	dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
 
 	dss_save_context();
 
@@ -1015,6 +1050,14 @@ static void core_dump_clocks(struct seq_file *s)
 		dss.dss_video_fck
 	};
 
+	const char *names[5] = {
+		"ick",
+		"fck",
+		"sys_clk",
+		"tv_fck",
+		"video_fck"
+	};
+
 	seq_printf(s, "- CORE -\n");
 
 	seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
@@ -1022,8 +1065,11 @@ static void core_dump_clocks(struct seq_file *s)
 	for (i = 0; i < 5; i++) {
 		if (!clocks[i])
 			continue;
-		seq_printf(s, "%-15s\t%lu\t%d\n",
+		seq_printf(s, "%s (%s)%*s\t%lu\t%d\n",
+				names[i],
 				clocks[i]->name,
+				24 - strlen(names[i]) - strlen(clocks[i]->name),
+				"",
 				clk_get_rate(clocks[i]),
 				clocks[i]->usecount);
 	}

+ 61 - 37
drivers/video/omap2/dss/dss.h

@@ -117,15 +117,6 @@ enum dss_clock {
 	DSS_CLK_VIDFCK	= 1 << 4,	/* DSS_96M_FCLK*/
 };
 
-enum dss_clk_source {
-	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,
@@ -236,7 +227,7 @@ 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);
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
 void dss_dump_clocks(struct seq_file *s);
 
 void dss_dump_regs(struct seq_file *s);
@@ -248,13 +239,14 @@ void dss_sdi_init(u8 datapairs);
 int dss_sdi_enable(void);
 void dss_sdi_disable(void);
 
-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_dispc_clk_source(enum omap_dss_clk_source clk_src);
+void dss_select_dsi_clk_source(int dsi_module,
+		enum omap_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);
+		enum omap_dss_clk_source clk_src);
+enum omap_dss_clk_source dss_get_dispc_clk_source(void);
+enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module);
+enum omap_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);
@@ -284,31 +276,39 @@ static inline void sdi_exit(void)
 
 /* DSI */
 #ifdef CONFIG_OMAP2_DSS_DSI
+
+struct dentry;
+struct file_operations;
+
 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);
-void dsi_dump_regs(struct seq_file *s);
+void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
+		const struct file_operations *debug_fops);
+void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
+		const struct file_operations *debug_fops);
 
 void dsi_save_context(void);
 void dsi_restore_context(void);
 
 int dsi_init_display(struct omap_dss_device *display);
 void dsi_irq_handler(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,
+unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
+int dsi_pll_set_clock_div(struct platform_device *dsidev,
+		struct dsi_clock_info *cinfo);
+int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
+		unsigned long req_pck, struct dsi_clock_info *cinfo,
 		struct dispc_clock_info *dispc_cinfo);
-int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
+int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
 		bool enable_hsdiv);
-void dsi_pll_uninit(void);
+void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
 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_pll_hsdiv_dispc_active(void);
-void dsi_wait_pll_hsdiv_dsi_active(void);
+void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
+void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
+struct platform_device *dsi_get_dsidev_from_id(int module);
 #else
 static inline int dsi_init_platform_driver(void)
 {
@@ -317,17 +317,47 @@ static inline int dsi_init_platform_driver(void)
 static inline void dsi_uninit_platform_driver(void)
 {
 }
-static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
+static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
 {
 	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 int dsi_pll_set_clock_div(struct platform_device *dsidev,
+		struct dsi_clock_info *cinfo)
+{
+	WARN("%s: DSI not compiled in\n", __func__);
+	return -ENODEV;
+}
+static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
+		bool is_tft, unsigned long req_pck,
+		struct dsi_clock_info *dsi_cinfo,
+		struct dispc_clock_info *dispc_cinfo)
+{
+	WARN("%s: DSI not compiled in\n", __func__);
+	return -ENODEV;
+}
+static inline int dsi_pll_init(struct platform_device *dsidev,
+		bool enable_hsclk, bool enable_hsdiv)
 {
+	WARN("%s: DSI not compiled in\n", __func__);
+	return -ENODEV;
 }
-static inline void dsi_wait_pll_hsdiv_dsi_active(void)
+static inline void dsi_pll_uninit(struct platform_device *dsidev,
+		bool disconnect_lanes)
 {
 }
+static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
+{
+}
+static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
+{
+}
+static inline struct platform_device *dsi_get_dsidev_from_id(int module)
+{
+	WARN("%s: DSI not compiled in, returning platform device as NULL\n",
+			__func__);
+	return NULL;
+}
 #endif
 
 /* DPI */
@@ -391,7 +421,8 @@ int dispc_setup_plane(enum omap_plane plane,
 		      enum omap_dss_rotation_type rotation_type,
 		      u8 rotation, bool mirror,
 		      u8 global_alpha, u8 pre_mult_alpha,
-		      enum omap_channel channel);
+		      enum omap_channel channel,
+		      u32 puv_addr);
 
 bool dispc_go_busy(enum omap_channel channel);
 void dispc_go(enum omap_channel channel);
@@ -485,13 +516,6 @@ void hdmi_panel_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);
-void rfbi_enable_rfbi(bool enable);
-void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
-		u16 height, void (callback)(void *data), void *data);
-void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
-unsigned long rfbi_get_max_tx_rate(void);
 int rfbi_init_display(struct omap_dss_device *display);
 #else
 static inline int rfbi_init_platform_driver(void)

+ 84 - 21
drivers/video/omap2/dss/dss_features.c

@@ -22,7 +22,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -52,7 +52,7 @@ struct omap_dss_features {
 };
 
 /* This struct is assigned to one of the below during initialization */
-static struct omap_dss_features *omap_current_dss_features;
+static const struct omap_dss_features *omap_current_dss_features;
 
 static const struct dss_reg_field omap2_dss_reg_fields[] = {
 	[FEAT_REG_FIRHINC]			= { 11, 0 },
@@ -177,22 +177,55 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
 	OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
 };
 
+static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
+	/* OMAP_DSS_GFX */
+	OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+	OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+	OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+	OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+	OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
+	OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 |
+	OMAP_DSS_COLOR_ARGB16_1555,
+
+	/* OMAP_DSS_VIDEO1 */
+	OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+	OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+	OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+	OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+	OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+	OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+	OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+	OMAP_DSS_COLOR_RGBX32,
+
+       /* OMAP_DSS_VIDEO2 */
+	OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+	OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+	OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+	OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+	OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+	OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+	OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+	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",
+	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "N/A",
+	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]	= "N/A",
+	[OMAP_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",
+	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "DSI1_PLL_FCLK",
+	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]	= "DSI2_PLL_FCLK",
+	[OMAP_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",
+	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "PLL1_CLK1",
+	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]	= "PLL1_CLK2",
+	[OMAP_DSS_CLK_SRC_FCK]			= "DSS_FCLK",
+	[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC]	= "PLL2_CLK1",
+	[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI]	= "PLL2_CLK2",
 };
 
 static const struct dss_param_range omap2_dss_param_range[] = {
@@ -226,7 +259,7 @@ static const struct dss_param_range omap4_dss_param_range[] = {
 };
 
 /* OMAP2 DSS Features */
-static struct omap_dss_features omap2_dss_features = {
+static const struct omap_dss_features omap2_dss_features = {
 	.reg_fields = omap2_dss_reg_fields,
 	.num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
 
@@ -244,7 +277,7 @@ static struct omap_dss_features omap2_dss_features = {
 };
 
 /* OMAP3 DSS Features */
-static struct omap_dss_features omap3430_dss_features = {
+static const struct omap_dss_features omap3430_dss_features = {
 	.reg_fields = omap3_dss_reg_fields,
 	.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
@@ -252,7 +285,8 @@ static struct omap_dss_features omap3430_dss_features = {
 		FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
 		FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
 		FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
-		FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF,
+		FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
+		FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC,
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
@@ -262,7 +296,7 @@ static struct omap_dss_features omap3430_dss_features = {
 	.dss_params = omap3_dss_param_range,
 };
 
-static struct omap_dss_features omap3630_dss_features = {
+static const struct omap_dss_features omap3630_dss_features = {
 	.reg_fields = omap3_dss_reg_fields,
 	.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
@@ -271,7 +305,8 @@ static struct omap_dss_features omap3630_dss_features = {
 		FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
 		FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
 		FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
-		FEAT_RESIZECONF,
+		FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG |
+		FEAT_DSI_PLL_FREQSEL,
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
@@ -282,19 +317,43 @@ static struct omap_dss_features omap3630_dss_features = {
 };
 
 /* OMAP4 DSS Features */
-static struct omap_dss_features omap4_dss_features = {
+/* For OMAP4430 ES 1.0 revision */
+static const struct omap_dss_features omap4430_es1_0_dss_features  = {
 	.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_GLOBAL_ALPHA_VID1 |
-		FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC,
+		FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
+		FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
+		FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
 
 	.num_mgrs = 3,
 	.num_ovls = 3,
 	.supported_displays = omap4_dss_supported_displays,
-	.supported_color_modes = omap3_dss_supported_color_modes,
+	.supported_color_modes = omap4_dss_supported_color_modes,
+	.clksrc_names = omap4_dss_clk_source_names,
+	.dss_params = omap4_dss_param_range,
+};
+
+/* For all the other OMAP4 versions */
+static const struct omap_dss_features omap4_dss_features = {
+	.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_GLOBAL_ALPHA_VID1 |
+		FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
+		FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
+		FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE |
+		FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
+
+	.num_mgrs = 3,
+	.num_ovls = 3,
+	.supported_displays = omap4_dss_supported_displays,
+	.supported_color_modes = omap4_dss_supported_color_modes,
 	.clksrc_names = omap4_dss_clk_source_names,
 	.dss_params = omap4_dss_param_range,
 };
@@ -337,7 +396,7 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
 			color_mode;
 }
 
-const char *dss_feat_get_clk_source_name(enum dss_clk_source id)
+const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
 {
 	return omap_current_dss_features->clksrc_names[id];
 }
@@ -365,6 +424,10 @@ void dss_features_init(void)
 		omap_current_dss_features = &omap3630_dss_features;
 	else if (cpu_is_omap34xx())
 		omap_current_dss_features = &omap3430_dss_features;
-	else
+	else if (omap_rev() == OMAP4430_REV_ES1_0)
+		omap_current_dss_features = &omap4430_es1_0_dss_features;
+	else if (cpu_is_omap44xx())
 		omap_current_dss_features = &omap4_dss_features;
+	else
+		DSSWARN("Unsupported OMAP version");
 }

+ 25 - 14
drivers/video/omap2/dss/dss_features.h

@@ -23,23 +23,34 @@
 #define MAX_DSS_MANAGERS	3
 #define MAX_DSS_OVERLAYS	3
 #define MAX_DSS_LCD_MANAGERS	2
+#define MAX_NUM_DSI		2
 
 /* DSS has feature id */
 enum dss_feat_id {
-	FEAT_GLOBAL_ALPHA	= 1 << 0,
-	FEAT_GLOBAL_ALPHA_VID1	= 1 << 1,
-	FEAT_PRE_MULT_ALPHA	= 1 << 2,
-	FEAT_LCDENABLEPOL	= 1 << 3,
-	FEAT_LCDENABLESIGNAL	= 1 << 4,
-	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,
+	FEAT_GLOBAL_ALPHA		= 1 << 0,
+	FEAT_GLOBAL_ALPHA_VID1		= 1 << 1,
+	FEAT_PRE_MULT_ALPHA		= 1 << 2,
+	FEAT_LCDENABLEPOL		= 1 << 3,
+	FEAT_LCDENABLESIGNAL		= 1 << 4,
+	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,
+	FEAT_CORE_CLK_DIV		= 1 << 11,
+	FEAT_LCD_CLK_SRC		= 1 << 12,
+	/* DSI-PLL power command 0x3 is not working */
+	FEAT_DSI_PLL_PWR_BUG		= 1 << 13,
+	FEAT_DSI_PLL_FREQSEL		= 1 << 14,
+	FEAT_DSI_DCS_CMD_CONFIG_VC	= 1 << 15,
+	FEAT_DSI_VC_OCP_WIDTH		= 1 << 16,
+	FEAT_DSI_REVERSE_TXCLKESC	= 1 << 17,
+	FEAT_DSI_GNQ			= 1 << 18,
+	FEAT_HDMI_CTS_SWMODE		= 1 << 19,
+	FEAT_HANDLE_UV_SEPARATE         = 1 << 20,
+	FEAT_ATTR2                      = 1 << 21,
 };
 
 /* DSS register field id */
@@ -77,7 +88,7 @@ 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);
+const char *dss_feat_get_clk_source_name(enum omap_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);

+ 446 - 15
drivers/video/omap2/dss/hdmi.c

@@ -29,10 +29,16 @@
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/string.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+	defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#endif
 
 #include "dss.h"
 #include "hdmi.h"
+#include "dss_features.h"
 
 static struct {
 	struct mutex lock;
@@ -1052,25 +1058,26 @@ static void update_hdmi_timings(struct hdmi_config *cfg,
 	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)
+static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
+		struct hdmi_pll_info *pi)
 {
-	unsigned long refclk;
+	unsigned long clkin, refclk;
 	u32 mf;
 
+	clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000;
 	/*
 	 * Input clock is predivided by N + 1
 	 * out put of which is reference clk
 	 */
-	refclk = clkin / (n + 1);
-	pi->regn = n;
+	pi->regn = dssdev->clocks.hdmi.regn;
+	refclk = clkin / (pi->regn + 1);
 
 	/*
 	 * multiplier is pixel_clk/ref_clk
 	 * Multiplying by 100 to avoid fractional part removal
 	 */
-	pi->regm = (phy * 100/(refclk))/100;
-	pi->regm2 = 1;
+	pi->regm = (phy * 100 / (refclk)) / 100;
+	pi->regm2 = dssdev->clocks.hdmi.regm2;
 
 	/*
 	 * fractional multiplier is remainder of the difference between
@@ -1078,14 +1085,14 @@ static void hdmi_compute_pll(unsigned long clkin, int phy,
 	 * multiplied by 2^18(262144) divided by the reference clock
 	 */
 	mf = (phy - pi->regm * refclk) * 262144;
-	pi->regmf = mf/(refclk);
+	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;
+	pi->regsd = ((pi->regm * clkin / 10) / ((pi->regn + 1) * 250) + 5) / 10;
 
 	DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
 	DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
@@ -1106,7 +1113,7 @@ 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;
+	unsigned long phy;
 
 	hdmi_enable_clocks(1);
 
@@ -1126,11 +1133,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 	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_compute_pll(dssdev, phy, &pll_data);
 
 	hdmi_wp_video_start(0);
 
@@ -1160,7 +1165,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 	 * dynamically by user. This can be moved to single location , say
 	 * Boardfile.
 	 */
-	dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+	dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
 
 	/* bypass TV gamma table */
 	dispc_enable_gamma_table(0);
@@ -1275,10 +1280,420 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
 	mutex_unlock(&hdmi.lock);
 }
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+	defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+static void hdmi_wp_audio_config_format(
+		struct hdmi_audio_format *aud_fmt)
+{
+	u32 r;
+
+	DSSDBG("Enter hdmi_wp_audio_config_format\n");
+
+	r = hdmi_read_reg(HDMI_WP_AUDIO_CFG);
+	r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
+	r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+	r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
+	r = FLD_MOD(r, aud_fmt->type, 4, 4);
+	r = FLD_MOD(r, aud_fmt->justification, 3, 3);
+	r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
+	r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
+	r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
+	hdmi_write_reg(HDMI_WP_AUDIO_CFG, r);
+}
+
+static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma)
+{
+	u32 r;
+
+	DSSDBG("Enter hdmi_wp_audio_config_dma\n");
+
+	r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2);
+	r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
+	r = FLD_MOD(r, aud_dma->block_size, 7, 0);
+	hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r);
+
+	r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL);
+	r = FLD_MOD(r, aud_dma->mode, 9, 9);
+	r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
+	hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r);
+}
+
+static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg)
+{
+	u32 r;
+
+	/* audio clock recovery parameters */
+	r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL);
+	r = FLD_MOD(r, cfg->use_mclk, 2, 2);
+	r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
+	r = FLD_MOD(r, cfg->cts_mode, 0, 0);
+	hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r);
+
+	REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
+	REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
+	REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
+
+	if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) {
+		REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
+		REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
+		REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
+	} else {
+		/*
+		 * HDMI IP uses this configuration to divide the MCLK to
+		 * update CTS value.
+		 */
+		REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
+
+		/* Configure clock for audio packets */
+		REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
+			cfg->aud_par_busclk, 7, 0);
+		REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
+			(cfg->aud_par_busclk >> 8), 7, 0);
+		REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
+			(cfg->aud_par_busclk >> 16), 7, 0);
+	}
+
+	/* Override of SPDIF sample frequency with value in I2S_CHST4 */
+	REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1);
+
+	/* I2S parameters */
+	REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0);
+
+	r = hdmi_read_reg(HDMI_CORE_AV_I2S_IN_CTRL);
+	r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7);
+	r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
+	r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5);
+	r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
+	r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3);
+	r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
+	r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
+	r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
+	hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r);
+
+	r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5);
+	r = FLD_MOD(r, cfg->freq_sample, 7, 4);
+	r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1);
+	r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0);
+	hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r);
+
+	REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0);
+
+	/* Audio channels and mode parameters */
+	REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
+	r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE);
+	r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4);
+	r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3);
+	r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
+	r = FLD_MOD(r, cfg->en_spdif, 1, 1);
+	hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r);
+}
+
+static void hdmi_core_audio_infoframe_config(
+		struct hdmi_core_infoframe_audio *info_aud)
+{
+	u8 val;
+	u8 sum = 0, checksum = 0;
+
+	/*
+	 * Set audio info frame type, version and length as
+	 * described in HDMI 1.4a Section 8.2.2 specification.
+	 * Checksum calculation is defined in Section 5.3.5.
+	 */
+	hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84);
+	hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01);
+	hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a);
+	sum += 0x84 + 0x001 + 0x00a;
+
+	val = (info_aud->db1_coding_type << 4)
+			| (info_aud->db1_channel_count - 1);
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val);
+	sum += val;
+
+	val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size;
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val);
+	sum += val;
+
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00);
+
+	val = info_aud->db4_channel_alloc;
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val);
+	sum += val;
+
+	val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3);
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val);
+	sum += val;
+
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
+	hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
+
+	checksum = 0x100 - sum;
+	hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum);
+
+	/*
+	 * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
+	 * is available.
+	 */
+}
+
+static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts)
+{
+	u32 r;
+	u32 deep_color = 0;
+	u32 pclk = hdmi.cfg.timings.timings.pixel_clock;
+
+	if (n == NULL || cts == NULL)
+		return -EINVAL;
+	/*
+	 * Obtain current deep color configuration. This needed
+	 * to calculate the TMDS clock based on the pixel clock.
+	 */
+	r = REG_GET(HDMI_WP_VIDEO_CFG, 1, 0);
+	switch (r) {
+	case 1: /* No deep color selected */
+		deep_color = 100;
+		break;
+	case 2: /* 10-bit deep color selected */
+		deep_color = 125;
+		break;
+	case 3: /* 12-bit deep color selected */
+		deep_color = 150;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (sample_freq) {
+	case 32000:
+		if ((deep_color == 125) && ((pclk == 54054)
+				|| (pclk == 74250)))
+			*n = 8192;
+		else
+			*n = 4096;
+		break;
+	case 44100:
+		*n = 6272;
+		break;
+	case 48000:
+		if ((deep_color == 125) && ((pclk == 54054)
+				|| (pclk == 74250)))
+			*n = 8192;
+		else
+			*n = 6144;
+		break;
+	default:
+		*n = 0;
+		return -EINVAL;
+	}
+
+	/* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
+	*cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
+
+	return 0;
+}
+
+static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *params,
+				    struct snd_soc_dai *dai)
+{
+	struct hdmi_audio_format audio_format;
+	struct hdmi_audio_dma audio_dma;
+	struct hdmi_core_audio_config core_cfg;
+	struct hdmi_core_infoframe_audio aud_if_cfg;
+	int err, n, cts;
+	enum hdmi_core_audio_sample_freq sample_freq;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		core_cfg.i2s_cfg.word_max_length =
+			HDMI_AUDIO_I2S_MAX_WORD_20BITS;
+		core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS;
+		core_cfg.i2s_cfg.in_length_bits =
+			HDMI_AUDIO_I2S_INPUT_LENGTH_16;
+		core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+		audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
+		audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
+		audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+		audio_dma.transfer_size = 0x10;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		core_cfg.i2s_cfg.word_max_length =
+			HDMI_AUDIO_I2S_MAX_WORD_24BITS;
+		core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS;
+		core_cfg.i2s_cfg.in_length_bits =
+			HDMI_AUDIO_I2S_INPUT_LENGTH_24;
+		audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
+		audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
+		audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+		core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+		audio_dma.transfer_size = 0x20;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_rate(params)) {
+	case 32000:
+		sample_freq = HDMI_AUDIO_FS_32000;
+		break;
+	case 44100:
+		sample_freq = HDMI_AUDIO_FS_44100;
+		break;
+	case 48000:
+		sample_freq = HDMI_AUDIO_FS_48000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = hdmi_config_audio_acr(params_rate(params), &n, &cts);
+	if (err < 0)
+		return err;
+
+	/* Audio wrapper config */
+	audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
+	audio_format.active_chnnls_msk = 0x03;
+	audio_format.type = HDMI_AUDIO_TYPE_LPCM;
+	audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+	/* Disable start/stop signals of IEC 60958 blocks */
+	audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF;
+
+	audio_dma.block_size = 0xC0;
+	audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
+	audio_dma.fifo_threshold = 0x20; /* in number of samples */
+
+	hdmi_wp_audio_config_dma(&audio_dma);
+	hdmi_wp_audio_config_format(&audio_format);
+
+	/*
+	 * I2S config
+	 */
+	core_cfg.i2s_cfg.en_high_bitrate_aud = false;
+	/* Only used with high bitrate audio */
+	core_cfg.i2s_cfg.cbit_order = false;
+	/* Serial data and word select should change on sck rising edge */
+	core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
+	core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
+	/* Set I2S word select polarity */
+	core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT;
+	core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
+	/* Set serial data to word select shift. See Phillips spec. */
+	core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
+	/* Enable one of the four available serial data channels */
+	core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
+
+	/* Core audio config */
+	core_cfg.freq_sample = sample_freq;
+	core_cfg.n = n;
+	core_cfg.cts = cts;
+	if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
+		core_cfg.aud_par_busclk = 0;
+		core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
+		core_cfg.use_mclk = false;
+	} else {
+		core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8);
+		core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
+		core_cfg.use_mclk = true;
+		core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS;
+	}
+	core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
+	core_cfg.en_spdif = false;
+	/* Use sample frequency from channel status word */
+	core_cfg.fs_override = true;
+	/* Enable ACR packets */
+	core_cfg.en_acr_pkt = true;
+	/* Disable direct streaming digital audio */
+	core_cfg.en_dsd_audio = false;
+	/* Use parallel audio interface */
+	core_cfg.en_parallel_aud_input = true;
+
+	hdmi_core_audio_config(&core_cfg);
+
+	/*
+	 * Configure packet
+	 * info frame audio see doc CEA861-D page 74
+	 */
+	aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM;
+	aud_if_cfg.db1_channel_count = 2;
+	aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM;
+	aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM;
+	aud_if_cfg.db4_channel_alloc = 0x00;
+	aud_if_cfg.db5_downmix_inh = false;
+	aud_if_cfg.db5_lsv = 0;
+
+	hdmi_core_audio_infoframe_config(&aud_if_cfg);
+	return 0;
+}
+
+static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
+				  struct snd_soc_dai *dai)
+{
+	int err = 0;
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0);
+		REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31);
+		REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0);
+		REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30);
+		REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31);
+		break;
+	default:
+		err = -EINVAL;
+	}
+	return err;
+}
+
+static int hdmi_audio_startup(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	if (!hdmi.mode) {
+		pr_err("Current video settings do not support audio.\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static struct snd_soc_codec_driver hdmi_audio_codec_drv = {
+};
+
+static struct snd_soc_dai_ops hdmi_audio_codec_ops = {
+	.hw_params = hdmi_audio_hw_params,
+	.trigger = hdmi_audio_trigger,
+	.startup = hdmi_audio_startup,
+};
+
+static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
+		.name = "hdmi-audio-codec",
+		.playback = {
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_32000 |
+				SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE,
+		},
+		.ops = &hdmi_audio_codec_ops,
+};
+#endif
+
 /* HDMI HW IP initialisation */
 static int omapdss_hdmihw_probe(struct platform_device *pdev)
 {
 	struct resource *hdmi_mem;
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+	defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+	int ret;
+#endif
 
 	hdmi.pdata = pdev->dev.platform_data;
 	hdmi.pdev = pdev;
@@ -1300,6 +1715,17 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 
 	hdmi_panel_init();
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+	defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+
+	/* Register ASoC codec DAI */
+	ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
+					&hdmi_codec_dai_drv, 1);
+	if (ret) {
+		DSSERR("can't register ASoC HDMI audio codec\n");
+		return ret;
+	}
+#endif
 	return 0;
 }
 
@@ -1307,6 +1733,11 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
 {
 	hdmi_panel_exit();
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+	defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+	snd_soc_unregister_codec(&pdev->dev);
+#endif
+
 	iounmap(hdmi.base_wp);
 
 	return 0;

+ 219 - 3
drivers/video/omap2/dss/hdmi.h

@@ -22,7 +22,7 @@
 #define _OMAP4_DSS_HDMI_H_
 
 #include <linux/string.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define HDMI_WP		0x0
 #define HDMI_CORE_SYS		0x400
@@ -48,6 +48,10 @@ struct hdmi_reg { u16 idx; };
 #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)
+#define HDMI_WP_AUDIO_CFG			HDMI_WP_REG(0x80)
+#define HDMI_WP_AUDIO_CFG2			HDMI_WP_REG(0x84)
+#define HDMI_WP_AUDIO_CTRL			HDMI_WP_REG(0x88)
+#define HDMI_WP_AUDIO_DATA			HDMI_WP_REG(0x8C)
 
 /* HDMI IP Core System */
 #define HDMI_CORE_SYS_REG(idx)			HDMI_REG(HDMI_CORE_SYS + idx)
@@ -105,6 +109,8 @@ struct hdmi_reg { u16 idx; };
 #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_AUD_DBYTE(n)		HDMI_CORE_AV_REG(n * 4 + 0x210)
+#define HDMI_CORE_AV_AUD_DBYTE_NELEMS		HDMI_CORE_AV_REG(10)
 #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)
@@ -153,6 +159,10 @@ struct hdmi_reg { u16 idx; };
 #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_AUDIO_TYPE		HDMI_CORE_AV_REG(0x200)
+#define HDMI_CORE_AV_AUDIO_VERS		HDMI_CORE_AV_REG(0x204)
+#define HDMI_CORE_AV_AUDIO_LEN			HDMI_CORE_AV_REG(0x208)
+#define HDMI_CORE_AV_AUDIO_CHSUM		HDMI_CORE_AV_REG(0x20C)
 #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)
@@ -272,7 +282,7 @@ enum hdmi_core_packet_ctrl {
 	HDMI_PACKETREPEATOFF = 0
 };
 
-/* INFOFRAME_AVI_ definitions */
+/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */
 enum hdmi_core_infoframe {
 	HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
 	HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
@@ -317,7 +327,36 @@ enum hdmi_core_infoframe {
 	HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
 	HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
 	HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
-	HDMI_INFOFRAME_AVI_DB5PR_10 = 9
+	HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
+	HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0,
+	HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1,
+	HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2,
+	HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3,
+	HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4,
+	HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5,
+	HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6,
+	HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7,
+	HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8,
+	HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9,
+	HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10,
+	HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11,
+	HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12,
+	HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13,
+	HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14,
+	HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0,
+	HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1,
+	HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2,
+	HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3,
+	HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4,
+	HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5,
+	HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6,
+	HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7,
+	HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0,
+	HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1,
+	HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2,
+	HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3,
+	HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0,
+	HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1
 };
 
 enum hdmi_packing_mode {
@@ -327,6 +366,121 @@ enum hdmi_packing_mode {
 	HDMI_PACK_ALREADYPACKED = 7
 };
 
+enum hdmi_core_audio_sample_freq {
+	HDMI_AUDIO_FS_32000 = 0x3,
+	HDMI_AUDIO_FS_44100 = 0x0,
+	HDMI_AUDIO_FS_48000 = 0x2,
+	HDMI_AUDIO_FS_88200 = 0x8,
+	HDMI_AUDIO_FS_96000 = 0xA,
+	HDMI_AUDIO_FS_176400 = 0xC,
+	HDMI_AUDIO_FS_192000 = 0xE,
+	HDMI_AUDIO_FS_NOT_INDICATED = 0x1
+};
+
+enum hdmi_core_audio_layout {
+	HDMI_AUDIO_LAYOUT_2CH = 0,
+	HDMI_AUDIO_LAYOUT_8CH = 1
+};
+
+enum hdmi_core_cts_mode {
+	HDMI_AUDIO_CTS_MODE_HW = 0,
+	HDMI_AUDIO_CTS_MODE_SW = 1
+};
+
+enum hdmi_stereo_channels {
+	HDMI_AUDIO_STEREO_NOCHANNELS = 0,
+	HDMI_AUDIO_STEREO_ONECHANNEL = 1,
+	HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
+	HDMI_AUDIO_STEREO_THREECHANNELS = 3,
+	HDMI_AUDIO_STEREO_FOURCHANNELS = 4
+};
+
+enum hdmi_audio_type {
+	HDMI_AUDIO_TYPE_LPCM = 0,
+	HDMI_AUDIO_TYPE_IEC = 1
+};
+
+enum hdmi_audio_justify {
+	HDMI_AUDIO_JUSTIFY_LEFT = 0,
+	HDMI_AUDIO_JUSTIFY_RIGHT = 1
+};
+
+enum hdmi_audio_sample_order {
+	HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
+	HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
+};
+
+enum hdmi_audio_samples_perword {
+	HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
+	HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
+};
+
+enum hdmi_audio_sample_size {
+	HDMI_AUDIO_SAMPLE_16BITS = 0,
+	HDMI_AUDIO_SAMPLE_24BITS = 1
+};
+
+enum hdmi_audio_transf_mode {
+	HDMI_AUDIO_TRANSF_DMA = 0,
+	HDMI_AUDIO_TRANSF_IRQ = 1
+};
+
+enum hdmi_audio_blk_strt_end_sig {
+	HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
+	HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
+};
+
+enum hdmi_audio_i2s_config {
+	HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0,
+	HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1,
+	HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
+	HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
+	HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0,
+	HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1,
+	HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0,
+	HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1,
+	HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6,
+	HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2,
+	HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4,
+	HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5,
+	HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1,
+	HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6,
+	HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2,
+	HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4,
+	HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5,
+	HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
+	HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
+	HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
+	HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9,
+	HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11,
+	HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
+	HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
+	HDMI_AUDIO_I2S_SD0_EN = 1,
+	HDMI_AUDIO_I2S_SD1_EN = 1 << 1,
+	HDMI_AUDIO_I2S_SD2_EN = 1 << 2,
+	HDMI_AUDIO_I2S_SD3_EN = 1 << 3,
+};
+
+enum hdmi_audio_mclk_mode {
+	HDMI_AUDIO_MCLK_128FS = 0,
+	HDMI_AUDIO_MCLK_256FS = 1,
+	HDMI_AUDIO_MCLK_384FS = 2,
+	HDMI_AUDIO_MCLK_512FS = 3,
+	HDMI_AUDIO_MCLK_768FS = 4,
+	HDMI_AUDIO_MCLK_1024FS = 5,
+	HDMI_AUDIO_MCLK_1152FS = 6,
+	HDMI_AUDIO_MCLK_192FS = 7
+};
+
 struct hdmi_core_video_config {
 	enum hdmi_core_inputbus_width	ip_bus_width;
 	enum hdmi_core_dither_trunc	op_dither_truc;
@@ -376,6 +530,19 @@ struct hdmi_core_infoframe_avi {
 	u16	db12_13_pixel_sofright;
 		/* Pixel number start of right bar */
 };
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_audio {
+	u8 db1_coding_type;
+	u8 db1_channel_count;
+	u8 db2_sample_freq;
+	u8 db2_sample_size;
+	u8 db4_channel_alloc;
+	bool db5_downmix_inh;
+	u8 db5_lsv;	/* Level shift values for downmix */
+};
 
 struct hdmi_core_packet_enable_repeat {
 	u32	audio_pkt;
@@ -412,4 +579,53 @@ struct hdmi_config {
 	struct hdmi_cm cm;
 };
 
+struct hdmi_audio_format {
+	enum hdmi_stereo_channels		stereo_channels;
+	u8					active_chnnls_msk;
+	enum hdmi_audio_type			type;
+	enum hdmi_audio_justify			justification;
+	enum hdmi_audio_sample_order		sample_order;
+	enum hdmi_audio_samples_perword		samples_per_word;
+	enum hdmi_audio_sample_size		sample_size;
+	enum hdmi_audio_blk_strt_end_sig	en_sig_blk_strt_end;
+};
+
+struct hdmi_audio_dma {
+	u8				transfer_size;
+	u8				block_size;
+	enum hdmi_audio_transf_mode	mode;
+	u16				fifo_threshold;
+};
+
+struct hdmi_core_audio_i2s_config {
+	u8 word_max_length;
+	u8 word_length;
+	u8 in_length_bits;
+	u8 justification;
+	u8 en_high_bitrate_aud;
+	u8 sck_edge_mode;
+	u8 cbit_order;
+	u8 vbit;
+	u8 ws_polarity;
+	u8 direction;
+	u8 shift;
+	u8 active_sds;
+};
+
+struct hdmi_core_audio_config {
+	struct hdmi_core_audio_i2s_config	i2s_cfg;
+	enum hdmi_core_audio_sample_freq	freq_sample;
+	bool					fs_override;
+	u32					n;
+	u32					cts;
+	u32					aud_par_busclk;
+	enum hdmi_core_audio_layout		layout;
+	enum hdmi_core_cts_mode			cts_mode;
+	bool					use_mclk;
+	enum hdmi_audio_mclk_mode		mclk_mode;
+	bool					en_acr_pkt;
+	bool					en_dsd_audio;
+	bool					en_parallel_aud_input;
+	bool					en_spdif;
+};
 #endif

+ 1 - 1
drivers/video/omap2/dss/hdmi_omap4_panel.c

@@ -24,7 +24,7 @@
 #include <linux/io.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "dss.h"
 

+ 12 - 2
drivers/video/omap2/dss/manager.c

@@ -29,7 +29,7 @@
 #include <linux/spinlock.h>
 #include <linux/jiffies.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -393,6 +393,7 @@ struct overlay_cache_data {
 
 	u32 paddr;
 	void __iomem *vaddr;
+	u32 p_uv_addr; /* relevant for NV12 format only */
 	u16 screen_width;
 	u16 width;
 	u16 height;
@@ -775,10 +776,17 @@ static int configure_overlay(enum omap_plane plane)
 		}
 
 		switch (c->color_mode) {
+		case OMAP_DSS_COLOR_NV12:
+			bpp = 8;
+			break;
 		case OMAP_DSS_COLOR_RGB16:
 		case OMAP_DSS_COLOR_ARGB16:
 		case OMAP_DSS_COLOR_YUV2:
 		case OMAP_DSS_COLOR_UYVY:
+		case OMAP_DSS_COLOR_RGBA16:
+		case OMAP_DSS_COLOR_RGBX16:
+		case OMAP_DSS_COLOR_ARGB16_1555:
+		case OMAP_DSS_COLOR_XRGB16_1555:
 			bpp = 16;
 			break;
 
@@ -854,7 +862,8 @@ static int configure_overlay(enum omap_plane plane)
 			c->mirror,
 			c->global_alpha,
 			c->pre_mult_alpha,
-			c->channel);
+			c->channel,
+			c->p_uv_addr);
 
 	if (r) {
 		/* this shouldn't happen */
@@ -1269,6 +1278,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
 		oc->paddr = ovl->info.paddr;
 		oc->vaddr = ovl->info.vaddr;
+		oc->p_uv_addr = ovl->info.p_uv_addr;
 		oc->screen_width = ovl->info.screen_width;
 		oc->width = ovl->info.width;
 		oc->height = ovl->info.height;

+ 31 - 12
drivers/video/omap2/dss/overlay.c

@@ -31,7 +31,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -201,12 +201,16 @@ static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
 static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
 		size_t size)
 {
-	int r;
+	int r, enable;
 	struct omap_overlay_info info;
 
 	ovl->get_overlay_info(ovl, &info);
 
-	info.enabled = simple_strtoul(buf, NULL, 10);
+	r = kstrtoint(buf, 0, &enable);
+	if (r)
+		return r;
+
+	info.enabled = !!enable;
 
 	r = ovl->set_overlay_info(ovl, &info);
 	if (r)
@@ -231,8 +235,13 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
 		const char *buf, size_t size)
 {
 	int r;
+	u8 alpha;
 	struct omap_overlay_info info;
 
+	r = kstrtou8(buf, 0, &alpha);
+	if (r)
+		return r;
+
 	ovl->get_overlay_info(ovl, &info);
 
 	/* Video1 plane does not support global alpha
@@ -242,7 +251,7 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
 			ovl->id == OMAP_DSS_VIDEO1)
 		info.global_alpha = 255;
 	else
-		info.global_alpha = simple_strtoul(buf, NULL, 10);
+		info.global_alpha = alpha;
 
 	r = ovl->set_overlay_info(ovl, &info);
 	if (r)
@@ -268,8 +277,13 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
 		const char *buf, size_t size)
 {
 	int r;
+	u8 alpha;
 	struct omap_overlay_info info;
 
+	r = kstrtou8(buf, 0, &alpha);
+	if (r)
+		return r;
+
 	ovl->get_overlay_info(ovl, &info);
 
 	/* only GFX and Video2 plane support pre alpha multiplied
@@ -279,7 +293,7 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
 		ovl->id == OMAP_DSS_VIDEO1)
 		info.pre_mult_alpha = 0;
 	else
-		info.pre_mult_alpha = simple_strtoul(buf, NULL, 10);
+		info.pre_mult_alpha = alpha;
 
 	r = ovl->set_overlay_info(ovl, &info);
 	if (r)
@@ -491,13 +505,18 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
 	ovl->manager = mgr;
 
 	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
-	 * errors. Waiting before changing the channel_out fixes it. I'm
-	 * guessing that the overlay is still somehow being used for the LCD,
-	 * but I don't understand how or why. */
-	msleep(40);
+	/* XXX: When there is an overlay on a DSI manual update display, and
+	 * the overlay is first disabled, then moved to tv, and enabled, we
+	 * seem to get SYNC_LOST_DIGIT error.
+	 *
+	 * Waiting doesn't seem to help, but updating the manual update display
+	 * after disabling the overlay seems to fix this. This hints that the
+	 * overlay is perhaps somehow tied to the LCD output until the output
+	 * is updated.
+	 *
+	 * Userspace workaround for this is to update the LCD after disabling
+	 * the overlay, but before moving the overlay to TV.
+	 */
 	dispc_set_channel_out(ovl->id, mgr->id);
 	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 

+ 30 - 146
drivers/video/omap2/dss/rfbi.c

@@ -32,8 +32,9 @@
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
 #include <linux/seq_file.h>
+#include <linux/semaphore.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include "dss.h"
 
 struct rfbi_reg { u16 idx; };
@@ -65,9 +66,6 @@ struct rfbi_reg { u16 idx; };
 #define REG_FLD_MOD(idx, val, start, end) \
 	rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
 
-/* To work around an RFBI transfer rate limitation */
-#define OMAP_RFBI_RATE_LIMIT    1
-
 enum omap_rfbi_cycleformat {
 	OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
 	OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
@@ -89,11 +87,6 @@ enum omap_rfbi_parallelmode {
 	OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
 };
 
-enum update_cmd {
-	RFBI_CMD_UPDATE = 0,
-	RFBI_CMD_SYNC   = 1,
-};
-
 static int rfbi_convert_timings(struct rfbi_timings *t);
 static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
 
@@ -114,20 +107,9 @@ static struct {
 
 	struct omap_dss_device *dssdev[2];
 
-	struct kfifo      cmd_fifo;
-	spinlock_t        cmd_lock;
-	struct completion cmd_done;
-	atomic_t          cmd_fifo_full;
-	atomic_t          cmd_pending;
+	struct semaphore bus_lock;
 } rfbi;
 
-struct update_region {
-	u16	x;
-	u16     y;
-	u16     w;
-	u16     h;
-};
-
 static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
 {
 	__raw_writel(val, rfbi.base + idx.idx);
@@ -146,9 +128,20 @@ static void rfbi_enable_clocks(bool enable)
 		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
+void rfbi_bus_lock(void)
+{
+	down(&rfbi.bus_lock);
+}
+EXPORT_SYMBOL(rfbi_bus_lock);
+
+void rfbi_bus_unlock(void)
+{
+	up(&rfbi.bus_lock);
+}
+EXPORT_SYMBOL(rfbi_bus_unlock);
+
 void omap_rfbi_write_command(const void *buf, u32 len)
 {
-	rfbi_enable_clocks(1);
 	switch (rfbi.parallelmode) {
 	case OMAP_DSS_RFBI_PARALLELMODE_8:
 	{
@@ -172,13 +165,11 @@ void omap_rfbi_write_command(const void *buf, u32 len)
 	default:
 		BUG();
 	}
-	rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_write_command);
 
 void omap_rfbi_read_data(void *buf, u32 len)
 {
-	rfbi_enable_clocks(1);
 	switch (rfbi.parallelmode) {
 	case OMAP_DSS_RFBI_PARALLELMODE_8:
 	{
@@ -206,13 +197,11 @@ void omap_rfbi_read_data(void *buf, u32 len)
 	default:
 		BUG();
 	}
-	rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_read_data);
 
 void omap_rfbi_write_data(const void *buf, u32 len)
 {
-	rfbi_enable_clocks(1);
 	switch (rfbi.parallelmode) {
 	case OMAP_DSS_RFBI_PARALLELMODE_8:
 	{
@@ -237,7 +226,6 @@ void omap_rfbi_write_data(const void *buf, u32 len)
 		BUG();
 
 	}
-	rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_write_data);
 
@@ -249,8 +237,6 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
 	int horiz_offset = scr_width - w;
 	int i;
 
-	rfbi_enable_clocks(1);
-
 	if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
 	   rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
 		const u16 __iomem *pd = buf;
@@ -295,12 +281,10 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
 	} else {
 		BUG();
 	}
-
-	rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_write_pixels);
 
-void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
+static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
 		u16 height, void (*callback)(void *data), void *data)
 {
 	u32 l;
@@ -317,8 +301,6 @@ void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
 	rfbi.framedone_callback = callback;
 	rfbi.framedone_callback_data = data;
 
-	rfbi_enable_clocks(1);
-
 	rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
 
 	l = rfbi_read_reg(RFBI_CONTROL);
@@ -337,15 +319,11 @@ static void framedone_callback(void *data, u32 mask)
 
 	REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
 
-	rfbi_enable_clocks(0);
-
 	callback = rfbi.framedone_callback;
 	rfbi.framedone_callback = NULL;
 
 	if (callback != NULL)
 		callback(rfbi.framedone_callback_data);
-
-	atomic_set(&rfbi.cmd_pending, 0);
 }
 
 #if 1 /* VERBOSE */
@@ -435,7 +413,7 @@ static int calc_extif_timings(struct rfbi_timings *t)
 }
 
 
-void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
+static void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
 {
 	int r;
 
@@ -447,7 +425,6 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
 
 	BUG_ON(!t->converted);
 
-	rfbi_enable_clocks(1);
 	rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
 	rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
 
@@ -456,7 +433,6 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
 		    (t->tim[2] ? 1 : 0), 4, 4);
 
 	rfbi_print_timings();
-	rfbi_enable_clocks(0);
 }
 
 static int ps_to_rfbi_ticks(int time, int div)
@@ -472,59 +448,6 @@ static int ps_to_rfbi_ticks(int time, int div)
 	return ret;
 }
 
-#ifdef OMAP_RFBI_RATE_LIMIT
-unsigned long rfbi_get_max_tx_rate(void)
-{
-	unsigned long   l4_rate, dss1_rate;
-	int             min_l4_ticks = 0;
-	int             i;
-
-	/* According to TI this can't be calculated so make the
-	 * adjustments for a couple of known frequencies and warn for
-	 * others.
-	 */
-	static const struct {
-		unsigned long l4_clk;           /* HZ */
-		unsigned long dss1_clk;         /* HZ */
-		unsigned long min_l4_ticks;
-	} ftab[] = {
-		{ 55,   132,    7, },           /* 7.86 MPix/s */
-		{ 110,  110,    12, },          /* 9.16 MPix/s */
-		{ 110,  132,    10, },          /* 11   Mpix/s */
-		{ 120,  120,    10, },          /* 12   Mpix/s */
-		{ 133,  133,    10, },          /* 13.3 Mpix/s */
-	};
-
-	l4_rate = rfbi.l4_khz / 1000;
-	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
-		 * for different DPLL multiplier / divider pairs.
-		 */
-		if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
-		    abs(ftab[i].dss1_clk - dss1_rate) < 3) {
-			min_l4_ticks = ftab[i].min_l4_ticks;
-			break;
-		}
-	}
-	if (i == ARRAY_SIZE(ftab)) {
-		/* Can't be sure, return anyway the maximum not
-		 * rate-limited. This might cause a problem only for the
-		 * tearing synchronisation.
-		 */
-		DSSERR("can't determine maximum RFBI transfer rate\n");
-		return rfbi.l4_khz * 1000;
-	}
-	return rfbi.l4_khz * 1000 / min_l4_ticks;
-}
-#else
-int rfbi_get_max_tx_rate(void)
-{
-	return rfbi.l4_khz * 1000;
-}
-#endif
-
 static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
 {
 	*clk_period = 1000000000 / rfbi.l4_khz;
@@ -644,7 +567,6 @@ int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
 	DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
 		mode, hs, vs, hs_pol_inv, vs_pol_inv);
 
-	rfbi_enable_clocks(1);
 	rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
 	rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
 
@@ -657,7 +579,6 @@ int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
 		l &= ~(1 << 20);
 	else
 		l |= 1 << 20;
-	rfbi_enable_clocks(0);
 
 	return 0;
 }
@@ -672,7 +593,6 @@ int omap_rfbi_enable_te(bool enable, unsigned line)
 	if (line > (1 << 11) - 1)
 		return -EINVAL;
 
-	rfbi_enable_clocks(1);
 	l = rfbi_read_reg(RFBI_CONFIG(0));
 	l &= ~(0x3 << 2);
 	if (enable) {
@@ -682,50 +602,12 @@ int omap_rfbi_enable_te(bool enable, unsigned line)
 		rfbi.te_enabled = 0;
 	rfbi_write_reg(RFBI_CONFIG(0), l);
 	rfbi_write_reg(RFBI_LINE_NUMBER, line);
-	rfbi_enable_clocks(0);
 
 	return 0;
 }
 EXPORT_SYMBOL(omap_rfbi_enable_te);
 
-#if 0
-static void rfbi_enable_config(int enable1, int enable2)
-{
-	u32 l;
-	int cs = 0;
-
-	if (enable1)
-		cs |= 1<<0;
-	if (enable2)
-		cs |= 1<<1;
-
-	rfbi_enable_clocks(1);
-
-	l = rfbi_read_reg(RFBI_CONTROL);
-
-	l = FLD_MOD(l, cs, 3, 2);
-	l = FLD_MOD(l, 0, 1, 1);
-
-	rfbi_write_reg(RFBI_CONTROL, l);
-
-
-	l = rfbi_read_reg(RFBI_CONFIG(0));
-	l = FLD_MOD(l, 0, 3, 2); /* TRIGGERMODE: ITE */
-	/*l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
-	/*l |= FLD_VAL(0, 8, 7); */ /* L4FORMAT, 1pix/L4 */
-
-	l = FLD_MOD(l, 0, 16, 16); /* A0POLARITY */
-	l = FLD_MOD(l, 1, 20, 20); /* TE_VSYNC_POLARITY */
-	l = FLD_MOD(l, 1, 21, 21); /* HSYNCPOLARITY */
-
-	l = FLD_MOD(l, OMAP_DSS_RFBI_PARALLELMODE_8, 1, 0);
-	rfbi_write_reg(RFBI_CONFIG(0), l);
-
-	rfbi_enable_clocks(0);
-}
-#endif
-
-int rfbi_configure(int rfbi_module, int bpp, int lines)
+static int rfbi_configure(int rfbi_module, int bpp, int lines)
 {
 	u32 l;
 	int cycle1 = 0, cycle2 = 0, cycle3 = 0;
@@ -821,8 +703,6 @@ int rfbi_configure(int rfbi_module, int bpp, int lines)
 		break;
 	}
 
-	rfbi_enable_clocks(1);
-
 	REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
 
 	l = 0;
@@ -856,11 +736,15 @@ int rfbi_configure(int rfbi_module, int bpp, int lines)
 	DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
 	       bpp, lines, cycle1, cycle2, cycle3);
 
-	rfbi_enable_clocks(0);
-
 	return 0;
 }
-EXPORT_SYMBOL(rfbi_configure);
+
+int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size,
+		int data_lines)
+{
+	return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines);
+}
+EXPORT_SYMBOL(omap_rfbi_configure);
 
 int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
 		u16 *x, u16 *y, u16 *w, u16 *h)
@@ -960,6 +844,8 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
 	int r;
 
+	rfbi_enable_clocks(1);
+
 	r = omap_dss_start_device(dssdev);
 	if (r) {
 		DSSERR("failed to start device\n");
@@ -1002,6 +888,8 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
 	omap_dispc_unregister_isr(framedone_callback, NULL,
 			DISPC_IRQ_FRAMEDONE);
 	omap_dss_stop_device(dssdev);
+
+	rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_disable);
 
@@ -1021,11 +909,7 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
 
 	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);
+	sema_init(&rfbi.bus_lock, 1);
 
 	rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
 	if (!rfbi_mem) {

+ 1 - 1
drivers/video/omap2/dss/sdi.c

@@ -25,7 +25,7 @@
 #include <linux/err.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 #include "dss.h"
 

+ 16 - 7
drivers/video/omap2/dss/venc.c

@@ -34,7 +34,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -373,8 +373,11 @@ static void venc_reset(void)
 		}
 	}
 
+#ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
 	/* the magical sleep that makes things work */
+	/* XXX more info? What bug this circumvents? */
 	msleep(20);
+#endif
 }
 
 static void venc_enable_clocks(int enable)
@@ -473,6 +476,12 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
 
 	mutex_lock(&venc.venc_lock);
 
+	r = omap_dss_start_device(dssdev);
+	if (r) {
+		DSSERR("failed to start device\n");
+		goto err0;
+	}
+
 	if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
 		r = -EINVAL;
 		goto err1;
@@ -484,10 +493,11 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
-	/* wait couple of vsyncs until enabling the LCD */
-	msleep(50);
-
+	mutex_unlock(&venc.venc_lock);
+	return 0;
 err1:
+	omap_dss_stop_device(dssdev);
+err0:
 	mutex_unlock(&venc.venc_lock);
 
 	return r;
@@ -510,10 +520,9 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
 
 	venc_power_off(dssdev);
 
-	/* wait at least 5 vsyncs after disabling the LCD */
-	msleep(100);
-
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+	omap_dss_stop_device(dssdev);
 end:
 	mutex_unlock(&venc.venc_lock);
 }

+ 11 - 3
drivers/video/omap2/omapfb/omapfb-ioctl.c

@@ -28,7 +28,7 @@
 #include <linux/omapfb.h>
 #include <linux/vmalloc.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vrfb.h>
 #include <plat/vram.h>
 
@@ -895,8 +895,16 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
 
 		p.display_info.xres = xres;
 		p.display_info.yres = yres;
-		p.display_info.width = 0;
-		p.display_info.height = 0;
+
+		if (display->driver->get_dimensions) {
+			u32 w, h;
+			display->driver->get_dimensions(display, &w, &h);
+			p.display_info.width = w;
+			p.display_info.height = h;
+		} else {
+			p.display_info.width = 0;
+			p.display_info.height = 0;
+		}
 
 		if (copy_to_user((void __user *)arg, &p.display_info,
 					sizeof(p.display_info)))

+ 131 - 100
drivers/video/omap2/omapfb/omapfb-main.c

@@ -30,7 +30,7 @@
 #include <linux/platform_device.h>
 #include <linux/omapfb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vram.h>
 #include <plat/vrfb.h>
 
@@ -702,8 +702,16 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
 			var->xres, var->yres,
 			var->xres_virtual, var->yres_virtual);
 
-	var->height             = -1;
-	var->width              = -1;
+	if (display && display->driver->get_dimensions) {
+		u32 w, h;
+		display->driver->get_dimensions(display, &w, &h);
+		var->width = DIV_ROUND_CLOSEST(w, 1000);
+		var->height = DIV_ROUND_CLOSEST(h, 1000);
+	} else {
+		var->height = -1;
+		var->width = -1;
+	}
+
 	var->grayscale          = 0;
 
 	if (display && display->driver->get_timings) {
@@ -749,35 +757,6 @@ static int omapfb_open(struct fb_info *fbi, int user)
 
 static int omapfb_release(struct fb_info *fbi, int user)
 {
-#if 0
-	struct omapfb_info *ofbi = FB2OFB(fbi);
-	struct omapfb2_device *fbdev = ofbi->fbdev;
-	struct omap_dss_device *display = fb2display(fbi);
-
-	DBG("Closing fb with plane index %d\n", ofbi->id);
-
-	omapfb_lock(fbdev);
-
-	if (display && display->get_update_mode && display->update) {
-		/* XXX this update should be removed, I think. But it's
-		 * good for debugging */
-		if (display->get_update_mode(display) ==
-				OMAP_DSS_UPDATE_MANUAL) {
-			u16 w, h;
-
-			if (display->sync)
-				display->sync(display);
-
-			display->get_resolution(display, &w, &h);
-			display->update(display, 0, 0, w, h);
-		}
-	}
-
-	if (display && display->sync)
-		display->sync(display);
-
-	omapfb_unlock(fbdev);
-#endif
 	return 0;
 }
 
@@ -1263,7 +1242,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
 	struct omapfb_info *ofbi = FB2OFB(fbi);
 	struct omapfb2_device *fbdev = ofbi->fbdev;
 	struct omap_dss_device *display = fb2display(fbi);
-	int do_update = 0;
 	int r = 0;
 
 	if (!display)
@@ -1279,11 +1257,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
 		if (display->driver->resume)
 			r = display->driver->resume(display);
 
-		if (r == 0 && display->driver->get_update_mode &&
-				display->driver->get_update_mode(display) ==
-				OMAP_DSS_UPDATE_MANUAL)
-			do_update = 1;
-
 		break;
 
 	case FB_BLANK_NORMAL:
@@ -1307,13 +1280,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
 exit:
 	omapfb_unlock(fbdev);
 
-	if (r == 0 && do_update && display->driver->update) {
-		u16 w, h;
-		display->driver->get_resolution(display, &w, &h);
-
-		r = display->driver->update(display, 0, 0, w, h);
-	}
-
 	return r;
 }
 
@@ -2030,9 +1996,9 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
 static int omapfb_mode_to_timings(const char *mode_str,
 		struct omap_video_timings *timings, u8 *bpp)
 {
-	struct fb_info fbi;
-	struct fb_var_screeninfo var;
-	struct fb_ops fbops;
+	struct fb_info *fbi;
+	struct fb_var_screeninfo *var;
+	struct fb_ops *fbops;
 	int r;
 
 #ifdef CONFIG_OMAP2_DSS_VENC
@@ -2050,39 +2016,66 @@ static int omapfb_mode_to_timings(const char *mode_str,
 	/* this is quite a hack, but I wanted to use the modedb and for
 	 * that we need fb_info and var, so we create dummy ones */
 
-	memset(&fbi, 0, sizeof(fbi));
-	memset(&var, 0, sizeof(var));
-	memset(&fbops, 0, sizeof(fbops));
-	fbi.fbops = &fbops;
-
-	r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
-
-	if (r != 0) {
-		timings->pixel_clock = PICOS2KHZ(var.pixclock);
-		timings->hbp = var.left_margin;
-		timings->hfp = var.right_margin;
-		timings->vbp = var.upper_margin;
-		timings->vfp = var.lower_margin;
-		timings->hsw = var.hsync_len;
-		timings->vsw = var.vsync_len;
-		timings->x_res = var.xres;
-		timings->y_res = var.yres;
-
-		switch (var.bits_per_pixel) {
-		case 16:
-			*bpp = 16;
-			break;
-		case 24:
-		case 32:
-		default:
-			*bpp = 24;
-			break;
-		}
+	*bpp = 0;
+	fbi = NULL;
+	var = NULL;
+	fbops = NULL;
 
-		return 0;
-	} else {
-		return -EINVAL;
+	fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
+	if (fbi == NULL) {
+		r = -ENOMEM;
+		goto err;
+	}
+
+	var = kzalloc(sizeof(*var), GFP_KERNEL);
+	if (var == NULL) {
+		r = -ENOMEM;
+		goto err;
+	}
+
+	fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
+	if (fbops == NULL) {
+		r = -ENOMEM;
+		goto err;
+	}
+
+	fbi->fbops = fbops;
+
+	r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
+	if (r == 0) {
+		r = -EINVAL;
+		goto err;
+	}
+
+	timings->pixel_clock = PICOS2KHZ(var->pixclock);
+	timings->hbp = var->left_margin;
+	timings->hfp = var->right_margin;
+	timings->vbp = var->upper_margin;
+	timings->vfp = var->lower_margin;
+	timings->hsw = var->hsync_len;
+	timings->vsw = var->vsync_len;
+	timings->x_res = var->xres;
+	timings->y_res = var->yres;
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		*bpp = 16;
+		break;
+	case 24:
+	case 32:
+	default:
+		*bpp = 24;
+		break;
 	}
+
+	r = 0;
+
+err:
+	kfree(fbi);
+	kfree(var);
+	kfree(fbops);
+
+	return r;
 }
 
 static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
@@ -2185,6 +2178,61 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
 	return r;
 }
 
+static int omapfb_init_display(struct omapfb2_device *fbdev,
+		struct omap_dss_device *dssdev)
+{
+	struct omap_dss_driver *dssdrv = dssdev->driver;
+	int r;
+
+	r = dssdrv->enable(dssdev);
+	if (r) {
+		dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
+				dssdev->name);
+		return r;
+	}
+
+	if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+		u16 w, h;
+		if (dssdrv->enable_te) {
+			r = dssdrv->enable_te(dssdev, 1);
+			if (r) {
+				dev_err(fbdev->dev, "Failed to set TE\n");
+				return r;
+			}
+		}
+
+		if (dssdrv->set_update_mode) {
+			r = dssdrv->set_update_mode(dssdev,
+					OMAP_DSS_UPDATE_MANUAL);
+			if (r) {
+				dev_err(fbdev->dev,
+						"Failed to set update mode\n");
+				return r;
+			}
+		}
+
+		dssdrv->get_resolution(dssdev, &w, &h);
+		r = dssdrv->update(dssdev, 0, 0, w, h);
+		if (r) {
+			dev_err(fbdev->dev,
+					"Failed to update display\n");
+			return r;
+		}
+	} else {
+		if (dssdrv->set_update_mode) {
+			r = dssdrv->set_update_mode(dssdev,
+					OMAP_DSS_UPDATE_AUTO);
+			if (r) {
+				dev_err(fbdev->dev,
+						"Failed to set update mode\n");
+				return r;
+			}
+		}
+	}
+
+	return 0;
+}
+
 static int omapfb_probe(struct platform_device *pdev)
 {
 	struct omapfb2_device *fbdev = NULL;
@@ -2284,30 +2332,13 @@ static int omapfb_probe(struct platform_device *pdev)
 	}
 
 	if (def_display) {
-		struct omap_dss_driver *dssdrv = def_display->driver;
-
-		r = def_display->driver->enable(def_display);
+		r = omapfb_init_display(fbdev, def_display);
 		if (r) {
-			dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
-					def_display->name);
+			dev_err(fbdev->dev,
+					"failed to initialize default "
+					"display\n");
 			goto cleanup;
 		}
-
-		if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-			u16 w, h;
-			if (dssdrv->enable_te)
-				dssdrv->enable_te(def_display, 1);
-			if (dssdrv->set_update_mode)
-				dssdrv->set_update_mode(def_display,
-						OMAP_DSS_UPDATE_MANUAL);
-
-			dssdrv->get_resolution(def_display, &w, &h);
-			def_display->driver->update(def_display, 0, 0, w, h);
-		} else {
-			if (dssdrv->set_update_mode)
-				dssdrv->set_update_mode(def_display,
-						OMAP_DSS_UPDATE_AUTO);
-		}
 	}
 
 	DBG("create sysfs for fbs\n");

+ 15 - 8
drivers/video/omap2/omapfb/omapfb-sysfs.c

@@ -29,7 +29,7 @@
 #include <linux/mm.h>
 #include <linux/omapfb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vrfb.h>
 
 #include "omapfb.h"
@@ -50,10 +50,12 @@ static ssize_t store_rotate_type(struct device *dev,
 	struct fb_info *fbi = dev_get_drvdata(dev);
 	struct omapfb_info *ofbi = FB2OFB(fbi);
 	struct omapfb2_mem_region *rg;
-	enum omap_dss_rotation_type rot_type;
+	int rot_type;
 	int r;
 
-	rot_type = simple_strtoul(buf, NULL, 0);
+	r = kstrtoint(buf, 0, &rot_type);
+	if (r)
+		return r;
 
 	if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
 		return -EINVAL;
@@ -102,14 +104,15 @@ static ssize_t store_mirror(struct device *dev,
 {
 	struct fb_info *fbi = dev_get_drvdata(dev);
 	struct omapfb_info *ofbi = FB2OFB(fbi);
-	unsigned long mirror;
+	int mirror;
 	int r;
 	struct fb_var_screeninfo new_var;
 
-	mirror = simple_strtoul(buf, NULL, 0);
+	r = kstrtoint(buf, 0, &mirror);
+	if (r)
+		return r;
 
-	if (mirror != 0 && mirror != 1)
-		return -EINVAL;
+	mirror = !!mirror;
 
 	if (!lock_fb_info(fbi))
 		return -ENODEV;
@@ -445,7 +448,11 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
 	int r;
 	int i;
 
-	size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
+	r = kstrtoul(buf, 0, &size);
+	if (r)
+		return r;
+
+	size = PAGE_ALIGN(size);
 
 	if (!lock_fb_info(fbi))
 		return -ENODEV;

+ 5 - 3
drivers/video/omap2/omapfb/omapfb.h

@@ -29,13 +29,15 @@
 
 #include <linux/rwsem.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #ifdef DEBUG
 extern unsigned int omapfb_debug;
 #define DBG(format, ...) \
-	if (omapfb_debug) \
-		printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
+	do { \
+		if (omapfb_debug) \
+			printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__); \
+	} while (0)
 #else
 #define DBG(format, ...)
 #endif

+ 95 - 26
drivers/video/s3c-fb.c

@@ -182,6 +182,7 @@ struct s3c_fb_vsync {
 
 /**
  * struct s3c_fb - overall hardware state of the hardware
+ * @slock: The spinlock protection for this data sturcture.
  * @dev: The device that we bound to, for printing, etc.
  * @regs_res: The resource we claimed for the IO registers.
  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
@@ -195,6 +196,7 @@ struct s3c_fb_vsync {
  * @vsync_info: VSYNC-related information (count, queues...)
  */
 struct s3c_fb {
+	spinlock_t		slock;
 	struct device		*dev;
 	struct resource		*regs_res;
 	struct clk		*bus_clk;
@@ -300,6 +302,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
 		var->blue.length	= 5;
 		break;
 
+	case 32:
 	case 28:
 	case 25:
 		var->transp.length	= var->bits_per_pixel - 24;
@@ -308,7 +311,6 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
 	case 24:
 		/* our 24bpp is unpacked, so 32bpp */
 		var->bits_per_pixel	= 32;
-	case 32:
 		var->red.offset		= 16;
 		var->red.length		= 8;
 		var->green.offset	= 8;
@@ -947,6 +949,8 @@ static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
 	void __iomem  *regs = sfb->regs;
 	u32 irq_sts_reg;
 
+	spin_lock(&sfb->slock);
+
 	irq_sts_reg = readl(regs + VIDINTCON1);
 
 	if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
@@ -963,6 +967,7 @@ static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
 	 */
 	s3c_fb_disable_irq(sfb);
 
+	spin_unlock(&sfb->slock);
 	return IRQ_HANDLED;
 }
 
@@ -1339,6 +1344,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
 	sfb->pdata = pd;
 	sfb->variant = fbdrv->variant;
 
+	spin_lock_init(&sfb->slock);
+
 	sfb->bus_clk = clk_get(dev, "lcd");
 	if (IS_ERR(sfb->bus_clk)) {
 		dev_err(dev, "failed to get bus clock\n");
@@ -1442,8 +1449,7 @@ err_ioremap:
 	iounmap(sfb->regs);
 
 err_req_region:
-	release_resource(sfb->regs_res);
-	kfree(sfb->regs_res);
+	release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
 err_clk:
 	clk_disable(sfb->bus_clk);
@@ -1479,8 +1485,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
 	clk_disable(sfb->bus_clk);
 	clk_put(sfb->bus_clk);
 
-	release_resource(sfb->regs_res);
-	kfree(sfb->regs_res);
+	release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
 	kfree(sfb);
 
@@ -1521,7 +1526,8 @@ static int s3c_fb_resume(struct device *dev)
 
 	clk_enable(sfb->bus_clk);
 
-	/* setup registers */
+	/* setup gpio and output polarity controls */
+	pd->setup_gpio();
 	writel(pd->vidcon1, sfb->regs + VIDCON1);
 
 	/* zero all windows before we do anything */
@@ -1549,7 +1555,7 @@ static int s3c_fb_resume(struct device *dev)
 	return 0;
 }
 
-int s3c_fb_runtime_suspend(struct device *dev)
+static int s3c_fb_runtime_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct s3c_fb *sfb = platform_get_drvdata(pdev);
@@ -1569,7 +1575,7 @@ int s3c_fb_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-int s3c_fb_runtime_resume(struct device *dev)
+static int s3c_fb_runtime_resume(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct s3c_fb *sfb = platform_get_drvdata(pdev);
@@ -1579,7 +1585,8 @@ int s3c_fb_runtime_resume(struct device *dev)
 
 	clk_enable(sfb->bus_clk);
 
-	/* setup registers */
+	/* setup gpio and output polarity controls */
+	pd->setup_gpio();
 	writel(pd->vidcon1, sfb->regs + VIDCON1);
 
 	/* zero all windows before we do anything */
@@ -1623,28 +1630,31 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
 		.has_osd_c	= 1,
 		.osd_size_off	= 0x8,
 		.palette_sz	= 256,
-		.valid_bpp	= VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
+		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
+				   VALID_BPP(18) | VALID_BPP(24)),
 	},
 	[1] = {
 		.has_osd_c	= 1,
 		.has_osd_d	= 1,
-		.osd_size_off	= 0x12,
+		.osd_size_off	= 0xc,
 		.has_osd_alpha	= 1,
 		.palette_sz	= 256,
 		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
 				   VALID_BPP(18) | VALID_BPP(19) |
-				   VALID_BPP(24) | VALID_BPP(25)),
+				   VALID_BPP(24) | VALID_BPP(25) |
+				   VALID_BPP(28)),
 	},
 	[2] = {
 		.has_osd_c	= 1,
 		.has_osd_d	= 1,
-		.osd_size_off	= 0x12,
+		.osd_size_off	= 0xc,
 		.has_osd_alpha	= 1,
 		.palette_sz	= 16,
 		.palette_16bpp	= 1,
 		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
 				   VALID_BPP(18) | VALID_BPP(19) |
-				   VALID_BPP(24) | VALID_BPP(25)),
+				   VALID_BPP(24) | VALID_BPP(25) |
+				   VALID_BPP(28)),
 	},
 	[3] = {
 		.has_osd_c	= 1,
@@ -1653,7 +1663,8 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
 		.palette_16bpp	= 1,
 		.valid_bpp	= (VALID_BPP124  | VALID_BPP(16) |
 				   VALID_BPP(18) | VALID_BPP(19) |
-				   VALID_BPP(24) | VALID_BPP(25)),
+				   VALID_BPP(24) | VALID_BPP(25) |
+				   VALID_BPP(28)),
 	},
 	[4] = {
 		.has_osd_c	= 1,
@@ -1662,7 +1673,65 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
 		.palette_16bpp	= 1,
 		.valid_bpp	= (VALID_BPP(1) | VALID_BPP(2) |
 				   VALID_BPP(16) | VALID_BPP(18) |
-				   VALID_BPP(24) | VALID_BPP(25)),
+				   VALID_BPP(19) | VALID_BPP(24) |
+				   VALID_BPP(25) | VALID_BPP(28)),
+	},
+};
+
+static struct s3c_fb_win_variant s3c_fb_data_s5p_wins[] = {
+	[0] = {
+		.has_osd_c	= 1,
+		.osd_size_off	= 0x8,
+		.palette_sz	= 256,
+		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
+				   VALID_BPP(15) | VALID_BPP(16) |
+				   VALID_BPP(18) | VALID_BPP(19) |
+				   VALID_BPP(24) | VALID_BPP(25) |
+				   VALID_BPP(32)),
+	},
+	[1] = {
+		.has_osd_c	= 1,
+		.has_osd_d	= 1,
+		.osd_size_off	= 0xc,
+		.has_osd_alpha	= 1,
+		.palette_sz	= 256,
+		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
+				   VALID_BPP(15) | VALID_BPP(16) |
+				   VALID_BPP(18) | VALID_BPP(19) |
+				   VALID_BPP(24) | VALID_BPP(25) |
+				   VALID_BPP(32)),
+	},
+	[2] = {
+		.has_osd_c	= 1,
+		.has_osd_d	= 1,
+		.osd_size_off	= 0xc,
+		.has_osd_alpha	= 1,
+		.palette_sz	= 256,
+		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
+				   VALID_BPP(15) | VALID_BPP(16) |
+				   VALID_BPP(18) | VALID_BPP(19) |
+				   VALID_BPP(24) | VALID_BPP(25) |
+				   VALID_BPP(32)),
+	},
+	[3] = {
+		.has_osd_c	= 1,
+		.has_osd_alpha	= 1,
+		.palette_sz	= 256,
+		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
+				   VALID_BPP(15) | VALID_BPP(16) |
+				   VALID_BPP(18) | VALID_BPP(19) |
+				   VALID_BPP(24) | VALID_BPP(25) |
+				   VALID_BPP(32)),
+	},
+	[4] = {
+		.has_osd_c	= 1,
+		.has_osd_alpha	= 1,
+		.palette_sz	= 256,
+		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
+				   VALID_BPP(15) | VALID_BPP(16) |
+				   VALID_BPP(18) | VALID_BPP(19) |
+				   VALID_BPP(24) | VALID_BPP(25) |
+				   VALID_BPP(32)),
 	},
 };
 
@@ -1719,11 +1788,11 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
 
 		.has_prtcon	= 1,
 	},
-	.win[0]	= &s3c_fb_data_64xx_wins[0],
-	.win[1]	= &s3c_fb_data_64xx_wins[1],
-	.win[2]	= &s3c_fb_data_64xx_wins[2],
-	.win[3]	= &s3c_fb_data_64xx_wins[3],
-	.win[4]	= &s3c_fb_data_64xx_wins[4],
+	.win[0]	= &s3c_fb_data_s5p_wins[0],
+	.win[1]	= &s3c_fb_data_s5p_wins[1],
+	.win[2]	= &s3c_fb_data_s5p_wins[2],
+	.win[3]	= &s3c_fb_data_s5p_wins[3],
+	.win[4]	= &s3c_fb_data_s5p_wins[4],
 };
 
 static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
@@ -1749,11 +1818,11 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
 
 		.has_shadowcon	= 1,
 	},
-	.win[0]	= &s3c_fb_data_64xx_wins[0],
-	.win[1]	= &s3c_fb_data_64xx_wins[1],
-	.win[2]	= &s3c_fb_data_64xx_wins[2],
-	.win[3]	= &s3c_fb_data_64xx_wins[3],
-	.win[4]	= &s3c_fb_data_64xx_wins[4],
+	.win[0]	= &s3c_fb_data_s5p_wins[0],
+	.win[1]	= &s3c_fb_data_s5p_wins[1],
+	.win[2]	= &s3c_fb_data_s5p_wins[2],
+	.win[3]	= &s3c_fb_data_s5p_wins[3],
+	.win[4]	= &s3c_fb_data_s5p_wins[4],
 };
 
 /* S3C2443/S3C2416 style hardware */

+ 3 - 5
drivers/video/s3c2410fb.c

@@ -867,7 +867,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
 		goto dealloc_fb;
 	}
 
-	size = (res->end - res->start) + 1;
+	size = resource_size(res);
 	info->mem = request_mem_region(res->start, size, pdev->name);
 	if (info->mem == NULL) {
 		dev_err(&pdev->dev, "failed to get memory region\n");
@@ -997,8 +997,7 @@ release_irq:
 release_regs:
 	iounmap(info->io);
 release_mem:
-	release_resource(info->mem);
-	kfree(info->mem);
+	release_mem_region(res->start, size);
 dealloc_fb:
 	platform_set_drvdata(pdev, NULL);
 	framebuffer_release(fbinfo);
@@ -1044,8 +1043,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev)
 
 	iounmap(info->io);
 
-	release_resource(info->mem);
-	kfree(info->mem);
+	release_mem_region(info->mem->start, resource_size(info->mem));
 
 	platform_set_drvdata(pdev, NULL);
 	framebuffer_release(fbinfo);

+ 202 - 7
drivers/video/s3fb.c

@@ -25,6 +25,9 @@
 #include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
 #include <video/vga.h>
 
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
@@ -36,6 +39,12 @@ struct s3fb_info {
 	struct mutex open_lock;
 	unsigned int ref_count;
 	u32 pseudo_palette[16];
+#ifdef CONFIG_FB_S3_DDC
+	u8 __iomem *mmio;
+	bool ddc_registered;
+	struct i2c_adapter ddc_adapter;
+	struct i2c_algo_bit_data ddc_algo;
+#endif
 };
 
 
@@ -105,6 +114,9 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
 #define CHIP_UNDECIDED_FLAG	0x80
 #define CHIP_MASK		0xFF
 
+#define MMIO_OFFSET		0x1000000
+#define MMIO_SIZE		0x10000
+
 /* CRT timing register sets */
 
 static const struct vga_regset s3_h_total_regs[]        = {{0x00, 0, 7}, {0x5D, 0, 0}, VGA_REGSET_END};
@@ -140,7 +152,7 @@ static const struct svga_timing_regs s3_timing_regs     = {
 /* Module parameters */
 
 
-static char *mode_option __devinitdata = "640x480-8@60";
+static char *mode_option __devinitdata;
 
 #ifdef CONFIG_MTRR
 static int mtrr __devinitdata = 1;
@@ -167,6 +179,119 @@ module_param(fasttext, int, 0644);
 MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, default=1)");
 
 
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_FB_S3_DDC
+
+#define DDC_REG		0xaa		/* Trio 3D/1X/2X */
+#define DDC_MMIO_REG	0xff20		/* all other chips */
+#define DDC_SCL_OUT	(1 << 0)
+#define DDC_SDA_OUT	(1 << 1)
+#define DDC_SCL_IN	(1 << 2)
+#define DDC_SDA_IN	(1 << 3)
+#define DDC_DRIVE_EN	(1 << 4)
+
+static bool s3fb_ddc_needs_mmio(int chip)
+{
+	return !(chip == CHIP_360_TRIO3D_1X  ||
+		 chip == CHIP_362_TRIO3D_2X  ||
+		 chip == CHIP_368_TRIO3D_2X);
+}
+
+static u8 s3fb_ddc_read(struct s3fb_info *par)
+{
+	if (s3fb_ddc_needs_mmio(par->chip))
+		return readb(par->mmio + DDC_MMIO_REG);
+	else
+		return vga_rcrt(par->state.vgabase, DDC_REG);
+}
+
+static void s3fb_ddc_write(struct s3fb_info *par, u8 val)
+{
+	if (s3fb_ddc_needs_mmio(par->chip))
+		writeb(val, par->mmio + DDC_MMIO_REG);
+	else
+		vga_wcrt(par->state.vgabase, DDC_REG, val);
+}
+
+static void s3fb_ddc_setscl(void *data, int val)
+{
+	struct s3fb_info *par = data;
+	unsigned char reg;
+
+	reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
+	if (val)
+		reg |= DDC_SCL_OUT;
+	else
+		reg &= ~DDC_SCL_OUT;
+	s3fb_ddc_write(par, reg);
+}
+
+static void s3fb_ddc_setsda(void *data, int val)
+{
+	struct s3fb_info *par = data;
+	unsigned char reg;
+
+	reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
+	if (val)
+		reg |= DDC_SDA_OUT;
+	else
+		reg &= ~DDC_SDA_OUT;
+	s3fb_ddc_write(par, reg);
+}
+
+static int s3fb_ddc_getscl(void *data)
+{
+	struct s3fb_info *par = data;
+
+	return !!(s3fb_ddc_read(par) & DDC_SCL_IN);
+}
+
+static int s3fb_ddc_getsda(void *data)
+{
+	struct s3fb_info *par = data;
+
+	return !!(s3fb_ddc_read(par) & DDC_SDA_IN);
+}
+
+static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)
+{
+	struct s3fb_info *par = info->par;
+
+	strlcpy(par->ddc_adapter.name, info->fix.id,
+		sizeof(par->ddc_adapter.name));
+	par->ddc_adapter.owner		= THIS_MODULE;
+	par->ddc_adapter.class		= I2C_CLASS_DDC;
+	par->ddc_adapter.algo_data	= &par->ddc_algo;
+	par->ddc_adapter.dev.parent	= info->device;
+	par->ddc_algo.setsda		= s3fb_ddc_setsda;
+	par->ddc_algo.setscl		= s3fb_ddc_setscl;
+	par->ddc_algo.getsda		= s3fb_ddc_getsda;
+	par->ddc_algo.getscl		= s3fb_ddc_getscl;
+	par->ddc_algo.udelay		= 10;
+	par->ddc_algo.timeout		= 20;
+	par->ddc_algo.data		= par;
+
+	i2c_set_adapdata(&par->ddc_adapter, par);
+
+	/*
+	 * some Virge cards have external MUX to switch chip I2C bus between
+	 * DDC and extension pins - switch it do DDC
+	 */
+/*	vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */
+	if (par->chip == CHIP_357_VIRGE_GX2 ||
+	    par->chip == CHIP_359_VIRGE_GX2P)
+		svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03);
+	else
+		svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03);
+	/* some Virge need this or the DDC is ignored */
+	svga_wcrt_mask(par->state.vgabase, 0x5c, 0x03, 0x03);
+
+	return i2c_bit_add_bus(&par->ddc_adapter);
+}
+#endif /* CONFIG_FB_S3_DDC */
+
+
 /* ------------------------------------------------------------------------- */
 
 /* Set font in S3 fast text mode */
@@ -994,6 +1119,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
 	struct s3fb_info *par;
 	int rc;
 	u8 regval, cr38, cr39;
+	bool found = false;
 
 	/* Ignore secondary VGA device because there is no VGA arbitration */
 	if (! svga_primary_device(dev)) {
@@ -1110,12 +1236,69 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
 	info->fix.ypanstep = 0;
 	info->fix.accel = FB_ACCEL_NONE;
 	info->pseudo_palette = (void*) (par->pseudo_palette);
+	info->var.bits_per_pixel = 8;
+
+#ifdef CONFIG_FB_S3_DDC
+	/* Enable MMIO if needed */
+	if (s3fb_ddc_needs_mmio(par->chip)) {
+		par->mmio = ioremap(info->fix.smem_start + MMIO_OFFSET, MMIO_SIZE);
+		if (par->mmio)
+			svga_wcrt_mask(par->state.vgabase, 0x53, 0x08, 0x08);	/* enable MMIO */
+		else
+			dev_err(info->device, "unable to map MMIO at 0x%lx, disabling DDC",
+				info->fix.smem_start + MMIO_OFFSET);
+	}
+	if (!s3fb_ddc_needs_mmio(par->chip) || par->mmio)
+		if (s3fb_setup_ddc_bus(info) == 0) {
+			u8 *edid = fb_ddc_read(&par->ddc_adapter);
+			par->ddc_registered = true;
+			if (edid) {
+				fb_edid_to_monspecs(edid, &info->monspecs);
+				kfree(edid);
+				if (!info->monspecs.modedb)
+					dev_err(info->device, "error getting mode database\n");
+				else {
+					const struct fb_videomode *m;
+
+					fb_videomode_to_modelist(info->monspecs.modedb,
+								 info->monspecs.modedb_len,
+								 &info->modelist);
+					m = fb_find_best_display(&info->monspecs, &info->modelist);
+					if (m) {
+						fb_videomode_to_var(&info->var, m);
+						/* fill all other info->var's fields */
+						if (s3fb_check_var(&info->var, info) == 0)
+							found = true;
+					}
+				}
+			}
+		}
+#endif
+	if (!mode_option && !found)
+		mode_option = "640x480-8@60";
 
 	/* Prepare startup mode */
-	rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
-	if (! ((rc == 1) || (rc == 2))) {
-		rc = -EINVAL;
-		dev_err(info->device, "mode %s not found\n", mode_option);
+	if (mode_option) {
+		rc = fb_find_mode(&info->var, info, mode_option,
+				   info->monspecs.modedb, info->monspecs.modedb_len,
+				   NULL, info->var.bits_per_pixel);
+		if (!rc || rc == 4) {
+			rc = -EINVAL;
+			dev_err(info->device, "mode %s not found\n", mode_option);
+			fb_destroy_modedb(info->monspecs.modedb);
+			info->monspecs.modedb = NULL;
+			goto err_find_mode;
+		}
+	}
+
+	fb_destroy_modedb(info->monspecs.modedb);
+	info->monspecs.modedb = NULL;
+
+	/* maximize virtual vertical size for fast scrolling */
+	info->var.yres_virtual = info->fix.smem_len * 8 /
+			(info->var.bits_per_pixel * info->var.xres_virtual);
+	if (info->var.yres_virtual < info->var.yres) {
+		dev_err(info->device, "virtual vertical size smaller than real\n");
 		goto err_find_mode;
 	}
 
@@ -1164,6 +1347,12 @@ err_reg_fb:
 	fb_dealloc_cmap(&info->cmap);
 err_alloc_cmap:
 err_find_mode:
+#ifdef CONFIG_FB_S3_DDC
+	if (par->ddc_registered)
+		i2c_del_adapter(&par->ddc_adapter);
+	if (par->mmio)
+		iounmap(par->mmio);
+#endif
 	pci_iounmap(dev, info->screen_base);
 err_iomap:
 	pci_release_regions(dev);
@@ -1180,12 +1369,11 @@ err_enable_device:
 static void __devexit s3_pci_remove(struct pci_dev *dev)
 {
 	struct fb_info *info = pci_get_drvdata(dev);
+	struct s3fb_info __maybe_unused *par = info->par;
 
 	if (info) {
 
 #ifdef CONFIG_MTRR
-		struct s3fb_info *par = info->par;
-
 		if (par->mtrr_reg >= 0) {
 			mtrr_del(par->mtrr_reg, 0, 0);
 			par->mtrr_reg = -1;
@@ -1195,6 +1383,13 @@ static void __devexit s3_pci_remove(struct pci_dev *dev)
 		unregister_framebuffer(info);
 		fb_dealloc_cmap(&info->cmap);
 
+#ifdef CONFIG_FB_S3_DDC
+		if (par->ddc_registered)
+			i2c_del_adapter(&par->ddc_adapter);
+		if (par->mmio)
+			iounmap(par->mmio);
+#endif
+
 		pci_iounmap(dev, info->screen_base);
 		pci_release_regions(dev);
 /*		pci_disable_device(dev); */

+ 2 - 0
drivers/video/savage/savagefb-i2c.c

@@ -171,6 +171,8 @@ void savagefb_create_i2c_busses(struct fb_info *info)
 
 	switch (par->chip) {
 	case S3_PROSAVAGE:
+	case S3_PROSAVAGEDDR:
+	case S3_TWISTER:
 		par->chan.reg         = CR_SERIAL2;
 		par->chan.ioaddr      = par->mmio.vbase;
 		par->chan.algo.setsda = prosavage_gpio_setsda;

+ 5 - 3
drivers/video/savage/savagefb.h

@@ -36,7 +36,6 @@
 #define PCI_CHIP_SAVAGE_IX    0x8c13
 #define PCI_CHIP_PROSAVAGE_PM 0x8a25
 #define PCI_CHIP_PROSAVAGE_KM 0x8a26
- /* Twister is a code name; hope I get the real name soon. */
 #define PCI_CHIP_S3TWISTER_P  0x8d01
 #define PCI_CHIP_S3TWISTER_K  0x8d02
 #define PCI_CHIP_PROSAVAGE_DDR          0x8d03
@@ -52,14 +51,15 @@
 #define PCI_CHIP_SUPSAV_IXCDDR		0x8c2f
 
 
+#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
 
 #define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
 
-#define S3_SAVAGE4_SERIES(chip)   ((chip==S3_SAVAGE4) || (chip==S3_PROSAVAGE))
+#define S3_SAVAGE4_SERIES(chip)   ((chip>=S3_SAVAGE4) || (chip<=S3_PROSAVAGEDDR))
 
 #define S3_SAVAGE_MOBILE_SERIES(chip)  ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
 
-#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip==S3_PROSAVAGEDDR))
 
 /* Chip tags.  These are used to group the adapters into
  * related families.
@@ -71,6 +71,8 @@ typedef enum {
   S3_SAVAGE_MX,
   S3_SAVAGE4,
   S3_PROSAVAGE,
+  S3_TWISTER,
+  S3_PROSAVAGEDDR,
   S3_SUPERSAVAGE,
   S3_SAVAGE2000,
   S3_LAST

+ 10 - 5
drivers/video/savage/savagefb_driver.c

@@ -328,7 +328,9 @@ SavageSetup2DEngine(struct savagefb_par  *par)
 		savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x0C, par);
 		break;
 	case S3_SAVAGE4:
+	case S3_TWISTER:
 	case S3_PROSAVAGE:
+	case S3_PROSAVAGEDDR:
 	case S3_SUPERSAVAGE:
 		/* Disable BCI */
 		savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par);
@@ -1886,6 +1888,8 @@ static int savage_init_hw(struct savagefb_par *par)
 		break;
 
 	case S3_PROSAVAGE:
+	case S3_PROSAVAGEDDR:
+	case S3_TWISTER:
 		videoRam = RamSavageNB[(config1 & 0xE0) >> 5] * 1024;
 		break;
 
@@ -1963,7 +1967,8 @@ static int savage_init_hw(struct savagefb_par *par)
 		}
 	}
 
-	if (S3_SAVAGE_MOBILE_SERIES(par->chip) && !par->crtonly)
+	if ((S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+	     S3_MOBILE_TWISTER_SERIES(par->chip)) && !par->crtonly)
 		par->display_type = DISP_LCD;
 	else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi))
 		par->display_type = DISP_DFP;
@@ -2111,19 +2116,19 @@ static int __devinit savage_init_fb_info(struct fb_info *info,
 		snprintf(info->fix.id, 16, "ProSavageKM");
 		break;
 	case FB_ACCEL_S3TWISTER_P:
-		par->chip = S3_PROSAVAGE;
+		par->chip = S3_TWISTER;
 		snprintf(info->fix.id, 16, "TwisterP");
 		break;
 	case FB_ACCEL_S3TWISTER_K:
-		par->chip = S3_PROSAVAGE;
+		par->chip = S3_TWISTER;
 		snprintf(info->fix.id, 16, "TwisterK");
 		break;
 	case FB_ACCEL_PROSAVAGE_DDR:
-		par->chip = S3_PROSAVAGE;
+		par->chip = S3_PROSAVAGEDDR;
 		snprintf(info->fix.id, 16, "ProSavageDDR");
 		break;
 	case FB_ACCEL_PROSAVAGE_DDRK:
-		par->chip = S3_PROSAVAGE;
+		par->chip = S3_PROSAVAGEDDR;
 		snprintf(info->fix.id, 16, "ProSavage8");
 		break;
 	}

+ 2 - 4
drivers/video/sh7760fb.c

@@ -551,8 +551,7 @@ out_unmap:
 		free_irq(par->irq, &par->vsync);
 	iounmap(par->base);
 out_res:
-	release_resource(par->ioarea);
-	kfree(par->ioarea);
+	release_mem_region(res->start, resource_size(res));
 out_fb:
 	framebuffer_release(info);
 	return ret;
@@ -570,8 +569,7 @@ static int __devexit sh7760fb_remove(struct platform_device *dev)
 	if (par->irq >= 0)
 		free_irq(par->irq, par);
 	iounmap(par->base);
-	release_resource(par->ioarea);
-	kfree(par->ioarea);
+	release_mem_region(par->ioarea->start, resource_size(par->ioarea));
 	framebuffer_release(info);
 	platform_set_drvdata(dev, NULL);
 

+ 8 - 2
drivers/video/sh_mobile_hdmi.c

@@ -1131,15 +1131,19 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 		pm_runtime_get_sync(hdmi->dev);
 
 		ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
-		if (ret < 0)
+		if (ret < 0) {
+			pm_runtime_put(hdmi->dev);
 			goto out;
+		}
 
 		hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
 
 		/* Reconfigure the clock */
 		ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate);
-		if (ret < 0)
+		if (ret < 0) {
+			pm_runtime_put(hdmi->dev);
 			goto out;
+		}
 
 		msleep(10);
 		sh_hdmi_configure(hdmi);
@@ -1336,6 +1340,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 ecodec:
 	free_irq(irq, hdmi);
 ereqirq:
+	pm_runtime_suspend(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	iounmap(hdmi->base);
 emap:
@@ -1372,6 +1377,7 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
 	free_irq(irq, hdmi);
 	/* Wait for already scheduled work */
 	cancel_delayed_work_sync(&hdmi->edid_work);
+	pm_runtime_suspend(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	clk_disable(hdmi->hdmi_clk);
 	clk_put(hdmi->hdmi_clk);

+ 106 - 20
drivers/video/sh_mobile_lcdcfb.c

@@ -27,6 +27,7 @@
 #include <asm/atomic.h>
 
 #include "sh_mobile_lcdcfb.h"
+#include "sh_mobile_meram.h"
 
 #define SIDE_B_OFFSET 0x1000
 #define MIRROR_OFFSET 0x2000
@@ -143,6 +144,7 @@ struct sh_mobile_lcdc_priv {
 	unsigned long saved_shared_regs[NR_SHARED_REGS];
 	int started;
 	int forced_bpp; /* 2 channel LCDC must share bpp setting */
+	struct sh_mobile_meram_info *meram_dev;
 };
 
 static bool banked(int reg_nr)
@@ -469,7 +471,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 	int bpp = 0;
 	unsigned long ldddsr;
 	int k, m;
-	int ret = 0;
 
 	/* enable clocks before accessing the hardware */
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
@@ -538,11 +539,12 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		lcdc_write_chan(ch, LDPMR, 0);
 
 		board_cfg = &ch->cfg.board_cfg;
-		if (board_cfg->setup_sys)
-			ret = board_cfg->setup_sys(board_cfg->board_data, ch,
-						   &sh_mobile_lcdc_sys_bus_ops);
-		if (ret)
-			return ret;
+		if (board_cfg->setup_sys) {
+			int ret = board_cfg->setup_sys(board_cfg->board_data,
+						ch, &sh_mobile_lcdc_sys_bus_ops);
+			if (ret)
+				return ret;
+		}
 	}
 
 	/* word and long word swap */
@@ -564,6 +566,9 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 	}
 
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+		unsigned long base_addr_y;
+		unsigned long base_addr_c = 0;
+		int pitch;
 		ch = &priv->ch[k];
 
 		if (!priv->ch[k].enabled)
@@ -598,16 +603,68 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		}
 		lcdc_write_chan(ch, LDDFR, tmp);
 
+		base_addr_y = ch->info->fix.smem_start;
+		base_addr_c = base_addr_y +
+				ch->info->var.xres *
+				ch->info->var.yres_virtual;
+		pitch = ch->info->fix.line_length;
+
+		/* test if we can enable meram */
+		if (ch->cfg.meram_cfg && priv->meram_dev &&
+				priv->meram_dev->ops) {
+			struct sh_mobile_meram_cfg *cfg;
+			struct sh_mobile_meram_info *mdev;
+			unsigned long icb_addr_y, icb_addr_c;
+			int icb_pitch;
+			int pf;
+
+			cfg = ch->cfg.meram_cfg;
+			mdev = priv->meram_dev;
+			/* we need to de-init configured ICBs before we
+			 * we can re-initialize them.
+			 */
+			if (ch->meram_enabled)
+				mdev->ops->meram_unregister(mdev, cfg);
+
+			ch->meram_enabled = 0;
+
+			if (ch->info->var.nonstd) {
+				if (ch->info->var.bits_per_pixel == 24)
+					pf = SH_MOBILE_MERAM_PF_NV24;
+				else
+					pf = SH_MOBILE_MERAM_PF_NV;
+			} else {
+				pf = SH_MOBILE_MERAM_PF_RGB;
+			}
+
+			ret = mdev->ops->meram_register(mdev, cfg, pitch,
+						ch->info->var.yres,
+						pf,
+						base_addr_y,
+						base_addr_c,
+						&icb_addr_y,
+						&icb_addr_c,
+						&icb_pitch);
+			if (!ret)  {
+				/* set LDSA1R value */
+				base_addr_y = icb_addr_y;
+				pitch = icb_pitch;
+
+				/* set LDSA2R value if required */
+				if (base_addr_c)
+					base_addr_c = icb_addr_c;
+
+				ch->meram_enabled = 1;
+			}
+		}
+
 		/* point out our frame buffer */
-		lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start);
+		lcdc_write_chan(ch, LDSA1R, base_addr_y);
 		if (ch->info->var.nonstd)
-			lcdc_write_chan(ch, LDSA2R,
-				ch->info->fix.smem_start +
-				ch->info->var.xres *
-				ch->info->var.yres_virtual);
+			lcdc_write_chan(ch, LDSA2R, base_addr_c);
 
 		/* set line size */
-		lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length);
+		lcdc_write_chan(ch, LDMLSR, pitch);
 
 		/* setup deferred io if SYS bus */
 		tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
@@ -692,6 +749,17 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
 			board_cfg->display_off(board_cfg->board_data);
 			module_put(board_cfg->owner);
 		}
+
+		/* disable the meram */
+		if (ch->meram_enabled) {
+			struct sh_mobile_meram_cfg *cfg;
+			struct sh_mobile_meram_info *mdev;
+			cfg = ch->cfg.meram_cfg;
+			mdev = priv->meram_dev;
+			mdev->ops->meram_unregister(mdev, cfg);
+			ch->meram_enabled = 0;
+		}
+
 	}
 
 	/* stop the lcdc */
@@ -875,9 +943,29 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 	} else
 		base_addr_c = 0;
 
-	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
-	if (base_addr_c)
-		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
+	if (!ch->meram_enabled) {
+		lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
+		if (base_addr_c)
+			lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
+	} else {
+		struct sh_mobile_meram_cfg *cfg;
+		struct sh_mobile_meram_info *mdev;
+		unsigned long icb_addr_y, icb_addr_c;
+		int ret;
+
+		cfg = ch->cfg.meram_cfg;
+		mdev = priv->meram_dev;
+		ret = mdev->ops->meram_update(mdev, cfg,
+					base_addr_y, base_addr_c,
+					&icb_addr_y, &icb_addr_c);
+		if (ret)
+			return ret;
+
+		lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y);
+		if (icb_addr_c)
+			lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c);
+
+	}
 
 	if (lcdc_chan_is_sublcd(ch))
 		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
@@ -1288,7 +1376,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
 	struct fb_info *info = event->info;
 	struct sh_mobile_lcdc_chan *ch = info->par;
 	struct sh_mobile_lcdc_board_cfg	*board_cfg = &ch->cfg.board_cfg;
-	int ret;
 
 	if (&ch->lcdc->notifier != nb)
 		return NOTIFY_DONE;
@@ -1302,7 +1389,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
 			board_cfg->display_off(board_cfg->board_data);
 			module_put(board_cfg->owner);
 		}
-		pm_runtime_put(info->device);
 		sh_mobile_lcdc_stop(ch->lcdc);
 		break;
 	case FB_EVENT_RESUME:
@@ -1316,9 +1402,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
 			module_put(board_cfg->owner);
 		}
 
-		ret = sh_mobile_lcdc_start(ch->lcdc);
-		if (!ret)
-			pm_runtime_get_sync(info->device);
+		sh_mobile_lcdc_start(ch->lcdc);
 	}
 
 	return NOTIFY_OK;
@@ -1420,6 +1504,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 		goto err1;
 	}
 
+	priv->meram_dev = pdata->meram_dev;
+
 	for (i = 0; i < j; i++) {
 		struct fb_var_screeninfo *var;
 		const struct fb_videomode *lcd_cfg, *max_cfg = NULL;

+ 1 - 0
drivers/video/sh_mobile_lcdcfb.h

@@ -39,6 +39,7 @@ struct sh_mobile_lcdc_chan {
 	int use_count;
 	int blank_status;
 	struct mutex open_lock;		/* protects the use counter */
+	int meram_enabled;
 };
 
 #endif

+ 567 - 0
drivers/video/sh_mobile_meram.c

@@ -0,0 +1,567 @@
+/*
+ * SuperH Mobile MERAM Driver for SuperH Mobile LCDC Driver
+ *
+ * Copyright (c) 2011	Damian Hobson-Garcia <dhobsong@igel.co.jp>
+ *                      Takanari Hayama <taki@igel.co.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include "sh_mobile_meram.h"
+
+/* meram registers */
+#define MExxCTL 0x0
+#define MExxBSIZE 0x4
+#define MExxMNCF 0x8
+#define MExxSARA 0x10
+#define MExxSARB 0x14
+#define MExxSBSIZE 0x18
+
+#define MERAM_MExxCTL_VAL(ctl, next_icb, addr)	\
+	((ctl) | (((next_icb) & 0x1f) << 11) | (((addr) & 0x7ff) << 16))
+#define	MERAM_MExxBSIZE_VAL(a, b, c) \
+	(((a) << 28) | ((b) << 16) | (c))
+
+#define MEVCR1 0x4
+#define MEACTS 0x10
+#define MEQSEL1 0x40
+#define MEQSEL2 0x44
+
+/* settings */
+#define MERAM_SEC_LINE 15
+#define MERAM_LINE_WIDTH 2048
+
+/*
+ * MERAM/ICB access functions
+ */
+
+#define MERAM_ICB_OFFSET(base, idx, off)	\
+	((base) + (0x400 + ((idx) * 0x20) + (off)))
+
+static inline void meram_write_icb(void __iomem *base, int idx, int off,
+	unsigned long val)
+{
+	iowrite32(val, MERAM_ICB_OFFSET(base, idx, off));
+}
+
+static inline unsigned long meram_read_icb(void __iomem *base, int idx, int off)
+{
+	return ioread32(MERAM_ICB_OFFSET(base, idx, off));
+}
+
+static inline void meram_write_reg(void __iomem *base, int off,
+		unsigned long val)
+{
+	iowrite32(val, base + off);
+}
+
+static inline unsigned long meram_read_reg(void __iomem *base, int off)
+{
+	return ioread32(base + off);
+}
+
+/*
+ * register ICB
+ */
+
+#define MERAM_CACHE_START(p)	 ((p) >> 16)
+#define MERAM_CACHE_END(p)	 ((p) & 0xffff)
+#define MERAM_CACHE_SET(o, s)	 ((((o) & 0xffff) << 16) | \
+				  (((o) + (s) - 1) & 0xffff))
+
+/*
+ * check if there's no overlaps in MERAM allocation.
+ */
+
+static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
+				      struct sh_mobile_meram_icb *new)
+{
+	int i;
+	int used_start, used_end, meram_start, meram_end;
+
+	/* valid ICB? */
+	if (new->marker_icb & ~0x1f || new->cache_icb & ~0x1f)
+		return 1;
+
+	if (test_bit(new->marker_icb, &priv->used_icb) ||
+			test_bit(new->cache_icb,  &priv->used_icb))
+		return  1;
+
+	for (i = 0; i < priv->used_meram_cache_regions; i++) {
+		used_start = MERAM_CACHE_START(priv->used_meram_cache[i]);
+		used_end   = MERAM_CACHE_END(priv->used_meram_cache[i]);
+		meram_start = new->meram_offset;
+		meram_end   = new->meram_offset + new->meram_size;
+
+		if ((meram_start >= used_start && meram_start < used_end) ||
+			(meram_end > used_start && meram_end < used_end))
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * mark the specified ICB as used
+ */
+
+static inline void meram_mark(struct sh_mobile_meram_priv *priv,
+			      struct sh_mobile_meram_icb *new)
+{
+	int n;
+
+	if (new->marker_icb < 0 || new->cache_icb < 0)
+		return;
+
+	__set_bit(new->marker_icb, &priv->used_icb);
+	__set_bit(new->cache_icb, &priv->used_icb);
+
+	n = priv->used_meram_cache_regions;
+
+	priv->used_meram_cache[n] = MERAM_CACHE_SET(new->meram_offset,
+						    new->meram_size);
+
+	priv->used_meram_cache_regions++;
+}
+
+/*
+ * unmark the specified ICB as used
+ */
+
+static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
+				struct sh_mobile_meram_icb *icb)
+{
+	int i;
+	unsigned long pattern;
+
+	if (icb->marker_icb < 0 || icb->cache_icb < 0)
+		return;
+
+	__clear_bit(icb->marker_icb, &priv->used_icb);
+	__clear_bit(icb->cache_icb, &priv->used_icb);
+
+	pattern = MERAM_CACHE_SET(icb->meram_offset, icb->meram_size);
+	for (i = 0; i < priv->used_meram_cache_regions; i++) {
+		if (priv->used_meram_cache[i] == pattern) {
+			while (i < priv->used_meram_cache_regions - 1) {
+				priv->used_meram_cache[i] =
+					priv->used_meram_cache[i + 1] ;
+				i++;
+			}
+			priv->used_meram_cache[i] = 0;
+			priv->used_meram_cache_regions--;
+			break;
+		}
+	}
+}
+
+/*
+ * is this a YCbCr(NV12, NV16 or NV24) colorspace
+ */
+static inline int is_nvcolor(int cspace)
+{
+	if (cspace == SH_MOBILE_MERAM_PF_NV ||
+			cspace == SH_MOBILE_MERAM_PF_NV24)
+		return 1;
+	return 0;
+}
+
+/*
+ * set the next address to fetch
+ */
+static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
+				       struct sh_mobile_meram_cfg *cfg,
+				       unsigned long base_addr_y,
+				       unsigned long base_addr_c)
+{
+	unsigned long target;
+
+	target = (cfg->current_reg) ? MExxSARA : MExxSARB;
+	cfg->current_reg ^= 1;
+
+	/* set the next address to fetch */
+	meram_write_icb(priv->base, cfg->icb[0].cache_icb,  target,
+			base_addr_y);
+	meram_write_icb(priv->base, cfg->icb[0].marker_icb, target,
+			base_addr_y + cfg->icb[0].cache_unit);
+
+	if (is_nvcolor(cfg->pixelformat)) {
+		meram_write_icb(priv->base, cfg->icb[1].cache_icb,  target,
+				base_addr_c);
+		meram_write_icb(priv->base, cfg->icb[1].marker_icb, target,
+				base_addr_c + cfg->icb[1].cache_unit);
+	}
+}
+
+/*
+ * get the next ICB address
+ */
+static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
+					   struct sh_mobile_meram_cfg *cfg,
+					   unsigned long *icb_addr_y,
+					   unsigned long *icb_addr_c)
+{
+	unsigned long icb_offset;
+
+	if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0)
+		icb_offset = 0x80000000 | (cfg->current_reg << 29);
+	else
+		icb_offset = 0xc0000000 | (cfg->current_reg << 23);
+
+	*icb_addr_y = icb_offset | (cfg->icb[0].marker_icb << 24);
+	if ((*icb_addr_c) && is_nvcolor(cfg->pixelformat))
+		*icb_addr_c = icb_offset | (cfg->icb[1].marker_icb << 24);
+}
+
+#define MERAM_CALC_BYTECOUNT(x, y) \
+	(((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1))
+
+/*
+ * initialize MERAM
+ */
+
+static int meram_init(struct sh_mobile_meram_priv *priv,
+		      struct sh_mobile_meram_icb *icb,
+		      int xres, int yres, int *out_pitch)
+{
+	unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
+	unsigned long bnm;
+	int lcdc_pitch, xpitch, line_cnt;
+	int save_lines;
+
+	/* adjust pitch to 1024, 2048, 4096 or 8192 */
+	lcdc_pitch = (xres - 1) | 1023;
+	lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 1);
+	lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 2);
+	lcdc_pitch += 1;
+
+	/* derive settings */
+	if (lcdc_pitch == 8192 && yres >= 1024) {
+		lcdc_pitch = xpitch = MERAM_LINE_WIDTH;
+		line_cnt = total_byte_count >> 11;
+		*out_pitch = xres;
+		save_lines = (icb->meram_size / 16 / MERAM_SEC_LINE);
+		save_lines *= MERAM_SEC_LINE;
+	} else {
+		xpitch = xres;
+		line_cnt = yres;
+		*out_pitch = lcdc_pitch;
+		save_lines = icb->meram_size / (lcdc_pitch >> 10) / 2;
+		save_lines &= 0xff;
+	}
+	bnm = (save_lines - 1) << 16;
+
+	/* TODO: we better to check if we have enough MERAM buffer size */
+
+	/* set up ICB */
+	meram_write_icb(priv->base, icb->cache_icb,  MExxBSIZE,
+			MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1));
+	meram_write_icb(priv->base, icb->marker_icb, MExxBSIZE,
+			MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1));
+
+	meram_write_icb(priv->base, icb->cache_icb,  MExxMNCF, bnm);
+	meram_write_icb(priv->base, icb->marker_icb, MExxMNCF, bnm);
+
+	meram_write_icb(priv->base, icb->cache_icb,  MExxSBSIZE, xpitch);
+	meram_write_icb(priv->base, icb->marker_icb, MExxSBSIZE, xpitch);
+
+	/* save a cache unit size */
+	icb->cache_unit = xres * save_lines;
+
+	/*
+	 * Set MERAM for framebuffer
+	 *
+	 * 0x70f:  WD = 0x3, WS=0x1, CM=0x1, MD=FB mode
+	 * we also chain the cache_icb and the marker_icb.
+	 * we also split the allocated MERAM buffer between two ICBs.
+	 */
+	meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
+			MERAM_MExxCTL_VAL(0x70f, icb->marker_icb,
+					  icb->meram_offset));
+	meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
+			MERAM_MExxCTL_VAL(0x70f, icb->cache_icb,
+					  icb->meram_offset +
+					  icb->meram_size / 2));
+
+	return 0;
+}
+
+static void meram_deinit(struct sh_mobile_meram_priv *priv,
+			struct sh_mobile_meram_icb *icb)
+{
+	/* disable ICB */
+	meram_write_icb(priv->base, icb->cache_icb,  MExxCTL, 0);
+	meram_write_icb(priv->base, icb->marker_icb, MExxCTL, 0);
+	icb->cache_unit = 0;
+}
+
+/*
+ * register the ICB
+ */
+
+static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
+				    struct sh_mobile_meram_cfg *cfg,
+				    int xres, int yres, int pixelformat,
+				    unsigned long base_addr_y,
+				    unsigned long base_addr_c,
+				    unsigned long *icb_addr_y,
+				    unsigned long *icb_addr_c,
+				    int *pitch)
+{
+	struct platform_device *pdev;
+	struct sh_mobile_meram_priv *priv;
+	int n, out_pitch;
+	int error = 0;
+
+	if (!pdata || !pdata->priv || !pdata->pdev || !cfg)
+		return -EINVAL;
+
+	if (pixelformat != SH_MOBILE_MERAM_PF_NV &&
+	    pixelformat != SH_MOBILE_MERAM_PF_NV24 &&
+	    pixelformat != SH_MOBILE_MERAM_PF_RGB)
+		return -EINVAL;
+
+	priv = pdata->priv;
+	pdev = pdata->pdev;
+
+	dev_dbg(&pdev->dev, "registering %dx%d (%s) (y=%08lx, c=%08lx)",
+		xres, yres, (!pixelformat) ? "yuv" : "rgb",
+		base_addr_y, base_addr_c);
+
+	mutex_lock(&priv->lock);
+
+	/* we can't handle wider than 8192px */
+	if (xres > 8192) {
+		dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
+		error = -EINVAL;
+		goto err;
+	}
+
+	if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
+		dev_err(&pdev->dev, "no more ICB available.");
+		error = -EINVAL;
+		goto err;
+	}
+
+	/* do we have at least one ICB config? */
+	if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) {
+		dev_err(&pdev->dev, "at least one ICB is required.");
+		error = -EINVAL;
+		goto err;
+	}
+
+	/* make sure that there's no overlaps */
+	if (meram_check_overlap(priv, &cfg->icb[0])) {
+		dev_err(&pdev->dev, "conflicting config detected.");
+		error = -EINVAL;
+		goto err;
+	}
+	n = 1;
+
+	/* do the same if we have the second ICB set */
+	if (cfg->icb[1].marker_icb >= 0 && cfg->icb[1].cache_icb >= 0) {
+		if (meram_check_overlap(priv, &cfg->icb[1])) {
+			dev_err(&pdev->dev, "conflicting config detected.");
+			error = -EINVAL;
+			goto err;
+		}
+		n = 2;
+	}
+
+	if (is_nvcolor(pixelformat) && n != 2) {
+		dev_err(&pdev->dev, "requires two ICB sets for planar Y/C.");
+		error =  -EINVAL;
+		goto err;
+	}
+
+	/* we now register the ICB */
+	cfg->pixelformat = pixelformat;
+	meram_mark(priv, &cfg->icb[0]);
+	if (is_nvcolor(pixelformat))
+		meram_mark(priv, &cfg->icb[1]);
+
+	/* initialize MERAM */
+	meram_init(priv, &cfg->icb[0], xres, yres, &out_pitch);
+	*pitch = out_pitch;
+	if (pixelformat == SH_MOBILE_MERAM_PF_NV)
+		meram_init(priv, &cfg->icb[1], xres, (yres + 1) / 2,
+			&out_pitch);
+	else if (pixelformat == SH_MOBILE_MERAM_PF_NV24)
+		meram_init(priv, &cfg->icb[1], 2 * xres, (yres + 1) / 2,
+			&out_pitch);
+
+	cfg->current_reg = 1;
+	meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
+	meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
+
+	dev_dbg(&pdev->dev, "registered - can access via y=%08lx, c=%08lx",
+		*icb_addr_y, *icb_addr_c);
+
+err:
+	mutex_unlock(&priv->lock);
+	return error;
+}
+
+static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata,
+				      struct sh_mobile_meram_cfg *cfg)
+{
+	struct sh_mobile_meram_priv *priv;
+
+	if (!pdata || !pdata->priv || !cfg)
+		return -EINVAL;
+
+	priv = pdata->priv;
+
+	mutex_lock(&priv->lock);
+
+	/* deinit & unmark */
+	if (is_nvcolor(cfg->pixelformat)) {
+		meram_deinit(priv, &cfg->icb[1]);
+		meram_unmark(priv, &cfg->icb[1]);
+	}
+	meram_deinit(priv, &cfg->icb[0]);
+	meram_unmark(priv, &cfg->icb[0]);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
+				  struct sh_mobile_meram_cfg *cfg,
+				  unsigned long base_addr_y,
+				  unsigned long base_addr_c,
+				  unsigned long *icb_addr_y,
+				  unsigned long *icb_addr_c)
+{
+	struct sh_mobile_meram_priv *priv;
+
+	if (!pdata || !pdata->priv || !cfg)
+		return -EINVAL;
+
+	priv = pdata->priv;
+
+	mutex_lock(&priv->lock);
+
+	meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
+	meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
+	.module			= THIS_MODULE,
+	.meram_register		= sh_mobile_meram_register,
+	.meram_unregister	= sh_mobile_meram_unregister,
+	.meram_update		= sh_mobile_meram_update,
+};
+
+/*
+ * initialize MERAM
+ */
+
+static int sh_mobile_meram_remove(struct platform_device *pdev);
+
+static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
+{
+	struct sh_mobile_meram_priv *priv;
+	struct sh_mobile_meram_info *pdata = pdev->dev.platform_data;
+	struct resource *res;
+	int error;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data defined\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "cannot get platform resources\n");
+		return -ENOENT;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "cannot allocate device data\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	/* initialize private data */
+	mutex_init(&priv->lock);
+	priv->base = ioremap_nocache(res->start, resource_size(res));
+	if (!priv->base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		error = -EFAULT;
+		goto err;
+	}
+	pdata->ops = &sh_mobile_meram_ops;
+	pdata->priv = priv;
+	pdata->pdev = pdev;
+
+	/* initialize ICB addressing mode */
+	if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
+		meram_write_reg(priv->base, MEVCR1, 1 << 29);
+
+	dev_info(&pdev->dev, "sh_mobile_meram initialized.");
+
+	return 0;
+
+err:
+	sh_mobile_meram_remove(pdev);
+
+	return error;
+}
+
+
+static int sh_mobile_meram_remove(struct platform_device *pdev)
+{
+	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+
+	if (priv->base)
+		iounmap(priv->base);
+
+	mutex_destroy(&priv->lock);
+
+	kfree(priv);
+
+	return 0;
+}
+
+static struct platform_driver sh_mobile_meram_driver = {
+	.driver	= {
+		.name		= "sh_mobile_meram",
+		.owner		= THIS_MODULE,
+	},
+	.probe		= sh_mobile_meram_probe,
+	.remove		= sh_mobile_meram_remove,
+};
+
+static int __init sh_mobile_meram_init(void)
+{
+	return platform_driver_register(&sh_mobile_meram_driver);
+}
+
+static void __exit sh_mobile_meram_exit(void)
+{
+	platform_driver_unregister(&sh_mobile_meram_driver);
+}
+
+module_init(sh_mobile_meram_init);
+module_exit(sh_mobile_meram_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile MERAM driver");
+MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama");
+MODULE_LICENSE("GPL v2");

+ 41 - 0
drivers/video/sh_mobile_meram.h

@@ -0,0 +1,41 @@
+#ifndef __sh_mobile_meram_h__
+#define __sh_mobile_meram_h__
+
+#include <linux/mutex.h>
+#include <video/sh_mobile_meram.h>
+
+/*
+ * MERAM private
+ */
+
+#define MERAM_ICB_Y 0x1
+#define MERAM_ICB_C 0x2
+
+/* MERAM cache size */
+#define SH_MOBILE_MERAM_ICB_NUM		32
+
+#define SH_MOBILE_MERAM_CACHE_OFFSET(p)	((p) >> 16)
+#define SH_MOBILE_MERAM_CACHE_SIZE(p)	((p) & 0xffff)
+
+struct sh_mobile_meram_priv {
+	void __iomem	*base;
+	struct mutex	lock;
+	unsigned long	used_icb;
+	int		used_meram_cache_regions;
+	unsigned long	used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
+};
+
+int sh_mobile_meram_alloc_icb(const struct sh_mobile_meram_cfg *cfg,
+		   int xres,
+		   int yres,
+		   unsigned int base_addr,
+		   int yuv_mode,
+		   int *marker_icb,
+		   int *out_pitch);
+
+void sh_mobile_meram_free_icb(int marker_icb);
+
+#define SH_MOBILE_MERAM_START(ind, ab) \
+	(0xC0000000 | ((ab & 0x1) << 23) | ((ind & 0x1F) << 24))
+
+#endif /* !__sh_mobile_meram_h__ */

+ 12 - 12
drivers/video/sm501fb.c

@@ -1625,22 +1625,22 @@ static int sm501fb_start(struct sm501fb_info *info,
 	return 0; /* everything is setup */
 
  err_mem_res:
-	release_resource(info->fbmem_res);
-	kfree(info->fbmem_res);
+	release_mem_region(info->fbmem_res->start,
+			   resource_size(info->fbmem_res));
 
  err_regs2d_map:
 	iounmap(info->regs2d);
 
  err_regs2d_res:
-	release_resource(info->regs2d_res);
-	kfree(info->regs2d_res);
+	release_mem_region(info->regs2d_res->start,
+			   resource_size(info->regs2d_res));
 
  err_regs_map:
 	iounmap(info->regs);
 
  err_regs_res:
-	release_resource(info->regs_res);
-	kfree(info->regs_res);
+	release_mem_region(info->regs_res->start,
+			   resource_size(info->regs_res));
 
  err_release:
 	return ret;
@@ -1652,16 +1652,16 @@ static void sm501fb_stop(struct sm501fb_info *info)
 	sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
 
 	iounmap(info->fbmem);
-	release_resource(info->fbmem_res);
-	kfree(info->fbmem_res);
+	release_mem_region(info->fbmem_res->start,
+			   resource_size(info->fbmem_res));
 
 	iounmap(info->regs2d);
-	release_resource(info->regs2d_res);
-	kfree(info->regs2d_res);
+	release_mem_region(info->regs2d_res->start,
+			   resource_size(info->regs2d_res));
 
 	iounmap(info->regs);
-	release_resource(info->regs_res);
-	kfree(info->regs_res);
+	release_mem_region(info->regs_res->start,
+			   resource_size(info->regs_res));
 }
 
 static int sm501fb_init_fb(struct fb_info *fb,

+ 17 - 3
drivers/video/udlfb.c

@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/prefetch.h>
 #include <linux/delay.h>
+#include <linux/prefetch.h>
 #include <video/udlfb.h>
 #include "edid.h"
 
@@ -1587,10 +1588,19 @@ static int dlfb_usb_probe(struct usb_interface *interface,
 		goto error;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
-		device_create_file(info->dev, &fb_device_attrs[i]);
+	for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
+		retval = device_create_file(info->dev, &fb_device_attrs[i]);
+		if (retval) {
+			pr_err("device_create_file failed %d\n", retval);
+			goto err_del_attrs;
+		}
+	}
 
-	device_create_bin_file(info->dev, &edid_attr);
+	retval = device_create_bin_file(info->dev, &edid_attr);
+	if (retval) {
+		pr_err("device_create_bin_file failed %d\n", retval);
+		goto err_del_attrs;
+	}
 
 	pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
 			" Using %dK framebuffer memory\n", info->node,
@@ -1599,6 +1609,10 @@ static int dlfb_usb_probe(struct usb_interface *interface,
 			info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
 	return 0;
 
+err_del_attrs:
+	for (i -= 1; i >= 0; i--)
+		device_remove_file(info->dev, &fb_device_attrs[i]);
+
 error:
 	if (dev) {
 

+ 4 - 4
arch/arm/plat-omap/include/plat/panel-generic-dpi.h → include/video/omap-panel-generic-dpi.h

@@ -17,10 +17,10 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
-#define __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
+#ifndef __OMAP_PANEL_GENERIC_DPI_H
+#define __OMAP_PANEL_GENERIC_DPI_H
 
-#include "display.h"
+struct omap_dss_device;
 
 /**
  * struct panel_generic_dpi_data - panel driver configuration data
@@ -34,4 +34,4 @@ struct panel_generic_dpi_data {
 	void (*platform_disable)(struct omap_dss_device *dssdev);
 };
 
-#endif /* __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H */
+#endif /* __OMAP_PANEL_GENERIC_DPI_H */

+ 8 - 6
arch/arm/plat-omap/include/plat/nokia-dsi-panel.h → include/video/omap-panel-nokia-dsi.h

@@ -1,14 +1,15 @@
-#ifndef __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H
-#define __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H
+#ifndef __OMAP_NOKIA_DSI_PANEL_H
+#define __OMAP_NOKIA_DSI_PANEL_H
 
-#include "display.h"
+struct omap_dss_device;
 
 /**
  * struct nokia_dsi_panel_data - Nokia DSI panel driver configuration
  * @name: panel name
  * @use_ext_te: use external TE
  * @ext_te_gpio: external TE GPIO
- * @use_esd_check: perform ESD checks
+ * @esd_interval: interval of ESD checks, 0 = disabled (ms)
+ * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
  * @max_backlight_level: maximum backlight level
  * @set_backlight: pointer to backlight set function
  * @get_backlight: pointer to backlight get function
@@ -21,11 +22,12 @@ struct nokia_dsi_panel_data {
 	bool use_ext_te;
 	int ext_te_gpio;
 
-	bool use_esd_check;
+	unsigned esd_interval;
+	unsigned ulps_timeout;
 
 	int max_backlight_level;
 	int (*set_backlight)(struct omap_dss_device *dssdev, int level);
 	int (*get_backlight)(struct omap_dss_device *dssdev);
 };
 
-#endif /* __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H */
+#endif /* __OMAP_NOKIA_DSI_PANEL_H */

+ 82 - 32
arch/arm/plat-omap/include/plat/display.h → include/video/omapdss.h

@@ -1,6 +1,4 @@
 /*
- * linux/include/asm-arm/arch-omap/display.h
- *
  * Copyright (C) 2008 Nokia Corporation
  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
  *
@@ -17,8 +15,8 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __ASM_ARCH_OMAP_DISPLAY_H
-#define __ASM_ARCH_OMAP_DISPLAY_H
+#ifndef __OMAP_OMAPDSS_H
+#define __OMAP_OMAPDSS_H
 
 #include <linux/list.h>
 #include <linux/kobject.h>
@@ -88,6 +86,11 @@ enum omap_color_mode {
 	OMAP_DSS_COLOR_ARGB32	= 1 << 11, /* ARGB32 */
 	OMAP_DSS_COLOR_RGBA32	= 1 << 12, /* RGBA32 */
 	OMAP_DSS_COLOR_RGBX32	= 1 << 13, /* RGBx32 */
+	OMAP_DSS_COLOR_NV12		= 1 << 14, /* NV12 format: YUV 4:2:0 */
+	OMAP_DSS_COLOR_RGBA16		= 1 << 15, /* RGBA16 - 4444 */
+	OMAP_DSS_COLOR_RGBX16		= 1 << 16, /* RGBx16 - 4444 */
+	OMAP_DSS_COLOR_ARGB16_1555	= 1 << 17, /* ARGB16 - 1555 */
+	OMAP_DSS_COLOR_XRGB16_1555	= 1 << 18, /* xRGB16 - 1555 */
 };
 
 enum omap_lcd_display_type {
@@ -174,6 +177,17 @@ enum omap_overlay_manager_caps {
 	OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0,
 };
 
+enum omap_dss_clk_source {
+	OMAP_DSS_CLK_SRC_FCK = 0,		/* OMAP2/3: DSS1_ALWON_FCLK
+						 * OMAP4: DSS_FCLK */
+	OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC,	/* OMAP3: DSI1_PLL_FCLK
+						 * OMAP4: PLL1_CLK1 */
+	OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI,	/* OMAP3: DSI2_PLL_FCLK
+						 * OMAP4: PLL1_CLK2 */
+	OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC,	/* OMAP4: PLL2_CLK1 */
+	OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI,	/* OMAP4: PLL2_CLK2 */
+};
+
 /* RFBI */
 
 struct rfbi_timings {
@@ -205,20 +219,30 @@ int omap_rfbi_enable_te(bool enable, unsigned line);
 int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
 			     unsigned hs_pulse_time, unsigned vs_pulse_time,
 			     int hs_pol_inv, int vs_pol_inv, int extif_div);
+void rfbi_bus_lock(void);
+void rfbi_bus_unlock(void);
 
 /* DSI */
-void dsi_bus_lock(void);
-void dsi_bus_unlock(void);
-int dsi_vc_dcs_write(int channel, u8 *data, int len);
-int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd);
-int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param);
-int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len);
-int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen);
-int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data);
-int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2);
-int dsi_vc_set_max_rx_packet_size(int channel, u16 len);
-int dsi_vc_send_null(int channel);
-int dsi_vc_send_bta_sync(int channel);
+void dsi_bus_lock(struct omap_dss_device *dssdev);
+void dsi_bus_unlock(struct omap_dss_device *dssdev);
+int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+		int len);
+int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel,
+		u8 dcs_cmd);
+int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+		u8 param);
+int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
+		u8 *data, int len);
+int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+		u8 *buf, int buflen);
+int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+		u8 *data);
+int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+		u8 *data1, u8 *data2);
+int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
+		u16 len);
+int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
+int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
 
 /* Board specific data */
 struct omap_dss_board_info {
@@ -226,6 +250,7 @@ struct omap_dss_board_info {
 	int num_devices;
 	struct omap_dss_device **devices;
 	struct omap_dss_device *default_device;
+	void (*dsi_mux_pads)(bool enable);
 };
 
 #if defined(CONFIG_OMAP2_DSS_MODULE) || defined(CONFIG_OMAP2_DSS)
@@ -280,6 +305,7 @@ struct omap_overlay_info {
 
 	u32 paddr;
 	void __iomem *vaddr;
+	u32 p_uv_addr;  /* for NV12 format */
 	u16 screen_width;
 	u16 width;
 	u16 height;
@@ -400,18 +426,12 @@ struct omap_dss_device {
 			u8 data1_pol;
 			u8 data2_lane;
 			u8 data2_pol;
+			u8 data3_lane;
+			u8 data3_pol;
+			u8 data4_lane;
+			u8 data4_pol;
 
-			struct {
-				u16 regn;
-				u16 regm;
-				u16 regm_dispc;
-				u16 regm_dsi;
-
-				u16 lp_clk_div;
-
-				u16 lck_div;
-				u16 pck_div;
-			} div;
+			int module;
 
 			bool ext_te;
 			u8 ext_te_gpio;
@@ -423,6 +443,33 @@ struct omap_dss_device {
 		} venc;
 	} phy;
 
+	struct {
+		struct {
+			struct {
+				u16 lck_div;
+				u16 pck_div;
+				enum omap_dss_clk_source lcd_clk_src;
+			} channel;
+
+			enum omap_dss_clk_source dispc_fclk_src;
+		} dispc;
+
+		struct {
+			u16 regn;
+			u16 regm;
+			u16 regm_dispc;
+			u16 regm_dsi;
+
+			u16 lp_clk_div;
+			enum omap_dss_clk_source dsi_fclk_src;
+		} dsi;
+
+		struct {
+			u16 regn;
+			u16 regm2;
+		} hdmi;
+	} clocks;
+
 	struct {
 		struct omap_video_timings timings;
 
@@ -503,6 +550,8 @@ struct omap_dss_driver {
 
 	void (*get_resolution)(struct omap_dss_device *dssdev,
 			u16 *xres, u16 *yres);
+	void (*get_dimensions)(struct omap_dss_device *dssdev,
+			u32 *width, u32 *height);
 	int (*get_recommended_bpp)(struct omap_dss_device *dssdev);
 
 	int (*check_timings)(struct omap_dss_device *dssdev,
@@ -519,9 +568,6 @@ struct omap_dss_driver {
 int omap_dss_register_driver(struct omap_dss_driver *);
 void omap_dss_unregister_driver(struct omap_dss_driver *);
 
-int omap_dss_register_device(struct omap_dss_device *);
-void omap_dss_unregister_device(struct omap_dss_device *);
-
 void omap_dss_get_device(struct omap_dss_device *dssdev);
 void omap_dss_put_device(struct omap_dss_device *dssdev);
 #define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
@@ -553,7 +599,8 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
 #define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver)
 #define to_dss_device(x) container_of((x), struct omap_dss_device, dev)
 
-void omapdss_dsi_vc_enable_hs(int channel, bool enable);
+void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
+		bool enable);
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
 
 int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
@@ -568,7 +615,8 @@ 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);
+void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
+		bool disconnect_lanes, bool enter_ulps);
 
 int omapdss_dpi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_dpi_display_disable(struct omap_dss_device *dssdev);
@@ -587,5 +635,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
 int omap_rfbi_update(struct omap_dss_device *dssdev,
 		u16 x, u16 y, u16 w, u16 h,
 		void (*callback)(void *), void *data);
+int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size,
+		int data_lines);
 
 #endif

+ 3 - 0
include/video/sh_mobile_lcdc.h

@@ -2,6 +2,7 @@
 #define __ASM_SH_MOBILE_LCDC_H__
 
 #include <linux/fb.h>
+#include <video/sh_mobile_meram.h>
 
 enum {
 	RGB8,   /* 24bpp, 8:8:8 */
@@ -87,11 +88,13 @@ struct sh_mobile_lcdc_chan_cfg {
 	struct sh_mobile_lcdc_bl_info bl_info;
 	struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
 	int nonstd;
+	struct sh_mobile_meram_cfg *meram_cfg;
 };
 
 struct sh_mobile_lcdc_info {
 	int clock_source;
 	struct sh_mobile_lcdc_chan_cfg ch[2];
+	struct sh_mobile_meram_info *meram_dev;
 };
 
 #endif /* __ASM_SH_MOBILE_LCDC_H__ */

+ 68 - 0
include/video/sh_mobile_meram.h

@@ -0,0 +1,68 @@
+#ifndef __VIDEO_SH_MOBILE_MERAM_H__
+#define __VIDEO_SH_MOBILE_MERAM_H__
+
+/* For sh_mobile_meram_info.addr_mode */
+enum {
+	SH_MOBILE_MERAM_MODE0 = 0,
+	SH_MOBILE_MERAM_MODE1
+};
+
+enum {
+	SH_MOBILE_MERAM_PF_NV = 0,
+	SH_MOBILE_MERAM_PF_RGB,
+	SH_MOBILE_MERAM_PF_NV24
+};
+
+
+struct sh_mobile_meram_priv;
+struct sh_mobile_meram_ops;
+
+struct sh_mobile_meram_info {
+	int				addr_mode;
+	struct sh_mobile_meram_ops	*ops;
+	struct sh_mobile_meram_priv	*priv;
+	struct platform_device		*pdev;
+};
+
+/* icb config */
+struct sh_mobile_meram_icb {
+	int marker_icb;		/* ICB # for Marker ICB */
+	int cache_icb;		/* ICB # for Cache ICB */
+	int meram_offset;	/* MERAM Buffer Offset to use */
+	int meram_size;		/* MERAM Buffer Size to use */
+
+	int cache_unit;		/* bytes to cache per ICB */
+};
+
+struct sh_mobile_meram_cfg {
+	struct sh_mobile_meram_icb	icb[2];
+	int				pixelformat;
+	int				current_reg;
+};
+
+struct module;
+struct sh_mobile_meram_ops {
+	struct module	*module;
+	/* register usage of meram */
+	int (*meram_register)(struct sh_mobile_meram_info *meram_dev,
+			      struct sh_mobile_meram_cfg *cfg,
+			      int xres, int yres, int pixelformat,
+			      unsigned long base_addr_y,
+			      unsigned long base_addr_c,
+			      unsigned long *icb_addr_y,
+			      unsigned long *icb_addr_c, int *pitch);
+
+	/* unregister usage of meram */
+	int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
+				struct sh_mobile_meram_cfg *cfg);
+
+	/* update meram settings */
+	int (*meram_update)(struct sh_mobile_meram_info *meram_dev,
+			    struct sh_mobile_meram_cfg *cfg,
+			    unsigned long base_addr_y,
+			    unsigned long base_addr_c,
+			    unsigned long *icb_addr_y,
+			    unsigned long *icb_addr_c);
+};
+
+#endif /* __VIDEO_SH_MOBILE_MERAM_H__  */

Some files were not shown because too many files changed in this diff