Merge branch 'for-paul-38-rebased' of git://gitorious.org/linux-omap-dss2/linux
authorPaul Mundt <lethal@linux-sh.org>
Tue, 11 Jan 2011 03:01:14 +0000 (12:01 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Tue, 11 Jan 2011 03:01:14 +0000 (12:01 +0900)
34 files changed:
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-3630sdp.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-zoom-display.c [new file with mode: 0644]
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/board-zoom.c
arch/arm/mach-omap2/include/mach/board-zoom.h
arch/arm/plat-omap/include/plat/display.h
arch/arm/plat-omap/include/plat/panel-generic-dpi.h [new file with mode: 0644]
drivers/video/omap2/displays/Kconfig
drivers/video/omap2/displays/Makefile
drivers/video/omap2/displays/panel-generic-dpi.c [new file with mode: 0644]
drivers/video/omap2/displays/panel-generic.c [deleted file]
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c [new file with mode: 0644]
drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c [deleted file]
drivers/video/omap2/displays/panel-toppoly-tdo35s.c [deleted file]
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/omapfb/omapfb-main.c

index cd7332f50b2dad334a99cfcf7131d6391d0f2b35..1c0c2b02d870b74a814c4d92a4d70e6de9f79748 100644 (file)
@@ -187,16 +187,19 @@ obj-$(CONFIG_MACH_NOKIA_RX51)             += board-rx51.o \
                                           hsmmc.o
 obj-$(CONFIG_MACH_OMAP_ZOOM2)          += board-zoom.o \
                                           board-zoom-peripherals.o \
+                                          board-zoom-display.o \
                                           board-flash.o \
                                           hsmmc.o \
                                           board-zoom-debugboard.o
 obj-$(CONFIG_MACH_OMAP_ZOOM3)          += board-zoom.o \
                                           board-zoom-peripherals.o \
+                                          board-zoom-display.o \
                                           board-flash.o \
                                           hsmmc.o \
                                           board-zoom-debugboard.o
 obj-$(CONFIG_MACH_OMAP_3630SDP)                += board-3630sdp.o \
                                           board-zoom-peripherals.o \
+                                          board-zoom-display.o \
                                           board-flash.o \
                                           hsmmc.o
 obj-$(CONFIG_MACH_CM_T35)              += board-cm-t35.o \
index 3b39ef1a680a54df7e930e282908f0c4b2656c79..d4e41ef86aa5ca555040728ef10d23c69abc7ab0 100644 (file)
@@ -38,6 +38,7 @@
 #include <plat/dma.h>
 #include <plat/gpmc.h>
 #include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 
 #include <plat/gpmc-smc91x.h>
 
@@ -270,13 +271,18 @@ static struct omap_dss_device sdp3430_lcd_device = {
        .platform_disable       = sdp3430_panel_disable_lcd,
 };
 
+static struct panel_generic_dpi_data dvi_panel = {
+       .name                   = "generic",
+       .platform_enable        = sdp3430_panel_enable_dvi,
+       .platform_disable       = sdp3430_panel_disable_dvi,
+};
+
 static struct omap_dss_device sdp3430_dvi_device = {
        .name                   = "dvi",
-       .driver_name            = "generic_panel",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
-       .platform_enable        = sdp3430_panel_enable_dvi,
-       .platform_disable       = sdp3430_panel_disable_dvi,
 };
 
 static struct omap_dss_device sdp3430_tv_device = {
index 5d41dbe059a3ffc2e7bb655e4cac7047f5b29052..62645640f5e4b8723394b5acfb634fe12ddca583 100644 (file)
@@ -207,6 +207,7 @@ static void __init omap_sdp_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
        zoom_peripherals_init();
+       zoom_display_init();
        board_smc91x_init();
        board_flash_init(sdp_flash_partitions, chip_sel_sdp);
        enable_board_wakeup_source();
index bc1562648020fc9f5748d870ea8164bd4f7199ce..10d60b7743cfa1a0b59c7ef75dacc9cd2de9532b 100644 (file)
@@ -35,6 +35,7 @@
 #include <plat/common.h>
 #include <plat/usb.h>
 #include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 
 #include "mux.h"
 #include "control.h"
@@ -303,13 +304,18 @@ static void am3517_evm_panel_disable_lcd(struct omap_dss_device *dssdev)
        lcd_enabled = 0;
 }
 
+static struct panel_generic_dpi_data lcd_panel = {
+       .name                   = "sharp_lq",
+       .platform_enable        = am3517_evm_panel_enable_lcd,
+       .platform_disable       = am3517_evm_panel_disable_lcd,
+};
+
 static struct omap_dss_device am3517_evm_lcd_device = {
        .type                   = OMAP_DISPLAY_TYPE_DPI,
        .name                   = "lcd",
-       .driver_name            = "sharp_lq_panel",
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &lcd_panel,
        .phy.dpi.data_lines     = 16,
-       .platform_enable        = am3517_evm_panel_enable_lcd,
-       .platform_disable       = am3517_evm_panel_disable_lcd,
 };
 
 static int am3517_evm_panel_enable_tv(struct omap_dss_device *dssdev)
@@ -346,13 +352,18 @@ static void am3517_evm_panel_disable_dvi(struct omap_dss_device *dssdev)
        dvi_enabled = 0;
 }
 
+static struct panel_generic_dpi_data dvi_panel = {
+       .name                   = "generic",
+       .platform_enable        = am3517_evm_panel_enable_dvi,
+       .platform_disable       = am3517_evm_panel_disable_dvi,
+};
+
 static struct omap_dss_device am3517_evm_dvi_device = {
        .type                   = OMAP_DISPLAY_TYPE_DPI,
        .name                   = "dvi",
-       .driver_name            = "generic_panel",
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
-       .platform_enable        = am3517_evm_panel_enable_dvi,
-       .platform_disable       = am3517_evm_panel_disable_dvi,
 };
 
 static struct omap_dss_device *am3517_evm_dss_devices[] = {
index 486a3de5f4018c9eb17aaf9c6f073d62e7dbb660..dac141610666442dd7e578acb92b97163948d95d 100644 (file)
@@ -46,6 +46,7 @@
 #include <plat/gpmc.h>
 #include <plat/usb.h>
 #include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 #include <plat/mcspi.h>
 
 #include <mach/hardware.h>
@@ -351,22 +352,32 @@ static void cm_t35_panel_disable_tv(struct omap_dss_device *dssdev)
 {
 }
 
+static struct panel_generic_dpi_data lcd_panel = {
+       .name                   = "toppoly_tdo35s",
+       .platform_enable        = cm_t35_panel_enable_lcd,
+       .platform_disable       = cm_t35_panel_disable_lcd,
+};
+
 static struct omap_dss_device cm_t35_lcd_device = {
        .name                   = "lcd",
-       .driver_name            = "toppoly_tdo35s_panel",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &lcd_panel,
        .phy.dpi.data_lines     = 18,
-       .platform_enable        = cm_t35_panel_enable_lcd,
-       .platform_disable       = cm_t35_panel_disable_lcd,
+};
+
+static struct panel_generic_dpi_data dvi_panel = {
+       .name                   = "generic",
+       .platform_enable        = cm_t35_panel_enable_dvi,
+       .platform_disable       = cm_t35_panel_disable_dvi,
 };
 
 static struct omap_dss_device cm_t35_dvi_device = {
        .name                   = "dvi",
-       .driver_name            = "generic_panel",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
-       .platform_enable        = cm_t35_panel_enable_dvi,
-       .platform_disable       = cm_t35_panel_disable_dvi,
 };
 
 static struct omap_dss_device cm_t35_tv_device = {
index 451e7ff08b18b4cf9c0bbca4623b094cc0613872..00bb1fc5e0175fb433dcb564ffce78ce46f2e0ff 100644 (file)
@@ -46,6 +46,7 @@
 #include <plat/nand.h>
 #include <plat/usb.h>
 #include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
@@ -149,23 +150,32 @@ static struct regulator_consumer_supply devkit8000_vmmc1_supply =
 static struct regulator_consumer_supply devkit8000_vio_supply =
        REGULATOR_SUPPLY("vcc", "spi2.0");
 
+static struct panel_generic_dpi_data lcd_panel = {
+       .name                   = "generic",
+       .platform_enable        = devkit8000_panel_enable_lcd,
+       .platform_disable       = devkit8000_panel_disable_lcd,
+};
+
 static struct omap_dss_device devkit8000_lcd_device = {
        .name                   = "lcd",
-       .driver_name            = "generic_panel",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &lcd_panel,
        .phy.dpi.data_lines     = 24,
-       .reset_gpio             = -EINVAL, /* will be replaced */
-       .platform_enable        = devkit8000_panel_enable_lcd,
-       .platform_disable       = devkit8000_panel_disable_lcd,
 };
+
+static struct panel_generic_dpi_data dvi_panel = {
+       .name                   = "generic",
+       .platform_enable        = devkit8000_panel_enable_dvi,
+       .platform_disable       = devkit8000_panel_disable_dvi,
+};
+
 static struct omap_dss_device devkit8000_dvi_device = {
        .name                   = "dvi",
-       .driver_name            = "generic_panel",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
-       .reset_gpio             = -EINVAL, /* will be replaced */
-       .platform_enable        = devkit8000_panel_enable_dvi,
-       .platform_disable       = devkit8000_panel_disable_dvi,
 };
 
 static struct omap_dss_device devkit8000_tv_device = {
index 0afa3011db0f138cdb4c2a7f91998fb9224e6ecd..ebaa230e67ed909658238f44483b668ad5d1358b 100644 (file)
@@ -31,6 +31,7 @@
 #include <plat/gpmc.h>
 #include <plat/usb.h>
 #include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 #include <plat/onenand.h>
 
 #include "mux.h"
@@ -459,13 +460,18 @@ static void igep2_disable_dvi(struct omap_dss_device *dssdev)
        gpio_direction_output(IGEP2_GPIO_DVI_PUP, 0);
 }
 
+static struct panel_generic_dpi_data dvi_panel = {
+       .name                   = "generic",
+       .platform_enable        = igep2_enable_dvi,
+       .platform_disable       = igep2_disable_dvi,
+};
+
 static struct omap_dss_device igep2_dvi_device = {
        .type                   = OMAP_DISPLAY_TYPE_DPI,
        .name                   = "dvi",
-       .driver_name            = "generic_panel",
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
-       .platform_enable        = igep2_enable_dvi,
-       .platform_disable       = igep2_disable_dvi,
 };
 
 static struct omap_dss_device *igep2_dss_devices[] = {
index 6c127605942ffd1fdfaec8dc1f013507dacb7f6d..a4fe8e1ee1bd6ae379c8875f48b6b71832069fa0 100644 (file)
@@ -41,6 +41,7 @@
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
@@ -194,14 +195,19 @@ static void beagle_disable_dvi(struct omap_dss_device *dssdev)
                gpio_set_value(dssdev->reset_gpio, 0);
 }
 
+static struct panel_generic_dpi_data dvi_panel = {
+       .name = "generic",
+       .platform_enable = beagle_enable_dvi,
+       .platform_disable = beagle_disable_dvi,
+};
+
 static struct omap_dss_device beagle_dvi_device = {
        .type = OMAP_DISPLAY_TYPE_DPI,
        .name = "dvi",
-       .driver_name = "generic_panel",
+       .driver_name = "generic_dpi_panel",
+       .data = &dvi_panel,
        .phy.dpi.data_lines = 24,
        .reset_gpio = 170,
-       .platform_enable = beagle_enable_dvi,
-       .platform_disable = beagle_disable_dvi,
 };
 
 static struct omap_dss_device beagle_tv_device = {
index 3de8d9b8ec76ee010aad26422fc7d7b950ccf9a2..323c3809ce394fdcd98323d10aabefef07495064 100644 (file)
@@ -43,6 +43,7 @@
 #include <plat/common.h>
 #include <plat/mcspi.h>
 #include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
@@ -301,13 +302,18 @@ static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev)
        dvi_enabled = 0;
 }
 
+static struct panel_generic_dpi_data dvi_panel = {
+       .name                   = "generic",
+       .platform_enable        = omap3_evm_enable_dvi,
+       .platform_disable       = omap3_evm_disable_dvi,
+};
+
 static struct omap_dss_device omap3_evm_dvi_device = {
        .name                   = "dvi",
-       .driver_name            = "generic_panel",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
-       .platform_enable        = omap3_evm_enable_dvi,
-       .platform_disable       = omap3_evm_disable_dvi,
 };
 
 static struct omap_dss_device *omap3_evm_dss_devices[] = {
index 9df9d9367608cf5e669247b2d448253663b0e982..2a2dad447e86b66b94575d289577670bdcfe1405 100644 (file)
@@ -40,6 +40,7 @@
 #include <plat/nand.h>
 #include <plat/usb.h>
 #include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
@@ -160,13 +161,18 @@ static void omap3_stalker_disable_lcd(struct omap_dss_device *dssdev)
        lcd_enabled = 0;
 }
 
+static struct panel_generic_dpi_data lcd_panel = {
+       .name                   = "generic",
+       .platform_enable        = omap3_stalker_enable_lcd,
+       .platform_disable       = omap3_stalker_disable_lcd,
+};
+
 static struct omap_dss_device omap3_stalker_lcd_device = {
        .name                   = "lcd",
-       .driver_name            = "generic_panel",
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &lcd_panel,
        .phy.dpi.data_lines     = 24,
        .type                   = OMAP_DISPLAY_TYPE_DPI,
-       .platform_enable        = omap3_stalker_enable_lcd,
-       .platform_disable       = omap3_stalker_disable_lcd,
 };
 
 static int omap3_stalker_enable_tv(struct omap_dss_device *dssdev)
@@ -208,13 +214,18 @@ static void omap3_stalker_disable_dvi(struct omap_dss_device *dssdev)
        dvi_enabled = 0;
 }
 
+static struct panel_generic_dpi_data dvi_panel = {
+       .name                   = "generic",
+       .platform_enable        = omap3_stalker_enable_dvi,
+       .platform_disable       = omap3_stalker_disable_dvi,
+};
+
 static struct omap_dss_device omap3_stalker_dvi_device = {
        .name                   = "dvi",
-       .driver_name            = "generic_panel",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
-       .platform_enable        = omap3_stalker_enable_dvi,
-       .platform_disable       = omap3_stalker_disable_dvi,
 };
 
 static struct omap_dss_device *omap3_stalker_dss_devices[] = {
diff --git a/arch/arm/mach-omap2/board-zoom-display.c b/arch/arm/mach-omap2/board-zoom-display.c
new file mode 100644 (file)
index 0000000..6bcd436
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Modified from mach-omap2/board-zoom-peripherals.c
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/i2c/twl.h>
+#include <linux/spi/spi.h>
+#include <plat/mcspi.h>
+#include <plat/display.h>
+
+#define LCD_PANEL_RESET_GPIO_PROD      96
+#define LCD_PANEL_RESET_GPIO_PILOT     55
+#define LCD_PANEL_QVGA_GPIO            56
+
+static void zoom_lcd_panel_init(void)
+{
+       int ret;
+       unsigned char lcd_panel_reset_gpio;
+
+       lcd_panel_reset_gpio = (omap_rev() > OMAP3430_REV_ES3_0) ?
+                       LCD_PANEL_RESET_GPIO_PROD :
+                       LCD_PANEL_RESET_GPIO_PILOT;
+
+       ret = gpio_request(lcd_panel_reset_gpio, "lcd reset");
+       if (ret) {
+               pr_err("Failed to get LCD reset GPIO (gpio%d).\n",
+                       lcd_panel_reset_gpio);
+               return;
+       }
+       gpio_direction_output(lcd_panel_reset_gpio, 1);
+
+       ret = gpio_request(LCD_PANEL_QVGA_GPIO, "lcd qvga");
+       if (ret) {
+               pr_err("Failed to get LCD_PANEL_QVGA_GPIO (gpio%d).\n",
+                       LCD_PANEL_QVGA_GPIO);
+               goto err0;
+       }
+       gpio_direction_output(LCD_PANEL_QVGA_GPIO, 1);
+
+       return;
+err0:
+       gpio_free(lcd_panel_reset_gpio);
+}
+
+static int zoom_panel_enable_lcd(struct omap_dss_device *dssdev)
+{
+       return 0;
+}
+
+static void zoom_panel_disable_lcd(struct omap_dss_device *dssdev)
+{
+}
+
+/*
+ * PWMA/B register offsets (TWL4030_MODULE_PWMA)
+ */
+#define TWL_INTBR_PMBR1        0xD
+#define TWL_INTBR_GPBR1        0xC
+#define TWL_LED_PWMON  0x0
+#define TWL_LED_PWMOFF 0x1
+
+static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
+{
+       unsigned char c;
+       u8 mux_pwm, enb_pwm;
+
+       if (level > 100)
+               return -1;
+
+       twl_i2c_read_u8(TWL4030_MODULE_INTBR, &mux_pwm, TWL_INTBR_PMBR1);
+       twl_i2c_read_u8(TWL4030_MODULE_INTBR, &enb_pwm, TWL_INTBR_GPBR1);
+
+       if (level == 0) {
+               /* disable pwm1 output and clock */
+               enb_pwm = enb_pwm & 0xF5;
+               /* change pwm1 pin to gpio pin */
+               mux_pwm = mux_pwm & 0xCF;
+               twl_i2c_write_u8(TWL4030_MODULE_INTBR,
+                                       enb_pwm, TWL_INTBR_GPBR1);
+               twl_i2c_write_u8(TWL4030_MODULE_INTBR,
+                                       mux_pwm, TWL_INTBR_PMBR1);
+               return 0;
+       }
+
+       if (!((enb_pwm & 0xA) && (mux_pwm & 0x30))) {
+               /* change gpio pin to pwm1 pin */
+               mux_pwm = mux_pwm | 0x30;
+               /* enable pwm1 output and clock*/
+               enb_pwm = enb_pwm | 0x0A;
+               twl_i2c_write_u8(TWL4030_MODULE_INTBR,
+                                       mux_pwm, TWL_INTBR_PMBR1);
+               twl_i2c_write_u8(TWL4030_MODULE_INTBR,
+                                       enb_pwm, TWL_INTBR_GPBR1);
+       }
+
+       c = ((50 * (100 - level)) / 100) + 1;
+       twl_i2c_write_u8(TWL4030_MODULE_PWM1, 0x7F, TWL_LED_PWMOFF);
+       twl_i2c_write_u8(TWL4030_MODULE_PWM1, c, TWL_LED_PWMON);
+
+       return 0;
+}
+
+static struct omap_dss_device zoom_lcd_device = {
+       .name                   = "lcd",
+       .driver_name            = "NEC_8048_panel",
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .phy.dpi.data_lines     = 24,
+       .platform_enable        = zoom_panel_enable_lcd,
+       .platform_disable       = zoom_panel_disable_lcd,
+       .max_backlight_level    = 100,
+       .set_backlight          = zoom_set_bl_intensity,
+};
+
+static struct omap_dss_device *zoom_dss_devices[] = {
+       &zoom_lcd_device,
+};
+
+static struct omap_dss_board_info zoom_dss_data = {
+       .num_devices            = ARRAY_SIZE(zoom_dss_devices),
+       .devices                = zoom_dss_devices,
+       .default_device         = &zoom_lcd_device,
+};
+
+static struct platform_device zoom_dss_device = {
+       .name                           = "omapdss",
+       .id                             = -1,
+       .dev                            = {
+               .platform_data          = &zoom_dss_data,
+       },
+};
+
+static struct omap2_mcspi_device_config dss_lcd_mcspi_config = {
+       .turbo_mode             = 1,
+       .single_channel = 1,  /* 0: slave, 1: master */
+};
+
+static struct spi_board_info nec_8048_spi_board_info[] __initdata = {
+       [0] = {
+               .modalias               = "nec_8048_spi",
+               .bus_num                = 1,
+               .chip_select            = 2,
+               .max_speed_hz           = 375000,
+               .controller_data        = &dss_lcd_mcspi_config,
+       },
+};
+
+static struct platform_device *zoom_display_devices[] __initdata = {
+       &zoom_dss_device,
+};
+
+void __init zoom_display_init(void)
+{
+       platform_add_devices(zoom_display_devices,
+                               ARRAY_SIZE(zoom_display_devices));
+       spi_register_board_info(nec_8048_spi_board_info,
+                               ARRAY_SIZE(nec_8048_spi_board_info));
+       zoom_lcd_panel_init();
+}
+
index 3fbd0edd712e4290796b34943d90ebec9b4b2e5e..14d95afa3f0d8d73654b952bfde399fa79160c28 100644 (file)
@@ -35,6 +35,8 @@
 #define OMAP_ZOOM_WLAN_PMENA_GPIO      (101)
 #define OMAP_ZOOM_WLAN_IRQ_GPIO                (162)
 
+#define LCD_PANEL_ENABLE_GPIO          (7 + OMAP_MAX_GPIO_LINES)
+
 /* Zoom2 has Qwerty keyboard*/
 static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_E),
@@ -224,9 +226,43 @@ static struct omap2_hsmmc_info mmc[] = {
        {}      /* Terminator */
 };
 
+static struct regulator_consumer_supply zoom_vpll2_supply =
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+
+static struct regulator_consumer_supply zoom_vdda_dac_supply =
+       REGULATOR_SUPPLY("vdda_dac", "omapdss");
+
+static struct regulator_init_data zoom_vpll2 = {
+       .constraints = {
+               .min_uV                 = 1800000,
+               .max_uV                 = 1800000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies          = 1,
+       .consumer_supplies              = &zoom_vpll2_supply,
+};
+
+static struct regulator_init_data zoom_vdac = {
+       .constraints = {
+               .min_uV                 = 1800000,
+               .max_uV                 = 1800000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies          = 1,
+       .consumer_supplies              = &zoom_vdda_dac_supply,
+};
+
 static int zoom_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
+       int ret;
+
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
        omap2_hsmmc_init(mmc);
@@ -238,7 +274,15 @@ static int zoom_twl_gpio_setup(struct device *dev,
        zoom_vsim_supply.dev = mmc[0].dev;
        zoom_vmmc2_supply.dev = mmc[1].dev;
 
-       return 0;
+       ret = gpio_request(LCD_PANEL_ENABLE_GPIO, "lcd enable");
+       if (ret) {
+               pr_err("Failed to get LCD_PANEL_ENABLE_GPIO (gpio%d).\n",
+                               LCD_PANEL_ENABLE_GPIO);
+               return ret;
+       }
+       gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
+
+       return ret;
 }
 
 /* EXTMUTE callback function */
@@ -301,7 +345,8 @@ static struct twl4030_platform_data zoom_twldata = {
        .vmmc1          = &zoom_vmmc1,
        .vmmc2          = &zoom_vmmc2,
        .vsim           = &zoom_vsim,
-
+       .vpll2          = &zoom_vpll2,
+       .vdac           = &zoom_vdac,
 };
 
 static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
index e041c537ea37d66fa3a84697ff124a5fda1b87e7..e26754c24ee84892515e47e4fec818a552b031d1 100644 (file)
@@ -130,6 +130,7 @@ static void __init omap_zoom_init(void)
                        ARRAY_SIZE(zoom_nand_partitions), ZOOM_NAND_CS);
        zoom_debugboard_init();
        zoom_peripherals_init();
+       zoom_display_init();
 }
 
 MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
index f93ca3928c3bd65aaa63473a72e732a869a89930..d20bd9c1a1061cfde9b547073b354fb23e8d0321 100644 (file)
@@ -1,9 +1,12 @@
 /*
  * Defines for zoom boards
  */
+#include <plat/display.h>
+
 #define ZOOM_NAND_CS    0
 
 extern int __init zoom_debugboard_init(void);
 extern void __init zoom_peripherals_init(void);
+extern void __init zoom_display_init(void);
 
 #define ZOOM2_HEADSET_EXTMUTE_GPIO     153
index c915a661f1f5668a6aa7f0b9b50cbf664507f2d4..537f4e449f50b429b05f3c21ac74e9f7920b18c9 100644 (file)
 #define DISPC_IRQ_SYNC_LOST            (1 << 14)
 #define DISPC_IRQ_SYNC_LOST_DIGIT      (1 << 15)
 #define DISPC_IRQ_WAKEUP               (1 << 16)
+#define DISPC_IRQ_SYNC_LOST2           (1 << 17)
+#define DISPC_IRQ_VSYNC2               (1 << 18)
+#define DISPC_IRQ_ACBIAS_COUNT_STAT2   (1 << 21)
+#define DISPC_IRQ_FRAMEDONE2           (1 << 22)
 
 struct omap_dss_device;
 struct omap_overlay_manager;
@@ -64,6 +68,7 @@ enum omap_plane {
 enum omap_channel {
        OMAP_DSS_CHANNEL_LCD    = 0,
        OMAP_DSS_CHANNEL_DIGIT  = 1,
+       OMAP_DSS_CHANNEL_LCD2   = 2,
 };
 
 enum omap_color_mode {
@@ -142,6 +147,7 @@ enum omap_dss_display_state {
 enum omap_dss_overlay_managers {
        OMAP_DSS_OVL_MGR_LCD,
        OMAP_DSS_OVL_MGR_TV,
+       OMAP_DSS_OVL_MGR_LCD2,
 };
 
 enum omap_dss_rotation_type {
@@ -268,6 +274,7 @@ struct omap_overlay_info {
        u16 out_width;  /* if 0, out_width == width */
        u16 out_height; /* if 0, out_height == height */
        u8 global_alpha;
+       u8 pre_mult_alpha;
 };
 
 struct omap_overlay {
@@ -351,6 +358,8 @@ struct omap_dss_device {
 
        enum omap_display_type type;
 
+       enum omap_channel channel;
+
        union {
                struct {
                        u8 data_lines;
diff --git a/arch/arm/plat-omap/include/plat/panel-generic-dpi.h b/arch/arm/plat-omap/include/plat/panel-generic-dpi.h
new file mode 100644 (file)
index 0000000..7906197
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Header for generic DPI panel driver
+ *
+ * Copyright (C) 2010 Canonical Ltd.
+ * Author: Bryan Wu <bryan.wu@canonical.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 __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
+#define __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
+
+#include "display.h"
+
+/**
+ * struct panel_generic_dpi_data - panel driver configuration data
+ * @name: panel name
+ * @platform_enable: platform specific panel enable function
+ * @platform_disable: platform specific panel disable function
+ */
+struct panel_generic_dpi_data {
+       const char *name;
+       int (*platform_enable)(struct omap_dss_device *dssdev);
+       void (*platform_disable)(struct omap_dss_device *dssdev);
+};
+
+#endif /* __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H */
index 12327bbfdbbba94118597ba73a3df7bc360884c9..940cab394c2e6b173c2cae0abae51db5ddd583bb 100644 (file)
@@ -1,11 +1,13 @@
 menu "OMAP2/3 Display Device Drivers"
         depends on OMAP2_DSS
 
-config PANEL_GENERIC
-        tristate "Generic Panel"
+config PANEL_GENERIC_DPI
+        tristate "Generic DPI Panel"
         help
-         Generic panel driver.
-         Used for DVI output for Beagle and OMAP3 SDP.
+         Generic DPI panel driver.
+         Supports DVI output for Beagle and OMAP3 SDP.
+         Supports LCD Panel used in TI SDP3430 and EVM boards,
+         OMAP3517 EVM boards and CM-T35.
 
 config PANEL_SHARP_LS037V7DW01
         tristate "Sharp LS037V7DW01 LCD Panel"
@@ -14,11 +16,12 @@ config PANEL_SHARP_LS037V7DW01
         help
           LCD Panel used in TI's SDP3430 and EVM boards
 
-config PANEL_SHARP_LQ043T1DG01
-        tristate "Sharp LQ043T1DG01 LCD Panel"
-        depends on OMAP2_DSS
-        help
-          LCD Panel used in TI's OMAP3517 EVM boards
+config PANEL_NEC_NL8048HL11_01B
+       tristate "NEC NL8048HL11-01B Panel"
+       depends on OMAP2_DSS
+       help
+               This NEC NL8048HL11-01B panel is TFT LCD
+               used in the Zoom2/3/3630 sdp boards.
 
 config PANEL_TAAL
         tristate "Taal DSI Panel"
@@ -26,12 +29,6 @@ config PANEL_TAAL
         help
           Taal DSI command mode panel from TPO.
 
-config PANEL_TOPPOLY_TDO35S
-        tristate "Toppoly TDO35S LCD Panel support"
-        depends on OMAP2_DSS
-        help
-          LCD Panel used in CM-T35
-
 config PANEL_TPO_TD043MTEA1
         tristate "TPO TD043MTEA1 LCD Panel"
         depends on OMAP2_DSS && SPI
index aa386095d7c4ef79f2a243592557f8fe54a9b1ed..861f0255ec6ba5d12739b40dcc194886a1986b51 100644 (file)
@@ -1,8 +1,7 @@
-obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
+obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o
 obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
-obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o
+obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
 
 obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
-obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o
 obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
 obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
new file mode 100644 (file)
index 0000000..07eb30e
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Generic DPI Panels support
+ *
+ * Copyright (C) 2010 Canonical Ltd.
+ * Author: Bryan Wu <bryan.wu@canonical.com>
+ *
+ * LCD panel driver for Sharp LQ043T1DG01
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * LCD panel driver for Toppoly TDO35S
+ *
+ * Copyright (C) 2009 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <plat/panel-generic-dpi.h>
+
+struct panel_config {
+       struct omap_video_timings timings;
+
+       int acbi;       /* ac-bias pin transitions per interrupt */
+       /* Unit: line clocks */
+       int acb;        /* ac-bias pin frequency */
+
+       enum omap_panel_config config;
+
+       int power_on_delay;
+       int power_off_delay;
+
+       /*
+        * Used to match device to panel configuration
+        * when use generic panel driver
+        */
+       const char *name;
+};
+
+/* Panel configurations */
+static struct panel_config generic_dpi_panels[] = {
+       /* Generic Panel */
+       {
+               {
+                       .x_res          = 640,
+                       .y_res          = 480,
+
+                       .pixel_clock    = 23500,
+
+                       .hfp            = 48,
+                       .hsw            = 32,
+                       .hbp            = 80,
+
+                       .vfp            = 3,
+                       .vsw            = 4,
+                       .vbp            = 7,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x0,
+               .config                 = OMAP_DSS_LCD_TFT,
+               .power_on_delay         = 0,
+               .power_off_delay        = 0,
+               .name                   = "generic",
+       },
+
+       /* Sharp LQ043T1DG01 */
+       {
+               {
+                       .x_res          = 480,
+                       .y_res          = 272,
+
+                       .pixel_clock    = 9000,
+
+                       .hsw            = 42,
+                       .hfp            = 3,
+                       .hbp            = 2,
+
+                       .vsw            = 11,
+                       .vfp            = 3,
+                       .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         = 50,
+               .power_off_delay        = 100,
+               .name                   = "sharp_lq",
+       },
+
+       /* Sharp LS037V7DW01 */
+       {
+               {
+                       .x_res          = 480,
+                       .y_res          = 640,
+
+                       .pixel_clock    = 19200,
+
+                       .hsw            = 2,
+                       .hfp            = 1,
+                       .hbp            = 28,
+
+                       .vsw            = 1,
+                       .vfp            = 1,
+                       .vbp            = 1,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x28,
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                               OMAP_DSS_LCD_IHS,
+               .power_on_delay         = 50,
+               .power_off_delay        = 100,
+               .name                   = "sharp_ls",
+       },
+
+       /* Toppoly TDO35S */
+       {
+               {
+                       .x_res          = 480,
+                       .y_res          = 640,
+
+                       .pixel_clock    = 26000,
+
+                       .hfp            = 104,
+                       .hsw            = 8,
+                       .hbp            = 8,
+
+                       .vfp            = 4,
+                       .vsw            = 2,
+                       .vbp            = 2,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x0,
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                       OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC |
+                                       OMAP_DSS_LCD_ONOFF,
+               .power_on_delay         = 0,
+               .power_off_delay        = 0,
+               .name                   = "toppoly_tdo35s",
+       },
+};
+
+struct panel_drv_data {
+
+       struct omap_dss_device *dssdev;
+
+       struct panel_config *panel_config;
+};
+
+static inline struct panel_generic_dpi_data
+*get_panel_data(const struct omap_dss_device *dssdev)
+{
+       return (struct panel_generic_dpi_data *) dssdev->data;
+}
+
+static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
+{
+       int r;
+       struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+       struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+       struct panel_config *panel_config = drv_data->panel_config;
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
+       r = omapdss_dpi_display_enable(dssdev);
+       if (r)
+               goto err0;
+
+       /* wait couple of vsyncs until enabling the LCD */
+       if (panel_config->power_on_delay)
+               msleep(panel_config->power_on_delay);
+
+       if (panel_data->platform_enable) {
+               r = panel_data->platform_enable(dssdev);
+               if (r)
+                       goto err1;
+       }
+
+       return 0;
+err1:
+       omapdss_dpi_display_disable(dssdev);
+err0:
+       return r;
+}
+
+static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
+{
+       struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+       struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+       struct panel_config *panel_config = drv_data->panel_config;
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
+       if (panel_data->platform_disable)
+               panel_data->platform_disable(dssdev);
+
+       /* wait couple of vsyncs after disabling the LCD */
+       if (panel_config->power_off_delay)
+               msleep(panel_config->power_off_delay);
+
+       omapdss_dpi_display_disable(dssdev);
+}
+
+static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
+{
+       struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+       struct panel_config *panel_config = NULL;
+       struct panel_drv_data *drv_data = NULL;
+       int i;
+
+       dev_dbg(&dssdev->dev, "probe\n");
+
+       if (!panel_data || !panel_data->name)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
+               if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
+                       panel_config = &generic_dpi_panels[i];
+                       break;
+               }
+       }
+
+       if (!panel_config)
+               return -EINVAL;
+
+       dssdev->panel.config = panel_config->config;
+       dssdev->panel.timings = panel_config->timings;
+       dssdev->panel.acb = panel_config->acb;
+       dssdev->panel.acbi = panel_config->acbi;
+
+       drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
+       if (!drv_data)
+               return -ENOMEM;
+
+       drv_data->dssdev = dssdev;
+       drv_data->panel_config = panel_config;
+
+       dev_set_drvdata(&dssdev->dev, drv_data);
+
+       return 0;
+}
+
+static void generic_dpi_panel_remove(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+       dev_dbg(&dssdev->dev, "remove\n");
+
+       kfree(drv_data);
+
+       dev_set_drvdata(&dssdev->dev, NULL);
+}
+
+static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+
+       r = generic_dpi_panel_power_on(dssdev);
+       if (r)
+               return r;
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       return 0;
+}
+
+static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
+{
+       generic_dpi_panel_power_off(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
+{
+       generic_dpi_panel_power_off(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+       return 0;
+}
+
+static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+
+       r = generic_dpi_panel_power_on(dssdev);
+       if (r)
+               return r;
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       return 0;
+}
+
+static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       dpi_set_timings(dssdev, timings);
+}
+
+static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       *timings = dssdev->panel.timings;
+}
+
+static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       return dpi_check_timings(dssdev, timings);
+}
+
+static struct omap_dss_driver dpi_driver = {
+       .probe          = generic_dpi_panel_probe,
+       .remove         = generic_dpi_panel_remove,
+
+       .enable         = generic_dpi_panel_enable,
+       .disable        = generic_dpi_panel_disable,
+       .suspend        = generic_dpi_panel_suspend,
+       .resume         = generic_dpi_panel_resume,
+
+       .set_timings    = generic_dpi_panel_set_timings,
+       .get_timings    = generic_dpi_panel_get_timings,
+       .check_timings  = generic_dpi_panel_check_timings,
+
+       .driver         = {
+               .name   = "generic_dpi_panel",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init generic_dpi_panel_drv_init(void)
+{
+       return omap_dss_register_driver(&dpi_driver);
+}
+
+static void __exit generic_dpi_panel_drv_exit(void)
+{
+       omap_dss_unregister_driver(&dpi_driver);
+}
+
+module_init(generic_dpi_panel_drv_init);
+module_exit(generic_dpi_panel_drv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c
deleted file mode 100644 (file)
index 395a68d..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Generic panel support
- *
- * Copyright (C) 2008 Nokia Corporation
- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-
-#include <plat/display.h>
-
-static struct omap_video_timings generic_panel_timings = {
-       /* 640 x 480 @ 60 Hz  Reduced blanking VESA CVT 0.31M3-R */
-       .x_res          = 640,
-       .y_res          = 480,
-       .pixel_clock    = 23500,
-       .hfp            = 48,
-       .hsw            = 32,
-       .hbp            = 80,
-       .vfp            = 3,
-       .vsw            = 4,
-       .vbp            = 7,
-};
-
-static int generic_panel_power_on(struct omap_dss_device *dssdev)
-{
-       int r;
-
-       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
-               return 0;
-
-       r = omapdss_dpi_display_enable(dssdev);
-       if (r)
-               goto err0;
-
-       if (dssdev->platform_enable) {
-               r = dssdev->platform_enable(dssdev);
-               if (r)
-                       goto err1;
-       }
-
-       return 0;
-err1:
-       omapdss_dpi_display_disable(dssdev);
-err0:
-       return r;
-}
-
-static void generic_panel_power_off(struct omap_dss_device *dssdev)
-{
-       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
-               return;
-
-       if (dssdev->platform_disable)
-               dssdev->platform_disable(dssdev);
-
-       omapdss_dpi_display_disable(dssdev);
-}
-
-static int generic_panel_probe(struct omap_dss_device *dssdev)
-{
-       dssdev->panel.config = OMAP_DSS_LCD_TFT;
-       dssdev->panel.timings = generic_panel_timings;
-
-       return 0;
-}
-
-static void generic_panel_remove(struct omap_dss_device *dssdev)
-{
-}
-
-static int generic_panel_enable(struct omap_dss_device *dssdev)
-{
-       int r = 0;
-
-       r = generic_panel_power_on(dssdev);
-       if (r)
-               return r;
-
-       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-       return 0;
-}
-
-static void generic_panel_disable(struct omap_dss_device *dssdev)
-{
-       generic_panel_power_off(dssdev);
-
-       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-}
-
-static int generic_panel_suspend(struct omap_dss_device *dssdev)
-{
-       generic_panel_power_off(dssdev);
-       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-       return 0;
-}
-
-static int generic_panel_resume(struct omap_dss_device *dssdev)
-{
-       int r = 0;
-
-       r = generic_panel_power_on(dssdev);
-       if (r)
-               return r;
-
-       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-       return 0;
-}
-
-static void generic_panel_set_timings(struct omap_dss_device *dssdev,
-               struct omap_video_timings *timings)
-{
-       dpi_set_timings(dssdev, timings);
-}
-
-static void generic_panel_get_timings(struct omap_dss_device *dssdev,
-               struct omap_video_timings *timings)
-{
-       *timings = dssdev->panel.timings;
-}
-
-static int generic_panel_check_timings(struct omap_dss_device *dssdev,
-               struct omap_video_timings *timings)
-{
-       return dpi_check_timings(dssdev, timings);
-}
-
-static struct omap_dss_driver generic_driver = {
-       .probe          = generic_panel_probe,
-       .remove         = generic_panel_remove,
-
-       .enable         = generic_panel_enable,
-       .disable        = generic_panel_disable,
-       .suspend        = generic_panel_suspend,
-       .resume         = generic_panel_resume,
-
-       .set_timings    = generic_panel_set_timings,
-       .get_timings    = generic_panel_get_timings,
-       .check_timings  = generic_panel_check_timings,
-
-       .driver         = {
-               .name   = "generic_panel",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init generic_panel_drv_init(void)
-{
-       return omap_dss_register_driver(&generic_driver);
-}
-
-static void __exit generic_panel_drv_exit(void)
-{
-       omap_dss_unregister_driver(&generic_driver);
-}
-
-module_init(generic_panel_drv_init);
-module_exit(generic_panel_drv_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
new file mode 100644 (file)
index 0000000..925e0fa
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Support for NEC-nl8048hl11-01b panel driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <plat/display.h>
+
+#define LCD_XRES               800
+#define LCD_YRES               480
+/*
+ * NEC PIX Clock Ratings
+ * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz
+ */
+#define LCD_PIXEL_CLOCK                23800
+
+struct nec_8048_data {
+       struct backlight_device *bl;
+};
+
+static const struct {
+       unsigned char addr;
+       unsigned char dat;
+} nec_8048_init_seq[] = {
+       { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 },
+       { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 },
+       { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 },
+       { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F },
+       { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F },
+       { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F },
+       { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F },
+       { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 },
+       { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 },
+       { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C },
+       { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 },
+       { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 },
+       { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 },
+       { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 },
+       { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC },
+       { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 },
+       { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 },
+       { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 },
+};
+
+/*
+ * NEC NL8048HL11-01B  Manual
+ * defines HFB, HSW, HBP, VFP, VSW, VBP as shown below
+ */
+
+static struct omap_video_timings nec_8048_panel_timings = {
+       /* 800 x 480 @ 60 Hz  Reduced blanking VESA CVT 0.31M3-R */
+       .x_res          = LCD_XRES,
+       .y_res          = LCD_YRES,
+       .pixel_clock    = LCD_PIXEL_CLOCK,
+       .hfp            = 6,
+       .hsw            = 1,
+       .hbp            = 4,
+       .vfp            = 3,
+       .vsw            = 1,
+       .vbp            = 4,
+};
+
+static int nec_8048_bl_update_status(struct backlight_device *bl)
+{
+       struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev);
+       int level;
+
+       if (!dssdev->set_backlight)
+               return -EINVAL;
+
+       if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
+                       bl->props.power == FB_BLANK_UNBLANK)
+               level = bl->props.brightness;
+       else
+               level = 0;
+
+       return dssdev->set_backlight(dssdev, level);
+}
+
+static int nec_8048_bl_get_brightness(struct backlight_device *bl)
+{
+       if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
+                       bl->props.power == FB_BLANK_UNBLANK)
+               return bl->props.brightness;
+
+       return 0;
+}
+
+static const struct backlight_ops nec_8048_bl_ops = {
+       .get_brightness = nec_8048_bl_get_brightness,
+       .update_status  = nec_8048_bl_update_status,
+};
+
+static int nec_8048_panel_probe(struct omap_dss_device *dssdev)
+{
+       struct backlight_device *bl;
+       struct nec_8048_data *necd;
+       struct backlight_properties props;
+       int r;
+
+       dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                               OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_RF |
+                               OMAP_DSS_LCD_ONOFF;
+       dssdev->panel.timings = nec_8048_panel_timings;
+
+       necd = kzalloc(sizeof(*necd), GFP_KERNEL);
+       if (!necd)
+               return -ENOMEM;
+
+       dev_set_drvdata(&dssdev->dev, necd);
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 255;
+
+       bl = backlight_device_register("nec-8048", &dssdev->dev, dssdev,
+                       &nec_8048_bl_ops, &props);
+       if (IS_ERR(bl)) {
+               r = PTR_ERR(bl);
+               kfree(necd);
+               return r;
+       }
+       necd->bl = bl;
+
+       bl->props.fb_blank = FB_BLANK_UNBLANK;
+       bl->props.power = FB_BLANK_UNBLANK;
+       bl->props.max_brightness = dssdev->max_backlight_level;
+       bl->props.brightness = dssdev->max_backlight_level;
+
+       r = nec_8048_bl_update_status(bl);
+       if (r < 0)
+               dev_err(&dssdev->dev, "failed to set lcd brightness\n");
+
+       return 0;
+}
+
+static void nec_8048_panel_remove(struct omap_dss_device *dssdev)
+{
+       struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
+       struct backlight_device *bl = necd->bl;
+
+       bl->props.power = FB_BLANK_POWERDOWN;
+       nec_8048_bl_update_status(bl);
+       backlight_device_unregister(bl);
+
+       kfree(necd);
+}
+
+static int nec_8048_panel_enable(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+       struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
+       struct backlight_device *bl = necd->bl;
+
+       if (dssdev->platform_enable) {
+               r = dssdev->platform_enable(dssdev);
+               if (r)
+                       return r;
+       }
+
+       r = nec_8048_bl_update_status(bl);
+       if (r < 0)
+               dev_err(&dssdev->dev, "failed to set lcd brightness\n");
+
+       r = omapdss_dpi_display_enable(dssdev);
+
+       return r;
+}
+
+static void nec_8048_panel_disable(struct omap_dss_device *dssdev)
+{
+       struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
+       struct backlight_device *bl = necd->bl;
+
+       omapdss_dpi_display_disable(dssdev);
+
+       bl->props.brightness = 0;
+       nec_8048_bl_update_status(bl);
+
+       if (dssdev->platform_disable)
+               dssdev->platform_disable(dssdev);
+}
+
+static int nec_8048_panel_suspend(struct omap_dss_device *dssdev)
+{
+       nec_8048_panel_disable(dssdev);
+       return 0;
+}
+
+static int nec_8048_panel_resume(struct omap_dss_device *dssdev)
+{
+       return nec_8048_panel_enable(dssdev);
+}
+
+static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev)
+{
+       return 16;
+}
+
+static struct omap_dss_driver nec_8048_driver = {
+       .probe                  = nec_8048_panel_probe,
+       .remove                 = nec_8048_panel_remove,
+       .enable                 = nec_8048_panel_enable,
+       .disable                = nec_8048_panel_disable,
+       .suspend                = nec_8048_panel_suspend,
+       .resume                 = nec_8048_panel_resume,
+       .get_recommended_bpp    = nec_8048_recommended_bpp,
+
+       .driver         = {
+               .name           = "NEC_8048_panel",
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr,
+                       unsigned char reg_data)
+{
+       int ret = 0;
+       unsigned int cmd = 0, data = 0;
+
+       cmd = 0x0000 | reg_addr; /* register address write */
+       data = 0x0100 | reg_data ; /* register data write */
+       data = (cmd << 16) | data;
+
+       ret = spi_write(spi, (unsigned char *)&data, 4);
+       if (ret)
+               pr_err("error in spi_write %x\n", data);
+
+       return ret;
+}
+
+static int init_nec_8048_wvga_lcd(struct spi_device *spi)
+{
+       unsigned int i;
+       /* Initialization Sequence */
+       /* nec_8048_spi_send(spi, REG, VAL) */
+       for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++)
+               nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
+                               nec_8048_init_seq[i].dat);
+       udelay(20);
+       nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
+                               nec_8048_init_seq[i].dat);
+       return 0;
+}
+
+static int nec_8048_spi_probe(struct spi_device *spi)
+{
+       spi->mode = SPI_MODE_0;
+       spi->bits_per_word = 32;
+       spi_setup(spi);
+
+       init_nec_8048_wvga_lcd(spi);
+
+       return omap_dss_register_driver(&nec_8048_driver);
+}
+
+static int nec_8048_spi_remove(struct spi_device *spi)
+{
+       omap_dss_unregister_driver(&nec_8048_driver);
+
+       return 0;
+}
+
+static int nec_8048_spi_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+       nec_8048_spi_send(spi, 2, 0x01);
+       mdelay(40);
+
+       return 0;
+}
+
+static int nec_8048_spi_resume(struct spi_device *spi)
+{
+       /* reinitialize the panel */
+       spi_setup(spi);
+       nec_8048_spi_send(spi, 2, 0x00);
+       init_nec_8048_wvga_lcd(spi);
+
+       return 0;
+}
+
+static struct spi_driver nec_8048_spi_driver = {
+       .probe          = nec_8048_spi_probe,
+       .remove         = __devexit_p(nec_8048_spi_remove),
+       .suspend        = nec_8048_spi_suspend,
+       .resume         = nec_8048_spi_resume,
+       .driver         = {
+               .name   = "nec_8048_spi",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init nec_8048_lcd_init(void)
+{
+       return spi_register_driver(&nec_8048_spi_driver);
+}
+
+static void __exit nec_8048_lcd_exit(void)
+{
+       return spi_unregister_driver(&nec_8048_spi_driver);
+}
+
+module_init(nec_8048_lcd_init);
+module_exit(nec_8048_lcd_exit);
+MODULE_AUTHOR("Erik Gilling <konkers@android.com>");
+MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
deleted file mode 100644 (file)
index 0c6896c..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * LCD panel driver for Sharp LQ043T1DG01
- *
- * Copyright (C) 2009 Texas Instruments Inc
- * Author: Vaibhav Hiremath <hvaibhav@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/err.h>
-
-#include <plat/display.h>
-
-static struct omap_video_timings sharp_lq_timings = {
-       .x_res = 480,
-       .y_res = 272,
-
-       .pixel_clock    = 9000,
-
-       .hsw            = 42,
-       .hfp            = 3,
-       .hbp            = 2,
-
-       .vsw            = 11,
-       .vfp            = 3,
-       .vbp            = 2,
-};
-
-static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev)
-{
-       int r;
-
-       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
-               return 0;
-
-       r = omapdss_dpi_display_enable(dssdev);
-       if (r)
-               goto err0;
-
-       /* wait couple of vsyncs until enabling the LCD */
-       msleep(50);
-
-       if (dssdev->platform_enable) {
-               r = dssdev->platform_enable(dssdev);
-               if (r)
-                       goto err1;
-       }
-
-       return 0;
-err1:
-       omapdss_dpi_display_disable(dssdev);
-err0:
-       return r;
-}
-
-static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev)
-{
-       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
-               return;
-
-       if (dssdev->platform_disable)
-               dssdev->platform_disable(dssdev);
-
-       /* wait at least 5 vsyncs after disabling the LCD */
-       msleep(100);
-
-       omapdss_dpi_display_disable(dssdev);
-}
-
-static int sharp_lq_panel_probe(struct omap_dss_device *dssdev)
-{
-
-       dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
-               OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO;
-       dssdev->panel.acb = 0x0;
-       dssdev->panel.timings = sharp_lq_timings;
-
-       return 0;
-}
-
-static void sharp_lq_panel_remove(struct omap_dss_device *dssdev)
-{
-}
-
-static int sharp_lq_panel_enable(struct omap_dss_device *dssdev)
-{
-       int r = 0;
-
-       r = sharp_lq_panel_power_on(dssdev);
-       if (r)
-               return r;
-
-       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-       return 0;
-}
-
-static void sharp_lq_panel_disable(struct omap_dss_device *dssdev)
-{
-       sharp_lq_panel_power_off(dssdev);
-
-       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-}
-
-static int sharp_lq_panel_suspend(struct omap_dss_device *dssdev)
-{
-       sharp_lq_panel_power_off(dssdev);
-       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-       return 0;
-}
-
-static int sharp_lq_panel_resume(struct omap_dss_device *dssdev)
-{
-       int r = 0;
-
-       r = sharp_lq_panel_power_on(dssdev);
-       if (r)
-               return r;
-
-       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-       return 0;
-}
-
-static struct omap_dss_driver sharp_lq_driver = {
-       .probe          = sharp_lq_panel_probe,
-       .remove         = sharp_lq_panel_remove,
-
-       .enable         = sharp_lq_panel_enable,
-       .disable        = sharp_lq_panel_disable,
-       .suspend        = sharp_lq_panel_suspend,
-       .resume         = sharp_lq_panel_resume,
-
-       .driver         = {
-               .name   = "sharp_lq_panel",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init sharp_lq_panel_drv_init(void)
-{
-       return omap_dss_register_driver(&sharp_lq_driver);
-}
-
-static void __exit sharp_lq_panel_drv_exit(void)
-{
-       omap_dss_unregister_driver(&sharp_lq_driver);
-}
-
-module_init(sharp_lq_panel_drv_init);
-module_exit(sharp_lq_panel_drv_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
deleted file mode 100644 (file)
index 526e906..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * LCD panel driver for Toppoly TDO35S
- *
- * Copyright (C) 2009 CompuLab, Ltd.
- * Author: Mike Rapoport <mike@compulab.co.il>
- *
- * Based on generic panel support
- * Copyright (C) 2008 Nokia Corporation
- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-
-#include <plat/display.h>
-
-static struct omap_video_timings toppoly_tdo_panel_timings = {
-       /* 640 x 480 @ 60 Hz  Reduced blanking VESA CVT 0.31M3-R */
-       .x_res          = 480,
-       .y_res          = 640,
-
-       .pixel_clock    = 26000,
-
-       .hfp            = 104,
-       .hsw            = 8,
-       .hbp            = 8,
-
-       .vfp            = 4,
-       .vsw            = 2,
-       .vbp            = 2,
-};
-
-static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev)
-{
-       int r;
-
-       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
-               return 0;
-
-       r = omapdss_dpi_display_enable(dssdev);
-       if (r)
-               goto err0;
-
-       if (dssdev->platform_enable) {
-               r = dssdev->platform_enable(dssdev);
-               if (r)
-                       goto err1;
-       }
-
-       return 0;
-err1:
-       omapdss_dpi_display_disable(dssdev);
-err0:
-       return r;
-}
-
-static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
-{
-       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
-               return;
-
-       if (dssdev->platform_disable)
-               dssdev->platform_disable(dssdev);
-
-       omapdss_dpi_display_disable(dssdev);
-}
-
-static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev)
-{
-       dssdev->panel.config = OMAP_DSS_LCD_TFT |
-                              OMAP_DSS_LCD_IVS |
-                              OMAP_DSS_LCD_IHS |
-                              OMAP_DSS_LCD_IPC |
-                              OMAP_DSS_LCD_ONOFF;
-
-       dssdev->panel.timings = toppoly_tdo_panel_timings;
-
-       return 0;
-}
-
-static void toppoly_tdo_panel_remove(struct omap_dss_device *dssdev)
-{
-}
-
-static int toppoly_tdo_panel_enable(struct omap_dss_device *dssdev)
-{
-       int r = 0;
-
-       r = toppoly_tdo_panel_power_on(dssdev);
-       if (r)
-               return r;
-
-       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-       return 0;
-}
-
-static void toppoly_tdo_panel_disable(struct omap_dss_device *dssdev)
-{
-       toppoly_tdo_panel_power_off(dssdev);
-
-       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-}
-
-static int toppoly_tdo_panel_suspend(struct omap_dss_device *dssdev)
-{
-       toppoly_tdo_panel_power_off(dssdev);
-       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-       return 0;
-}
-
-static int toppoly_tdo_panel_resume(struct omap_dss_device *dssdev)
-{
-       int r = 0;
-
-       r = toppoly_tdo_panel_power_on(dssdev);
-       if (r)
-               return r;
-
-       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-       return 0;
-}
-
-static struct omap_dss_driver generic_driver = {
-       .probe          = toppoly_tdo_panel_probe,
-       .remove         = toppoly_tdo_panel_remove,
-
-       .enable         = toppoly_tdo_panel_enable,
-       .disable        = toppoly_tdo_panel_disable,
-       .suspend        = toppoly_tdo_panel_suspend,
-       .resume         = toppoly_tdo_panel_resume,
-
-       .driver         = {
-               .name   = "toppoly_tdo35s_panel",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init toppoly_tdo_panel_drv_init(void)
-{
-       return omap_dss_register_driver(&generic_driver);
-}
-
-static void __exit toppoly_tdo_panel_drv_exit(void)
-{
-       omap_dss_unregister_driver(&generic_driver);
-}
-
-module_init(toppoly_tdo_panel_drv_init);
-module_exit(toppoly_tdo_panel_drv_exit);
-MODULE_LICENSE("GPL");
index fa40fa59a9acf9c89b2b4b562472871dfd0a1a2f..9f8c69f16e619dd1eec954f5ae5eba13c659ec06 100644 (file)
 /* DISPC */
 #define DISPC_BASE                     0x48050400
 
-#define DISPC_SZ_REGS                  SZ_1K
+#define DISPC_SZ_REGS                  SZ_4K
 
 struct dispc_reg { u16 idx; };
 
 #define DISPC_REG(idx)                 ((const struct dispc_reg) { idx })
 
-/* DISPC common */
+/*
+ * DISPC common registers and
+ * DISPC channel registers , ch = 0 for LCD, ch = 1 for
+ * DIGIT, and ch = 2 for LCD2
+ */
 #define DISPC_REVISION                 DISPC_REG(0x0000)
 #define DISPC_SYSCONFIG                        DISPC_REG(0x0010)
 #define DISPC_SYSSTATUS                        DISPC_REG(0x0014)
 #define DISPC_IRQSTATUS                        DISPC_REG(0x0018)
 #define DISPC_IRQENABLE                        DISPC_REG(0x001C)
 #define DISPC_CONTROL                  DISPC_REG(0x0040)
+#define DISPC_CONTROL2                 DISPC_REG(0x0238)
 #define DISPC_CONFIG                   DISPC_REG(0x0044)
+#define DISPC_CONFIG2                  DISPC_REG(0x0620)
 #define DISPC_CAPABLE                  DISPC_REG(0x0048)
-#define DISPC_DEFAULT_COLOR0           DISPC_REG(0x004C)
-#define DISPC_DEFAULT_COLOR1           DISPC_REG(0x0050)
-#define DISPC_TRANS_COLOR0             DISPC_REG(0x0054)
-#define DISPC_TRANS_COLOR1             DISPC_REG(0x0058)
+#define DISPC_DEFAULT_COLOR(ch)                DISPC_REG(ch == 0 ? 0x004C : \
+                                       (ch == 1 ? 0x0050 : 0x03AC))
+#define DISPC_TRANS_COLOR(ch)          DISPC_REG(ch == 0 ? 0x0054 : \
+                                       (ch == 1 ? 0x0058 : 0x03B0))
 #define DISPC_LINE_STATUS              DISPC_REG(0x005C)
 #define DISPC_LINE_NUMBER              DISPC_REG(0x0060)
-#define DISPC_TIMING_H                 DISPC_REG(0x0064)
-#define DISPC_TIMING_V                 DISPC_REG(0x0068)
-#define DISPC_POL_FREQ                 DISPC_REG(0x006C)
-#define DISPC_DIVISOR                  DISPC_REG(0x0070)
+#define DISPC_TIMING_H(ch)             DISPC_REG(ch != 2 ? 0x0064 : 0x0400)
+#define DISPC_TIMING_V(ch)             DISPC_REG(ch != 2 ? 0x0068 : 0x0404)
+#define DISPC_POL_FREQ(ch)             DISPC_REG(ch != 2 ? 0x006C : 0x0408)
+#define DISPC_DIVISOR(ch)              DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
 #define DISPC_GLOBAL_ALPHA             DISPC_REG(0x0074)
 #define DISPC_SIZE_DIG                 DISPC_REG(0x0078)
-#define DISPC_SIZE_LCD                 DISPC_REG(0x007C)
+#define DISPC_SIZE_LCD(ch)             DISPC_REG(ch != 2 ? 0x007C : 0x03CC)
 
 /* DISPC GFX plane */
 #define DISPC_GFX_BA0                  DISPC_REG(0x0080)
@@ -86,13 +92,12 @@ struct dispc_reg { u16 idx; };
 #define DISPC_GFX_WINDOW_SKIP          DISPC_REG(0x00B4)
 #define DISPC_GFX_TABLE_BA             DISPC_REG(0x00B8)
 
-#define DISPC_DATA_CYCLE1              DISPC_REG(0x01D4)
-#define DISPC_DATA_CYCLE2              DISPC_REG(0x01D8)
-#define DISPC_DATA_CYCLE3              DISPC_REG(0x01DC)
-
-#define DISPC_CPR_COEF_R               DISPC_REG(0x0220)
-#define DISPC_CPR_COEF_G               DISPC_REG(0x0224)
-#define DISPC_CPR_COEF_B               DISPC_REG(0x0228)
+#define DISPC_DATA_CYCLE1(ch)          DISPC_REG(ch != 2 ? 0x01D4 : 0x03C0)
+#define DISPC_DATA_CYCLE2(ch)          DISPC_REG(ch != 2 ? 0x01D8 : 0x03C4)
+#define DISPC_DATA_CYCLE3(ch)          DISPC_REG(ch != 2 ? 0x01DC : 0x03C8)
+#define DISPC_CPR_COEF_R(ch)           DISPC_REG(ch != 2 ? 0x0220 : 0x03BC)
+#define DISPC_CPR_COEF_G(ch)           DISPC_REG(ch != 2 ? 0x0224 : 0x03B8)
+#define DISPC_CPR_COEF_B(ch)           DISPC_REG(ch != 2 ? 0x0228 : 0x03B4)
 
 #define DISPC_GFX_PRELOAD              DISPC_REG(0x022C)
 
@@ -217,18 +222,29 @@ void dispc_save_context(void)
        SR(IRQENABLE);
        SR(CONTROL);
        SR(CONFIG);
-       SR(DEFAULT_COLOR0);
-       SR(DEFAULT_COLOR1);
-       SR(TRANS_COLOR0);
-       SR(TRANS_COLOR1);
+       SR(DEFAULT_COLOR(0));
+       SR(DEFAULT_COLOR(1));
+       SR(TRANS_COLOR(0));
+       SR(TRANS_COLOR(1));
        SR(LINE_NUMBER);
-       SR(TIMING_H);
-       SR(TIMING_V);
-       SR(POL_FREQ);
-       SR(DIVISOR);
+       SR(TIMING_H(0));
+       SR(TIMING_V(0));
+       SR(POL_FREQ(0));
+       SR(DIVISOR(0));
        SR(GLOBAL_ALPHA);
        SR(SIZE_DIG);
-       SR(SIZE_LCD);
+       SR(SIZE_LCD(0));
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               SR(CONTROL2);
+               SR(DEFAULT_COLOR(2));
+               SR(TRANS_COLOR(2));
+               SR(SIZE_LCD(2));
+               SR(TIMING_H(2));
+               SR(TIMING_V(2));
+               SR(POL_FREQ(2));
+               SR(DIVISOR(2));
+               SR(CONFIG2);
+       }
 
        SR(GFX_BA0);
        SR(GFX_BA1);
@@ -241,13 +257,22 @@ void dispc_save_context(void)
        SR(GFX_WINDOW_SKIP);
        SR(GFX_TABLE_BA);
 
-       SR(DATA_CYCLE1);
-       SR(DATA_CYCLE2);
-       SR(DATA_CYCLE3);
-
-       SR(CPR_COEF_R);
-       SR(CPR_COEF_G);
-       SR(CPR_COEF_B);
+       SR(DATA_CYCLE1(0));
+       SR(DATA_CYCLE2(0));
+       SR(DATA_CYCLE3(0));
+
+       SR(CPR_COEF_R(0));
+       SR(CPR_COEF_G(0));
+       SR(CPR_COEF_B(0));
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               SR(CPR_COEF_B(2));
+               SR(CPR_COEF_G(2));
+               SR(CPR_COEF_R(2));
+
+               SR(DATA_CYCLE1(2));
+               SR(DATA_CYCLE2(2));
+               SR(DATA_CYCLE3(2));
+       }
 
        SR(GFX_PRELOAD);
 
@@ -356,18 +381,28 @@ void dispc_restore_context(void)
        /*RR(IRQENABLE);*/
        /*RR(CONTROL);*/
        RR(CONFIG);
-       RR(DEFAULT_COLOR0);
-       RR(DEFAULT_COLOR1);
-       RR(TRANS_COLOR0);
-       RR(TRANS_COLOR1);
+       RR(DEFAULT_COLOR(0));
+       RR(DEFAULT_COLOR(1));
+       RR(TRANS_COLOR(0));
+       RR(TRANS_COLOR(1));
        RR(LINE_NUMBER);
-       RR(TIMING_H);
-       RR(TIMING_V);
-       RR(POL_FREQ);
-       RR(DIVISOR);
+       RR(TIMING_H(0));
+       RR(TIMING_V(0));
+       RR(POL_FREQ(0));
+       RR(DIVISOR(0));
        RR(GLOBAL_ALPHA);
        RR(SIZE_DIG);
-       RR(SIZE_LCD);
+       RR(SIZE_LCD(0));
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               RR(DEFAULT_COLOR(2));
+               RR(TRANS_COLOR(2));
+               RR(SIZE_LCD(2));
+               RR(TIMING_H(2));
+               RR(TIMING_V(2));
+               RR(POL_FREQ(2));
+               RR(DIVISOR(2));
+               RR(CONFIG2);
+       }
 
        RR(GFX_BA0);
        RR(GFX_BA1);
@@ -380,13 +415,22 @@ void dispc_restore_context(void)
        RR(GFX_WINDOW_SKIP);
        RR(GFX_TABLE_BA);
 
-       RR(DATA_CYCLE1);
-       RR(DATA_CYCLE2);
-       RR(DATA_CYCLE3);
-
-       RR(CPR_COEF_R);
-       RR(CPR_COEF_G);
-       RR(CPR_COEF_B);
+       RR(DATA_CYCLE1(0));
+       RR(DATA_CYCLE2(0));
+       RR(DATA_CYCLE3(0));
+
+       RR(CPR_COEF_R(0));
+       RR(CPR_COEF_G(0));
+       RR(CPR_COEF_B(0));
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               RR(DATA_CYCLE1(2));
+               RR(DATA_CYCLE2(2));
+               RR(DATA_CYCLE3(2));
+
+               RR(CPR_COEF_B(2));
+               RR(CPR_COEF_G(2));
+               RR(CPR_COEF_R(2));
+       }
 
        RR(GFX_PRELOAD);
 
@@ -490,7 +534,8 @@ void dispc_restore_context(void)
 
        /* enable last, because LCD & DIGIT enable are here */
        RR(CONTROL);
-
+       if (dss_has_feature(FEAT_MGR_LCD2))
+               RR(CONTROL2);
        /* clear spurious SYNC_LOST_DIGIT interrupts */
        dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
 
@@ -516,42 +561,63 @@ bool dispc_go_busy(enum omap_channel channel)
 {
        int bit;
 
-       if (channel == OMAP_DSS_CHANNEL_LCD)
+       if (channel == OMAP_DSS_CHANNEL_LCD ||
+                       channel == OMAP_DSS_CHANNEL_LCD2)
                bit = 5; /* GOLCD */
        else
                bit = 6; /* GODIGIT */
 
-       return REG_GET(DISPC_CONTROL, bit, bit) == 1;
+       if (channel == OMAP_DSS_CHANNEL_LCD2)
+               return REG_GET(DISPC_CONTROL2, bit, bit) == 1;
+       else
+               return REG_GET(DISPC_CONTROL, bit, bit) == 1;
 }
 
 void dispc_go(enum omap_channel channel)
 {
        int bit;
+       bool enable_bit, go_bit;
 
        enable_clocks(1);
 
-       if (channel == OMAP_DSS_CHANNEL_LCD)
+       if (channel == OMAP_DSS_CHANNEL_LCD ||
+                       channel == OMAP_DSS_CHANNEL_LCD2)
                bit = 0; /* LCDENABLE */
        else
                bit = 1; /* DIGITALENABLE */
 
        /* if the channel is not enabled, we don't need GO */
-       if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
+       if (channel == OMAP_DSS_CHANNEL_LCD2)
+               enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1;
+       else
+               enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
+
+       if (!enable_bit)
                goto end;
 
-       if (channel == OMAP_DSS_CHANNEL_LCD)
+       if (channel == OMAP_DSS_CHANNEL_LCD ||
+                       channel == OMAP_DSS_CHANNEL_LCD2)
                bit = 5; /* GOLCD */
        else
                bit = 6; /* GODIGIT */
 
-       if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
+       if (channel == OMAP_DSS_CHANNEL_LCD2)
+               go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1;
+       else
+               go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
+
+       if (go_bit) {
                DSSERR("GO bit not down for channel %d\n", channel);
                goto end;
        }
 
-       DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
+       DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" :
+               (channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT"));
 
-       REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
+       if (channel == OMAP_DSS_CHANNEL_LCD2)
+               REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit);
+       else
+               REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
 end:
        enable_clocks(0);
 }
@@ -773,13 +839,26 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
        dispc_write_reg(vsi_reg[plane-1], val);
 }
 
+static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable)
+{
+       if (!dss_has_feature(FEAT_PRE_MULT_ALPHA))
+               return;
+
+       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+               plane == OMAP_DSS_VIDEO1)
+               return;
+
+       REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 28, 28);
+}
+
 static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
 {
        if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
                return;
 
-       BUG_ON(!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
-                       plane == OMAP_DSS_VIDEO1);
+       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+               plane == OMAP_DSS_VIDEO1)
+               return;
 
        if (plane == OMAP_DSS_GFX)
                REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
@@ -851,6 +930,7 @@ static void _dispc_set_channel_out(enum omap_plane plane,
 {
        int shift;
        u32 val;
+       int chan = 0, chan2 = 0;
 
        switch (plane) {
        case OMAP_DSS_GFX:
@@ -866,7 +946,29 @@ static void _dispc_set_channel_out(enum omap_plane plane,
        }
 
        val = dispc_read_reg(dispc_reg_att[plane]);
-       val = FLD_MOD(val, channel, shift, shift);
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               switch (channel) {
+               case OMAP_DSS_CHANNEL_LCD:
+                       chan = 0;
+                       chan2 = 0;
+                       break;
+               case OMAP_DSS_CHANNEL_DIGIT:
+                       chan = 1;
+                       chan2 = 0;
+                       break;
+               case OMAP_DSS_CHANNEL_LCD2:
+                       chan = 0;
+                       chan2 = 1;
+                       break;
+               default:
+                       BUG();
+               }
+
+               val = FLD_MOD(val, chan, shift, shift);
+               val = FLD_MOD(val, chan2, 31, 30);
+       } else {
+               val = FLD_MOD(val, channel, shift, shift);
+       }
        dispc_write_reg(dispc_reg_att[plane], val);
 }
 
@@ -923,13 +1025,13 @@ void dispc_enable_replication(enum omap_plane plane, bool enable)
        enable_clocks(0);
 }
 
-void dispc_set_lcd_size(u16 width, u16 height)
+void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
 {
        u32 val;
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
        enable_clocks(1);
-       dispc_write_reg(DISPC_SIZE_LCD, val);
+       dispc_write_reg(DISPC_SIZE_LCD(channel), val);
        enable_clocks(0);
 }
 
@@ -1426,12 +1528,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
        }
 }
 
-static unsigned long calc_fclk_five_taps(u16 width, u16 height,
-               u16 out_width, u16 out_height, enum omap_color_mode color_mode)
+static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
+               u16 height, u16 out_width, u16 out_height,
+               enum omap_color_mode color_mode)
 {
        u32 fclk = 0;
        /* FIXME venc pclk? */
-       u64 tmp, pclk = dispc_pclk_rate();
+       u64 tmp, pclk = dispc_pclk_rate(channel);
 
        if (height > out_height) {
                /* FIXME get real display PPL */
@@ -1463,8 +1566,8 @@ static unsigned long calc_fclk_five_taps(u16 width, u16 height,
        return fclk;
 }
 
-static unsigned long calc_fclk(u16 width, u16 height,
-               u16 out_width, u16 out_height)
+static unsigned long calc_fclk(enum omap_channel channel, u16 width,
+               u16 height, u16 out_width, u16 out_height)
 {
        unsigned int hf, vf;
 
@@ -1488,7 +1591,7 @@ static unsigned long calc_fclk(u16 width, u16 height,
                vf = 1;
 
        /* FIXME venc pclk? */
-       return dispc_pclk_rate() * vf * hf;
+       return dispc_pclk_rate(channel) * vf * hf;
 }
 
 void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
@@ -1507,7 +1610,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
                bool ilace,
                enum omap_dss_rotation_type rotation_type,
                u8 rotation, int mirror,
-               u8 global_alpha)
+               u8 global_alpha, u8 pre_mult_alpha,
+               enum omap_channel channel)
 {
        const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
        bool five_taps = 0;
@@ -1536,29 +1640,12 @@ static int _dispc_setup_plane(enum omap_plane plane,
                                height, pos_y, out_height);
        }
 
+       if (!dss_feat_color_mode_supported(plane, color_mode))
+               return -EINVAL;
+
        if (plane == OMAP_DSS_GFX) {
                if (width != out_width || height != out_height)
                        return -EINVAL;
-
-               switch (color_mode) {
-               case OMAP_DSS_COLOR_ARGB16:
-               case OMAP_DSS_COLOR_ARGB32:
-               case OMAP_DSS_COLOR_RGBA32:
-                       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
-                               return -EINVAL;
-               case OMAP_DSS_COLOR_RGBX32:
-                       if (cpu_is_omap24xx())
-                               return -EINVAL;
-                       /* fall through */
-               case OMAP_DSS_COLOR_RGB12U:
-               case OMAP_DSS_COLOR_RGB16:
-               case OMAP_DSS_COLOR_RGB24P:
-               case OMAP_DSS_COLOR_RGB24U:
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
        } else {
                /* video plane */
 
@@ -1572,42 +1659,16 @@ static int _dispc_setup_plane(enum omap_plane plane,
                   out_height > height * 8)
                        return -EINVAL;
 
-               switch (color_mode) {
-               case OMAP_DSS_COLOR_RGBX32:
-               case OMAP_DSS_COLOR_RGB12U:
-                       if (cpu_is_omap24xx())
-                               return -EINVAL;
-                       /* fall through */
-               case OMAP_DSS_COLOR_RGB16:
-               case OMAP_DSS_COLOR_RGB24P:
-               case OMAP_DSS_COLOR_RGB24U:
-                       break;
-
-               case OMAP_DSS_COLOR_ARGB16:
-               case OMAP_DSS_COLOR_ARGB32:
-               case OMAP_DSS_COLOR_RGBA32:
-                       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
-                               return -EINVAL;
-                       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
-                                       plane == OMAP_DSS_VIDEO1)
-                               return -EINVAL;
-                       break;
-
-               case OMAP_DSS_COLOR_YUV2:
-               case OMAP_DSS_COLOR_UYVY:
+               if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+                       color_mode == OMAP_DSS_COLOR_UYVY)
                        cconv = 1;
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
 
                /* Must use 5-tap filter? */
                five_taps = height > out_height * 2;
 
                if (!five_taps) {
-                       fclk = calc_fclk(width, height,
-                                       out_width, out_height);
+                       fclk = calc_fclk(channel, width, height, out_width,
+                                       out_height);
 
                        /* Try 5-tap filter if 3-tap fclk is too high */
                        if (cpu_is_omap34xx() && height > out_height &&
@@ -1621,7 +1682,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
                }
 
                if (five_taps)
-                       fclk = calc_fclk_five_taps(width, height,
+                       fclk = calc_fclk_five_taps(channel, width, height,
                                        out_width, out_height, color_mode);
 
                DSSDBG("required fclk rate = %lu Hz\n", fclk);
@@ -1693,8 +1754,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
 
        _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
 
-       if (plane != OMAP_DSS_VIDEO1)
-               _dispc_setup_global_alpha(plane, global_alpha);
+       _dispc_set_pre_mult_alpha(plane, pre_mult_alpha);
+       _dispc_setup_global_alpha(plane, global_alpha);
 
        return 0;
 }
@@ -1710,36 +1771,44 @@ static void dispc_disable_isr(void *data, u32 mask)
        complete(compl);
 }
 
-static void _enable_lcd_out(bool enable)
+static void _enable_lcd_out(enum omap_channel channel, bool enable)
 {
-       REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
+       if (channel == OMAP_DSS_CHANNEL_LCD2)
+               REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0);
+       else
+               REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
 }
 
-static void dispc_enable_lcd_out(bool enable)
+static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
 {
        struct completion frame_done_completion;
        bool is_on;
        int r;
+       u32 irq;
 
        enable_clocks(1);
 
        /* When we disable LCD output, we need to wait until frame is done.
         * Otherwise the DSS is still working, and turning off the clocks
         * prevents DSS from going to OFF mode */
-       is_on = REG_GET(DISPC_CONTROL, 0, 0);
+       is_on = channel == OMAP_DSS_CHANNEL_LCD2 ?
+                       REG_GET(DISPC_CONTROL2, 0, 0) :
+                       REG_GET(DISPC_CONTROL, 0, 0);
+
+       irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 :
+                       DISPC_IRQ_FRAMEDONE;
 
        if (!enable && is_on) {
                init_completion(&frame_done_completion);
 
                r = omap_dispc_register_isr(dispc_disable_isr,
-                               &frame_done_completion,
-                               DISPC_IRQ_FRAMEDONE);
+                               &frame_done_completion, irq);
 
                if (r)
                        DSSERR("failed to register FRAMEDONE isr\n");
        }
 
-       _enable_lcd_out(enable);
+       _enable_lcd_out(channel, enable);
 
        if (!enable && is_on) {
                if (!wait_for_completion_timeout(&frame_done_completion,
@@ -1747,8 +1816,7 @@ static void dispc_enable_lcd_out(bool enable)
                        DSSERR("timeout waiting for FRAME DONE\n");
 
                r = omap_dispc_unregister_isr(dispc_disable_isr,
-                               &frame_done_completion,
-                               DISPC_IRQ_FRAMEDONE);
+                               &frame_done_completion, irq);
 
                if (r)
                        DSSERR("failed to unregister FRAMEDONE isr\n");
@@ -1818,6 +1886,8 @@ static void dispc_enable_digit_out(bool enable)
                unsigned long flags;
                spin_lock_irqsave(&dispc.irq_lock, flags);
                dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
+               if (dss_has_feature(FEAT_MGR_LCD2))
+                       dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
                dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
                _omap_dispc_set_irqs();
                spin_unlock_irqrestore(&dispc.irq_lock, flags);
@@ -1832,14 +1902,17 @@ bool dispc_is_channel_enabled(enum omap_channel channel)
                return !!REG_GET(DISPC_CONTROL, 0, 0);
        else if (channel == OMAP_DSS_CHANNEL_DIGIT)
                return !!REG_GET(DISPC_CONTROL, 1, 1);
+       else if (channel == OMAP_DSS_CHANNEL_LCD2)
+               return !!REG_GET(DISPC_CONTROL2, 0, 0);
        else
                BUG();
 }
 
 void dispc_enable_channel(enum omap_channel channel, bool enable)
 {
-       if (channel == OMAP_DSS_CHANNEL_LCD)
-               dispc_enable_lcd_out(enable);
+       if (channel == OMAP_DSS_CHANNEL_LCD ||
+                       channel == OMAP_DSS_CHANNEL_LCD2)
+               dispc_enable_lcd_out(channel, enable);
        else if (channel == OMAP_DSS_CHANNEL_DIGIT)
                dispc_enable_digit_out(enable);
        else
@@ -1848,6 +1921,9 @@ void dispc_enable_channel(enum omap_channel channel, bool enable)
 
 void dispc_lcd_enable_signal_polarity(bool act_high)
 {
+       if (!dss_has_feature(FEAT_LCDENABLEPOL))
+               return;
+
        enable_clocks(1);
        REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
        enable_clocks(0);
@@ -1855,6 +1931,9 @@ void dispc_lcd_enable_signal_polarity(bool act_high)
 
 void dispc_lcd_enable_signal(bool enable)
 {
+       if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
+               return;
+
        enable_clocks(1);
        REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
        enable_clocks(0);
@@ -1862,20 +1941,27 @@ void dispc_lcd_enable_signal(bool enable)
 
 void dispc_pck_free_enable(bool enable)
 {
+       if (!dss_has_feature(FEAT_PCKFREEENABLE))
+               return;
+
        enable_clocks(1);
        REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
        enable_clocks(0);
 }
 
-void dispc_enable_fifohandcheck(bool enable)
+void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable)
 {
        enable_clocks(1);
-       REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
+       if (channel == OMAP_DSS_CHANNEL_LCD2)
+               REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16);
+       else
+               REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
        enable_clocks(0);
 }
 
 
-void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
+void dispc_set_lcd_display_type(enum omap_channel channel,
+               enum omap_lcd_display_type type)
 {
        int mode;
 
@@ -1894,7 +1980,10 @@ void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
        }
 
        enable_clocks(1);
-       REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
+       if (channel == OMAP_DSS_CHANNEL_LCD2)
+               REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3);
+       else
+               REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
        enable_clocks(0);
 }
 
@@ -1908,25 +1997,21 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode)
 
 void dispc_set_default_color(enum omap_channel channel, u32 color)
 {
-       const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
-                               DISPC_DEFAULT_COLOR1 };
-
        enable_clocks(1);
-       dispc_write_reg(def_reg[channel], color);
+       dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
        enable_clocks(0);
 }
 
 u32 dispc_get_default_color(enum omap_channel channel)
 {
-       const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
-                               DISPC_DEFAULT_COLOR1 };
        u32 l;
 
        BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
-              channel != OMAP_DSS_CHANNEL_LCD);
+               channel != OMAP_DSS_CHANNEL_LCD &&
+               channel != OMAP_DSS_CHANNEL_LCD2);
 
        enable_clocks(1);
-       l = dispc_read_reg(def_reg[channel]);
+       l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel));
        enable_clocks(0);
 
        return l;
@@ -1936,16 +2021,15 @@ void dispc_set_trans_key(enum omap_channel ch,
                enum omap_dss_trans_key_type type,
                u32 trans_key)
 {
-       const struct dispc_reg tr_reg[] = {
-               DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
-
        enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
-       else /* OMAP_DSS_CHANNEL_DIGIT */
+       else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
+       else /* OMAP_DSS_CHANNEL_LCD2 */
+               REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11);
 
-       dispc_write_reg(tr_reg[ch], trans_key);
+       dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
        enable_clocks(0);
 }
 
@@ -1953,21 +2037,20 @@ void dispc_get_trans_key(enum omap_channel ch,
                enum omap_dss_trans_key_type *type,
                u32 *trans_key)
 {
-       const struct dispc_reg tr_reg[] = {
-               DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
-
        enable_clocks(1);
        if (type) {
                if (ch == OMAP_DSS_CHANNEL_LCD)
                        *type = REG_GET(DISPC_CONFIG, 11, 11);
                else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                        *type = REG_GET(DISPC_CONFIG, 13, 13);
+               else if (ch == OMAP_DSS_CHANNEL_LCD2)
+                       *type = REG_GET(DISPC_CONFIG2, 11, 11);
                else
                        BUG();
        }
 
        if (trans_key)
-               *trans_key = dispc_read_reg(tr_reg[ch]);
+               *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
        enable_clocks(0);
 }
 
@@ -1976,8 +2059,10 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable)
        enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
-       else /* OMAP_DSS_CHANNEL_DIGIT */
+       else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
+       else /* OMAP_DSS_CHANNEL_LCD2 */
+               REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
        enable_clocks(0);
 }
 void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
@@ -1988,8 +2073,10 @@ void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
        enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
-       else /* OMAP_DSS_CHANNEL_DIGIT */
+       else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
+       else /* OMAP_DSS_CHANNEL_LCD2 */
+               REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18);
        enable_clocks(0);
 }
 bool dispc_alpha_blending_enabled(enum omap_channel ch)
@@ -2003,13 +2090,14 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
        if (ch == OMAP_DSS_CHANNEL_LCD)
                enabled = REG_GET(DISPC_CONFIG, 18, 18);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
-               enabled = REG_GET(DISPC_CONFIG, 18, 18);
+               enabled = REG_GET(DISPC_CONFIG, 19, 19);
+       else if (ch == OMAP_DSS_CHANNEL_LCD2)
+               enabled = REG_GET(DISPC_CONFIG2, 18, 18);
        else
                BUG();
        enable_clocks(0);
 
        return enabled;
-
 }
 
 
@@ -2022,6 +2110,8 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
                enabled = REG_GET(DISPC_CONFIG, 10, 10);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                enabled = REG_GET(DISPC_CONFIG, 12, 12);
+       else if (ch == OMAP_DSS_CHANNEL_LCD2)
+               enabled = REG_GET(DISPC_CONFIG2, 10, 10);
        else
                BUG();
        enable_clocks(0);
@@ -2030,7 +2120,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
 }
 
 
-void dispc_set_tft_data_lines(u8 data_lines)
+void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
 {
        int code;
 
@@ -2053,11 +2143,15 @@ void dispc_set_tft_data_lines(u8 data_lines)
        }
 
        enable_clocks(1);
-       REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
+       if (channel == OMAP_DSS_CHANNEL_LCD2)
+               REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8);
+       else
+               REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
        enable_clocks(0);
 }
 
-void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
+void dispc_set_parallel_interface_mode(enum omap_channel channel,
+               enum omap_parallel_interface_mode mode)
 {
        u32 l;
        int stallmode;
@@ -2087,13 +2181,17 @@ void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
 
        enable_clocks(1);
 
-       l = dispc_read_reg(DISPC_CONTROL);
-
-       l = FLD_MOD(l, stallmode, 11, 11);
-       l = FLD_MOD(l, gpout0, 15, 15);
-       l = FLD_MOD(l, gpout1, 16, 16);
-
-       dispc_write_reg(DISPC_CONTROL, l);
+       if (channel == OMAP_DSS_CHANNEL_LCD2) {
+               l = dispc_read_reg(DISPC_CONTROL2);
+               l = FLD_MOD(l, stallmode, 11, 11);
+               dispc_write_reg(DISPC_CONTROL2, l);
+       } else {
+               l = dispc_read_reg(DISPC_CONTROL);
+               l = FLD_MOD(l, stallmode, 11, 11);
+               l = FLD_MOD(l, gpout0, 15, 15);
+               l = FLD_MOD(l, gpout1, 16, 16);
+               dispc_write_reg(DISPC_CONTROL, l);
+       }
 
        enable_clocks(0);
 }
@@ -2129,8 +2227,8 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
                        timings->vfp, timings->vbp);
 }
 
-static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
-                                  int vsw, int vfp, int vbp)
+static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
+               int hfp, int hbp, int vsw, int vfp, int vbp)
 {
        u32 timing_h, timing_v;
 
@@ -2149,13 +2247,14 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
        }
 
        enable_clocks(1);
-       dispc_write_reg(DISPC_TIMING_H, timing_h);
-       dispc_write_reg(DISPC_TIMING_V, timing_v);
+       dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
+       dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
        enable_clocks(0);
 }
 
 /* change name to mode? */
-void dispc_set_lcd_timings(struct omap_video_timings *timings)
+void dispc_set_lcd_timings(enum omap_channel channel,
+               struct omap_video_timings *timings)
 {
        unsigned xtot, ytot;
        unsigned long ht, vt;
@@ -2165,10 +2264,11 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
                                timings->vfp, timings->vbp))
                BUG();
 
-       _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
-                       timings->vsw, timings->vfp, timings->vbp);
+       _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp,
+                       timings->hbp, timings->vsw, timings->vfp,
+                       timings->vbp);
 
-       dispc_set_lcd_size(timings->x_res, timings->y_res);
+       dispc_set_lcd_size(channel, timings->x_res, timings->y_res);
 
        xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
        ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
@@ -2176,7 +2276,8 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
        ht = (timings->pixel_clock * 1000) / xtot;
        vt = (timings->pixel_clock * 1000) / xtot / ytot;
 
-       DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
+       DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res,
+                       timings->y_res);
        DSSDBG("pck %u\n", timings->pixel_clock);
        DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
                        timings->hsw, timings->hfp, timings->hbp,
@@ -2185,21 +2286,23 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
        DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
 }
 
-static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
+static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
+               u16 pck_div)
 {
        BUG_ON(lck_div < 1);
        BUG_ON(pck_div < 2);
 
        enable_clocks(1);
-       dispc_write_reg(DISPC_DIVISOR,
+       dispc_write_reg(DISPC_DIVISOR(channel),
                        FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
        enable_clocks(0);
 }
 
-static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
+static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
+               int *pck_div)
 {
        u32 l;
-       l = dispc_read_reg(DISPC_DIVISOR);
+       l = dispc_read_reg(DISPC_DIVISOR(channel));
        *lck_div = FLD_GET(l, 23, 16);
        *pck_div = FLD_GET(l, 7, 0);
 }
@@ -2219,13 +2322,13 @@ unsigned long dispc_fclk_rate(void)
        return r;
 }
 
-unsigned long dispc_lclk_rate(void)
+unsigned long dispc_lclk_rate(enum omap_channel channel)
 {
        int lcd;
        unsigned long r;
        u32 l;
 
-       l = dispc_read_reg(DISPC_DIVISOR);
+       l = dispc_read_reg(DISPC_DIVISOR(channel));
 
        lcd = FLD_GET(l, 23, 16);
 
@@ -2234,13 +2337,13 @@ unsigned long dispc_lclk_rate(void)
        return r / lcd;
 }
 
-unsigned long dispc_pclk_rate(void)
+unsigned long dispc_pclk_rate(enum omap_channel channel)
 {
        int lcd, pcd;
        unsigned long r;
        u32 l;
 
-       l = dispc_read_reg(DISPC_DIVISOR);
+       l = dispc_read_reg(DISPC_DIVISOR(channel));
 
        lcd = FLD_GET(l, 23, 16);
        pcd = FLD_GET(l, 7, 0);
@@ -2256,8 +2359,6 @@ void dispc_dump_clocks(struct seq_file *s)
 
        enable_clocks(1);
 
-       dispc_get_lcd_divisor(&lcd, &pcd);
-
        seq_printf(s, "- DISPC -\n");
 
        seq_printf(s, "dispc fclk source = %s\n",
@@ -2265,9 +2366,25 @@ void dispc_dump_clocks(struct seq_file *s)
                        "dss1_alwon_fclk" : "dsi1_pll_fclk");
 
        seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
-       seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
-       seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
 
+       seq_printf(s, "- LCD1 -\n");
+
+       dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
+
+       seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+                       dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd);
+       seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
+                       dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd);
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               seq_printf(s, "- LCD2 -\n");
+
+               dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
+
+               seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+                               dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd);
+               seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
+                               dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
+       }
        enable_clocks(0);
 }
 
@@ -2309,6 +2426,12 @@ void dispc_dump_irqs(struct seq_file *s)
        PIS(SYNC_LOST);
        PIS(SYNC_LOST_DIGIT);
        PIS(WAKEUP);
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               PIS(FRAMEDONE2);
+               PIS(VSYNC2);
+               PIS(ACBIAS_COUNT_STAT2);
+               PIS(SYNC_LOST2);
+       }
 #undef PIS
 }
 #endif
@@ -2327,19 +2450,30 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_CONTROL);
        DUMPREG(DISPC_CONFIG);
        DUMPREG(DISPC_CAPABLE);
-       DUMPREG(DISPC_DEFAULT_COLOR0);
-       DUMPREG(DISPC_DEFAULT_COLOR1);
-       DUMPREG(DISPC_TRANS_COLOR0);
-       DUMPREG(DISPC_TRANS_COLOR1);
+       DUMPREG(DISPC_DEFAULT_COLOR(0));
+       DUMPREG(DISPC_DEFAULT_COLOR(1));
+       DUMPREG(DISPC_TRANS_COLOR(0));
+       DUMPREG(DISPC_TRANS_COLOR(1));
        DUMPREG(DISPC_LINE_STATUS);
        DUMPREG(DISPC_LINE_NUMBER);
-       DUMPREG(DISPC_TIMING_H);
-       DUMPREG(DISPC_TIMING_V);
-       DUMPREG(DISPC_POL_FREQ);
-       DUMPREG(DISPC_DIVISOR);
+       DUMPREG(DISPC_TIMING_H(0));
+       DUMPREG(DISPC_TIMING_V(0));
+       DUMPREG(DISPC_POL_FREQ(0));
+       DUMPREG(DISPC_DIVISOR(0));
        DUMPREG(DISPC_GLOBAL_ALPHA);
        DUMPREG(DISPC_SIZE_DIG);
-       DUMPREG(DISPC_SIZE_LCD);
+       DUMPREG(DISPC_SIZE_LCD(0));
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               DUMPREG(DISPC_CONTROL2);
+               DUMPREG(DISPC_CONFIG2);
+               DUMPREG(DISPC_DEFAULT_COLOR(2));
+               DUMPREG(DISPC_TRANS_COLOR(2));
+               DUMPREG(DISPC_TIMING_H(2));
+               DUMPREG(DISPC_TIMING_V(2));
+               DUMPREG(DISPC_POL_FREQ(2));
+               DUMPREG(DISPC_DIVISOR(2));
+               DUMPREG(DISPC_SIZE_LCD(2));
+       }
 
        DUMPREG(DISPC_GFX_BA0);
        DUMPREG(DISPC_GFX_BA1);
@@ -2353,13 +2487,22 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_GFX_WINDOW_SKIP);
        DUMPREG(DISPC_GFX_TABLE_BA);
 
-       DUMPREG(DISPC_DATA_CYCLE1);
-       DUMPREG(DISPC_DATA_CYCLE2);
-       DUMPREG(DISPC_DATA_CYCLE3);
-
-       DUMPREG(DISPC_CPR_COEF_R);
-       DUMPREG(DISPC_CPR_COEF_G);
-       DUMPREG(DISPC_CPR_COEF_B);
+       DUMPREG(DISPC_DATA_CYCLE1(0));
+       DUMPREG(DISPC_DATA_CYCLE2(0));
+       DUMPREG(DISPC_DATA_CYCLE3(0));
+
+       DUMPREG(DISPC_CPR_COEF_R(0));
+       DUMPREG(DISPC_CPR_COEF_G(0));
+       DUMPREG(DISPC_CPR_COEF_B(0));
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               DUMPREG(DISPC_DATA_CYCLE1(2));
+               DUMPREG(DISPC_DATA_CYCLE2(2));
+               DUMPREG(DISPC_DATA_CYCLE3(2));
+
+               DUMPREG(DISPC_CPR_COEF_R(2));
+               DUMPREG(DISPC_CPR_COEF_G(2));
+               DUMPREG(DISPC_CPR_COEF_B(2));
+       }
 
        DUMPREG(DISPC_GFX_PRELOAD);
 
@@ -2458,8 +2601,8 @@ void dispc_dump_regs(struct seq_file *s)
 #undef DUMPREG
 }
 
-static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
-                               bool ihs, bool ivs, u8 acbi, u8 acb)
+static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
+               bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, u8 acb)
 {
        u32 l = 0;
 
@@ -2476,13 +2619,14 @@ static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
        l |= FLD_VAL(acb, 7, 0);
 
        enable_clocks(1);
-       dispc_write_reg(DISPC_POL_FREQ, l);
+       dispc_write_reg(DISPC_POL_FREQ(channel), l);
        enable_clocks(0);
 }
 
-void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
+void dispc_set_pol_freq(enum omap_channel channel,
+               enum omap_panel_config config, u8 acbi, u8 acb)
 {
-       _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
+       _dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0,
                        (config & OMAP_DSS_LCD_RF) != 0,
                        (config & OMAP_DSS_LCD_IEO) != 0,
                        (config & OMAP_DSS_LCD_IPC) != 0,
@@ -2551,24 +2695,26 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
        return 0;
 }
 
-int dispc_set_clock_div(struct dispc_clock_info *cinfo)
+int dispc_set_clock_div(enum omap_channel channel,
+               struct dispc_clock_info *cinfo)
 {
        DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
        DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
 
-       dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
+       dispc_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
 
        return 0;
 }
 
-int dispc_get_clock_div(struct dispc_clock_info *cinfo)
+int dispc_get_clock_div(enum omap_channel channel,
+               struct dispc_clock_info *cinfo)
 {
        unsigned long fck;
 
        fck = dispc_fclk_rate();
 
-       cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
-       cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
+       cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16);
+       cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0);
 
        cinfo->lck = fck / cinfo->lck_div;
        cinfo->pck = cinfo->lck / cinfo->pck_div;
@@ -2708,6 +2854,8 @@ static void print_irq_status(u32 status)
        PIS(VID2_FIFO_UNDERFLOW);
        PIS(SYNC_LOST);
        PIS(SYNC_LOST_DIGIT);
+       if (dss_has_feature(FEAT_MGR_LCD2))
+               PIS(SYNC_LOST2);
 #undef PIS
 
        printk("\n");
@@ -2926,6 +3074,45 @@ static void dispc_error_worker(struct work_struct *work)
                }
        }
 
+       if (errors & DISPC_IRQ_SYNC_LOST2) {
+               struct omap_overlay_manager *manager = NULL;
+               bool enable = false;
+
+               DSSERR("SYNC_LOST for LCD2, disabling LCD2\n");
+
+               for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
+                       struct omap_overlay_manager *mgr;
+                       mgr = omap_dss_get_overlay_manager(i);
+
+                       if (mgr->id == OMAP_DSS_CHANNEL_LCD2) {
+                               manager = mgr;
+                               enable = mgr->device->state ==
+                                               OMAP_DSS_DISPLAY_ACTIVE;
+                               mgr->device->driver->disable(mgr->device);
+                               break;
+                       }
+               }
+
+               if (manager) {
+                       struct omap_dss_device *dssdev = manager->device;
+                       for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+                               struct omap_overlay *ovl;
+                               ovl = omap_dss_get_overlay(i);
+
+                               if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
+                                       continue;
+
+                               if (ovl->id != 0 && ovl->manager == manager)
+                                       dispc_enable_plane(ovl->id, 0);
+                       }
+
+                       dispc_go(manager->id);
+                       mdelay(50);
+                       if (enable)
+                               dssdev->driver->enable(dssdev);
+               }
+       }
+
        if (errors & DISPC_IRQ_OCP_ERR) {
                DSSERR("OCP_ERR\n");
                for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
@@ -3033,6 +3220,8 @@ static void _omap_dispc_initialize_irq(void)
        memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
 
        dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
+       if (dss_has_feature(FEAT_MGR_LCD2))
+               dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
 
        /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
         * so clear it */
@@ -3065,7 +3254,8 @@ static void _omap_dispc_initial_config(void)
        dispc_write_reg(DISPC_SYSCONFIG, l);
 
        /* FUNCGATED */
-       REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
+       if (dss_has_feature(FEAT_FUNCGATED))
+               REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
 
        /* L3 firewall setting: enable access to OCM RAM */
        /* XXX this should be somewhere in plat-omap */
@@ -3139,17 +3329,18 @@ int dispc_setup_plane(enum omap_plane plane,
                       enum omap_color_mode color_mode,
                       bool ilace,
                       enum omap_dss_rotation_type rotation_type,
-                      u8 rotation, bool mirror, u8 global_alpha)
+                      u8 rotation, bool mirror, u8 global_alpha,
+                      u8 pre_mult_alpha, enum omap_channel channel)
 {
        int r = 0;
 
        DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
-              "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
+              "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
               plane, paddr, screen_width, pos_x, pos_y,
               width, height,
               out_width, out_height,
               ilace, color_mode,
-              rotation, mirror);
+              rotation, mirror, channel);
 
        enable_clocks(1);
 
@@ -3161,7 +3352,8 @@ int dispc_setup_plane(enum omap_plane plane,
                           color_mode, ilace,
                           rotation_type,
                           rotation, mirror,
-                          global_alpha);
+                          global_alpha,
+                          pre_mult_alpha, channel);
 
        enable_clocks(0);
 
index 960e977a8bf0f39ff8dce42c0893fc9604ea8081..75fb0a5154304a92bbe5b0164a1257064436d2ec 100644 (file)
@@ -40,8 +40,9 @@ static struct {
 } dpi;
 
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
-               unsigned long *fck, int *lck_div, int *pck_div)
+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)
 {
        struct dsi_clock_info dsi_cinfo;
        struct dispc_clock_info dispc_cinfo;
@@ -58,7 +59,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
 
        dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
 
-       r = dispc_set_clock_div(&dispc_cinfo);
+       r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
                return r;
 
@@ -69,8 +70,9 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
        return 0;
 }
 #else
-static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
-               unsigned long *fck, int *lck_div, int *pck_div)
+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)
 {
        struct dss_clock_info dss_cinfo;
        struct dispc_clock_info dispc_cinfo;
@@ -84,7 +86,7 @@ static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
        if (r)
                return r;
 
-       r = dispc_set_clock_div(&dispc_cinfo);
+       r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
                return r;
 
@@ -107,17 +109,17 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
 
        dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
 
-       dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
-                       dssdev->panel.acb);
+       dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
+                       dssdev->panel.acbi, dssdev->panel.acb);
 
        is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
-                       &fck, &lck_div, &pck_div);
+       r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
+                       &lck_div, &pck_div);
 #else
-       r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
-                       &fck, &lck_div, &pck_div);
+       r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
+                       &lck_div, &pck_div);
 #endif
        if (r)
                goto err0;
@@ -132,7 +134,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
                t->pixel_clock = pck;
        }
 
-       dispc_set_lcd_timings(t);
+       dispc_set_lcd_timings(dssdev->manager->id, t);
 
 err0:
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
@@ -145,10 +147,12 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
 
        is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
-       dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
-       dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
-                       OMAP_DSS_LCD_DISPLAY_STN);
-       dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
+       dispc_set_parallel_interface_mode(dssdev->manager->id,
+                       OMAP_DSS_PARALLELMODE_BYPASS);
+       dispc_set_lcd_display_type(dssdev->manager->id, is_tft ?
+                       OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
+       dispc_set_tft_data_lines(dssdev->manager->id,
+                       dssdev->phy.dpi.data_lines);
 
        return 0;
 }
@@ -234,7 +238,7 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
        dssdev->panel.timings = *timings;
        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
                dpi_set_mode(dssdev);
-               dispc_go(OMAP_DSS_CHANNEL_LCD);
+               dispc_go(dssdev->manager->id);
        }
 }
 EXPORT_SYMBOL(dpi_set_timings);
index aa4f7a5fae29fca001d297d31982ae1f5b88f46c..ddf3a05608228ac58c83f0c3246a43631a202e08 100644 (file)
@@ -792,7 +792,8 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
 }
 
 /* calculate clock rates using dividers in cinfo */
-static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
+static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
+               struct dsi_clock_info *cinfo)
 {
        if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
                return -EINVAL;
@@ -812,7 +813,7 @@ static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
                 * with DSS2_FCK source also */
                cinfo->highfreq = 0;
        } else {
-               cinfo->clkin = dispc_pclk_rate();
+               cinfo->clkin = dispc_pclk_rate(dssdev->manager->id);
 
                if (cinfo->clkin < 32000000)
                        cinfo->highfreq = 0;
@@ -1206,8 +1207,8 @@ void dsi_dump_clocks(struct seq_file *s)
 
        seq_printf(s,   "VP_CLK\t\t%lu\n"
                        "VP_PCLK\t\t%lu\n",
-                       dispc_lclk_rate(),
-                       dispc_pclk_rate());
+                       dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD),
+                       dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD));
 
        enable_clocks(0);
 }
@@ -2888,7 +2889,7 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
        if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
                dss_setup_partial_planes(dssdev, x, y, w, h,
                                enlarge_update_area);
-               dispc_set_lcd_size(*w, *h);
+               dispc_set_lcd_size(dssdev->manager->id, *w, *h);
        }
 
        return 0;
@@ -2947,12 +2948,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
                return r;
        }
 
-       dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
+       dispc_set_lcd_display_type(dssdev->manager->id,
+                       OMAP_DSS_LCD_DISPLAY_TFT);
 
-       dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI);
-       dispc_enable_fifohandcheck(1);
+       dispc_set_parallel_interface_mode(dssdev->manager->id,
+                       OMAP_DSS_PARALLELMODE_DSI);
+       dispc_enable_fifohandcheck(dssdev->manager->id, 1);
 
-       dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
+       dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
 
        {
                struct omap_video_timings timings = {
@@ -2964,7 +2967,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
                        .vbp            = 0,
                };
 
-               dispc_set_lcd_timings(&timings);
+               dispc_set_lcd_timings(dssdev->manager->id, &timings);
        }
 
        return 0;
@@ -2987,7 +2990,7 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
        cinfo.regm  = dssdev->phy.dsi.div.regm;
        cinfo.regm3 = dssdev->phy.dsi.div.regm3;
        cinfo.regm4 = dssdev->phy.dsi.div.regm4;
-       r = dsi_calc_clock_rates(&cinfo);
+       r = dsi_calc_clock_rates(dssdev, &cinfo);
        if (r) {
                DSSERR("Failed to calc dsi clocks\n");
                return r;
@@ -3019,7 +3022,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
                return r;
        }
 
-       r = dispc_set_clock_div(&dispc_cinfo);
+       r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r) {
                DSSERR("Failed to set dispc clocks\n");
                return r;
index 5c7940d5f282f3137be4f8451c76a5692609b3a0..b394951120ac349a5bf78f702f89af8a9fc2bb9f 100644 (file)
@@ -333,9 +333,9 @@ void dispc_disable_sidle(void);
 void dispc_lcd_enable_signal_polarity(bool act_high);
 void dispc_lcd_enable_signal(bool enable);
 void dispc_pck_free_enable(bool enable);
-void dispc_enable_fifohandcheck(bool enable);
+void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable);
 
-void dispc_set_lcd_size(u16 width, u16 height);
+void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
 void dispc_set_digit_size(u16 width, u16 height);
 u32 dispc_get_plane_fifo_size(enum omap_plane plane);
 void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
@@ -359,7 +359,8 @@ int dispc_setup_plane(enum omap_plane plane,
                      bool ilace,
                      enum omap_dss_rotation_type rotation_type,
                      u8 rotation, bool mirror,
-                     u8 global_alpha);
+                     u8 global_alpha, u8 pre_mult_alpha,
+                     enum omap_channel channel);
 
 bool dispc_go_busy(enum omap_channel channel);
 void dispc_go(enum omap_channel channel);
@@ -368,9 +369,11 @@ bool dispc_is_channel_enabled(enum omap_channel channel);
 int dispc_enable_plane(enum omap_plane plane, bool enable);
 void dispc_enable_replication(enum omap_plane plane, bool enable);
 
-void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
-void dispc_set_tft_data_lines(u8 data_lines);
-void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
+void dispc_set_parallel_interface_mode(enum omap_channel channel,
+               enum omap_parallel_interface_mode mode);
+void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines);
+void dispc_set_lcd_display_type(enum omap_channel channel,
+               enum omap_lcd_display_type type);
 void dispc_set_loadmode(enum omap_dss_load_mode mode);
 
 void dispc_set_default_color(enum omap_channel channel, u32 color);
@@ -387,17 +390,21 @@ bool dispc_trans_key_enabled(enum omap_channel ch);
 bool dispc_alpha_blending_enabled(enum omap_channel ch);
 
 bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
-void dispc_set_lcd_timings(struct omap_video_timings *timings);
+void dispc_set_lcd_timings(enum omap_channel channel,
+               struct omap_video_timings *timings);
 unsigned long dispc_fclk_rate(void);
-unsigned long dispc_lclk_rate(void);
-unsigned long dispc_pclk_rate(void);
-void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
+unsigned long dispc_lclk_rate(enum omap_channel channel);
+unsigned long dispc_pclk_rate(enum omap_channel channel);
+void dispc_set_pol_freq(enum omap_channel channel,
+               enum omap_panel_config config, u8 acbi, u8 acb);
 void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
                struct dispc_clock_info *cinfo);
 int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
                struct dispc_clock_info *cinfo);
-int dispc_set_clock_div(struct dispc_clock_info *cinfo);
-int dispc_get_clock_div(struct dispc_clock_info *cinfo);
+int dispc_set_clock_div(enum omap_channel channel,
+               struct dispc_clock_info *cinfo);
+int dispc_get_clock_div(enum omap_channel channel,
+               struct dispc_clock_info *cinfo);
 
 
 /* VENC */
@@ -424,8 +431,8 @@ 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(u16 width, u16 height,
-                            void (callback)(void *data), void *data);
+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);
index 867f68de125f6ed6221f7a276c46f3a23936f6b5..cf3ef696e141ee7be4f8a2e3feb99afa86d7f417 100644 (file)
@@ -82,6 +82,18 @@ static const enum omap_display_type omap3_dss_supported_displays[] = {
        OMAP_DISPLAY_TYPE_VENC,
 };
 
+static const enum omap_display_type omap4_dss_supported_displays[] = {
+       /* OMAP_DSS_CHANNEL_LCD */
+       OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
+
+       /* OMAP_DSS_CHANNEL_DIGIT */
+       OMAP_DISPLAY_TYPE_VENC,
+
+       /* OMAP_DSS_CHANNEL_LCD2 */
+       OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+       OMAP_DISPLAY_TYPE_DSI,
+};
+
 static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
        /* OMAP_DSS_GFX */
        OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
@@ -127,6 +139,10 @@ static struct omap_dss_features omap2_dss_features = {
        .reg_fields = omap2_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
 
+       .has_feature    =
+               FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL |
+               FEAT_PCKFREEENABLE | FEAT_FUNCGATED,
+
        .num_mgrs = 2,
        .num_ovls = 3,
        .supported_displays = omap2_dss_supported_displays,
@@ -134,11 +150,29 @@ static struct omap_dss_features omap2_dss_features = {
 };
 
 /* OMAP3 DSS Features */
-static struct omap_dss_features omap3_dss_features = {
+static struct omap_dss_features omap3430_dss_features = {
+       .reg_fields = omap3_dss_reg_fields,
+       .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+       .has_feature    =
+               FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
+               FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
+               FEAT_FUNCGATED,
+
+       .num_mgrs = 2,
+       .num_ovls = 3,
+       .supported_displays = omap3_dss_supported_displays,
+       .supported_color_modes = omap3_dss_supported_color_modes,
+};
+
+static struct omap_dss_features omap3630_dss_features = {
        .reg_fields = omap3_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
-       .has_feature    = FEAT_GLOBAL_ALPHA,
+       .has_feature    =
+               FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
+               FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
+               FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED,
 
        .num_mgrs = 2,
        .num_ovls = 3,
@@ -146,6 +180,21 @@ static struct omap_dss_features omap3_dss_features = {
        .supported_color_modes = omap3_dss_supported_color_modes,
 };
 
+/* OMAP4 DSS Features */
+static struct omap_dss_features omap4_dss_features = {
+       .reg_fields = omap3_dss_reg_fields,
+       .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+       .has_feature    =
+               FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
+               FEAT_MGR_LCD2,
+
+       .num_mgrs = 3,
+       .num_ovls = 3,
+       .supported_displays = omap4_dss_supported_displays,
+       .supported_color_modes = omap3_dss_supported_color_modes,
+};
+
 /* Functions returning values related to a DSS feature */
 int dss_feat_get_num_mgrs(void)
 {
@@ -167,6 +216,13 @@ enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
        return omap_current_dss_features->supported_color_modes[plane];
 }
 
+bool dss_feat_color_mode_supported(enum omap_plane plane,
+               enum omap_color_mode color_mode)
+{
+       return omap_current_dss_features->supported_color_modes[plane] &
+                       color_mode;
+}
+
 /* DSS has_feature check */
 bool dss_has_feature(enum dss_feat_id id)
 {
@@ -186,6 +242,10 @@ void dss_features_init(void)
 {
        if (cpu_is_omap24xx())
                omap_current_dss_features = &omap2_dss_features;
+       else if (cpu_is_omap3630())
+               omap_current_dss_features = &omap3630_dss_features;
+       else if (cpu_is_omap34xx())
+               omap_current_dss_features = &omap3430_dss_features;
        else
-               omap_current_dss_features = &omap3_dss_features;
+               omap_current_dss_features = &omap4_dss_features;
 }
index cb231eaa9b31c890361974e799378285b6f0edaa..b9c70be9258874dbdca30c6f53eeaefba6307267 100644 (file)
 #ifndef __OMAP2_DSS_FEATURES_H
 #define __OMAP2_DSS_FEATURES_H
 
-#define MAX_DSS_MANAGERS       2
+#define MAX_DSS_MANAGERS       3
 #define MAX_DSS_OVERLAYS       3
 
 /* 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,
 };
 
 /* DSS register field id */
@@ -43,6 +49,8 @@ int dss_feat_get_num_mgrs(void);
 int dss_feat_get_num_ovls(void);
 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);
 
 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);
index 545e9b9a4d92fc19eac470e5d62cb508461f0e4c..172d4e69730917e3a2a4630c8bdcaf4d24c60e92 100644 (file)
@@ -406,6 +406,7 @@ struct overlay_cache_data {
        u16 out_width;  /* if 0, out_width == width */
        u16 out_height; /* if 0, out_height == height */
        u8 global_alpha;
+       u8 pre_mult_alpha;
 
        enum omap_channel channel;
        bool replication;
@@ -512,11 +513,14 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
        unsigned long timeout = msecs_to_jiffies(500);
        u32 irq;
 
-       if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
+       if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
                irq = DISPC_IRQ_EVSYNC_ODD;
-       else
-               irq = DISPC_IRQ_VSYNC;
-
+       } else {
+               if (mgr->id == OMAP_DSS_CHANNEL_LCD)
+                       irq = DISPC_IRQ_VSYNC;
+               else
+                       irq = DISPC_IRQ_VSYNC2;
+       }
        return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
 }
 
@@ -524,7 +528,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
 {
        unsigned long timeout = msecs_to_jiffies(500);
        struct manager_cache_data *mc;
-       enum omap_channel channel;
        u32 irq;
        int r;
        int i;
@@ -535,7 +538,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
 
        if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
                irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
-               channel = OMAP_DSS_CHANNEL_DIGIT;
        } else {
                if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
                        enum omap_dss_update_mode mode;
@@ -543,11 +545,14 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
                        if (mode != OMAP_DSS_UPDATE_AUTO)
                                return 0;
 
-                       irq = DISPC_IRQ_FRAMEDONE;
+                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+                               DISPC_IRQ_FRAMEDONE
+                               : DISPC_IRQ_FRAMEDONE2;
                } else {
-                       irq = DISPC_IRQ_VSYNC;
+                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+                               DISPC_IRQ_VSYNC
+                               : DISPC_IRQ_VSYNC2;
                }
-               channel = OMAP_DSS_CHANNEL_LCD;
        }
 
        mc = &dss_cache.manager_cache[mgr->id];
@@ -594,7 +599,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
 int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
 {
        unsigned long timeout = msecs_to_jiffies(500);
-       enum omap_channel channel;
        struct overlay_cache_data *oc;
        struct omap_dss_device *dssdev;
        u32 irq;
@@ -611,7 +615,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
 
        if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
                irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
-               channel = OMAP_DSS_CHANNEL_DIGIT;
        } else {
                if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
                        enum omap_dss_update_mode mode;
@@ -619,11 +622,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
                        if (mode != OMAP_DSS_UPDATE_AUTO)
                                return 0;
 
-                       irq = DISPC_IRQ_FRAMEDONE;
+                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+                               DISPC_IRQ_FRAMEDONE
+                               : DISPC_IRQ_FRAMEDONE2;
                } else {
-                       irq = DISPC_IRQ_VSYNC;
+                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+                               DISPC_IRQ_VSYNC
+                               : DISPC_IRQ_VSYNC2;
                }
-               channel = OMAP_DSS_CHANNEL_LCD;
        }
 
        oc = &dss_cache.overlay_cache[ovl->id];
@@ -842,7 +848,9 @@ static int configure_overlay(enum omap_plane plane)
                        c->rotation_type,
                        c->rotation,
                        c->mirror,
-                       c->global_alpha);
+                       c->global_alpha,
+                       c->pre_mult_alpha,
+                       c->channel);
 
        if (r) {
                /* this shouldn't happen */
@@ -894,10 +902,10 @@ static int configure_dispc(void)
        r = 0;
        busy = false;
 
-       mgr_busy[0] = dispc_go_busy(0);
-       mgr_busy[1] = dispc_go_busy(1);
-       mgr_go[0] = false;
-       mgr_go[1] = false;
+       for (i = 0; i < num_mgrs; i++) {
+               mgr_busy[i] = dispc_go_busy(i);
+               mgr_go[i] = false;
+       }
 
        /* Commit overlay settings */
        for (i = 0; i < num_ovls; ++i) {
@@ -1156,9 +1164,10 @@ static void dss_apply_irq_handler(void *data, u32 mask)
        const int num_mgrs = dss_feat_get_num_mgrs();
        int i, r;
        bool mgr_busy[MAX_DSS_MANAGERS];
+       u32 irq_mask;
 
-       mgr_busy[0] = dispc_go_busy(0);
-       mgr_busy[1] = dispc_go_busy(1);
+       for (i = 0; i < num_mgrs; i++)
+               mgr_busy[i] = dispc_go_busy(i);
 
        spin_lock(&dss_cache.lock);
 
@@ -1179,8 +1188,8 @@ static void dss_apply_irq_handler(void *data, u32 mask)
                goto end;
 
        /* re-read busy flags */
-       mgr_busy[0] = dispc_go_busy(0);
-       mgr_busy[1] = dispc_go_busy(1);
+       for (i = 0; i < num_mgrs; i++)
+               mgr_busy[i] = dispc_go_busy(i);
 
        /* keep running as long as there are busy managers, so that
         * we can collect overlay-applied information */
@@ -1189,9 +1198,12 @@ static void dss_apply_irq_handler(void *data, u32 mask)
                        goto end;
        }
 
-       omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
-                       DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
-                       DISPC_IRQ_EVSYNC_EVEN);
+       irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
+                       DISPC_IRQ_EVSYNC_EVEN;
+       if (dss_has_feature(FEAT_MGR_LCD2))
+               irq_mask |= DISPC_IRQ_VSYNC2;
+
+       omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
        dss_cache.irq_enabled = false;
 
 end:
@@ -1265,6 +1277,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
                oc->out_width = ovl->info.out_width;
                oc->out_height = ovl->info.out_height;
                oc->global_alpha = ovl->info.global_alpha;
+               oc->pre_mult_alpha = ovl->info.pre_mult_alpha;
 
                oc->replication =
                        dss_use_replication(dssdev, ovl->info.color_mode);
@@ -1383,9 +1396,14 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
        r = 0;
        dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
        if (!dss_cache.irq_enabled) {
-               r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
-                               DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
-                               DISPC_IRQ_EVSYNC_EVEN);
+               u32 mask;
+
+               mask = DISPC_IRQ_VSYNC  | DISPC_IRQ_EVSYNC_ODD |
+                       DISPC_IRQ_EVSYNC_EVEN;
+               if (dss_has_feature(FEAT_MGR_LCD2))
+                       mask |= DISPC_IRQ_VSYNC2;
+
+               r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
                dss_cache.irq_enabled = true;
        }
        configure_dispc();
@@ -1477,6 +1495,10 @@ int dss_init_overlay_managers(struct platform_device *pdev)
                        mgr->name = "tv";
                        mgr->id = OMAP_DSS_CHANNEL_DIGIT;
                        break;
+               case 2:
+                       mgr->name = "lcd2";
+                       mgr->id = OMAP_DSS_CHANNEL_LCD2;
+                       break;
                }
 
                mgr->set_device = &omap_dss_set_device;
index 75642c22cac7f50724879ff3b8ef699b52aee14f..456efef03c20c6de3a30bcd6aa1355862c4e6c05 100644 (file)
@@ -257,6 +257,43 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
        return size;
 }
 
+static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
+               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       ovl->info.pre_mult_alpha);
+}
+
+static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
+               const char *buf, size_t size)
+{
+       int r;
+       struct omap_overlay_info info;
+
+       ovl->get_overlay_info(ovl, &info);
+
+       /* only GFX and Video2 plane support pre alpha multiplied
+        * set zero for Video1 plane
+        */
+       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+               ovl->id == OMAP_DSS_VIDEO1)
+               info.pre_mult_alpha = 0;
+       else
+               info.pre_mult_alpha = simple_strtoul(buf, NULL, 10);
+
+       r = ovl->set_overlay_info(ovl, &info);
+       if (r)
+               return r;
+
+       if (ovl->manager) {
+               r = ovl->manager->apply(ovl->manager);
+               if (r)
+                       return r;
+       }
+
+       return size;
+}
+
 struct overlay_attribute {
        struct attribute attr;
        ssize_t (*show)(struct omap_overlay *, char *);
@@ -280,6 +317,9 @@ static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
                overlay_enabled_show, overlay_enabled_store);
 static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
                overlay_global_alpha_show, overlay_global_alpha_store);
+static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
+               overlay_pre_mult_alpha_show,
+               overlay_pre_mult_alpha_store);
 
 static struct attribute *overlay_sysfs_attrs[] = {
        &overlay_attr_name.attr,
@@ -290,6 +330,7 @@ static struct attribute *overlay_sysfs_attrs[] = {
        &overlay_attr_output_size.attr,
        &overlay_attr_enabled.attr,
        &overlay_attr_global_alpha.attr,
+       &overlay_attr_pre_mult_alpha.attr,
        NULL
 };
 
@@ -623,12 +664,22 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
        int i;
        struct omap_overlay_manager *lcd_mgr;
        struct omap_overlay_manager *tv_mgr;
+       struct omap_overlay_manager *lcd2_mgr = NULL;
        struct omap_overlay_manager *mgr = NULL;
 
        lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
        tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
-
-       if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
+       if (dss_has_feature(FEAT_MGR_LCD2))
+               lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2);
+
+       if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
+               if (!lcd2_mgr->device || force) {
+                       if (lcd2_mgr->device)
+                               lcd2_mgr->unset_device(lcd2_mgr);
+                       lcd2_mgr->set_device(lcd2_mgr, dssdev);
+                       mgr = lcd2_mgr;
+               }
+       } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
                if (!lcd_mgr->device || force) {
                        if (lcd_mgr->device)
                                lcd_mgr->unset_device(lcd_mgr);
index bbe62464e92df533309f20ea59f4e2dbbe6c6d3e..10a2ffe02882e929f6c64250ba2ba9d87242ccaf 100644 (file)
@@ -301,8 +301,8 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
 }
 EXPORT_SYMBOL(omap_rfbi_write_pixels);
 
-void rfbi_transfer_area(u16 width, u16 height,
-                            void (callback)(void *data), void *data)
+void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
+               u16 height, void (*callback)(void *data), void *data)
 {
        u32 l;
 
@@ -311,9 +311,9 @@ void rfbi_transfer_area(u16 width, u16 height,
 
        DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
 
-       dispc_set_lcd_size(width, height);
+       dispc_set_lcd_size(dssdev->manager->id, width, height);
 
-       dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true);
+       dispc_enable_channel(dssdev->manager->id, true);
 
        rfbi.framedone_callback = callback;
        rfbi.framedone_callback_data = data;
@@ -887,7 +887,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
 
        if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
                dss_setup_partial_planes(dssdev, x, y, w, h, true);
-               dispc_set_lcd_size(*w, *h);
+               dispc_set_lcd_size(dssdev->manager->id, *w, *h);
        }
 
        return 0;
@@ -899,7 +899,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev,
                void (*callback)(void *), void *data)
 {
        if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
-               rfbi_transfer_area(w, h, callback, data);
+               rfbi_transfer_area(dssdev, w, h, callback, data);
        } else {
                struct omap_overlay *ovl;
                void __iomem *addr;
@@ -1018,11 +1018,13 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
                goto err1;
        }
 
-       dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
+       dispc_set_lcd_display_type(dssdev->manager->id,
+                       OMAP_DSS_LCD_DISPLAY_TFT);
 
-       dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI);
+       dispc_set_parallel_interface_mode(dssdev->manager->id,
+                       OMAP_DSS_PARALLELMODE_RFBI);
 
-       dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
+       dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
 
        rfbi_configure(dssdev->phy.rfbi.channel,
                               dssdev->ctrl.pixel_size,
index ee07a3cc22ef88d7c9f5a3a3f27794f669b8a0fc..b64adf7dfc88b20963829245e0061c6ad1df4960 100644 (file)
@@ -35,12 +35,16 @@ static struct {
        struct regulator *vdds_sdi_reg;
 } sdi;
 
-static void sdi_basic_init(void)
+static void sdi_basic_init(struct omap_dss_device *dssdev)
+
 {
-       dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
+       dispc_set_parallel_interface_mode(dssdev->manager->id,
+                       OMAP_DSS_PARALLELMODE_BYPASS);
+
+       dispc_set_lcd_display_type(dssdev->manager->id,
+                       OMAP_DSS_LCD_DISPLAY_TFT);
 
-       dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
-       dispc_set_tft_data_lines(24);
+       dispc_set_tft_data_lines(dssdev->manager->id, 24);
        dispc_lcd_enable_signal_polarity(1);
 }
 
@@ -68,20 +72,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        if (!sdi.skip_init)
                dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
 
-       sdi_basic_init();
+       sdi_basic_init(dssdev);
 
        /* 15.5.9.1.2 */
        dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
 
-       dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
-                       dssdev->panel.acb);
+       dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
+                       dssdev->panel.acbi, dssdev->panel.acb);
 
        if (!sdi.skip_init) {
                r = dss_calc_clock_div(1, t->pixel_clock * 1000,
                                &dss_cinfo, &dispc_cinfo);
        } else {
                r = dss_get_clock_div(&dss_cinfo);
-               r = dispc_get_clock_div(&dispc_cinfo);
+               r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo);
        }
 
        if (r)
@@ -102,13 +106,13 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        }
 
 
-       dispc_set_lcd_timings(t);
+       dispc_set_lcd_timings(dssdev->manager->id, t);
 
        r = dss_set_clock_div(&dss_cinfo);
        if (r)
                goto err2;
 
-       r = dispc_set_clock_div(&dispc_cinfo);
+       r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
                goto err2;
 
index 6a704f176c222a004f8732268e04cafb82ed1a70..4fdab8e9c4963249ab9d47b19eb33c56a9422fbe 100644 (file)
@@ -2132,8 +2132,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
        char *str, *options, *this_opt;
        int r = 0;
 
-       str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
-       strcpy(str, def_mode);
+       str = kstrdup(def_mode, GFP_KERNEL);
+       if (!str)
+               return -ENOMEM;
        options = str;
 
        while (!r && (this_opt = strsep(&options, ",")) != NULL) {