]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
FB: OMAP: Add support for framebuffer
authorImre Deak <imre.deak@nokia.com>
Mon, 9 May 2005 21:21:24 +0000 (14:21 -0700)
committerTony Lindgren <tony@atomide.com>
Mon, 9 May 2005 21:21:24 +0000 (14:21 -0700)
Adds support for OMAP framebuffer.

Signed-off-by: Imre Deak <imre.deak@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
16 files changed:
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/omap/Makefile [new file with mode: 0644]
drivers/video/omap/debug.h [new file with mode: 0644]
drivers/video/omap/lcd_h2.c [new file with mode: 0644]
drivers/video/omap/lcd_h3.c [new file with mode: 0644]
drivers/video/omap/lcd_inn1510.c [new file with mode: 0644]
drivers/video/omap/lcd_inn1610.c [new file with mode: 0644]
drivers/video/omap/lcd_osk.c [new file with mode: 0644]
drivers/video/omap/lcd_p2.c [new file with mode: 0644]
drivers/video/omap/omap_lcdc.c [new file with mode: 0644]
drivers/video/omap/omapfb.h [new file with mode: 0644]
drivers/video/omap/omapfb_main.c [new file with mode: 0644]
drivers/video/omap/sossi.c [new file with mode: 0644]
drivers/video/omap/sossi.h [new file with mode: 0644]
include/linux/fb.h

index 6be8fbec0a0e2e1d454bc1513df3eba8fa49d248..61e23979770c8b518ccc7c2890c8210fb10156fc 100644 (file)
@@ -1468,6 +1468,48 @@ config FB_S1D13XXX
          working with S1D13806). Product specs at
          <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
 
+config FB_OMAP
+       tristate "OMAP frame buffer support (EXPERIMENTAL)"
+        depends on FB && ARCH_OMAP1
+       select FB_SOFT_CURSOR
+        help
+          This is the new frame buffer device driver with 2D acceleration
+          for OMAP boards.
+
+config FB_OMAP_INTERNAL_LCDC
+       bool "OMAP internal LCD controller support"
+       depends on FB_OMAP
+       default y
+       help
+         Say Y here, if you want to have support for the internal OMAP
+         LCD controller. If unsure, say Y.
+
+config FB_OMAP_EXTERNAL_LCDC
+       bool "OMAP external LCD controller support"
+       depends on FB_OMAP
+       help
+         Say Y here, if you want to have support for boards with an
+         external LCD controller connected to the SoSSI interface.
+
+config FB_OMAP_MANUAL_UPDATE
+       bool "Default to manual update mode"
+       depends on FB_OMAP_EXTERNAL_LCDC
+       help
+         Say Y here, if your user-space applications are capable of
+         notifying the frame buffer driver when a change has occured in
+          the frame buffer content and thus a reload of the image data is
+          required. If unsure, say N.
+
+config FB_OMAP_DMA_TUNE
+        bool "Set DMA SDRAM access priority high"
+        depends on FB_OMAP
+        help
+          On systems in which video memory is in system memory
+          (SDRAM) this will speed up graphics DMA operations.
+          If you have such a system and want to use rotation
+          answer yes. Answer no if you have a dedicated video
+          memory, or don't use any of the accelerated features.
+
 config FB_VIRTUAL
        tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
        depends on FB
index bd8dc0ffe723d9070b054af1e74703b053d3da75..20b83d8483ed8714a7d80d5bdc5da133391003ae 100644 (file)
@@ -96,6 +96,7 @@ obj-$(CONFIG_FB_IMX)              += imxfb.o
 obj-$(CONFIG_FB_VESA)             += vesafb.o
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
 obj-$(CONFIG_FB_OF)               += offb.o
+obj-$(CONFIG_FB_OMAP)            += omap/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile
new file mode 100644 (file)
index 0000000..e5bfd03
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the new OMAP framebuffer device driver
+#
+
+obj-$(CONFIG_FB_OMAP) += omapfb.o
+
+objs-yy := omapfb_main.o
+objs-y$(CONFIG_FB_OMAP_INTERNAL_LCDC) += omap_lcdc.o
+objs-y$(CONFIG_FB_OMAP_EXTERNAL_LCDC) += sossi.o
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
+objs-y$(CONFIG_MACH_OMAP_H2) += lcd_h2.o
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
+objs-$(CONFIG_ARCH_OMAP1510)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
+objs-$(CONFIG_ARCH_OMAP730)$(CONFIG_MACH_OMAP_PERSEUS2) += lcd_p2.o
+
+omapfb-objs := $(objs-yy)
+
diff --git a/drivers/video/omap/debug.h b/drivers/video/omap/debug.h
new file mode 100644 (file)
index 0000000..cbc5db8
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * File: drivers/video/omap_new/debug.c
+ *
+ * Debug support for the omapfb driver
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __OMAPFB_DEBUG_H
+#define __OMAPFB_DEBUG_H
+
+#ifdef OMAPFB_DBG
+
+#define DBG_BUF_SIZE           2048
+#define MAX_DBG_INDENT_LEVEL   5
+#define DBG_INDENT_SIZE                3
+#define MAX_DBG_MESSAGES       0
+
+static int dbg_indent;
+static int dbg_cnt;
+static char dbg_buf[DBG_BUF_SIZE];
+static spinlock_t dbg_spinlock = SPIN_LOCK_UNLOCKED;
+
+static inline void dbg_print(int level, const char *fmt, ...)
+{
+       if (level <= OMAPFB_DBG) {
+               if (!MAX_DBG_MESSAGES || dbg_cnt < MAX_DBG_MESSAGES) {
+                       va_list args;
+                       int     ind = dbg_indent;
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&dbg_spinlock, flags);
+                       dbg_cnt++;
+                       if (ind > MAX_DBG_INDENT_LEVEL)
+                               ind = MAX_DBG_INDENT_LEVEL;
+
+                       printk("%*s", ind * DBG_INDENT_SIZE, "");
+                       va_start(args, fmt);
+                       vsnprintf(dbg_buf, sizeof(dbg_buf), fmt, args);
+                       printk(dbg_buf);
+                       va_end(args);
+                       spin_unlock_irqrestore(&dbg_spinlock, flags);
+               }
+       }
+}
+
+#define DBGPRINT       dbg_print
+
+#define DBGENTER(level)        do { \
+               dbg_print(level, "%s: Enter\n", __FUNCTION__); \
+               dbg_indent++; \
+       } while (0)
+
+#define DBGLEAVE(level)        do { \
+               dbg_indent--; \
+               dbg_print(level, "%s: Leave\n", __FUNCTION__); \
+       } while (0)
+
+static inline void dump_dma_regs(int lch)
+{
+#define _R(x) __REG16(OMAP_DMA_##x(lch))
+
+       dbg_print(4, "\nCSDP  :%#06x CCR      :%#06x CSSA_U  :%#06x "
+                   "\nCDSA_L:%#06x CDSA_U   :%#06x CEN     :%#06x "
+                   "\nCFN   :%#06x CSFI     :%#06x CSEI    :%#06x "
+                   "\nCSAC  :%#06x CICR     :%#06x CSR     :%04x "
+                   "\nCSSA_L:%#06x CDAC     :%#06x CDEI    :%#06x "
+                   "\nCDFI  :%#06x COLOR_L  :%#06x COLOR_U :%#06x "
+                   "\nCCR2  :%#06x CLNK_CTRL:%#06x LCH_CTRL:%#06x\n",
+                   _R(CSDP), _R(CCR), _R(CSSA_U),
+                   _R(CDSA_L), _R(CDSA_U), _R(CEN),
+                   _R(CFN), _R(CSFI), _R(CSEI),
+                   _R(CSAC), _R(CICR), 0, /* _R(CSR), */
+                   _R(CSSA_L), _R(CDAC), _R(CDEI),
+                   _R(CDFI), _R(COLOR_L), _R(COLOR_U),
+                   _R(CCR2), _R(CLNK_CTRL), _R(LCH_CTRL));
+#undef _R
+}
+
+#define DUMP_DMA_REGS(lch) dump_dma_regs(lch)
+
+#else  /* OMAPFB_DBG */
+
+#define DBGPRINT(level, format, ...)
+#define DBGENTER(level)
+#define DBGLEAVE(level)
+#define DUMP_DMA_REGS(lch)
+
+#endif /* OMAPFB_DBG */
+
+#endif /* __OMAPFB_DEBUG_H */
diff --git a/drivers/video/omap/lcd_h2.c b/drivers/video/omap/lcd_h2.c
new file mode 100644 (file)
index 0000000..981cf1e
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * File: drivers/video/omap_new/lcd-h2.c
+ *
+ * LCD panel support for the TI OMAP H2 board 
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+
+#include <asm/arch/mux.h>
+
+#include "omapfb.h"
+
+// #define OMAPFB_DBG 1
+
+#include "debug.h"
+#include "../drivers/ssi/omap-uwire.h"
+
+#define TSC2101_UWIRE_CS       1
+
+static int tsc2101_write_reg(int page, int reg, u16 data)
+{
+       u16     cmd;
+       int     r;
+
+       DBGENTER(1);
+
+       cmd = ((page & 3) << 11) | ((reg & 0x3f) << 5);
+       if (omap_uwire_data_transfer(TSC2101_UWIRE_CS, cmd, 16, 0, NULL, 1))
+               r = -1;
+       else
+               r = omap_uwire_data_transfer(TSC2101_UWIRE_CS, data, 16, 0, NULL, 0);
+
+       DBGLEAVE(1);
+       return r;
+}
+
+static int h2_panel_init(struct lcd_panel *panel)
+{
+       unsigned long uwire_flags;
+       DBGENTER(1);
+
+        /* Configure N15 pin to be uWire CS1 */
+       omap_cfg_reg(N15_1610_UWIRE_CS1);
+       uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+       uwire_flags |= UWIRE_FREQ_DIV_8;
+       omap_uwire_configure_mode(TSC2101_UWIRE_CS, uwire_flags);
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void h2_panel_cleanup(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+}
+
+static int h2_panel_enable(struct lcd_panel *panel)
+{
+       int r;
+
+       DBGENTER(1);
+
+       /* Assert LCD_EN, BKLIGHT_EN pins on LCD panel
+        * page2, GPIO config reg, GPIO(0,1) to out and asserted
+        */
+       r = tsc2101_write_reg(2, 0x23, 0xCC00) ? -1 : 0;
+
+       DBGLEAVE(1);
+       return r;
+}
+
+static void h2_panel_disable(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+
+       /* Deassert LCD_EN and BKLIGHT_EN pins on LCD panel
+        * page2, GPIO config reg, GPIO(0,1) to out and deasserted
+        */
+       if (tsc2101_write_reg(2, 0x23, 0x8800))
+               PRNERR("failed to disable LCD panel\n");
+
+       DBGLEAVE(1);
+}
+
+static unsigned long h2_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static struct lcdc_video_mode mode240x320 = {
+       .x_res = 240,
+       .y_res = 320,
+       .pixel_clock = 12500,
+       .bpp = 16,
+       .hsw = 12,
+       .hfp = 14,
+       .hbp = 72 - 12,
+       .vsw = 1,
+       .vfp = 1,
+       .vbp = 0,
+       .pcd = 12,
+};
+
+struct lcd_panel h2_panel = {
+       .name       = "h2",
+       .config     = LCD_PANEL_TFT,
+       .video_mode = &mode240x320,
+       
+       .init    = h2_panel_init,
+       .cleanup = h2_panel_cleanup,
+       .enable  = h2_panel_enable,
+       .disable = h2_panel_disable,
+       .get_caps= h2_panel_get_caps,
+};
+
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
new file mode 100644 (file)
index 0000000..27deb6a
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * File: drivers/video/omap_new/lcd-h3.c
+ *
+ * LCD panel support for the TI OMAP H3 board 
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
+
+#include "omapfb.h"
+
+// #define OMAPFB_DBG 1
+
+#include "debug.h"
+
+static int h3_panel_init(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void h3_panel_cleanup(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+}
+
+static int h3_panel_enable(struct lcd_panel *panel)
+{
+       int r = 0;
+
+       DBGENTER(1);
+
+       /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */
+       r = tps65010_set_gpio_out_value(GPIO1, HIGH);
+       if (!r)
+               r = tps65010_set_gpio_out_value(GPIO2, HIGH);
+       if (r)
+               PRNERR("Unable to turn on LCD panel\n");
+
+       DBGLEAVE(1);
+       return r;
+}
+
+static void h3_panel_disable(struct lcd_panel *panel)
+{
+       int r = 0;
+
+       DBGENTER(1);
+
+       /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */
+       r = tps65010_set_gpio_out_value(GPIO1, LOW);
+       if (!r)
+               tps65010_set_gpio_out_value(GPIO2, LOW);
+       if (r)
+               PRNERR("Unable to turn off LCD panel\n");
+
+       DBGLEAVE(1);
+}
+
+static unsigned long h3_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static struct lcdc_video_mode mode240x320 = {
+       .x_res = 240,
+       .y_res = 320,
+       .pixel_clock = 12500,
+       .bpp = 16,
+       .hsw = 12,
+       .hfp = 14,
+       .hbp = 72 - 12,
+       .vsw = 1,
+       .vfp = 1,
+       .vbp = 0,
+       .pcd = 4,
+};
+
+struct lcd_panel h3_panel = {
+       .name       = "h3",
+       .config     = LCD_PANEL_TFT,
+       .video_mode = &mode240x320,
+
+       .init    = h3_panel_init,
+       .cleanup = h3_panel_cleanup,
+       .enable  = h3_panel_enable,
+       .disable = h3_panel_disable,
+       .get_caps= h3_panel_get_caps,
+};
+
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c
new file mode 100644 (file)
index 0000000..45f1bdf
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * File: drivers/video/omap_new/lcd-inn1510.c
+ *
+ * LCD panel support for the TI OMAP1510 Innovator board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/fpga.h>
+
+#include "omapfb.h"
+
+// #define OMAPFB_DBG 1
+
+#include "debug.h"
+
+static int innovator1510_panel_init(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void innovator1510_panel_cleanup(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+}
+
+static int innovator1510_panel_enable(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+
+       fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL);
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void innovator1510_panel_disable(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+
+       fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL);
+
+       DBGLEAVE(1);
+}
+
+static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static struct lcdc_video_mode mode240x320 = {
+       .x_res = 240,
+       .y_res = 320,
+       .pixel_clock = 12500,
+       .bpp = 16,
+       .hsw = 40,
+       .hfp = 40,
+       .hbp = 72,
+       .vsw = 1,
+       .vfp = 1,
+       .vbp = 0,
+       .pcd = 12,
+};
+
+struct lcd_panel innovator1510_panel = {
+       .name       = "inn1510",
+       .config     = LCD_PANEL_TFT,
+       .video_mode = &mode240x320,
+
+       .init    = innovator1510_panel_init,
+       .cleanup = innovator1510_panel_cleanup,
+       .enable  = innovator1510_panel_enable,
+       .disable = innovator1510_panel_disable,
+       .get_caps= innovator1510_panel_get_caps,
+};
+
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
new file mode 100644 (file)
index 0000000..2d31695
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * File: drivers/video/omap_new/lcd-inn1610.c
+ *
+ * LCD panel support for the TI OMAP1610 Innovator board 
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+
+#include <asm/arch/gpio.h>
+
+#include "omapfb.h"
+
+// #define OMAPFB_DBG 1
+
+#include "debug.h"
+
+static int innovator1610_panel_init(struct lcd_panel *panel)
+{
+       int r = 0;
+
+       DBGENTER(1);
+
+       if (omap_request_gpio(14)) {
+               PRNERR("can't request GPIO 14\n");
+               r = -1;
+               goto exit;
+       }
+       if (omap_request_gpio(15)) {
+               PRNERR("can't request GPIO 15\n");
+               omap_free_gpio(14);
+               r = -1;
+               goto exit;
+       }
+       /* configure GPIO(14, 15) as outputs */
+       omap_set_gpio_direction(14, 0);
+       omap_set_gpio_direction(15, 0);
+exit:
+       DBGLEAVE(1);
+       return r;
+}
+
+static void innovator1610_panel_cleanup(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+
+       omap_free_gpio(15);
+       omap_free_gpio(14);
+
+       DBGLEAVE(1);
+}
+
+static int innovator1610_panel_enable(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+
+       /* set GPIO14 and GPIO15 high */
+       omap_set_gpio_dataout(14, 1);
+       omap_set_gpio_dataout(15, 1);
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void innovator1610_panel_disable(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+
+       /* set GPIO13, GPIO14 and GPIO15 low */
+       omap_set_gpio_dataout(14, 0);
+       omap_set_gpio_dataout(15, 0);
+
+       DBGLEAVE(1);
+}
+
+static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static struct lcdc_video_mode mode320x240 = {
+       .x_res = 320,
+       .y_res = 240,
+       .pixel_clock = 12500,
+       .bpp = 16,
+       .hsw = 40,
+       .hfp = 40,
+       .hbp = 72,
+       .vsw = 1,
+       .vfp = 1,
+       .vbp = 0,
+       .pcd = 12,
+};
+
+struct lcd_panel innovator1610_panel = {
+       .name       = "inn1610",
+       .config     = LCD_PANEL_TFT,
+       .video_mode = &mode320x240,
+       
+       .init    = innovator1610_panel_init,
+       .cleanup = innovator1610_panel_cleanup,
+       .enable  = innovator1610_panel_enable,
+       .disable = innovator1610_panel_disable,
+       .get_caps= innovator1610_panel_get_caps,
+};
+
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
new file mode 100644 (file)
index 0000000..4a48832
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * File: drivers/video/omap_new/lcd-osk.c
+ *
+ * LCD panel support for the TI OMAP OSK board 
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ * Adapted for OSK by <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
+#include "omapfb.h"
+
+// #define OMAPFB_DBG 1
+
+#include "debug.h"
+
+static int osk_panel_init(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void osk_panel_cleanup(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+}
+
+static int osk_panel_enable(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+
+       /* configure PWL pin */
+       omap_cfg_reg(PWL);
+
+       /* Enable PWL unit */
+       omap_writeb(0x01, OMAP16XX_PWL_CLK_ENABLE);
+
+       /* Set PWL level */
+       omap_writeb(0xFF, OMAP16XX_PWL_ENABLE);
+
+       /* configure GPIO2 as output */
+       omap_set_gpio_direction(2, 0);
+
+       /* set GPIO2 high */
+       omap_set_gpio_dataout(2, 1);
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void osk_panel_disable(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+
+       /* Set PWL level to zero */
+       omap_writeb(0x00, OMAP16XX_PWL_ENABLE);
+
+       /* Disable PWL unit */
+       omap_writeb(0x00, OMAP16XX_PWL_CLK_ENABLE);
+
+       /* set GPIO2 low */
+       omap_set_gpio_dataout(2, 0);
+
+       DBGLEAVE(1);
+}
+
+static unsigned long osk_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static struct lcdc_video_mode mode240x320 = {
+       .x_res = 240,
+       .y_res = 320,
+       .pixel_clock = 12500,
+       .bpp = 16,
+       .hsw = 40,
+       .hfp = 40,
+       .hbp = 72,
+       .vsw = 1,
+       .vfp = 1,
+       .vbp = 0,
+       .pcd = 12,
+};
+
+struct lcd_panel osk_panel = {
+       .name       = "osk",
+       .config     = LCD_PANEL_TFT,
+       .video_mode = &mode240x320,
+
+       .init    = osk_panel_init,
+       .cleanup = osk_panel_cleanup,
+       .enable  = osk_panel_enable,
+       .disable = osk_panel_disable,
+       .get_caps= osk_panel_get_caps,
+};
+
diff --git a/drivers/video/omap/lcd_p2.c b/drivers/video/omap/lcd_p2.c
new file mode 100644 (file)
index 0000000..64be10f
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * File: drivers/video/omap_new/lcd-p2.c
+ *
+ * LCD panel support for the TI OMAP P2 board 
+ *
+ * Authors:
+ *   jekyll <jekyll@mail.jekyll.idv.tw>
+ *   B Jp <lastjp_fr@yahoo.fr>
+ *   Brian Swetland <swetland@android.com>
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+
+#include "omapfb.h"
+
+/*
+ * File: epson-md-tft.h
+ *
+ * This file contains definitions for Epsons MD-TF LCD Module
+ *
+ * Copyright (C) 2004 MPC-Data Limited  (http://www.mpc-data.co.uk)
+ * Author: Dave Peverley <dpeverley at mpc-data.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS  PROVIDED  ``AS  IS''  AND   ANY  EXPRESS  OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please report all bugs and problems to the author.
+ *
+ */
+
+/* LCD uWire commands & params
+ * All values from Epson
+ */
+#define LCD_DISON 0xAF
+#define LCD_DISOFF 0xAE
+#define LCD_DISNOR 0xA6
+#define LCD_DISINV 0xA7
+#define LCD_DISCTL 0xCA
+#define LCD_GCP64 0xCB
+#define LCD_GCP16 0xCC
+#define LCD_GSSET 0xCD
+#define LCD_SLPIN 0x95
+#define LCD_SLPOUT 0x94
+#define LCD_SD_PSET 0x75
+#define LCD_MD_PSET 0x76
+#define LCD_SD_CSET 0x15
+#define LCD_MD_CSET 0x16
+#define LCD_DATCTL 0xBC
+#define LCD_RAMWR 0x5C
+#define LCD_RAMRD 0x5D
+#define LCD_PTLIN 0xA8
+#define LCD_PTLOUT 0xA9
+#define LCD_ASCSET 0xAA
+#define LCD_SCSTART 0xAB
+#define LCD_VOLCTL 0xC6
+#define LCD_NOP 0x25
+#define LCD_OSCISEL 0x7
+#define LCD_3500KSET 0xD1
+#define LCD_3500KEND 0xD2
+#define LCD_14MSET 0xD3
+#define LCD_14MEND 0xD4
+
+#define INIT_3500KSET 0x45
+#define INIT_14MSET 0x4B
+#define INIT_DATCTL 0x08 /* 6.6.6 bits for D-Sample */
+
+#define INIT_OSCISEL 0x05
+
+#define INIT_VOLCTL 0x77 /* Nominel "volume" */
+
+#define INIT_VOLCTL_Ton 0x98 /* Activate power-IC timer */
+#define INIT_GSSET 0x00
+
+const unsigned short INIT_DISCTL[11] =
+{
+       0xDE, 0x01, 0x64, 0x00, 0x1B, 0xF4, 0x00, 0xDC, 0x00, 0x02, 0x00
+};
+
+const unsigned short INIT_GCP64[126] =
+{
+       0x3B,0x00,0x42,0x00,0x4A,0x00,0x51,0x00,
+       0x58,0x00,0x5F,0x00,0x66,0x00,0x6E,0x00,
+       0x75,0x00,0x7C,0x00,0x83,0x00,0x8A,0x00,
+       0x92,0x00,0x99,0x00,0xA0,0x00,0xA7,0x00,
+       0xAE,0x00,0xB6,0x00,0xBD,0x00,0xC4,0x00,
+       0xCB,0x00,0xD2,0x00,0xDA,0x00,0xE1,0x00,
+       0xE8,0x00,0xEF,0x00,0xF6,0x00,0xFE,0x00,
+       0x05,0x01,0x0C,0x01,0x13,0x01,0x1A,0x01,
+       0x22,0x01,0x29,0x01,0x30,0x01,0x37,0x01,
+       0x3E,0x01,0x46,0x01,0x4D,0x01,0x54,0x01,
+       0x5B,0x01,0x62,0x01,0x6A,0x01,0x71,0x01,
+       0x78,0x01,0x7F,0x01,0x86,0x01,0x8E,0x01,
+       0x95,0x01,0x9C,0x01,0xA3,0x01,0xAA,0x01,
+       0xB2,0x01,0xB9,0x01,0xC0,0x01,0xC7,0x01,
+       0xCE,0x01,0xD6,0x01,0xDD,0x01,0xE4,0x01,
+       0xEB,0x01,0xF2,0x01,0xFA,0x01
+};
+
+const unsigned short INIT_GCP16[15] =
+{
+       0x1A,0x31,0x48,0x54,0x5F,0x67,0x70,0x76,0x7C,0x80,0x83,0x84,0x85,0x87,0x96
+};
+
+const unsigned short INIT_MD_PSET[4] = { 0, 0, 219, 0 };
+const unsigned short INIT_MD_CSET[4] = { 2, 0, 177, 0 };
+
+const unsigned short INIT_SD_PSET[4] = { 0x00, 0x01, 0x00, 0x01 };
+const unsigned short INIT_SD_CSET[4] = { 0x00, 0x02, 0x00, 0x02 };
+
+const unsigned short INIT_ASCSET[7] = { 0x00, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0x01 };
+const unsigned short INIT_SCSTART[2] = { 0x00, 0x00 };
+
+/* ----- end of epson_md_tft.h ----- */
+
+
+#include "debug.h"
+#include "../drivers/ssi/omap-uwire.h"
+
+#define LCD_UWIRE_CS 0
+
+static int p2_panel_init(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void p2_panel_cleanup(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+}
+
+static int p2_panel_enable(struct lcd_panel *panel)
+{
+       int i;
+       unsigned long value;
+       DBGENTER(1);
+
+               /* thwack the reset line */
+       omap_set_gpio_direction(19, 0);
+       omap_set_gpio_dataout(19, 0);
+       mdelay(2);
+       omap_set_gpio_dataout(19, 1);
+
+               /* bits 31:28 -> 0  LCD_PXL_15 .. 12 */
+       value = omap_readl(OMAP730_IO_CONF_3) & 0x0FFFFFFF;
+       omap_writel(value, OMAP730_IO_CONF_3);
+
+               /* bits 19:0 -> 0  LCD_VSYNC, AC, PXL_0, PCLK, HSYNC,
+               **                 PXL_9..1, PXL_10, PXL_11
+               */
+       value = omap_readl(OMAP730_IO_CONF_4) & 0xFFF00000;
+       omap_writel(value, OMAP730_IO_CONF_4);
+
+       omap_uwire_configure_mode(0,16);
+
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISOFF, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SLPIN, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISNOR, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GSSET, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GSSET | 0x100), 9, 0,NULL,1);
+
+       /* DISCTL */ 
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISCTL, 9, 0,NULL,1); 
+       for (i = 0; i < (sizeof(INIT_DISCTL)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_DISCTL[i] | 0x100), 9, 0,NULL,1);
+
+       /* GCP64 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GCP64, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_GCP64)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GCP64[i] | 0x100), 9, 0,NULL,1);
+
+       /* GCP16 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GCP16, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_GCP16)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GCP16[i] | 0x100), 9, 0,NULL,1);
+       
+       /* MD_CSET */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_MD_CSET, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_MD_CSET)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_MD_CSET[i] | 0x100), 9, 0,NULL,1);
+
+       /* MD_PSET */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_MD_PSET, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_MD_PSET)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_MD_PSET[i] | 0x100), 9, 0,NULL,1);
+
+       /* SD_CSET */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SD_CSET, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_SD_CSET)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_SD_CSET[i] | 0x100), 9, 0,NULL,1);
+
+       /* SD_PSET */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SD_PSET, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_SD_PSET)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_SD_PSET[i] | 0x100), 9, 0,NULL,1);
+
+       /* DATCTL */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DATCTL, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_DATCTL | 0x100), 9, 0,NULL,1);
+
+       /* OSSISEL = d'5 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_OSCISEL, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_OSCISEL | 0x100), 9, 0,NULL,1);
+
+       /* 14MSET = d'74 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_14MSET, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_14MSET | 0x100), 9, 0,NULL,1);
+
+       /* 14MEND */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_14MEND, 9, 0,NULL,1);
+
+       /* 3500KSET = d'69 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_3500KSET, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_3500KSET | 0x100), 9, 0,NULL,1);
+
+       /* 3500KEND */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_3500KEND, 9, 0,NULL,1);
+       
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SLPOUT, 9, 0,NULL,1);
+       
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_VOLCTL, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_VOLCTL_Ton | 0x100), 9, 0,NULL,1);
+       
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_VOLCTL, 9, 0,NULL,1);
+
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_VOLCTL | 0x100), 9, 0,NULL,1);
+       
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISON, 9, 0,NULL,1);
+
+       /* enable backlight */
+       omap_set_gpio_direction(134, 0);
+       omap_set_gpio_dataout(134, 1);
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void p2_panel_disable(struct lcd_panel *panel)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+}
+
+static unsigned long p2_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static struct lcdc_video_mode mode176x220 = {
+       .x_res = 176,
+       .y_res = 220,
+       .pixel_clock = 12500,
+       .bpp = 16,
+       .hsw = 5,
+       .hfp = 1,
+       .hbp = 1,
+       .vsw = 2,
+       .vfp = 12,
+       .vbp = 1,
+       .pcd = 4,
+       .flags = OMAP_LCDC_INV_PIX_CLOCK,
+};
+
+struct lcd_panel p2_panel = {
+       .name       = "p2",
+       .config     = LCD_PANEL_TFT,
+       .video_mode = &mode176x220,
+       
+       .init    = p2_panel_init,
+       .cleanup = p2_panel_cleanup,
+       .enable  = p2_panel_enable,
+       .disable = p2_panel_disable,
+       .get_caps= p2_panel_get_caps,
+};
+
diff --git a/drivers/video/omap/omap_lcdc.c b/drivers/video/omap/omap_lcdc.c
new file mode 100644 (file)
index 0000000..fdc3af2
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * linux/arch/arm/mach-omap/omap_lcdc.c
+ *
+ * OMAP internal LCD controller
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */                                    
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+
+#include <asm/arch/dma.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/clock.h>
+
+#include "omapfb.h"
+#include "debug.h"
+
+#define OMAP_LCDC_BASE                 0xfffec000
+#define OMAP_LCDC_SIZE                 256
+#define OMAP_LCDC_IRQ                  INT_LCD_CTRL
+
+#define OMAP_LCDC_CONTROL              (OMAP_LCDC_BASE + 0x00)
+#define OMAP_LCDC_TIMING0              (OMAP_LCDC_BASE + 0x04)
+#define OMAP_LCDC_TIMING1              (OMAP_LCDC_BASE + 0x08)
+#define OMAP_LCDC_TIMING2              (OMAP_LCDC_BASE + 0x0c)
+#define OMAP_LCDC_STATUS               (OMAP_LCDC_BASE + 0x10)
+#define OMAP_LCDC_SUBPANEL             (OMAP_LCDC_BASE + 0x14)
+#define OMAP_LCDC_LINE_INT             (OMAP_LCDC_BASE + 0x18)
+#define OMAP_LCDC_DISPLAY_STATUS       (OMAP_LCDC_BASE + 0x1c)
+
+#define OMAP_LCDC_STAT_DONE            (1 << 0)
+#define OMAP_LCDC_STAT_VSYNC           (1 << 1)
+#define OMAP_LCDC_STAT_SYNC_LOST       (1 << 2)
+#define OMAP_LCDC_STAT_ABC             (1 << 3)
+#define OMAP_LCDC_STAT_LINE_INT                (1 << 4)
+#define OMAP_LCDC_STAT_FUF             (1 << 5)
+#define OMAP_LCDC_STAT_LOADED_PALETTE  (1 << 6)
+
+#define OMAP_LCDC_CTRL_LCD_EN          (1 << 0)
+#define OMAP_LCDC_CTRL_LCD_TFT         (1 << 7)
+#define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL        (1 << 10)
+
+#define OMAP_LCDC_IRQ_VSYNC            (1 << 2)
+#define OMAP_LCDC_IRQ_DONE             (1 << 3)
+#define OMAP_LCDC_IRQ_LOADED_PALETTE   (1 << 4)
+#define OMAP_LCDC_IRQ_LINE_NIRQ                (1 << 5)
+#define OMAP_LCDC_IRQ_LINE             (1 << 6)
+#define OMAP_LCDC_IRQ_MASK             (((1 << 5) - 1) << 2)
+
+#define MAX_PALETTE_SIZE               PAGE_SIZE
+
+enum lcdc_load_mode {
+       OMAP_LCDC_LOAD_PALETTE,
+       OMAP_LCDC_LOAD_FRAME,
+       OMAP_LCDC_LOAD_PALETTE_AND_FRAME
+};
+
+static struct omap_lcd_controller {
+       enum fb_update_mode     update_mode;
+       unsigned int            irq_mask;
+       struct completion       last_frame_complete;
+       struct completion       palette_load_complete;
+       struct clk              *lcd_ck;
+} omap_lcdc;
+
+static void inline enable_irqs(int mask)
+{
+       omap_lcdc.irq_mask |= mask;
+}
+
+static void inline disable_irqs(int mask)
+{
+       omap_lcdc.irq_mask &= ~mask;
+}
+
+static void set_load_mode(enum lcdc_load_mode mode)
+{
+       u32 l;
+
+       l = omap_readl(OMAP_LCDC_CONTROL);
+       l &= ~(3 << 20);
+       switch (mode) {
+       case OMAP_LCDC_LOAD_PALETTE:
+               l |= 1 << 20;
+               break;
+       case OMAP_LCDC_LOAD_FRAME:
+               l |= 2 << 20;
+               break;
+       case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
+               break;
+       default:
+               BUG();
+       }
+       omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void enable_controller(void)
+{
+       u32 l;
+
+       l = omap_readl(OMAP_LCDC_CONTROL);
+       l |= OMAP_LCDC_CTRL_LCD_EN;
+       l &= ~OMAP_LCDC_IRQ_MASK;
+       l |= omap_lcdc.irq_mask | OMAP_LCDC_IRQ_DONE;   /* enabled IRQs */
+       omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void disable_controller_async(void)
+{
+       u32 l;
+       u32 mask;
+
+       init_completion(&omap_lcdc.last_frame_complete);
+       l = omap_readl(OMAP_LCDC_CONTROL);
+       mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
+       /* Preserve the DONE mask, since we still want to get the
+        * final DONE irq. It will be disabled in the IRQ handler.
+        */
+       mask &= ~OMAP_LCDC_IRQ_DONE;
+       l &= ~mask;
+       omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void last_frame_timeout(unsigned long data)
+{
+       printk(KERN_ERR "omap_lcdc: timeout waiting for DONE flag\n");
+       complete(&omap_lcdc.last_frame_complete);
+}
+
+static void inline wait_for_frame_done(void)
+{
+       struct timer_list timeout;
+
+       init_timer(&timeout);
+       timeout.function = last_frame_timeout;
+       timeout.expires = jiffies + msecs_to_jiffies(500);
+       add_timer(&timeout);
+       wait_for_completion(&omap_lcdc.last_frame_complete);
+       del_timer_sync(&timeout);
+}
+
+static void disable_controller(void)
+{
+       disable_controller_async();
+       wait_for_frame_done();
+}
+
+static void reset_controller(u32 status)
+{
+        static unsigned long reset_count = 0;
+        static unsigned long last_jiffies = 0;
+
+        disable_controller_async();
+        reset_count++;
+        if (reset_count == 1 ||
+            time_after(jiffies, last_jiffies + HZ)) {
+                printk(KERN_ERR "omap_lcdc: resetting "
+                                 "(status %#010x,reset count %lu)\n",
+                                  status, reset_count);
+                last_jiffies = jiffies;
+        }
+        if (reset_count < 100) {
+                enable_controller();
+        } else {
+                reset_count = 0;
+                printk(KERN_ERR "omap_lcdc: too many reset attempts, "
+                                "giving up.\n");
+        }
+}
+
+/* Configure the LCD DMA according to the current mode specified by parameters
+ * in fbdev and fbdev->var.
+ */
+static void setup_lcd_dma(struct omapfb_device *fbdev)
+{
+       static const int dma_elem_type[] = {
+               0,
+               OMAP_DMA_DATA_TYPE_S8,
+               OMAP_DMA_DATA_TYPE_S16,
+               0,
+               OMAP_DMA_DATA_TYPE_S32,
+       };
+       struct fb_var_screeninfo *var = &fbdev->fb_info->var;
+       unsigned long   src;
+       int             esize, xelem, yelem;
+
+       src = fbdev->lcddma_handle + fbdev->vis_frame_org + fbdev->view_org;
+       switch (var->rotate) {
+       case 0:
+               esize = fbdev->mirror || (src & 3) ? 2 : 4;
+               xelem = var->xres * var->bits_per_pixel / 8 / esize;
+               yelem = var->yres;
+               break;
+       case 90:
+       case 180:
+       case 270:
+               esize = 2;
+               xelem = var->xres * var->bits_per_pixel / 16;
+               yelem = var->yres;
+               break;
+       default:
+               BUG();
+               return;
+       }
+       DBGPRINT(1, "setup_dma: src=%#010x esize=%d xelem=%d yelem=%d\n",
+                src, esize, xelem, yelem);
+       omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
+       omap_set_lcd_dma_single_transfer(0);
+       if (!cpu_is_omap1510()) {
+               /* Set virtual xres elem size */
+               omap_set_lcd_dma_b1_vxres(
+                       fbdev->fb_info->fix.line_length / esize);
+               /* Setup transformations */
+               omap_set_lcd_dma_b1_rotation(var->rotate);
+               omap_set_lcd_dma_b1_mirror(fbdev->mirror);
+               omap_set_lcd_dma_b1_scale(fbdev->xscale, fbdev->yscale);
+       }
+       omap_setup_lcd_dma();
+}
+
+static irqreturn_t lcdc_irq_handler(int irq, void *dev_id,
+                                        struct pt_regs *fp)
+{
+       u32 status;
+
+       status = omap_readl(OMAP_LCDC_STATUS);
+
+       if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
+               reset_controller(status);
+       else {
+               if (status & OMAP_LCDC_STAT_DONE) {
+                       u32 l;
+
+                       /* Disable IRQ_DONE. The status bit will be cleared
+                        * only when the controller is reenabled and we don't
+                        * want to get more interrupts.
+                        */
+                       l = omap_readl(OMAP_LCDC_CONTROL);
+                       l &= ~OMAP_LCDC_IRQ_DONE;
+                       omap_writel(l, OMAP_LCDC_CONTROL);
+                       complete(&omap_lcdc.last_frame_complete);
+               }
+               if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
+                       disable_controller_async();
+                       complete(&omap_lcdc.palette_load_complete);
+               }
+       }
+
+       /* Clear these interrupt status bits.
+        * Sync_lost, FUF bits were cleared by disabling the LCD controller
+        * LOADED_PALETTE can be cleared this way only in palette only
+        * load mode. In other load modes it's cleared by disabling the
+        * controller.
+        */
+       status &= ~(OMAP_LCDC_STAT_VSYNC |
+                   OMAP_LCDC_STAT_LOADED_PALETTE |
+                   OMAP_LCDC_STAT_ABC |
+                   OMAP_LCDC_STAT_LINE_INT);
+       omap_writel(status, OMAP_LCDC_STATUS);
+       return IRQ_HANDLED;
+}
+
+/* Change to a new video mode. We defer this to a later time to avoid any
+ * flicker and not to mess up the current LCD DMA context. For this we disable
+ * the LCD controler, which will generate a DONE irq after the last frame has
+ * been transferred. Then it'll be safe to reconfigure both the LCD controller
+ * as well as the LCD DMA.
+ */
+static void omap_lcdc_change_mode(struct omapfb_device *fbdev)
+{
+       DBGENTER(1);
+
+       omap_stop_lcd_dma();
+       disable_controller();
+       setup_lcd_dma(fbdev);
+       enable_controller();
+
+       DBGLEAVE(1);
+}
+
+/* Configure the LCD DMA for a palette load operation and do the palette
+ * downloading synchronously. We don't use the frame+palette load mode of
+ * the controller, since the palette can always be downloaded seperately.
+ */
+static void load_palette(struct omapfb_device *fbdev)
+{
+       u8              *palette;
+       u32             code;
+       unsigned long   size;
+       unsigned long   palette_org;
+
+       DBGENTER(1);
+
+       switch (fbdev->panel->video_mode->bpp) {
+       case 1:
+               /* 0 is already set */
+               code = 0;
+               size = 256;
+               break;
+       case 2:
+               code = 0x1000;
+               size = 256;
+               break;
+       case 4:
+               code = 0x2000;
+               size = 256;
+               break;
+       case 8:
+               code = 0x3000;
+               size = 256;
+               break;
+       case 12:
+       case 16:
+               code = 0x4000;
+               size = 32;
+               break;
+       default:
+               BUG();
+               return;
+       }
+       palette_org = MAX_PALETTE_SIZE - size;
+       palette = fbdev->lcddma_base + palette_org;
+       memset(palette, 0, size);
+       *(u32 *)palette = code;
+
+       omap_set_lcd_dma_b1(fbdev->lcddma_handle + palette_org,
+                           size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
+       omap_set_lcd_dma_single_transfer(1);
+       omap_setup_lcd_dma();
+
+       init_completion(&omap_lcdc.palette_load_complete);
+       enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
+       set_load_mode(OMAP_LCDC_LOAD_PALETTE);
+       enable_controller();
+       wait_for_completion(&omap_lcdc.palette_load_complete);
+       /* The controller gets disabled in the irq handler */
+       disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
+       omap_stop_lcd_dma();
+
+       DBGLEAVE(1);
+}
+
+static void inline setup_regs(struct omapfb_device *fbdev)
+{
+       u32 l;
+       struct lcdc_video_mode *mode = fbdev->panel->video_mode;
+       int tft = fbdev->panel->config & LCD_PANEL_TFT;
+       int signal_levels = fbdev->panel->signals;
+
+       l = omap_readl(OMAP_LCDC_CONTROL);
+       l &= ~OMAP_LCDC_CTRL_LCD_TFT;
+       l |= tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
+       omap_writel(l, OMAP_LCDC_CONTROL);
+
+       l = omap_readl(OMAP_LCDC_TIMING2);
+       l &= ~(((1 << 6) - 1) << 20);
+       l |= signal_levels << 20;
+       omap_writel(l, OMAP_LCDC_TIMING2);
+
+       l = mode->x_res - 1;
+       l |= (mode->hsw - 1) << 10;
+       l |= (mode->hfp - 1) << 16;
+       l |= (mode->hbp - 1) << 24;
+       omap_writel(l, OMAP_LCDC_TIMING0);
+
+       l = mode->y_res - 1;
+       l |= (mode->vsw - 1) << 10;
+       l |= mode->vfp << 16;
+       l |= mode->vbp << 24;
+       omap_writel(l, OMAP_LCDC_TIMING1);
+
+       l = omap_readl(OMAP_LCDC_TIMING2);
+       l &= ~0xff;
+
+       if (!cpu_is_omap730())
+               l |= mode->pcd;
+
+       if (machine_is_omap_perseus2()) {
+               u32 clock1, clock2;
+               int pcd;
+
+               clock1 = mode->pixel_clock * 1000;
+               clock2 = clk_get_rate(omap_lcdc.lcd_ck);
+
+               if (clock1 != 0) {
+                       pcd = clock2 / clock1;
+                       if (pcd > 255)
+                               pcd = 0;
+               } else {
+                       pcd = 0;
+               }
+               
+               if (pcd == 0)
+                       l |= mode->pcd;
+               else
+                       l |= pcd;
+
+//             printk("%% ck1: %d  ck2: %d  pcd: %d %%\n",clock1, clock2, pcd);        
+       }
+
+       l |= mode->acb << 8;
+       if (mode->flags & OMAP_LCDC_INV_PIX_CLOCK)
+               l |= 1 << 22;
+       omap_writel(l, OMAP_LCDC_TIMING2);
+}
+
+/* Configure the LCD controller, download the color palette and start a looped
+ * DMA transfer of the frame image data. */
+static int omap_lcdc_set_update_mode(struct omapfb_device *fbdev,
+                                    enum fb_update_mode mode)
+{
+       int r = 0;
+
+       DBGENTER(1);
+
+       if (mode != omap_lcdc.update_mode) {
+               switch (mode) {
+               case FB_AUTO_UPDATE:
+                       setup_regs(fbdev);
+                       load_palette(fbdev);
+
+                       /* Setup and start LCD DMA */
+                       setup_lcd_dma(fbdev);
+
+                       set_load_mode(OMAP_LCDC_LOAD_FRAME);
+                       enable_irqs(OMAP_LCDC_IRQ_DONE);
+                       /* This will start the actual DMA transfer */
+                       enable_controller();
+                       omap_lcdc.update_mode = mode;
+                       break;
+               case FB_UPDATE_DISABLED:
+                       disable_controller();
+                       omap_stop_lcd_dma();
+                       omap_lcdc.update_mode = mode;
+                       break;
+               default:
+                       r = -EINVAL;
+               }
+       }       
+
+       DBGLEAVE(1);
+       return r;
+}
+
+static enum fb_update_mode omap_lcdc_get_update_mode(struct omapfb_device *fbdev)
+{
+       return omap_lcdc.update_mode;
+}
+
+static void omap_lcdc_suspend(struct omapfb_device *fbdev)
+{
+       if (omap_lcdc.update_mode == FB_AUTO_UPDATE) {
+               disable_controller();
+               omap_stop_lcd_dma();
+       }
+}
+
+static void omap_lcdc_resume(struct omapfb_device *fbdev)
+{
+       if (omap_lcdc.update_mode == FB_AUTO_UPDATE) {
+               setup_regs(fbdev);
+               load_palette(fbdev);
+               setup_lcd_dma(fbdev);
+               set_load_mode(OMAP_LCDC_LOAD_FRAME);
+               enable_irqs(OMAP_LCDC_IRQ_DONE);
+               enable_controller();
+       }
+}
+
+static int omap_lcdc_init(struct omapfb_device *fbdev)
+{
+       int r;
+       u32 l;
+       int rate;
+       struct clk *tc_ck;
+
+       DBGENTER(1);
+
+       omap_lcdc.irq_mask = 0;
+
+       l = 0;
+       omap_writel(l, OMAP_LCDC_CONTROL);
+
+       /* FIXME:
+        * According to errata some platforms have a clock rate limitiation
+        */
+       omap_lcdc.lcd_ck = clk_get(NULL, "lcd_ck");
+       if (IS_ERR(omap_lcdc.lcd_ck)) {
+               printk(KERN_ERR "omap_lcdc: unable to access LCD clock\n");
+               r = PTR_ERR(omap_lcdc.lcd_ck);
+               goto fail0;
+       }
+
+       tc_ck = clk_get(NULL, "tc_ck");
+       if (IS_ERR(tc_ck)) {
+               printk(KERN_ERR "omap_lcdc: unable to access TC clock\n");
+               r = PTR_ERR(tc_ck);
+               goto fail1;
+       }
+
+       rate = clk_get_rate(tc_ck);
+       clk_put(tc_ck);
+
+       if (machine_is_omap_h3())
+               rate /= 3;
+       r = clk_set_rate(omap_lcdc.lcd_ck, rate);
+       if (r) {
+               printk(KERN_ERR "omap_lcdc: failed to adjust LCD rate\n");
+               goto fail1;
+       }
+       clk_use(omap_lcdc.lcd_ck);
+
+       r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, "omap-lcdc", fbdev);
+       if (r) {
+               printk(KERN_ERR "omap_lcdc: unable to get IRQ\n");
+               goto fail2;
+       }
+
+       r = omap_request_lcd_dma(NULL, NULL);
+       if (r) {
+               printk(KERN_ERR "omap_lcdc: unable to get LCD DMA\n");
+               goto fail3;
+       }
+
+       printk(KERN_INFO "OMAP LCD controller initialized.\n");
+       DBGLEAVE(1);
+       return 0;
+fail3:
+       free_irq(OMAP_LCDC_IRQ, fbdev);
+fail2:
+       clk_unuse(omap_lcdc.lcd_ck);
+fail1:
+       clk_put(omap_lcdc.lcd_ck);
+fail0:
+       DBGLEAVE(1);
+        return r;
+}
+
+static void omap_lcdc_cleanup(struct omapfb_device *fbdev)
+{
+       omap_free_lcd_dma();
+       free_irq(OMAP_LCDC_IRQ, fbdev);
+       clk_unuse(omap_lcdc.lcd_ck);
+       clk_put(omap_lcdc.lcd_ck);
+}
+
+static void omap_lcdc_get_mem_layout(struct omapfb_device *fbdev,
+                                    unsigned long *size, unsigned long *fb_org)
+{
+       struct lcdc_video_mode *mode = fbdev->panel->video_mode;
+
+       *size = MAX_PALETTE_SIZE;
+       *fb_org = *size;
+       *size += mode->x_res * mode->bpp / 8 * mode->y_res;
+}
+
+static unsigned long omap_lcdc_get_caps(struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+struct lcd_ctrl omapfb_lcdc_ctrl = {
+       .name                   = "internal",
+       .init                   = omap_lcdc_init,
+       .cleanup                = omap_lcdc_cleanup,
+       .get_mem_layout         = omap_lcdc_get_mem_layout,
+       .get_caps               = omap_lcdc_get_caps,
+       .set_update_mode        = omap_lcdc_set_update_mode,
+       .get_update_mode        = omap_lcdc_get_update_mode,
+       .update_window          = NULL,
+       .suspend                = omap_lcdc_suspend, 
+       .resume                 = omap_lcdc_resume,
+       .change_mode            = omap_lcdc_change_mode,
+};
+
+MODULE_DESCRIPTION("TI OMAP LCDC controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap/omapfb.h b/drivers/video/omap/omapfb.h
new file mode 100644 (file)
index 0000000..33f2086
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * File: drivers/video/omap_new/omapfb.c
+ *
+ * Framebuffer driver for TI OMAP boards
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __OMAPFB_H
+#define __OMAPFB_H
+
+/* IOCTL commands. */
+
+#define OMAP_IOW(num, dtype)   _IOW('O', num, dtype)
+#define OMAP_IOR(num, dtype)   _IOR('O', num, dtype)
+#define OMAP_IOWR(num, dtype)  _IOWR('O', num, dtype)
+#define OMAP_IO(num)           _IO('O', num)
+
+#define OMAPFB_FILLRECT                OMAP_IOW(0, struct fb_fillrect)
+#define OMAPFB_COPYAREA                OMAP_IOW(1, struct fb_copyarea)
+#define OMAPFB_IMAGEBLIT       OMAP_IOW(2, struct fb_image)
+
+#define OMAPFB_TRANSPARENT_BLIT        OMAP_IOW(30, struct fb_image)
+#define OMAPFB_MIRROR          OMAP_IOW(31, int)
+#define OMAPFB_SCALE           OMAP_IOW(32, struct fb_scale)
+#define OMAPFB_SELECT_VIS_FRAME        OMAP_IOW(33, int)
+#define OMAPFB_SELECT_SRC_FRAME OMAP_IOW(34, int)
+#define OMAPFB_SELECT_DST_FRAME        OMAP_IOW(35, int)
+#define OMAPFB_GET_FRAME_OFFSET        OMAP_IOWR(36, struct fb_frame_offset)
+#define OMAPFB_SYNC_GFX                OMAP_IO(37)
+#define OMAPFB_VSYNC           OMAP_IO(38)
+#define OMAPFB_LATE_ACTIVATE   OMAP_IO(39)
+#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, enum fb_update_mode)
+#define OMAPFB_UPDATE_WINDOW   OMAP_IOW(41, struct fb_update_window)
+#define OMAPFB_GET_CAPS                OMAP_IOR(42, unsigned long)
+#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, enum fb_update_mode)
+#define OMAPFB_GET_GFX_STATUS  OMAP_IOR(44, unsigned long)
+
+#define FBCAPS_GENERIC_MASK    0x00000fff
+#define FBCAPS_LCDC_MASK       0x00fff000
+#define FBCAPS_PANEL_MASK      0xff000000
+
+#define FBCAPS_MANUAL_UPDATE   0x00001000
+#define FBCAPS_SET_BACKLIGHT   0x01000000
+
+enum omapfb_gfx_status {
+       OMAPFB_GFX_STATUS_OK    = 0,
+       OMAPFB_GFX_STATUS_CHANGED
+};
+
+#define OMAPFB_UPDATE_FAILED   0x01
+#define OMAPFB_FILLRECT_FAILED 0x02
+#define OMAPFB_COPYAREA_FAILED 0x04
+#define OMAPFB_IMGBLIT_FAILED  0x08
+
+struct fb_copyarea_ext {
+       __u32 dx;
+       __u32 dy;
+       __u32 width;
+       __u32 height;
+       __u32 sx;
+       __u32 sy;
+       __u32 trans_color;
+       __u32 rev_dir;
+};
+
+struct fb_scale {
+       unsigned int xscale, yscale;
+};
+
+struct fb_frame_offset {
+       unsigned int idx;
+       unsigned long offset;
+};
+
+struct fb_update_window {
+       unsigned int x, y;
+       unsigned int width, height;
+};
+
+enum fb_update_mode {
+       FB_UPDATE_DISABLED = 0,
+       FB_AUTO_UPDATE,
+       FB_MANUAL_UPDATE
+};
+
+#ifdef __KERNEL__
+
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+
+#define OMAPFB_DEVICE "omapfb"
+#define OMAPFB_DRIVER "omapfb"
+
+#define PRNERR(fmt, args...)  printk(KERN_ERR OMAPFB_DRIVER ": " fmt, ## args)
+
+#define GFX_FIFO_SIZE 2
+
+#define LCD_PANEL_TFT 0x01
+
+#define OMAP_LCDC_INV_VSYNC             0x01
+#define OMAP_LCDC_INV_HSYNC             0x02
+#define OMAP_LCDC_INV_PIX_CLOCK         0x04
+#define OMAP_LCDC_INV_OUTPUT_EN         0x08
+#define OMAP_LCDC_HSVS_RISING_EDGE      0x10
+#define OMAP_LCDC_HSVS_OPPOSITE         0x20
+
+struct lcdc_video_mode {
+       u16     x_res, y_res;
+       u32     pixel_clock;    /* In kHz */
+       int     bpp;
+       u8      hsw;            /* Horizontal synchronization pulse width */
+       u8      hfp;            /* Horizontal front porch */
+       u8      hbp;            /* Horizontal back porch */
+       u8      vsw;            /* Vertical synchronization pulse width */
+       u8      vfp;            /* Vertical front porch */
+       u8      vbp;            /* Vertical back porch */
+       u8      acb;            /* ac-bias pin frequency */
+       u8      pcd;            /* Pixel clock divider (this will change) */
+       u8  flags;
+};
+
+struct lcd_panel {
+       const char *name;
+       int  config;
+       int  signals;
+       struct lcdc_video_mode *video_mode;
+
+       int  (*init)    (struct lcd_panel *panel);
+       void (*cleanup) (struct lcd_panel *panel);
+       int  (*enable)  (struct lcd_panel *panel);
+       void (*disable) (struct lcd_panel *panel);
+       unsigned long (*get_caps)(struct lcd_panel *panel);
+       int           (*set_bklight_level)(struct lcd_panel *panel,
+                                          unsigned int level);
+       unsigned int  (*get_bklight_level)(struct lcd_panel *panel);
+       unsigned int  (*get_bklight_max)  (struct lcd_panel *panel);
+};
+
+struct omapfb_device;
+
+struct lcd_ctrl {
+       const char      *name;
+       void            *data;
+       int             (*init)           (struct omapfb_device *fbdev);
+       void            (*cleanup)        (struct omapfb_device *fbdev);
+       void            (*get_mem_layout) (struct omapfb_device *fbdev,
+                                          unsigned long *size,
+                                          unsigned long *fb_org);
+       unsigned long   (*get_caps)       (struct omapfb_device *fbdev);
+       int             (*set_update_mode)(struct omapfb_device *fbdev,
+                                          enum fb_update_mode mode);
+       enum fb_update_mode (*get_update_mode)(struct omapfb_device *fbdev);
+       int             (*update_window)  (struct omapfb_device *fbdev,
+                                          struct fb_update_window *win);
+       void            (*suspend)        (struct omapfb_device *fbdev);
+       void            (*resume)         (struct omapfb_device *fbdev);
+       void            (*change_mode)    (struct omapfb_device *fbdev);
+};
+
+enum omapfb_state {
+       OMAPFB_DISABLED = 0,
+       OMAPFB_SUSPENDED= 99,
+       OMAPFB_ACTIVE   = 100
+};
+
+struct gfx_lchannel {
+       int                     lch_num;
+       struct gfx_lchannel     *next, *prev;
+};
+
+struct gfx_dma {
+       spinlock_t              spinlock;
+
+       struct completion       sync_complete;          /* Signalled when the
+                                                          fifo gets empty */
+       volatile int            done;                   /* Indicates the
+                                                          end of a DMA chain
+                                                          transfer */
+       struct gfx_lchannel     fifo[GFX_FIFO_SIZE];
+       struct gfx_lchannel     *f_head, *f_tail;       /* Process and insert
+                                                          points on the
+                                                          fifo */
+       struct gfx_lchannel     *f_chain_end;           /* Points to the new
+                                                          chain end */
+       struct semaphore        f_free;                 /* # of free lch-s */
+       int                     f_run;                  /* # of active lch-s */
+       int                     f_wait;                 /* # of lch-s
+                                                          waiting */
+       struct tasklet_struct   dequeue_tasklet;        /* Processes new DMA
+                                                          chain  transfers on
+                                                          the fifo */
+};
+
+#define OMAPFB_RQUEUE_SIZE 20
+
+struct omapfb_fillrect_params
+{
+       struct fb_info          *fbi;
+       struct fb_fillrect      rect; 
+};
+
+struct omapfb_copyarea_params
+{
+       struct fb_info          *fbi;
+       struct fb_copyarea_ext  area;
+};
+
+struct omapfb_update_window_params
+{
+       struct fb_info          *fbi;
+       struct fb_update_window win;
+};
+
+struct omapfb_imageblit_params
+{
+       struct fb_info  *fbi;
+       struct fb_image image;
+       int             flags;
+};
+
+union req_params
+{
+       /* All possible requests are to be listed here */
+       struct omapfb_fillrect_params           fillrect;
+       struct omapfb_copyarea_params           copyarea;
+       struct omapfb_update_window_params      update_window;
+       struct omapfb_imageblit_params          imageblit;
+};
+
+struct omapfb_request
+{
+       struct list_head        entry;
+       int                     (*function)(void *par);
+       union req_params        par;
+};
+
+struct omapfb_rqueue
+{
+       spinlock_t              lock;
+       struct list_head        free_list;
+       struct list_head        pending_list;
+       struct completion       rqueue_empty;
+       struct semaphore        free_sema;
+       struct omapfb_request   req_pool[OMAPFB_RQUEUE_SIZE];
+       struct work_struct      work;
+       unsigned long           status;
+};
+
+struct omapfb_device {
+       int                     state;
+       int                     ext_lcdc;               /* Using external
+                                                           LCD controller */
+       void                    *lcddma_base;           /* MPU virtual
+                                                          address */
+       dma_addr_t              lcddma_handle;          /* Bus physical
+                                                          address */
+       unsigned long           lcddma_mem_size;
+       unsigned long           palette_org;            /* Palette offset into
+                                                          lcddma_base/handle */
+       unsigned long           frame0_org, frame1_org; /* Frame offsets for
+                                                          back and front
+                                                          frame buffers into
+                                                          lcddma_base/handle */
+       unsigned long           vis_frame_org;          /* Offset of visible
+                                                          frame buffer.
+                                                          = frame0/1_org */
+       unsigned long           src_frame_org;          /* Offset of source
+                                                          frame for drawing
+                                                          operations.
+                                                          = frame0/1_org */
+       unsigned long           dst_frame_org;          /* Offset of dest
+                                                          frame for drawing
+                                                          operations.
+                                                          = frame0/1_org */
+       unsigned long           view_org;               /* View offset into
+                                                          lcddma_base/handle+
+                                                          vis_frame_org.
+                                                          Used for panning */
+       unsigned long           palette_size;
+       int                     xscale, yscale, mirror; /* transformations.
+                                                          rotate is stored in
+                                                          fb_info->var */
+
+       u32                     pseudo_palette[17];
+
+       struct gfx_dma          gfx;                    /* Accelerator */
+       struct omapfb_rqueue    rqueue;
+       struct lcd_panel        *panel;                 /* LCD panel */
+       struct lcd_ctrl         *ctrl;                  /* LCD controller */
+
+       struct fb_info          *fb_info;               /* Linux fbdev
+                                                          framework data */
+       struct device           *dev;
+};
+
+extern struct lcd_panel h3_panel;
+extern struct lcd_panel h2_panel;
+extern struct lcd_panel p2_panel;
+extern struct lcd_panel osk_panel;
+extern struct lcd_panel innovator1610_panel;
+extern struct lcd_panel innovator1510_panel;
+
+extern struct lcd_ctrl omapfb_lcdc_ctrl;
+
+#endif /* __KERNEL__ */
+
+#endif /* __OMAPFB_H */
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
new file mode 100644 (file)
index 0000000..aeb66c8
--- /dev/null
@@ -0,0 +1,2269 @@
+/*
+ * File: drivers/video/omap/omapfb_main.c
+ *
+ * Framebuffer driver for TI OMAP boards
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * Acknowledgements:
+ *   Alex McMains <aam@ridgerun.com>       - Original driver
+ *   Juha Yrjola <juha.yrjola@nokia.com>   - Original driver and improvements
+ *   Dirk Behme <dirk.behme@de.bosch.com>  - changes for 2.6 kernel API
+ *   Texas Instruments                     - H3 support
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/board.h>
+
+#include "omapfb.h"
+
+// #define OMAPFB_DBG_FIFO 1
+// #define OMAPFB_DBG 1
+
+#include "debug.h"
+
+#define COPY_MODE_REV_DIR      0x01
+#define COPY_MODE_TRANSPARENT  0x02
+#define COPY_MODE_IMAGE                0x04
+
+#ifdef OMAPFB_DBG_FIFO
+struct gfx_stat {
+       unsigned long f_run[GFX_FIFO_SIZE];
+} stat;
+#endif
+
+static unsigned int    def_accel;
+static unsigned long   def_vram;
+static long            def_vxres;
+static long            def_vyres;
+static unsigned int    def_rotate;
+static unsigned int    def_mirror;
+
+#ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
+static int             manual_update = 1;
+#else
+static int             manual_update;
+#endif
+
+static struct caps_table_struct {
+        unsigned long flag;
+        const char *name;
+} omapfb_caps_table[] = {
+       { FBCAPS_MANUAL_UPDATE, "manual update" },
+       { FBCAPS_SET_BACKLIGHT, "backlight setting" },
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * LCD panel
+ * ---------------------------------------------------------------------------
+ */
+static struct lcd_panel *panels[] = {
+#ifdef CONFIG_MACH_OMAP_H2
+       &h2_panel,
+#endif
+#ifdef CONFIG_MACH_OMAP_H3
+       &h3_panel,
+#endif
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+       &p2_panel,
+#endif
+#ifdef CONFIG_MACH_OMAP_OSK
+       &osk_panel,
+#endif
+#ifdef CONFIG_MACH_OMAP_INNOVATOR
+#ifdef CONFIG_ARCH_OMAP1510
+       &innovator1510_panel,
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+       &innovator1610_panel,
+#endif
+#endif
+};
+
+static struct lcd_ctrl *ctrls[] = {
+#ifdef CONFIG_FB_OMAP_INTERNAL_LCDC
+       &omapfb_lcdc_ctrl,
+#endif
+};
+
+static struct omapfb_request *omapfb_rqueue_alloc_req(struct omapfb_rqueue *rq)
+{
+       struct omapfb_request *req;
+
+       down(&rq->free_sema);
+       spin_lock(&rq->lock);
+       req = list_entry(rq->free_list.next, struct omapfb_request, entry);
+       list_del(&req->entry);
+       spin_unlock(&rq->lock);
+       return req;
+}
+
+static void __omapfb_rqueue_free_req(struct omapfb_rqueue *rq,
+                                    struct omapfb_request *req)
+{
+       list_add(&req->entry, &rq->free_list);
+       up(&rq->free_sema);
+}
+
+static void omapfb_rqueue_process(void *data)
+{
+       struct omapfb_rqueue *rq = data;
+
+       spin_lock(&rq->lock);
+       while (!list_empty(&rq->pending_list)) {
+               struct omapfb_request *req;
+
+               req = list_entry(rq->pending_list.next,
+                                  struct omapfb_request, entry);
+               list_del(&req->entry);
+               spin_unlock(&rq->lock);
+               rq->status |= req->function(&req->par);
+               spin_lock(&rq->lock);
+               __omapfb_rqueue_free_req(rq, req);
+       }
+       complete(&rq->rqueue_empty);
+       spin_unlock(&rq->lock);
+}
+
+static void omapfb_rqueue_schedule_req(struct omapfb_rqueue *rq,
+                                      struct omapfb_request *req)
+{
+       spin_lock(&rq->lock);
+       list_add_tail(&req->entry, &rq->pending_list);
+       spin_unlock(&rq->lock);
+       schedule_work(&rq->work);
+}
+
+static void omapfb_rqueue_sync(struct omapfb_rqueue *rq)
+{
+       int wait = 0;
+
+       spin_lock(&rq->lock);
+       if (!list_empty(&rq->pending_list)) {
+               wait = 1;
+               init_completion(&rq->rqueue_empty);
+       }
+       spin_unlock(&rq->lock);
+       if (wait)
+               wait_for_completion(&rq->rqueue_empty);
+}
+
+static void omapfb_rqueue_reset(struct omapfb_rqueue *rq, unsigned long *status)
+{
+       omapfb_rqueue_sync(rq);
+       spin_lock(&rq->lock);
+       *status = rq->status;
+       rq->status = 0;
+       spin_unlock(&rq->lock);
+}
+
+static void omapfb_rqueue_init(struct omapfb_rqueue *rq)
+{
+       int i;
+
+       spin_lock_init(&rq->lock);
+       sema_init(&rq->free_sema, OMAPFB_RQUEUE_SIZE);
+       init_completion(&rq->rqueue_empty);
+       INIT_WORK(&rq->work, omapfb_rqueue_process, rq);
+       INIT_LIST_HEAD(&rq->free_list);
+       INIT_LIST_HEAD(&rq->pending_list);
+       for (i = 0; i < OMAPFB_RQUEUE_SIZE; i++)
+               list_add(&rq->req_pool[i].entry, &rq->free_list);
+}
+
+static void omapfb_rqueue_cleanup(struct omapfb_rqueue *rq)
+{
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * gfx DMA
+ * ---------------------------------------------------------------------------
+ */
+/* Get a new logical channel from the gfx fifo. */
+static void inline gfxdma_get_lch(struct gfx_dma *gfx, int *lch)
+{
+       DBGENTER(3);
+
+       down(&gfx->f_free);
+
+       spin_lock_bh(&gfx->spinlock);
+
+       *lch = gfx->f_tail->lch_num;
+       gfx->f_tail = gfx->f_tail->next;
+
+       spin_unlock_bh(&gfx->spinlock);
+
+       DBGLEAVE(3);
+}
+
+/* Set basic transfer params for the logical channel */
+static inline void gfxdma_set_lch_params(int lch, int data_type,
+                                        int enumber, int fnumber,
+                                        unsigned long src_start, int src_amode,
+                                        unsigned long dst_start, int dst_amode)
+{
+       omap_set_dma_transfer_params(lch, data_type, enumber, fnumber, 0);
+       omap_set_dma_src_params(lch, OMAP_DMA_PORT_EMIFF,
+                               src_amode, src_start);
+       omap_set_dma_dest_params(lch, OMAP_DMA_PORT_EMIFF,
+                                dst_amode, dst_start);
+}
+
+/* Set element and frame indexes for the logical channel, to support
+ * image transformations
+ */
+static inline void gfxdma_set_lch_index(int lch, int src_eidx, int src_fidx,
+                                       int dst_eidx, int dst_fidx)
+{
+       omap_set_dma_src_index(lch, src_eidx, src_fidx);
+       omap_set_dma_dest_index(lch, dst_eidx, dst_fidx);
+}
+
+/* Set color parameter for the logical channel, to support constant fill and
+ * transparent copy operations
+ */
+static inline void gfxdma_set_lch_color(int lch, u32 color,
+                                       enum omap_dma_color_mode mode)
+{
+       omap_set_dma_color_mode(lch, mode, color);
+}
+
+
+/* Start a new transfer consisting of a single DMA logical channel,
+ * or a chain (f_run > 1). Can be called in interrupt context.
+ * gfx->spinlock must be held.
+ */
+static void inline gfxdma_start_chain(struct gfx_dma *gfx)
+{
+       DBGENTER(3);
+
+       gfx->f_run = gfx->f_wait;
+#ifdef OMAPFB_DBG_FIFO
+       stat.f_run[gfx->f_run - 1]++;
+#endif
+       gfx->f_wait = 0;
+       omap_enable_dma_irq(gfx->f_chain_end->lch_num, OMAP_DMA_BLOCK_IRQ);
+       /* Let it go */
+       DBGPRINT(1, "start %d\n", gfx->f_head->lch_num);
+       omap_start_dma(gfx->f_head->lch_num);
+       gfx->f_chain_end = gfx->f_chain_end->next;
+
+       DBGLEAVE(3);
+}
+
+/* Enqueue a logical channel, that has been set up. If no other transfers
+ * are pending start this new one right away. */
+static void inline gfxdma_enqueue(struct gfx_dma *gfx, int lch)
+{
+       DBGENTER(3);
+
+       spin_lock_bh(&gfx->spinlock);
+       DBGPRINT(3, "run:%d wait:%d\n", gfx->f_run, gfx->f_wait);
+       if (gfx->f_wait) {
+               DBGPRINT(1, "link %d, %d\n", gfx->f_chain_end->lch_num, lch);
+               omap_dma_link_lch(gfx->f_chain_end->lch_num, lch);
+               gfx->f_chain_end = gfx->f_chain_end->next;
+       }
+       omap_disable_dma_irq(lch, OMAP_DMA_BLOCK_IRQ);
+
+       gfx->f_wait++;
+
+       if (!gfx->f_run)
+               gfxdma_start_chain(gfx);
+       spin_unlock_bh(&gfx->spinlock);
+
+       DBGLEAVE(3);
+}
+
+/* Called by DMA core when the last transfer ended, or there is an error
+ * condition. We dispatch handling of the end of transfer case to a tasklet.
+ * Called in interrupt context.
+ */
+static void gfxdma_handler(int lch, u16 ch_status, void *data)
+{
+       struct gfx_dma *gfx = (struct gfx_dma *)data;
+       int done = 0;
+
+       DBGENTER(3);
+
+       DBGPRINT(4, "lch=%d status=%#010x\n", lch, ch_status);
+       if (unlikely(ch_status & (OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ))) {
+               PRNERR("gfx DMA error. status=%#010x\n", ch_status);
+               done = 1;
+       } else if (likely(ch_status & OMAP_DMA_BLOCK_IRQ))
+               done = 1;
+       if (likely(done)) {
+               gfx->done = 1;
+               tasklet_schedule(&gfx->dequeue_tasklet);
+       }
+
+       DBGLEAVE(3);
+}
+
+/* Let the DMA core know that the last transfer has ended. If there are
+ * pending transfers in the fifo start them now.
+ * Called in interrupt context.
+ */
+static void gfxdma_dequeue_tasklet(unsigned long data)
+{
+       struct gfx_dma *gfx = (struct gfx_dma *)data;
+       struct gfx_lchannel *f_chain;
+
+       DBGENTER(3);
+
+       /* start an already programmed transfer
+        */
+       while (likely(gfx->done)) {
+               gfx->done = 0;
+               spin_lock(&gfx->spinlock);
+               f_chain = gfx->f_head;
+               omap_stop_dma(f_chain->lch_num);
+               /* Would be better w/o a loop.. */
+               while (gfx->f_run--) {
+                       if (gfx->f_run)
+                               omap_dma_unlink_lch(f_chain->lch_num,
+                                                   f_chain->next->lch_num);
+                       f_chain = f_chain->next;
+                       up(&gfx->f_free);
+               }
+               gfx->f_run = 0;
+               gfx->f_head = f_chain;
+               if (likely(gfx->f_wait))
+                       gfxdma_start_chain(gfx);
+               else
+                       complete(&gfx->sync_complete);
+               spin_unlock(&gfx->spinlock);
+       }
+
+       DBGLEAVE(3);
+}
+
+/* Wait till any pending transfers end. */
+static void gfxdma_sync(struct gfx_dma *gfx)
+{
+       int wait = 0;
+
+       DBGENTER(1);
+
+       for (;;) {
+               spin_lock_bh(&gfx->spinlock);
+               if (gfx->f_run + gfx->f_wait) {
+                       wait = 1;
+                       init_completion(&gfx->sync_complete);
+               }
+               spin_unlock_bh(&gfx->spinlock);
+               if (wait) {
+                       wait_for_completion(&gfx->sync_complete);
+                       wait = 0;
+               } else
+                       break;
+       }
+
+       DBGLEAVE(1);
+}
+
+/* Initialize the gfx DMA object.
+ * Allocate DMA logical channels according to the fifo size.
+ * Set the channel parameters that will be the same for all transfers.
+ */
+static int gfxdma_init(struct gfx_dma *gfx)
+{
+       int                     r = 0;
+       int                     i;
+
+       DBGENTER(1);
+
+       for (i = 0; i < GFX_FIFO_SIZE; i++) {
+               int next_idx;
+               int lch_num;
+
+               r = omap_request_dma(0, OMAPFB_DRIVER,
+                                    gfxdma_handler, gfx, &lch_num);
+               if (r) {
+                       int j;
+
+                       PRNERR("unable to get GFX DMA %d\n", i);
+                       for (j = 0; j < i; j++)
+                               omap_free_dma(lch_num);
+                       r = -1;
+                       goto exit;
+               }
+               omap_set_dma_src_data_pack(lch_num, 1);
+               omap_set_dma_src_burst_mode(lch_num, OMAP_DMA_DATA_BURST_4);
+               omap_set_dma_dest_data_pack(lch_num, 1);
+               omap_set_dma_dest_burst_mode(lch_num, OMAP_DMA_DATA_BURST_4);
+
+               gfx->fifo[i].lch_num = lch_num;
+
+               next_idx = i < GFX_FIFO_SIZE - 1 ? i + 1 : 0;
+               gfx->fifo[next_idx].prev = &gfx->fifo[i];
+               gfx->fifo[i].next = &gfx->fifo[next_idx];
+       }
+       gfx->f_head = gfx->f_tail = gfx->f_chain_end = &gfx->fifo[0];
+       sema_init(&gfx->f_free, GFX_FIFO_SIZE);
+
+       spin_lock_init(&gfx->spinlock);
+
+       tasklet_init(&gfx->dequeue_tasklet, gfxdma_dequeue_tasklet,
+                    (unsigned long)gfx);
+
+       init_completion(&gfx->sync_complete);
+exit:
+       DBGLEAVE(1);
+       return r;
+}
+
+/* Clean up the gfx DMA object */
+static void gfxdma_cleanup(struct gfx_dma *gfx)
+{
+       int i;
+
+       DBGENTER(1);
+
+       for (i = 0; i < GFX_FIFO_SIZE; i++)
+               omap_free_dma(gfx->fifo[i].lch_num);
+
+       DBGLEAVE(1);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * LCD controller and LCD DMA
+ * ---------------------------------------------------------------------------
+ */
+/* Lookup table to map elem size to elem type. */
+static const int dma_elem_type[] = {
+       0,
+       OMAP_DMA_DATA_TYPE_S8,
+       OMAP_DMA_DATA_TYPE_S16,
+       0,
+       OMAP_DMA_DATA_TYPE_S32,
+};
+
+/* Allocate resources needed for LCD controller and LCD DMA operations. Video
+ * memory is allocated from system memory according to the virtual display
+ * size, except if a bigger memory size is specified explicitly as a kernel
+ * parameter.
+ */
+static int ctrl_init(struct omapfb_device *fbdev)
+{
+       unsigned long mem_size;
+       int r;
+
+       DBGENTER(1);
+
+       r = fbdev->ctrl->init(fbdev);
+       if (r < 0)
+               goto exit;
+       fbdev->ctrl->get_mem_layout(fbdev, &mem_size, &fbdev->frame0_org);
+
+       if (def_vram) {
+               if (mem_size > def_vram) {
+                       PRNERR("specified frame buffer memory too small\n");
+                       r = -ENOMEM;
+                       goto cleanup_ctrl;
+               }
+               mem_size = def_vram;
+       }
+       fbdev->lcddma_mem_size = PAGE_SIZE << get_order(mem_size);
+       fbdev->lcddma_base = dma_alloc_writecombine(fbdev->dev,
+                                                   fbdev->lcddma_mem_size,
+                                                   &fbdev->lcddma_handle,
+                                                   GFP_KERNEL);
+       if (fbdev->lcddma_base == NULL) {
+               PRNERR("unable to allocate fb DMA memory\n");
+               r = -ENOMEM;
+               goto cleanup_ctrl;
+       }
+
+       memset(fbdev->lcddma_base, 0, fbdev->lcddma_mem_size);
+
+       DBGPRINT(1, "lcddma_base=%#10x lcddma_handle=%#10x lcddma_mem_size=%d"
+                "palette_size=%d frame0_org=%d palette_org=%d\n",
+                fbdev->lcddma_base, fbdev->lcddma_handle,
+                fbdev->lcddma_mem_size,
+                fbdev->palette_size,
+                fbdev->frame0_org, fbdev->palette_org);
+
+       DBGLEAVE(1);
+       return 0;
+cleanup_ctrl:
+        fbdev->ctrl->cleanup(fbdev);
+exit:
+       DBGLEAVE(1);
+       return r;
+}
+
+static void ctrl_cleanup(struct omapfb_device *fbdev)
+{
+       fbdev->ctrl->cleanup(fbdev);
+       dma_free_writecombine(fbdev->dev, fbdev->lcddma_mem_size,
+                             fbdev->lcddma_base, fbdev->lcddma_handle);
+}
+
+static void ctrl_change_mode(struct omapfb_device *fbdev)
+{
+       fbdev->ctrl->change_mode(fbdev);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * fbdev framework callbacks and the ioctl interface
+ * ---------------------------------------------------------------------------
+ */
+/* Called each time the omapfb device is opened */
+static int omapfb_open(struct fb_info *info, int user)
+{
+       DBGENTER(1);
+
+#ifdef OMAPFB_DBG_FIFO
+       memset(&stat, 0, sizeof(stat));
+#endif
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+/* Called when the omapfb device is closed. We make sure that any pending
+ * gfx DMA operations are ended, before we return. */
+static int omapfb_release(struct fb_info *info, int user)
+{
+       struct omapfb_device *dev = (struct omapfb_device *)info->par;
+       int sync = 0;
+
+       DBGENTER(1);
+
+       spin_lock_bh(&dev->gfx.spinlock);
+       if (dev->gfx.f_run)
+               sync = 1;
+       spin_unlock_bh(&dev->gfx.spinlock);
+       if (sync) {
+               gfxdma_sync(&dev->gfx);
+       }
+#ifdef OMAPFB_DBG_FIFO
+       {
+               int i;
+               for (i = 0; i < GFX_FIFO_SIZE; i++)
+                       printk(KERN_INFO "f_run[%d]=%lu\n", i + 1,
+                                       stat.f_run[i]);
+       }
+#endif
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+/* Store a single color palette entry into a pseudo palette or the hardware
+ * palette if one is available. For now we support only 16bpp and thus store
+ * the entry only to the pseudo palette.
+ */
+static int omapfb_setcolreg(u_int regno, u_int red, u_int green,
+                           u_int blue, u_int transp,
+                           struct fb_info *info)
+{
+       u16 pal;
+       int r = 0;
+
+       DBGENTER(2);
+
+       if (regno >= 16) {
+               r = -1;
+               goto exit;
+       }
+       pal = ((red >> 11) << 11) | ((green >> 10) << 5) | (blue >> 11);
+       ((u32 *)(info->pseudo_palette))[regno] = pal;
+
+exit:
+       DBGLEAVE(2);
+       return r;
+}
+
+static int omapfb_suspend(struct device *dev, pm_message_t mesg, u32 level);
+static int omapfb_resume(struct device *dev, u32 level);
+
+static int omapfb_blank(int blank, struct fb_info *info)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)info->par;
+       int r = 0;
+
+       DBGENTER(1);
+       switch (blank) {
+       case VESA_NO_BLANKING:
+               omapfb_resume(fbdev->dev, 0);
+               break;
+       case VESA_POWERDOWN:
+               omapfb_suspend(fbdev->dev, 0, 0);
+               break;
+       default:
+               r = -EINVAL;
+       }
+
+       DBGLEAVE(1);
+       return r;
+}
+
+/* Setup a constant fill DMA transfer. Destination must be elem size aligned. */
+static inline void fill_block(struct omapfb_device *fbdev,
+                             unsigned long dst, unsigned long enumber,
+                             unsigned long height, int esize, u32 color)
+{
+       unsigned long   fidx;
+       int             lch;
+
+       DBGPRINT(2, "dst:%#010x enumber:%d height:%d esize:%d color:%#010x\n",
+                dst, enumber, height, esize, color);
+       fidx = fbdev->fb_info->fix.line_length - enumber * esize + 1;
+       gfxdma_get_lch(&fbdev->gfx, &lch);
+       gfxdma_set_lch_params(lch, dma_elem_type[esize], enumber, height,
+                             0, OMAP_DMA_AMODE_CONSTANT,
+                             dst, OMAP_DMA_AMODE_DOUBLE_IDX);
+       gfxdma_set_lch_index(lch, 0, 0, 1, fidx);
+       gfxdma_set_lch_color(lch, color, OMAP_DMA_CONSTANT_FILL);
+       gfxdma_enqueue(&fbdev->gfx, lch);
+
+       DUMP_DMA_REGS(lch);
+}
+
+/* Fill the specified rectangle with a solid color.
+ * ROP_XOR and bpp<8 can't be handled by the DMA hardware.
+ * When frame flipping is in effect use the destination frame.
+ * We'll make our best to use the largest possible elem size, doing the fill
+ * in more parts if alignment requires us to do so.
+ */
+static int omapfb_fillrect(void *data)
+{
+       struct omapfb_fillrect_params *par = data;
+       struct omapfb_device *fbdev = (struct omapfb_device *)par->fbi->par;
+
+       int             dx = par->rect.dx, dy = par->rect.dy;
+       int             vxres = par->fbi->var.xres_virtual;
+       int             vyres = par->fbi->var.yres_virtual;
+       int             width = par->rect.width, height = par->rect.height;
+       unsigned long   dst;
+       u32             color;
+       int             bpp;
+       int             enumber, esize;
+       int             r = 0;
+
+       DBGENTER(2);
+       bpp = par->fbi->var.bits_per_pixel;
+       /* bpp < 8 is tbd.
+        * We can't do ROP_XOR with DMA
+        * If IRQs are disabled we can't use DMA
+        */
+       if (bpp < 8 || par->rect.rop == ROP_XOR || irqs_disabled()) {
+               r = OMAPFB_FILLRECT_FAILED;
+               goto exit;
+       }
+       /* Clipping */
+       if (!width || !height || dx > vxres || dy > vyres)
+               goto exit;
+       if (dx + width > vxres)
+               width = vxres - dx;
+       if (dy + height > vyres)
+               height = vyres - dy;
+
+       if (bpp == 12)
+               bpp = 16;
+       width = width * bpp / 8;
+
+       dst = fbdev->lcddma_handle + fbdev->dst_frame_org;
+       dst += dx * bpp / 8 + dy * par->fbi->fix.line_length;
+
+       color = par->rect.color;
+       switch (bpp) {
+       case 8:
+               color |= color << 8;
+               /* Fall through */
+       case 16:
+               color |= color << 16;
+       }
+
+       if ((dst & 3) || width < 4) {
+               if (!(dst & 1) && width > 1) {
+                       esize = 2;
+                       enumber = 1;
+                       width -= 2;
+               } else {
+                       esize = 1;
+                       enumber = 4 - (esize & 3);
+                       if (enumber > width)
+                               enumber = width;
+                       width -= enumber;
+               }
+               fill_block(fbdev, dst, enumber, height, esize, color);
+               dst = (dst + 3) & ~3;
+       }
+       if (width) {
+               enumber = width / 4;
+               fill_block(fbdev, dst, enumber, height, 4, color);
+               dst += enumber * 4;
+               width -= enumber * 4;
+       }
+       if (width) {
+               if (width == 2) {
+                       esize = 2;
+                       enumber = 1;
+               } else {
+                       esize = 1;
+                       enumber = width;
+               }
+               fill_block(fbdev, dst, enumber, height, esize, color);
+       }
+
+exit:
+       DBGLEAVE(2);
+       return r;
+}
+
+static int omapfb_schedule_fillrect(struct fb_info *fbi,
+                                    const struct fb_fillrect *rect)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       struct omapfb_request *req;
+
+       if ((req = omapfb_rqueue_alloc_req(&fbdev->rqueue)) == NULL)
+               return -ENOMEM;
+       req->function = omapfb_fillrect;
+       req->par.fillrect.fbi = fbi;
+       req->par.fillrect.rect = *rect;
+       omapfb_rqueue_schedule_req(&fbdev->rqueue, req);
+       return fbdev->rqueue.status ? OMAPFB_GFX_STATUS_CHANGED : 0;
+}
+
+/* Setup a gfx DMA transfer to a rectangular area.
+ * A color parameter can be specified for transparent copy.
+ * Transfer direction can be setup to use either incremental or decremental
+ * addresses.
+ * Source and destination must be elem size aligned.
+ */
+static inline void transfer_block(struct omapfb_device *fbdev,
+                                 unsigned long src, unsigned long dst,
+                                 unsigned long img_width,
+                                 unsigned long enumber, unsigned long height,
+                                 int esize, u32 trans_color, int flags)
+{
+       s16     eidx;
+       s16     s_fidx, d_fidx;
+       int     lch;
+
+       eidx = 1;
+       s_fidx = img_width - enumber * esize + 1;
+       d_fidx = fbdev->fb_info->fix.line_length - enumber * esize + 1;
+       if (flags & COPY_MODE_REV_DIR) {
+               eidx = -2 * esize + 1;
+               s_fidx = -s_fidx + eidx + 1;
+               d_fidx = -d_fidx + eidx + 1;
+       }
+
+       DBGPRINT(2, "src:%#010x dst:%#010x enumber:%d height:%d "
+                "esize:%d eidx:%d s_fidx:%d d_fidx bg_color:%#010x flags:%d\n",
+                src, dst, enumber, height, esize, eidx, s_fidx, d_fidx,
+                bg_color, flags);
+
+       gfxdma_get_lch(&fbdev->gfx, &lch);
+       gfxdma_set_lch_params(lch, dma_elem_type[esize], enumber, height,
+                             src, OMAP_DMA_AMODE_DOUBLE_IDX,
+                             dst, OMAP_DMA_AMODE_DOUBLE_IDX);
+       gfxdma_set_lch_index(lch, eidx, s_fidx, eidx, d_fidx);
+       if (flags & COPY_MODE_TRANSPARENT)
+               gfxdma_set_lch_color(lch, trans_color,
+                                    OMAP_DMA_TRANSPARENT_COPY);
+       else
+               gfxdma_set_lch_color(lch, 0, OMAP_DMA_COLOR_DIS);
+       gfxdma_enqueue(&fbdev->gfx, lch);
+
+       DUMP_DMA_REGS(lch);
+}
+
+/* Copy a rectangular area or an image to another rectangular area.
+ * A color parameter can be specified for transparent copy.
+ * Transfer direction can be setup to use either incremental or decremental
+ * addresses.
+ * Currently both source and destination area must be entirely contained in
+ * frame buffer memory.
+ * The largest possible transfer elem size will be determined according to
+ * source and destination address alignment, dividing the transfer into more
+ * parts if necessary.
+ */
+static inline void copy_data(struct omapfb_device *fbdev,
+                            unsigned long src, unsigned long dst,
+                            unsigned long width, unsigned long height,
+                            u32 trans_color, int flags)
+{
+       struct fb_info   *fbi = fbdev->fb_info;
+       int              esize, stripe_esize;
+       int              step, rest, enumber;
+       unsigned long    img_width;
+       static const int esize_arr[] = {4, 1, 2, 1};
+       int              rev;
+
+       /* Check alignment constraints */
+       esize = esize_arr[(src ^ dst) & 3];
+
+       rev = flags & COPY_MODE_REV_DIR;
+       if (rev) {
+               rest = src & (esize - 1);
+               if (rest > width)
+                       rest = width;
+               src -= rest ? rest : esize;
+               dst -= rest ? rest : esize;
+       } else {
+               rest = esize - (src & (esize - 1));
+               if (rest > width)
+                       rest = width;
+       }
+       if (width < esize)
+               rest = width;
+
+       img_width = flags & COPY_MODE_IMAGE ? width : fbi->fix.line_length;
+
+       DBGPRINT(2, "\nrev=%d src=%#010lx dst=%#010lx \n"
+                "esize=%d width=%d rest=%d\n",
+                rev, src, dst, esize, width, rest);
+       if (rest) {
+               /* Transfer this unaligned stripe, so that afterwards
+                * we have both src and dst 16bit or 32bit aligned.
+                */
+               if (rest == 2) {
+                       /* Area body is 32bit aligned */
+                       stripe_esize = 2;
+                       enumber = 1;
+                       step = rev ? -esize : 2;
+                       width -= 2;
+               } else {
+                       stripe_esize = 1;
+                       enumber = rest;
+                       step = rev ? -esize : rest;
+               }
+               transfer_block(fbdev, src, dst, img_width, enumber, height,
+                              stripe_esize, trans_color, flags);
+               src += step;
+               dst += step;
+       }
+       if (width) {
+               /* Transfer area body */
+               enumber = (width & ~(esize - 1)) / esize;
+               transfer_block(fbdev, src, dst, img_width, enumber, height,
+                              esize, trans_color, flags);
+               step = enumber * esize;
+               width -= step;
+               if (rev)
+                       step = -step + esize - width;
+               src += step;
+               dst += step;
+       }
+       if (width) {
+               /* Transfer the remaining unaligned stripe */
+               if (width == 2) {
+                       stripe_esize = 2;
+                       enumber = 1;
+               } else {
+                       stripe_esize = 1;
+                       enumber = width;
+               }
+               transfer_block(fbdev, src, dst, img_width, enumber, height,
+                              stripe_esize, trans_color, flags);
+       }
+
+       DBGLEAVE(2);
+}
+
+/* Copy a rectangular area in the frame buffer to another rectangular area.
+ * Calculate the source and destination addresses.
+ * Transfer direction will be determined taking care of possible area
+ * overlapping.
+ * Currently both source and destination area must be entirely contained in
+ * frame buffer memory, in case of frame flipping source and destination frame
+ * respectively.
+ */
+static int omapfb_copyarea(void *data)
+{
+       struct omapfb_copyarea_params *par = data;
+       struct omapfb_device *fbdev = (struct omapfb_device *)par->fbi->par;
+
+       int             width = par->area.width, height = par->area.height;
+       int             sx = par->area.sx, sy = par->area.sy;
+       int             dx = par->area.dx, dy = par->area.dy;
+       unsigned long   dst, dst_ofs, src, src_ofs;
+       unsigned long   end_ofs;
+       int             bpp = par->fbi->var.bits_per_pixel;
+       int             flags;
+       int             r = 0;
+
+       DBGENTER(2);
+
+       if (!width || !height)
+               goto exit;
+
+       /* Bpp < 8 is tbd. If IRQs are disabled we can't use DMA */
+       if (bpp < 8 || irqs_disabled()) {
+               r = OMAPFB_COPYAREA_FAILED;
+               goto exit;
+       }
+
+       src = fbdev->lcddma_handle;
+       dst = src;
+       src_ofs = fbdev->src_frame_org + sx * bpp / 8 +
+                 sy * par->fbi->fix.line_length;
+       dst_ofs = fbdev->dst_frame_org + dx * bpp / 8 +
+                 dy * par->fbi->fix.line_length;
+       end_ofs = (height - 1) * par->fbi->fix.line_length + width * bpp / 8;
+       src += src_ofs;
+       dst += dst_ofs;
+
+       DBGPRINT(2, "src:%#010lx dst:%#010lx end_ofs:%#010lx\n",
+                   src, dst, end_ofs);
+
+       /* Currently we support only transfers where both source and destination
+        * area is contained entirely in fbmem. This is because of DMA memory
+        * constraints.
+        */
+       if (src_ofs + end_ofs > fbdev->lcddma_mem_size ||
+           dst_ofs + end_ofs > fbdev->lcddma_mem_size) {
+               r = OMAPFB_COPYAREA_FAILED;
+               goto exit;
+       }
+
+       flags = 0;
+       if (par->area.rev_dir) {
+               flags = COPY_MODE_REV_DIR;
+               src += end_ofs;
+               dst += end_ofs;
+       }
+       if (par->area.trans_color != -1)
+               flags |= COPY_MODE_TRANSPARENT;
+
+       width = width * bpp / 8;
+       copy_data(fbdev, src, dst, width, height, par->area.trans_color, flags);
+exit:
+       DBGLEAVE(2);
+       return r;
+}
+
+static int omapfb_schedule_copyarea(struct fb_info *fbi,
+                                    const struct fb_copyarea_ext *area)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       struct omapfb_request *req;
+
+       if ((req = omapfb_rqueue_alloc_req(&fbdev->rqueue)) == NULL)
+               return -ENOMEM;
+       req->function = omapfb_copyarea;
+       req->par.copyarea.fbi = fbi;
+       req->par.copyarea.area = *area;
+       omapfb_rqueue_schedule_req(&fbdev->rqueue, req);
+       return fbdev->rqueue.status ? OMAPFB_GFX_STATUS_CHANGED : 0;
+}
+
+/* Copy an image to a rectangular area in the frame buffer.
+ * A color parameter can be specified for transparent copy.
+ * Calculate the source and destination addresses.
+ * Transfer direction will be determined taking care of possible area
+ * overlapping.
+ * Currently both source and destination area must be entirely contained in
+ * frame buffer memory, in case of frame flipping source and destination frame
+ * respectively.
+ */
+static int do_imageblit(void *data)
+{
+       struct omapfb_imageblit_params *par = data;
+       struct omapfb_device *fbdev = (struct omapfb_device *)par->fbi->par;
+
+       int             width = par->image.width, height = par->image.height;
+       int             dx = par->image.dx, dy = par->image.dy;
+       const char      *img_data = par->image.data;
+       unsigned long   dst, dst_ofs;
+       unsigned long   dst_end_ofs;
+       int             bpp = par->fbi->var.bits_per_pixel;
+       u32             bg_color;
+       int             r = 0;
+
+       DBGENTER(2);
+
+       if (!width || !height)
+               goto exit;
+
+       /* bpp conversion is not supported, let the default function handle it.
+        * Note that image->depth is either 1 for monochrome image, or equals
+        * bpp of the current video mode, so we can't rely on it.
+        * If IRQs are disabled we can't use DMA.
+        */
+       if (bpp < 8 || par->image.depth != bpp || irqs_disabled()) {
+               r = OMAPFB_IMGBLIT_FAILED;
+               goto exit;
+       }
+
+       dst = fbdev->lcddma_handle;
+       dst_ofs = fbdev->dst_frame_org +
+                 dx * bpp / 8 + dy * par->fbi->fix.line_length;
+       dst_end_ofs = (height - 1) * par->fbi->fix.line_length +
+                 width * bpp / 8;
+       dst += dst_ofs;
+
+       DBGPRINT(2, "data:%#010lx dst:%#010lx dst_end_ofs:%#010lx\n",
+                   img_data, dst, dst_end_ofs);
+
+        /* Check that both source and destination is DMA -able */
+       if (dst_ofs + dst_end_ofs > fbdev->lcddma_mem_size) {
+               r = OMAPFB_IMGBLIT_FAILED;
+               goto exit;
+       }
+
+       if (((unsigned long)img_data < (unsigned long)fbdev->lcddma_base) ||
+           ((unsigned long)img_data + width * bpp / 8 * height >
+            (unsigned long)fbdev->lcddma_base + fbdev->lcddma_mem_size)) {
+               r = OMAPFB_IMGBLIT_FAILED;
+               goto exit;
+       }
+
+       bg_color = par->image.bg_color;
+       if (par->flags & COPY_MODE_TRANSPARENT) {
+               switch (bpp) {
+               case 8:
+                       bg_color |= bg_color << 8;
+                       /* Fall through */
+               case 16:
+                       bg_color |= bg_color << 16;
+               }
+       }
+
+       width = width * bpp / 8;
+       copy_data(fbdev, (unsigned long)img_data, dst, width, height,
+                 bg_color, par->flags | COPY_MODE_IMAGE);
+exit:
+       DBGLEAVE(2);
+       return r;
+}
+
+static int omapfb_schedule_imageblit(struct fb_info *fbi,
+                                     const struct fb_image *image, int flags)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       struct omapfb_request *req;
+
+       if ((req = omapfb_rqueue_alloc_req(&fbdev->rqueue)) == NULL)
+               return -ENOMEM;
+       req->function = do_imageblit;
+       req->par.imageblit.fbi = fbi;
+       req->par.imageblit.image = *image;
+       req->par.imageblit.flags = flags;
+       omapfb_rqueue_schedule_req(&fbdev->rqueue, req);
+       return fbdev->rqueue.status ? OMAPFB_GFX_STATUS_CHANGED : 0;
+}
+
+/* Set fb_info.fix fields and also updates fbdev.
+ * When calling this fb_info.var must be set up already.
+ */
+static void set_fb_fix(struct omapfb_device *fbdev)
+{
+       struct fb_info           *fbi = fbdev->fb_info;
+       struct fb_fix_screeninfo *fix = &fbi->fix;
+       struct fb_var_screeninfo *var = &fbi->var;
+       int frame_size;
+
+       strncpy(fix->id, OMAPFB_DRIVER, sizeof(fix->id));
+       fix->type               = FB_TYPE_PACKED_PIXELS;
+       switch (var->bits_per_pixel) {
+       case 16:
+               fix->visual = FB_VISUAL_TRUECOLOR;
+               break;
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               fix->visual = FB_VISUAL_PSEUDOCOLOR;
+               break;
+       }
+       fix->accel              = FB_ACCEL_OMAP1610;
+       fix->line_length        = var->xres_virtual * var->bits_per_pixel / 8;
+       fix->smem_len           = fbdev->lcddma_mem_size - fbdev->frame0_org;
+       fix->smem_start         = fbdev->lcddma_handle + fbdev->frame0_org;
+
+       /* Set the second frame buffer offset for flipping if there is
+        * room for it. */
+       frame_size = fix->line_length * var->yres;
+       fbdev->frame1_org = fbdev->frame0_org + frame_size;
+       if (fbdev->frame1_org + frame_size > fbdev->lcddma_mem_size)
+               fbdev->frame1_org = 0;
+       fbdev->vis_frame_org = fbdev->src_frame_org = fbdev->dst_frame_org =
+               fbdev->frame0_org;
+
+       fbdev->view_org = var->yoffset * fix->line_length +
+                         var->xoffset * var->bits_per_pixel / 8;
+}
+
+/* Check the values in var against our capabilities and in case of out of
+ * bound values try to adjust them.
+ */
+static int set_fb_var(struct omapfb_device *fbdev,
+                     struct fb_var_screeninfo *var)
+{
+       int             bpp;
+       unsigned long   max_frame_size;
+       unsigned long   line_size;
+
+       bpp = var->bits_per_pixel = fbdev->panel->video_mode->bpp;
+       if (bpp != 16)
+               /* Not yet supported */
+               return -1;
+       switch (var->rotate) {
+       case 0:
+       case 180:
+               var->xres = fbdev->panel->video_mode->x_res;
+               var->yres = fbdev->panel->video_mode->y_res;
+               break;
+       case 90:
+       case 270:
+               var->xres = fbdev->panel->video_mode->y_res;
+               var->yres = fbdev->panel->video_mode->x_res;
+               break;
+       default:
+               return -1;
+       }
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
+       if (var->yres_virtual < var->yres)
+               var->yres_virtual = var->yres;
+       max_frame_size = fbdev->lcddma_mem_size - fbdev->frame0_org;
+       line_size = var->xres_virtual * bpp / 8;
+       if (line_size * var->yres_virtual > max_frame_size) {
+               /* Try to keep yres_virtual first */
+               line_size = max_frame_size / var->yres_virtual;
+               var->xres_virtual = line_size * 8 / bpp;
+               if (var->xres_virtual < var->xres) {
+                       /* Still doesn't fit. Shrink yres_virtual too */
+                       var->xres_virtual = var->xres;
+                       line_size = var->xres * bpp / 8;
+                       var->yres_virtual = max_frame_size / line_size;
+               }
+       }
+       if (var->xres + var->xoffset > var->xres_virtual)
+               var->xoffset = var->xres_virtual - var->xres;
+       if (var->yres + var->yoffset > var->yres_virtual)
+               var->yoffset = var->yres_virtual - var->yres;
+       line_size = var->xres * bpp / 8;
+
+       var->red.offset  = 11; var->red.length   = 5; var->red.msb_right   = 0;
+       var->green.offset= 5;  var->green.length = 6; var->green.msb_right = 0;
+       var->blue.offset = 0;  var->blue.length  = 5; var->blue.msb_right  = 0;
+
+       var->height             = -1;
+       var->width              = -1;
+       var->grayscale          = 0;
+       var->nonstd             = 0;
+
+       /* TODO: video timing params, sync */
+       var->pixclock           = -1;
+       var->left_margin        = -1;
+       var->right_margin       = -1;
+       var->upper_margin       = -1;
+       var->lower_margin       = -1;
+       var->hsync_len          = -1;
+       var->vsync_len          = -1;
+
+       var->vmode              = FB_VMODE_NONINTERLACED;
+       var->sync               = 0;
+
+       return 0;
+}
+
+static struct fb_var_screeninfo new_var;
+
+/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
+static void omapfb_rotate(struct fb_info *fbi, int rotate)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+
+       DBGENTER(1);
+
+       if (cpu_is_omap1510() && rotate != fbdev->fb_info->var.rotate) {
+               memcpy(&new_var, &fbi->var, sizeof(new_var));
+               new_var.rotate = rotate;
+               if (set_fb_var(fbdev, &new_var) == 0 &&
+                   memcmp(&new_var, &fbi->var, sizeof(new_var))) {
+                       memcpy(&fbi->var, &new_var, sizeof(new_var));
+                       set_fb_fix(fbdev);
+                       ctrl_change_mode(fbdev);
+               }
+       }
+
+       DBGLEAVE(1);
+}
+
+/* Set new x,y offsets in the virtual display for the visible area and switch
+ * to the new mode.
+ */
+static int omapfb_pan_display(struct fb_var_screeninfo *var,
+                              struct fb_info *fbi)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       int r = 0;
+
+       DBGENTER(1);
+
+       if (var->xoffset != fbi->var.xoffset ||
+           var->yoffset != fbi->var.yoffset) {
+               memcpy(&new_var, &fbi->var, sizeof(new_var));
+               new_var.xoffset = var->xoffset;
+               new_var.yoffset = var->yoffset;
+               if (set_fb_var(fbdev, &new_var))
+                       r = -EINVAL;
+               else {
+                       memcpy(&fbi->var, &new_var, sizeof(new_var));
+                       set_fb_fix(fbdev);
+                       ctrl_change_mode(fbdev);
+               }
+       }
+
+       DBGLEAVE(1);
+       return r;
+}
+
+/* Set mirror to vertical axis and switch to the new mode. */
+static int omapfb_mirror(struct fb_info *fbi, int mirror)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       int r = 0;
+
+       DBGENTER(1);
+
+       mirror = mirror ? 1 : 0;
+       if (cpu_is_omap1510())
+               r = -EINVAL;
+       else if (mirror != fbdev->mirror) {
+               fbdev->mirror = mirror;
+               ctrl_change_mode(fbdev);
+       }
+
+       DBGLEAVE(1);
+       return r;
+}
+
+/* Set x,y scale and switch to the new mode */
+static int omapfb_scale(struct fb_info *fbi,
+                     unsigned int xscale, unsigned int yscale)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       int r = 0;
+
+       DBGENTER(1);
+
+       if (cpu_is_omap1510())
+               r = -EINVAL;
+       else if (xscale != fbdev->xscale || yscale != fbdev->yscale) {
+               if (fbi->var.xres * xscale > fbi->var.xres_virtual ||
+                   fbi->var.yres * yscale > fbi->var.yres_virtual)
+                       r = -EINVAL;
+               else {
+                       fbdev->xscale = xscale;
+                       fbdev->yscale = yscale;
+                       ctrl_change_mode(fbdev);
+               }
+       }
+
+       DBGLEAVE(1);
+       return r;
+}
+
+/* Check values in var, try to adjust them in case of out of bound values if
+ * possible, or return error.
+ */
+static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       int r;
+
+       DBGENTER(1);
+
+       r = set_fb_var(fbdev, var);
+
+       DBGLEAVE(1);
+       return r;
+}
+
+/* Switch to a new mode. The parameters for it has been check already by
+ * omapfb_check_var.
+ */
+static int omapfb_set_par(struct fb_info *fbi)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+
+       DBGENTER(1);
+
+       set_fb_fix(fbdev);
+       ctrl_change_mode(fbdev);
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+/* Frame flipping support. Assign the primary or the secondary frame to the
+ * visible frame, as well as the source and destination frames for graphics
+ * operations like rectangle fill and area copy. Flipping is only possible
+ * if we have enough video memory for the secondary frame.
+ */
+static int omapfb_select_vis_frame(struct fb_info *fbi, unsigned int vis_idx)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+
+       if (vis_idx > 1 || (vis_idx == 1 && !fbdev->frame1_org))
+               return -EINVAL;
+       fbdev->vis_frame_org = vis_idx ? fbdev->frame1_org : fbdev->frame0_org;
+       ctrl_change_mode(fbdev);
+       return 0;
+}
+
+static int omapfb_select_src_frame(struct fb_info *fbi, unsigned int src_idx)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+
+       if (src_idx > 1 || (src_idx == 1 && !fbdev->frame1_org))
+               return -EINVAL;
+       fbdev->src_frame_org = src_idx ? fbdev->frame1_org : fbdev->frame0_org;
+       return 0;
+}
+
+static int omapfb_select_dst_frame(struct fb_info *fbi, unsigned int dst_idx)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+
+       if (dst_idx > 1 || (dst_idx == 1 && !fbdev->frame1_org))
+               return -EINVAL;
+       fbdev->dst_frame_org = dst_idx ? fbdev->frame1_org : fbdev->frame0_org;
+       DBGPRINT(1, "dst_frame_org=%#010x\n", fbdev->dst_frame_org);
+       return 0;
+}
+
+/* Get the address of the primary and secondary frames */
+static int omapfb_get_frame_offset(struct fb_info *fbi,
+                                  struct fb_frame_offset *fb_offset)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+
+       if (fb_offset->idx > 1)
+               return -EINVAL;
+       if (fb_offset->idx == 1 && !fbdev->frame1_org)
+               return -EINVAL;
+       fb_offset->offset = fb_offset->idx ? fbdev->frame1_org :
+               fbdev->frame0_org;
+       return 0;
+}
+
+static int omapfb_update_window(void *data)
+{
+       struct omapfb_update_window_params *par = data;
+       struct omapfb_device *fbdev = (struct omapfb_device *)par->fbi->par;
+
+       gfxdma_sync(&fbdev->gfx);
+       if (fbdev->ctrl->update_window(fbdev, &par->win))
+               return OMAPFB_UPDATE_FAILED;
+       else
+               return 0;
+}
+
+static int omapfb_schedule_update_window(struct fb_info *fbi,
+                                        struct fb_update_window *win)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       struct omapfb_request *req;
+
+       if (!fbdev->ctrl->update_window ||
+           win->x >= fbi->var.xres || win->y >= fbi->var.yres)
+               return -EINVAL;
+       if (win->x + win->width >= fbi->var.xres)
+               win->width = fbi->var.xres - win->x;
+       if (win->y + win->height >= fbi->var.yres)
+               win->height = fbi->var.yres - win->y;
+       if (!win->width || !win->height)
+               return 0;
+       if ((req = omapfb_rqueue_alloc_req(&fbdev->rqueue)) == NULL)
+               return -ENOMEM;
+       req->function = omapfb_update_window;
+       req->par.update_window.fbi = fbi;
+       req->par.update_window.win = *win;
+       omapfb_rqueue_schedule_req(&fbdev->rqueue, req);
+       return fbdev->rqueue.status ? OMAPFB_GFX_STATUS_CHANGED : 0;
+}
+
+static int omapfb_schedule_full_update(struct fb_info *fbi)
+{
+       struct fb_update_window win;
+
+       win.x = 0;
+       win.y = 0;
+       win.width = fbi->var.xres;
+       win.height = fbi->var.yres;
+       return omapfb_schedule_update_window(fbi, &win);
+}
+
+static unsigned long omapfb_get_caps(struct fb_info *fbi)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       unsigned long caps;
+
+       caps = 0;
+       caps |= fbdev->panel->get_caps(fbdev->panel);
+       caps |= fbdev->ctrl->get_caps(fbdev);
+       return caps;
+}
+
+static int omapfb_set_update_mode(struct omapfb_device *fbdev,
+                                 enum fb_update_mode new_mode);
+
+static enum fb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev);
+
+/* Ioctl interface. Part of the kernel mode frame buffer API is duplicated
+ * here to be accessible by user mode code. In addition transparent copy
+ * graphics transformations, frame flipping support is provided through this
+ * interface.
+ */
+static int omapfb_ioctl(struct inode *inode, struct file *file,
+                       unsigned int cmd, unsigned long arg,
+                       struct fb_info *fbi)
+{
+       struct omapfb_device    *fbdev = (struct omapfb_device *)fbi->par;
+       struct fb_ops           *ops = fbi->fbops;
+       union {
+               struct fb_fillrect      rect;
+               struct fb_copyarea_ext  area;
+               struct fb_image         image;
+               struct fb_scale         scale;
+               struct fb_frame_offset  frame_offset;
+               struct fb_update_window update_window;
+               unsigned int            frame_idx;
+               unsigned int            mirror;
+               enum fb_update_mode     update_mode;
+               unsigned long           caps;
+               unsigned long           rqueue_status;
+       } p;
+       int                     r = 0;
+
+       DBGENTER(2);
+
+       BUG_ON(!ops);
+       DBGPRINT(2, "cmd=%010x\n", cmd);
+       switch (cmd)
+       {
+       case OMAPFB_FILLRECT:
+               if (copy_from_user(&p.rect, (void __user *)arg, sizeof(p.rect)))
+                       r = -EFAULT;
+               else
+                       r = omapfb_schedule_fillrect(fbi, &p.rect);
+               break;
+       case OMAPFB_COPYAREA:
+               if (copy_from_user(&p.area, (void __user *)arg, sizeof(p.area)))
+                       r = -EFAULT;
+               else
+                       r = omapfb_schedule_copyarea(fbi, &p.area);
+               break;
+       case OMAPFB_IMAGEBLIT:
+               if (copy_from_user(&p.image, (void __user *)arg,
+                                               sizeof(p.image)))
+                       r = -EFAULT;
+               else
+                       r = omapfb_schedule_imageblit(fbi, &p.image, 0);
+               break;
+       case OMAPFB_TRANSPARENT_BLIT:
+               if (copy_from_user(&p.image, (void __user *)arg,
+                                               sizeof(p.image)))
+                       r = -EFAULT;
+               else
+                       r = omapfb_schedule_imageblit(fbi, &p.image,
+                                                     COPY_MODE_TRANSPARENT);
+               break;
+       case OMAPFB_MIRROR:
+               if (get_user(p.mirror, (int __user *)arg))
+                       r = -EFAULT;
+               else
+                       omapfb_mirror(fbi, p.mirror);
+               break;
+       case OMAPFB_SCALE:
+               if (copy_from_user(&p.scale, (void __user *)arg,
+                                               sizeof(p.scale)))
+                       r = -EFAULT;
+               else
+                       r = omapfb_scale(fbi, p.scale.xscale, p.scale.yscale);
+               break;
+       case OMAPFB_SELECT_VIS_FRAME:
+               if (get_user(p.frame_idx, (int __user *)arg))
+                       r = -EFAULT;
+               else
+                       r = omapfb_select_vis_frame(fbi, p.frame_idx);
+               break;
+       case OMAPFB_SELECT_SRC_FRAME:
+               if (get_user(p.frame_idx, (int __user *)arg))
+                       r = - EFAULT;
+               else
+                       r = omapfb_select_src_frame(fbi, p.frame_idx);
+               break;
+       case OMAPFB_SELECT_DST_FRAME:
+               if (get_user(p.frame_idx, (int __user *)arg))
+                       r = -EFAULT;
+               else
+                       r = omapfb_select_dst_frame(fbi, p.frame_idx);
+               break;
+       case OMAPFB_GET_FRAME_OFFSET:
+               if (copy_from_user(&p.frame_offset, (void __user *)arg,
+                                  sizeof(p.frame_offset)))
+                       r = -EFAULT;
+               else {
+                       r = omapfb_get_frame_offset(fbi, &p.frame_offset);
+                       if (copy_to_user((void __user *)arg, &p.frame_offset,
+                                        sizeof(p.frame_offset)))
+                               r = -EFAULT;
+               }
+               break;
+       case OMAPFB_SYNC_GFX:
+               omapfb_rqueue_sync(&fbdev->rqueue);
+               break;
+       case OMAPFB_VSYNC:
+               break;
+       case OMAPFB_LATE_ACTIVATE:
+               printk(KERN_WARNING OMAPFB_DRIVER
+                       ": LATE_ACTIVATE obsoleted by SET_UPDATE_MODE.\n");
+//             r = -EINVAL;
+               break;
+       case OMAPFB_SET_UPDATE_MODE:
+               if (get_user(p.update_mode, (int __user *)arg))
+                       r = -EFAULT;
+               else
+                       r = omapfb_set_update_mode(fbdev, p.update_mode);
+               break;
+       case OMAPFB_GET_UPDATE_MODE:
+               p.update_mode = omapfb_get_update_mode(fbdev);
+               if (put_user(p.update_mode, (enum fb_update_mode __user *)arg))
+                       r = -EFAULT;
+               break;
+       case OMAPFB_UPDATE_WINDOW:
+               if (copy_from_user(&p.update_window, (void __user *)arg,
+                                  sizeof(p.update_window)))
+                       r = -EFAULT;
+               else
+                       r = omapfb_schedule_update_window(fbi, &p.update_window);
+               break;
+       case OMAPFB_GET_CAPS:
+               p.caps = omapfb_get_caps(fbi);
+               if (put_user(p.caps, (unsigned long __user *)arg))
+                       r = -EFAULT;
+               break;
+       case OMAPFB_GET_GFX_STATUS:
+               omapfb_rqueue_reset(&fbdev->rqueue, &p.rqueue_status);
+               if (put_user(p.rqueue_status, (unsigned long *)arg))
+                       r = -EFAULT;
+               break;
+       default:
+               r = -EINVAL;
+       }
+
+       DBGLEAVE(2);
+       return r;
+}
+
+/* Callback table for the frame buffer framework. Some of these pointers
+ * will be changed according to the current setting of fb_info->accel_flags.
+ */
+static struct fb_ops omapfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_open        = omapfb_open,
+       .fb_release     = omapfb_release,
+       .fb_setcolreg   = omapfb_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+       .fb_cursor      = soft_cursor,
+       .fb_blank       = omapfb_blank,
+       .fb_ioctl       = omapfb_ioctl,
+       .fb_check_var   = omapfb_check_var,
+       .fb_set_par     = omapfb_set_par,
+       .fb_rotate      = omapfb_rotate,
+       .fb_pan_display = omapfb_pan_display,
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * Sysfs interface 
+ * ---------------------------------------------------------------------------
+ */
+/* omapfbX sysfs entries */
+static ssize_t omapfb_show_caps_num(struct device *dev, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+       return snprintf(buf, PAGE_SIZE, "%#010lx\n",
+               omapfb_get_caps(fbdev->fb_info));
+}
+
+static ssize_t omapfb_show_caps_text(struct device *dev, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       int pos = 0;
+       int i;
+       unsigned long caps;
+
+       caps = omapfb_get_caps(fbdev->fb_info);
+       for (i = 0; i < ARRAY_SIZE(omapfb_caps_table) && pos < PAGE_SIZE; i++) {
+               if (omapfb_caps_table[i].flag & caps) {
+                       pos += snprintf(&buf[pos], PAGE_SIZE - pos, "%s\n",
+                                       omapfb_caps_table[i].name);
+               }
+       }
+       return min((int)PAGE_SIZE, pos);
+}
+
+static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
+static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
+
+/* panel sysfs entries */
+static ssize_t omapfb_show_panel_name(struct device *dev, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
+}
+
+static ssize_t omapfb_show_bklight_level(struct device *dev, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       int r;
+
+       if (fbdev->panel->get_bklight_level) {
+               r = snprintf(buf, PAGE_SIZE, "%d\n",
+                            fbdev->panel->get_bklight_level(fbdev->panel));
+       } else
+               r = -ENODEV;
+       return r;
+}
+
+static ssize_t omapfb_store_bklight_level(struct device *dev, const char *buf,
+                                         size_t size)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       int r;
+
+       if (fbdev->panel->set_bklight_level) {
+               unsigned int level;
+
+               if (sscanf(buf, "%10d", &level) == 1) {
+                       r = fbdev->panel->set_bklight_level(fbdev->panel,
+                                                           level);
+               } else
+                       r = -EINVAL;
+       } else
+               r = -ENODEV;
+       return r ? r : size;
+}
+
+static ssize_t omapfb_show_bklight_max(struct device *dev, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       int r;
+
+       if (fbdev->panel->get_bklight_level) {
+               r = snprintf(buf, PAGE_SIZE, "%d\n",
+                            fbdev->panel->get_bklight_max(fbdev->panel));
+       } else
+               r = -ENODEV;
+       return r;
+}
+
+static struct device_attribute dev_attr_panel_name =
+       __ATTR(name, 0444, omapfb_show_panel_name, NULL);
+static DEVICE_ATTR(backlight_level, 0664,
+                  omapfb_show_bklight_level, omapfb_store_bklight_level);
+static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
+
+static struct attribute *panel_attrs[] = {
+       &dev_attr_panel_name.attr,
+       &dev_attr_backlight_level.attr,
+       &dev_attr_backlight_max.attr,
+       NULL,
+};
+
+static struct attribute_group panel_attr_grp = {
+       .name  = "panel",
+       .attrs = panel_attrs,
+};
+
+/* ctrl sysfs entries */
+static ssize_t omapfb_show_ctrl_name(struct device *dev, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
+}
+
+static struct device_attribute dev_attr_ctrl_name =
+       __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
+
+static struct attribute *ctrl_attrs[] = {
+       &dev_attr_ctrl_name.attr,
+       NULL,
+};
+
+static struct attribute_group ctrl_attr_grp = {
+       .name  = "ctrl",
+       .attrs = ctrl_attrs,
+};
+
+static int omapfb_register_sysfs(struct omapfb_device *fbdev)
+{
+       int r;
+
+       if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
+               goto fail0;
+       
+       if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
+               goto fail1;
+
+       if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
+               goto fail2;
+
+       if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
+               goto fail3;
+
+       return 0;
+fail3:
+       sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
+fail2:
+       device_remove_file(fbdev->dev, &dev_attr_caps_text);
+fail1:
+       device_remove_file(fbdev->dev, &dev_attr_caps_num);
+fail0:
+       PRNERR("unable to register sysfs interface\n");
+       return r;
+}
+
+static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
+{
+       sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
+       sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
+       device_remove_file(fbdev->dev, &dev_attr_caps_num);
+       device_remove_file(fbdev->dev, &dev_attr_caps_text);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * LDM callbacks
+ * ---------------------------------------------------------------------------
+ */
+/* Initialize system fb_info object and set the default video mode.
+ * The frame buffer memory already allocated by lcddma_init
+ */
+static int fbinfo_init(struct omapfb_device *fbdev)
+{
+       struct fb_info                  *info = fbdev->fb_info;
+       struct fb_var_screeninfo        *var = &info->var;
+       int                             r = 0;
+
+       DBGENTER(1);
+
+       BUG_ON(!fbdev->lcddma_base);
+       info->fbops = &omapfb_ops;
+       info->flags = FBINFO_FLAG_DEFAULT;
+       info->screen_base = (char __iomem *) fbdev->lcddma_base
+                               + fbdev->frame0_org;
+       info->pseudo_palette = fbdev->pseudo_palette;
+
+       var->accel_flags  = def_accel ? FB_ACCELF_TEXT : 0;
+       var->xres_virtual = def_vxres;
+       var->yres_virtual = def_vyres;
+       var->rotate       = def_rotate;
+
+       fbdev->mirror = def_mirror;
+
+       set_fb_var(fbdev, var);
+       set_fb_fix(fbdev);
+
+       r = fb_alloc_cmap(&info->cmap, 16, 0);
+       if (r != 0)
+               PRNERR("unable to allocate color map memory\n");
+
+       DBGLEAVE(1);
+       return r;
+}
+
+/* Release the fb_info object */
+static void fbinfo_cleanup(struct omapfb_device *fbdev)
+{
+       DBGENTER(1);
+
+       fb_dealloc_cmap(&fbdev->fb_info->cmap);
+
+       DBGLEAVE(1);
+}
+
+/* Free driver resources. Can be called to rollback an aborted initialization
+ * sequence.
+ */
+static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
+{
+       switch (state) {
+       case OMAPFB_ACTIVE:
+               unregister_framebuffer(fbdev->fb_info);
+       case 8:
+               omapfb_unregister_sysfs(fbdev);
+       case 7:
+               omapfb_set_update_mode(fbdev, FB_UPDATE_DISABLED);
+       case 6:
+               fbdev->panel->disable(fbdev->panel);
+       case 5:
+               gfxdma_cleanup(&fbdev->gfx);
+       case 4:
+               fbinfo_cleanup(fbdev);
+       case 3:
+               ctrl_cleanup(fbdev);
+       case 2:
+               fbdev->panel->cleanup(fbdev->panel);
+       case 1:
+               omapfb_rqueue_cleanup(&fbdev->rqueue);
+               dev_set_drvdata(fbdev->dev, NULL);
+               framebuffer_release(fbdev->fb_info);
+       case 0:
+               /* nothing to free */
+               break;
+       default:
+               BUG();
+       }
+}
+
+static int omapfb_find_panel(struct omapfb_device *fbdev)
+{
+       const struct omap_lcd_config *cfg;
+       char name[17];
+       int i;
+
+       fbdev->panel = NULL;
+       cfg = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+       if (cfg == NULL) {
+               const char *def_name = NULL;
+
+               if (machine_is_omap_h2())
+                       def_name = "h2";
+               if (machine_is_omap_h3())
+                       def_name = "h3";
+               if (machine_is_omap_perseus2())
+                       def_name = "p2";
+               if (machine_is_omap_osk())
+                       def_name = "osk";
+               if (machine_is_omap_innovator() && cpu_is_omap1610())
+                       def_name = "inn1610";
+               if (machine_is_omap_innovator() && cpu_is_omap1510())
+                       def_name = "inn1510";
+               if (def_name == NULL)
+                       return -1;
+               strncpy(name, def_name, sizeof(name) - 1);
+       } else
+               strncpy(name, cfg->panel_name, sizeof(name) - 1);
+       name[sizeof(name) - 1] = 0;
+       for (i = 0; i < ARRAY_SIZE(panels); i++) {
+               if (strcmp(panels[i]->name, name) == 0) {
+                       fbdev->panel = panels[i];
+                       break;
+               }
+       }
+       if (fbdev->panel == NULL)
+               return -1;
+       return 0;
+}
+
+static int omapfb_find_ctrl(struct omapfb_device *fbdev)
+{
+       const struct omap_lcd_config *cfg;
+       char name[17];
+       int i;
+
+       fbdev->ctrl = NULL;
+       cfg = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+       if (cfg == NULL) {
+               strcpy(name, "internal");
+       } else
+               strncpy(name, cfg->ctrl_name, sizeof(name) - 1);
+       name[sizeof(name) - 1] = 0;
+       for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
+               if (strcmp(ctrls[i]->name, name) == 0) {
+                       fbdev->ctrl = ctrls[i];
+                       break;
+               }
+       }
+       if (fbdev->ctrl == NULL)
+               return -1;
+       return 0;
+}
+
+static void check_required_callbacks(struct omapfb_device *fbdev)
+{
+#define _C(x) (fbdev->ctrl->x)
+#define _P(x) (fbdev->panel->x)
+       BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
+                _C(get_mem_layout) && _C(set_update_mode) && _C(change_mode) &&
+                _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
+                _P(get_caps)));
+#undef _P
+#undef _C
+}
+
+static int omapfb_set_update_mode(struct omapfb_device *fbdev,
+                                 enum fb_update_mode mode)
+{
+       return fbdev->ctrl->set_update_mode(fbdev, mode);
+}
+
+static enum fb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
+{
+       return fbdev->ctrl->get_update_mode(fbdev);
+}
+
+/* Called by LDM binding to probe and attach a new device.
+ * Initialization sequence:
+ *   1. allocate system fb_info structure
+ *      select panel type according to machine type
+ *   2. init LCD panel
+ *   3. init LCD controller and LCD DMA
+ *   4. init system fb_info structure
+ *   5. init gfx DMA
+ *   6. enable LCD panel
+ *      start LCD frame transfer
+ *   7. register system fb_info structure
+ */
+static int omapfb_probe(struct device *dev)
+{
+       struct platform_device  *pdev;
+       struct omapfb_device    *fbdev = NULL;
+       struct fb_info          *fbi;
+       int                     init_state;
+       int                     r = 0;
+
+       DBGENTER(1);
+
+       init_state = 0;
+
+       pdev = to_platform_device(dev);
+       if (pdev->num_resources != 0) {
+               PRNERR("probed for an unknown device\n");
+               r = -ENODEV;
+               goto cleanup;
+       }
+
+       fbi = framebuffer_alloc(sizeof(struct omapfb_device), dev);
+       if (!fbi) {
+               PRNERR("unable to allocate memory for device info\n");
+               r = -ENOMEM;
+               goto cleanup;
+       }
+
+       fbdev = (struct omapfb_device *)fbi->par;
+       fbdev->fb_info = fbi;
+       fbdev->dev = dev;
+       dev_set_drvdata(dev, fbdev);
+
+       init_state++;
+       if (omapfb_find_ctrl(fbdev) < 0) {
+               PRNERR("LCD controller not found, board not supported\n");
+               r = -ENODEV;
+               goto cleanup;
+       }               
+       if (omapfb_find_panel(fbdev) < 0) {
+               PRNERR("LCD panel not found, board not supported\n");
+               r = -ENODEV;
+               goto cleanup;
+       }
+
+       check_required_callbacks(fbdev);
+       
+       printk(KERN_INFO OMAPFB_DRIVER ": configured for panel %s\n",
+              fbdev->panel->name);
+
+       omapfb_rqueue_init(&fbdev->rqueue);
+
+       r = fbdev->panel->init(fbdev->panel);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+       r = ctrl_init(fbdev);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+       r = fbinfo_init(fbdev);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+       r = gfxdma_init(&fbdev->gfx);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+#ifdef CONFIG_FB_OMAP_DMA_TUNE
+       /* Set DMA priority for EMIFF access to highest */
+       omap_set_dma_priority(OMAP_DMA_PORT_EMIFF, 15);
+#endif
+
+       r = fbdev->panel->enable(fbdev->panel);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+       r = omapfb_set_update_mode(fbdev, manual_update ?
+                                  FB_MANUAL_UPDATE : FB_AUTO_UPDATE);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+       r = omapfb_register_sysfs(fbdev);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+       r = register_framebuffer(fbdev->fb_info);
+       if (r != 0) {
+               PRNERR("register_framebuffer failed\n");
+               goto cleanup;
+       }
+
+       fbdev->state = OMAPFB_ACTIVE;
+
+       printk(KERN_INFO "OMAP framebuffer initialized vram=%lu\n",
+                        fbdev->lcddma_mem_size);
+
+       DBGLEAVE(1);
+       return 0;
+
+cleanup:
+       omapfb_free_resources(fbdev, init_state);
+
+       DBGLEAVE(1);
+       return r;
+}
+
+/* Called when the device is being detached from the driver */
+static int omapfb_remove(struct device *dev)
+{
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
+       enum omapfb_state saved_state = fbdev->state;
+
+       DBGENTER(1);
+       /* FIXME: wait till completion of pending events */
+
+       fbdev->state = OMAPFB_DISABLED;
+       omapfb_free_resources(fbdev, saved_state);
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+/* PM suspend */
+static int omapfb_suspend(struct device *dev, pm_message_t mesg, u32 level)
+{
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
+
+       DBGENTER(1);
+
+       if (fbdev->state == OMAPFB_ACTIVE) {
+               if (fbdev->ctrl->suspend)
+                       fbdev->ctrl->suspend(fbdev);
+               fbdev->panel->disable(fbdev->panel);
+               fbdev->state = OMAPFB_SUSPENDED;
+       }
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+/* PM resume */
+static int omapfb_resume(struct device *dev, u32 level)
+{
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
+
+       DBGENTER(1);
+
+       if (fbdev->state == OMAPFB_SUSPENDED) {
+               fbdev->panel->enable(fbdev->panel);
+               if (fbdev->ctrl->resume)
+                       fbdev->ctrl->resume(fbdev);
+               fbdev->state = OMAPFB_ACTIVE;
+               if (manual_update)
+                       omapfb_schedule_full_update(fbdev->fb_info);
+       }
+
+       DBGLEAVE(1);
+       return 0;
+}
+
+static void omapfb_release_dev(struct device *dev)
+{
+       DBGENTER(1);
+       DBGLEAVE(1);
+}
+
+static u64 omapfb_dmamask = ~(u32)0;
+
+static struct platform_device omapfb_device = {
+       .name           = OMAPFB_DEVICE,
+       .id             = -1,
+       .dev = {
+               .release  = omapfb_release_dev,
+               .dma_mask = &omapfb_dmamask,
+               .coherent_dma_mask = 0xffffffff,
+       },
+       .num_resources = 0,
+};
+
+static struct device_driver omapfb_driver = {
+       .name           = OMAPFB_DRIVER,
+       .bus            = &platform_bus_type,
+       .probe          = omapfb_probe,
+       .remove         = omapfb_remove,
+       .suspend        = omapfb_suspend,
+       .resume         = omapfb_resume
+};
+
+#ifndef MODULE
+
+/* Process kernel command line parameters */
+static int __init omapfb_setup(char *options)
+{
+       char *this_opt = NULL;
+       int r = 0;
+
+       DBGENTER(1);
+
+       if (!options || !*options)
+               goto exit;
+
+       while (!r && (this_opt = strsep(&options, ",")) != NULL) {
+               if (!strncmp(this_opt, "accel", 5))
+                       def_accel = 1;
+               else if (!strncmp(this_opt, "vram:", 5)) {
+                       char *suffix;
+                       def_vram = (simple_strtoul(this_opt + 5, &suffix, 0));
+                       switch (suffix[0]) {
+                       case 'm':
+                       case 'M':
+                               def_vram *= 1024 * 1024;
+                               break;
+                       case 'k':
+                       case 'K':
+                               def_vram *= 1024;
+                               break;
+                       default:
+                               PRNERR("invalid vram suffix\n");
+                               r = -1;
+                       }
+               }
+               else if (!strncmp(this_opt, "vxres:", 6))
+                       def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
+               else if (!strncmp(this_opt, "vyres:", 6))
+                       def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
+               else if (!strncmp(this_opt, "rotate:", 7))
+                       def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
+               else if (!strncmp(this_opt, "mirror:", 7))
+                       def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
+               else if (!strncmp(this_opt, "manual_update", 13))
+                       manual_update = 1;
+               else {
+                       PRNERR("invalid option\n");
+                       r = -1;
+               }
+       }
+exit:
+       DBGLEAVE(1);
+       return r;
+}
+
+#endif
+
+/* Register both the driver and the device */
+static int __init omapfb_init(void)
+{
+       int r = 0;
+
+       DBGENTER(1);
+
+#ifndef MODULE
+       {
+               char *option;
+               
+               if (fb_get_options("omapfb", &option)) {
+                       r = -ENODEV;
+                       goto exit;
+               }
+               omapfb_setup(option);
+       }
+#endif
+       /* Register the device with LDM */
+       if (platform_device_register(&omapfb_device)) {
+               PRNERR("failed to register omapfb device\n");
+               r = -ENODEV;
+               goto exit;
+       }
+       /* Register the driver with LDM */
+       if (driver_register(&omapfb_driver)) {
+               PRNERR("failed to register omapfb driver\n");
+               platform_device_unregister(&omapfb_device);
+               r = -ENODEV;
+               goto exit;
+       }
+
+exit:
+       DBGLEAVE(1);
+       return r;
+}
+
+static void __exit omapfb_cleanup(void)
+{
+       DBGENTER(1);
+
+       driver_unregister(&omapfb_driver);
+       platform_device_unregister(&omapfb_device);
+
+       DBGLEAVE(1);
+}
+
+module_param_named(accel, def_accel, uint, 0664);
+module_param_named(vram, def_vram, ulong, 0664);
+module_param_named(vxres, def_vxres, long, 0664);
+module_param_named(vyres, def_vyres, long, 0664);
+module_param_named(rotate, def_rotate, uint, 0664);
+module_param_named(mirror, def_mirror, uint, 0664);
+module_param_named(manual_update, manual_update, bool, 0664);
+
+module_init(omapfb_init);
+module_exit(omapfb_cleanup);
+
+MODULE_DESCRIPTION("TI OMAP framebuffer driver");
+MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c
new file mode 100644 (file)
index 0000000..b2006d7
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * File: drivers/video/omap_new/omapfb_main.c
+ *
+ * Special optimiSed Screen Interface driver for TI OMAP boards
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+
+#include "sossi.h"
+
+#define OMAP_SOSSI_BASE         0xfffbac00
+#define SOSSI_ID_REG           0x00
+#define SOSSI_INIT1_REG                0x04
+#define SOSSI_INIT2_REG                0x08
+#define SOSSI_INIT3_REG                0x0c
+#define SOSSI_FIFO_REG         0x10
+#define SOSSI_REOTABLE_REG     0x14
+#define SOSSI_TEARING_REG      0x18
+#define SOSSI_INIT1B_REG       0x1c
+#define SOSSI_FIFOB_REG                0x20
+
+#define DMA_GSCR          0xfffedc04
+#define DMA_LCD_CCR       0xfffee3c2
+#define DMA_LCD_CTRL      0xfffee3c4
+#define DMA_LCD_LCH_CTRL  0xfffee3ea
+
+static int sossi_base = IO_ADDRESS(OMAP_SOSSI_BASE);
+
+static inline u32 sossi_read_reg(int reg)
+{
+        return readl(sossi_base + reg);
+}
+
+static inline u16 sossi_read_reg16(int reg)
+{
+        return readw(sossi_base + reg);
+}
+
+static inline u8 sossi_read_reg8(int reg)
+{
+        return readb(sossi_base + reg);
+}
+
+static inline void sossi_write_reg(int reg, u32 value)
+{
+        writel(value, sossi_base + reg);
+}
+
+static inline void sossi_write_reg16(int reg, u16 value)
+{
+        writew(value, sossi_base + reg);
+}
+
+static inline void sossi_write_reg8(int reg, u8 value)
+{
+        writeb(value, sossi_base + reg);
+}
+
+static void sossi_set_bits(int reg, u32 bits)
+{
+        sossi_write_reg(reg, sossi_read_reg(reg) | bits);
+}
+
+static void sossi_clear_bits(int reg, u32 bits)
+{
+        sossi_write_reg(reg, sossi_read_reg(reg) & ~bits);
+}
+
+#if 1
+void sossi_dump(void)
+{
+       printk("  INIT1:    0x%08x\n", sossi_read_reg(SOSSI_INIT1_REG));
+       printk("  INIT2:    0x%08x\n", sossi_read_reg(SOSSI_INIT2_REG));
+       printk("  INIT3:    0x%08x\n", sossi_read_reg(SOSSI_INIT3_REG));
+       printk("  TEARING:  0x%08x\n", sossi_read_reg(SOSSI_TEARING_REG));
+       printk("  INIT1B:   0x%08x\n", sossi_read_reg(SOSSI_INIT1B_REG));
+}
+#endif
+
+static void sossi_dma_init(void)
+{
+       /* OMAP3.1 mapping disable */
+       omap_writel(omap_readl(DMA_GSCR) | (1 << 3), DMA_GSCR);
+       /* Logical channel type to b0100 */
+       omap_writew(omap_readw(DMA_LCD_LCH_CTRL) | (1 << 2), DMA_LCD_LCH_CTRL);
+       /* LCD_DMA dest port to 1 */
+       omap_writew(omap_readw(DMA_LCD_CTRL) | (1 << 8), DMA_LCD_CTRL);
+       /* LCD_CCR OMAP31 comp mode */
+       omap_writew(omap_readw(DMA_LCD_CCR) | (1 << 10), DMA_LCD_CCR);
+}
+
+#define MOD_CONF_CTRL_1   0xfffe1110
+#define CONF_SOSSI_RESET_R      (1 << 23)
+#define CONF_MOD_SOSSI_CLK_EN_R (1 << 16)
+
+int sossi_init(void)
+{
+       u32 l, k;
+
+       /* Reset and enable the SoSSI module */
+       l = omap_readl(MOD_CONF_CTRL_1);
+       l |= CONF_SOSSI_RESET_R;
+       omap_writel(l, MOD_CONF_CTRL_1);
+       l &= ~CONF_SOSSI_RESET_R;
+       omap_writel(l, MOD_CONF_CTRL_1);
+
+       l |= CONF_MOD_SOSSI_CLK_EN_R;
+       /* FIXME: Hardcode divide ratio 3 */
+       l |= 2 << 17;
+       omap_writel(l, MOD_CONF_CTRL_1);
+
+       omap_writel(omap_readl(ARM_IDLECT2) | (1 << 11), ARM_IDLECT2);
+       omap_writel(omap_readl(ARM_IDLECT1) | (1 << 6), ARM_IDLECT1);
+
+       sossi_dma_init();
+
+       l = sossi_read_reg(SOSSI_INIT2_REG);
+       /* Enable and reset the SoSSI block */
+       l |= (1 << 0) | (1 << 1);
+       sossi_write_reg(SOSSI_INIT2_REG, l);
+       /* Take SoSSI out of reset */
+       l &= ~(1 << 1);
+       sossi_write_reg(SOSSI_INIT2_REG, l);
+
+       sossi_write_reg(SOSSI_ID_REG, 0);
+       l = sossi_read_reg(SOSSI_ID_REG);
+       k = sossi_read_reg(SOSSI_ID_REG);
+       
+       if (l != 0x55555555 || k != 0xaaaaaaaa) {
+               printk(KERN_ERR "Invalid SoSSI sync pattern: %08x, %08x\n", l, k);
+               return -ENODEV;
+       }
+       l = sossi_read_reg(SOSSI_ID_REG); /* Component code */
+       l = sossi_read_reg(SOSSI_ID_REG);
+       printk(KERN_INFO "SoSSI rev. %d.%d initialized\n", l >> 16, l & 0xffff);
+
+       l = sossi_read_reg(SOSSI_INIT1_REG);
+       l |= (1 << 19); /* DMA_MODE */
+       l &= ~(1 << 31); /* REORDERING */
+       sossi_write_reg(SOSSI_INIT1_REG, l);
+
+       return 0;
+}
+
+static void set_timings(int tw0, int tw1)
+{
+       u32 l;
+
+       l = sossi_read_reg(SOSSI_INIT1_REG);
+       l &= ~((0x0f << 20) | (0x3f << 24));
+       l |= ((tw0 & 0x0f) << 20) | ((tw1 & 0x3f) << 24);
+       sossi_write_reg(SOSSI_INIT1_REG, l);
+}
+
+static struct sossi {
+       int bus_pick_width;
+} sossi;
+
+void sossi_set_xfer_params(int tw0, int tw1, int bus_pick_count, int bus_pick_width)
+{
+       u32 l;
+
+       set_timings(tw0, tw1);  
+       sossi.bus_pick_width = bus_pick_width;
+       l = ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
+       sossi_write_reg(SOSSI_INIT3_REG, l);
+}
+
+void sossi_start_transfer(void)
+{
+       /* WE */
+       sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4);
+       /* CS active low */
+       sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30);
+       /* FIXME: locking? */
+}
+
+void sossi_stop_transfer(void)
+{
+       /* WE */
+       sossi_set_bits(SOSSI_INIT2_REG, 1 << 4);
+       /* CS active low */
+       sossi_set_bits(SOSSI_INIT1_REG, 1 << 30);
+       /* FIXME: locking? */
+}
+
+static void send_data(const void *data, unsigned int len)
+{
+       while (len >= 4) {
+               sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data);
+               len -= 4;
+               data += 4;
+       }
+       while (len >= 2) {
+               sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data);
+               len -= 2;
+               data += 2;
+       }
+       while (len) {
+               sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data);
+               len--;
+               data++;
+       }
+}
+
+static void set_cycles(unsigned int len)
+{
+       int nr_cycles = len / (sossi.bus_pick_width / 8);
+
+       sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff);
+       sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff);
+}
+
+void sossi_send_cmd(const void *data, unsigned int len)
+{
+       sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18);
+        set_cycles(len);
+       send_data(data, len);
+}
+
+void sossi_send_data(const void *data, unsigned int len)
+{
+       sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+        set_cycles(len);
+       send_data(data, len);
+}
+
+void sossi_prepare_dma_transfer(unsigned int count)
+{
+       sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+        set_cycles(count);
+}
+
+void sossi_send_data_const32(u32 data, unsigned int count)
+{
+       sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+        set_cycles(count * 4);
+       while (count > 0) {
+               sossi_write_reg(SOSSI_FIFO_REG, data);
+               count--;
+       }
+}
+
+void sossi_set_tearing(int mode, int hs_counter, int detect_limit,
+                      int vs_counter, int vs_detect_limit, int flags)
+{
+       u32 l = 0;
+
+       l |= vs_counter << 30;
+       if (flags & SOSSI_FLAG_HS_INVERTED)
+               l |= 1 << 29;
+       if (flags & SOSSI_FLAG_VS_INVERTED)
+               l |= 1 << 28;
+       l |= mode << 26;
+       l |= hs_counter << 15;
+       l |= vs_detect_limit << 3;
+       l |= detect_limit;
+       sossi_write_reg(SOSSI_TEARING_REG, l);
+}
+
+void sossi_read_data(void *data, unsigned int len)
+{
+       /* Before reading we must check if some writings are going on */
+       while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3)));
+       sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+        set_cycles(len);
+       while (len >= 4) {
+               *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG);
+               len -= 4;
+               data += 4;
+       }
+       while (len >= 2) {
+               *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG);
+               len -= 2;
+               data += 2;
+       }
+       while (len) {
+               *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG);
+               len--;
+               data++;
+       }
+}
diff --git a/drivers/video/omap/sossi.h b/drivers/video/omap/sossi.h
new file mode 100644 (file)
index 0000000..4cd18d7
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef DRIVERS_VIDEO_OMAP_SOSSI_H
+#define DRIVERS_VIDEO_OMAP_SOSSI_H
+
+#define SOSSI_FLAG_HS_INVERTED          0x01
+#define SOSSI_FLAG_VS_INVERTED          0x02
+
+extern int sossi_init(void);
+extern void sossi_set_xfer_params(int tw0, int tw1, int bus_pick_count, int bus_pick_width);
+extern void sossi_start_transfer(void);
+extern void sossi_stop_transfer(void);
+extern void sossi_send_cmd(const void *data, unsigned int len);
+extern void sossi_send_data(const void *data, unsigned int len);
+extern void sossi_send_data_const32(u32 data, unsigned int count);
+extern void sossi_prepare_dma_transfer(unsigned int count);
+extern void sossi_read_data(void *data, unsigned int len);
+extern void sossi_set_tearing(int mode, int hs_counter, int detect_limit,
+                             int vs_counter, int vs_detect_limit, int flags);
+
+#endif
index b468bf49654782d1d7cc6e6f12dc79d04fd34325..edff021b27e1d403aa8c6d59288c307e0b6f2e2c 100644 (file)
 #define FB_ACCEL_NV_20          44      /* nVidia Arch 20               */
 #define FB_ACCEL_NV_30          45      /* nVidia Arch 30               */
 #define FB_ACCEL_NV_40          46      /* nVidia Arch 40               */
+#define FB_ACCEL_OMAP1610       47     /* TI OMAP16xx */
 #define FB_ACCEL_NEOMAGIC_NM2070 90    /* NeoMagic NM2070              */
 #define FB_ACCEL_NEOMAGIC_NM2090 91    /* NeoMagic NM2090              */
 #define FB_ACCEL_NEOMAGIC_NM2093 92    /* NeoMagic NM2093              */