Staging: sm7xx: add a new framebuffer driver
authorWu Zhangjin <wuzhangjin@gmail.com>
Mon, 23 Nov 2009 02:28:24 +0000 (10:28 +0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 23 Dec 2009 19:27:44 +0000 (11:27 -0800)
Yeeloong netbook has a sm712 video card, need this driver, but it is not
ready to upstream yet, so, go to drivers/staing at first.

This source code is originally from Silicon Motion Technology Corp, and
maintained at http://dev.lemote.com/code/linux_loongson for YeeLoong
netbook. I have done a lot of cleanups for it and merged it into my git
repository at http://dev.lemote.com/code/rt4ls.

Thanks to Simon for testing it on a little-endian x86 platform.

Thanks to Olivier Croset <olivier.croset@actis-computer.com> for
reporting the problem about __BIG_ENDIAN compiling problem and send a
relative patch.

The suspend/resume and blank support are contributed by Jason from
Silicon Motion Technology.

Tested-by: Simon Braunschmidt <sbraun@emlix.com>
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/sm7xx/Kconfig [new file with mode: 0644]
drivers/staging/sm7xx/Makefile [new file with mode: 0644]
drivers/staging/sm7xx/TODO [new file with mode: 0644]
drivers/staging/sm7xx/smtc2d.c [new file with mode: 0644]
drivers/staging/sm7xx/smtc2d.h [new file with mode: 0644]
drivers/staging/sm7xx/smtcfb.c [new file with mode: 0644]
drivers/staging/sm7xx/smtcfb.h [new file with mode: 0644]

index 093f57af32d3d9614973372af2e6abce81268706..db0de940949e3c2f25727dbbd51dafcc6b8bb0c5 100644 (file)
@@ -145,5 +145,7 @@ source "drivers/staging/wavelan/Kconfig"
 
 source "drivers/staging/netwave/Kconfig"
 
+source "drivers/staging/sm7xx/Kconfig"
+
 endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
index 069864f4391ecbc20c68e820a22c324669b4240f..73c6a71155e03d2a8100d60ee66beed184624a65 100644 (file)
@@ -53,3 +53,4 @@ obj-$(CONFIG_ARLAN)           += arlan/
 obj-$(CONFIG_WAVELAN)          += wavelan/
 obj-$(CONFIG_PCMCIA_WAVELAN)   += wavelan/
 obj-$(CONFIG_PCMCIA_NETWAVE)   += netwave/
+obj-$(CONFIG_FB_SM7XX)         += sm7xx/
diff --git a/drivers/staging/sm7xx/Kconfig b/drivers/staging/sm7xx/Kconfig
new file mode 100644 (file)
index 0000000..204dbfc
--- /dev/null
@@ -0,0 +1,15 @@
+config FB_SM7XX
+       tristate "Silicon Motion SM7XX Frame Buffer Support"
+       depends on FB
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       help
+         Frame Buffer driver for the Silicon Motion SM7XX serial graphic card.
+
+config FB_SM7XX_ACCEL
+       bool "Siliconmotion Acceleration functions (EXPERIMENTAL)"
+       depends on FB_SM7XX && EXPERIMENTAL
+       help
+         This will compile the Trident frame buffer device with
+         acceleration functions.
diff --git a/drivers/staging/sm7xx/Makefile b/drivers/staging/sm7xx/Makefile
new file mode 100644 (file)
index 0000000..f43cb91
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_FB_SM7XX) += sm7xx.o
+
+sm7xx-y := smtcfb.o
diff --git a/drivers/staging/sm7xx/TODO b/drivers/staging/sm7xx/TODO
new file mode 100644 (file)
index 0000000..1f61f5e
--- /dev/null
@@ -0,0 +1,10 @@
+TODO:
+- Dual head support
+- use kernel coding style
+- checkpatch.pl clean
+- refine the code and remove unused code
+- use kernel framebuffer mode setting instead of hard code
+- move it to drivers/video/sm7xx/ or make it be drivers/video/sm7xxfb.c
+
+Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
+Teddy Wang <teddy.wang@siliconmotion.com.cn>.
diff --git a/drivers/staging/sm7xx/smtc2d.c b/drivers/staging/sm7xx/smtc2d.c
new file mode 100644 (file)
index 0000000..133b86c
--- /dev/null
@@ -0,0 +1,979 @@
+/*
+ * Silicon Motion SM7XX 2D drawing engine functions.
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Author: Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzj@lemote.com
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ * Version 0.10.26192.21.01
+ *     - Add PowerPC support
+ *     - Add 2D support for Lynx -
+ * Verified on 2.6.19.2
+ *     Boyod.yang  <boyod.yang@siliconmotion.com.cn>
+ */
+
+unsigned char smtc_de_busy;
+
+void SMTC_write2Dreg(unsigned long nOffset, unsigned long nData)
+{
+       writel(nData, smtc_2DBaseAddress + nOffset);
+}
+
+unsigned long SMTC_read2Dreg(unsigned long nOffset)
+{
+       return readl(smtc_2DBaseAddress + nOffset);
+}
+
+void SMTC_write2Ddataport(unsigned long nOffset, unsigned long nData)
+{
+       writel(nData, smtc_2Ddataport + nOffset);
+}
+
+/**********************************************************************
+ *
+ * deInit
+ *
+ * Purpose
+ *    Drawing engine initialization.
+ *
+ **********************************************************************/
+
+void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
+               unsigned int bpp)
+{
+       /* Get current power configuration. */
+       unsigned char clock;
+       clock = smtc_seqr(0x21);
+
+       /* initialize global 'mutex lock' variable */
+       smtc_de_busy = 0;
+
+       /* Enable 2D Drawing Engine */
+       smtc_seqw(0x21, clock & 0xF8);
+
+       SMTC_write2Dreg(DE_CLIP_TL,
+                       FIELD_VALUE(0, DE_CLIP_TL, TOP, 0) |
+                       FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE) |
+                       FIELD_SET(0, DE_CLIP_TL, INHIBIT, OUTSIDE) |
+                       FIELD_VALUE(0, DE_CLIP_TL, LEFT, 0));
+
+       if (bpp >= 24) {
+               SMTC_write2Dreg(DE_PITCH,
+                               FIELD_VALUE(0, DE_PITCH, DESTINATION,
+                                           nModeWidth * 3) | FIELD_VALUE(0,
+                                                                 DE_PITCH,
+                                                                 SOURCE,
+                                                                 nModeWidth
+                                                                 * 3));
+       } else {
+               SMTC_write2Dreg(DE_PITCH,
+                               FIELD_VALUE(0, DE_PITCH, DESTINATION,
+                                           nModeWidth) | FIELD_VALUE(0,
+                                                             DE_PITCH,
+                                                             SOURCE,
+                                                             nModeWidth));
+       }
+
+       SMTC_write2Dreg(DE_WINDOW_WIDTH,
+                       FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+                                   nModeWidth) | FIELD_VALUE(0,
+                                                             DE_WINDOW_WIDTH,
+                                                             SOURCE,
+                                                             nModeWidth));
+
+       switch (bpp) {
+       case 8:
+               SMTC_write2Dreg(DE_STRETCH_FORMAT,
+                               FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
+                                         NORMAL) | FIELD_VALUE(0,
+                                                       DE_STRETCH_FORMAT,
+                                                       PATTERN_Y,
+                                                       0) |
+                               FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
+                                   0) | FIELD_SET(0, DE_STRETCH_FORMAT,
+                                                  PIXEL_FORMAT,
+                                                  8) | FIELD_SET(0,
+                                                         DE_STRETCH_FORMAT,
+                                                         ADDRESSING,
+                                                         XY) |
+                               FIELD_VALUE(0, DE_STRETCH_FORMAT,
+                                       SOURCE_HEIGHT, 3));
+               break;
+       case 24:
+               SMTC_write2Dreg(DE_STRETCH_FORMAT,
+                               FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
+                                         NORMAL) | FIELD_VALUE(0,
+                                                       DE_STRETCH_FORMAT,
+                                                       PATTERN_Y,
+                                                       0) |
+                               FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
+                                   0) | FIELD_SET(0, DE_STRETCH_FORMAT,
+                                                          PIXEL_FORMAT,
+                                                          24) | FIELD_SET(0,
+                                                          DE_STRETCH_FORMAT,
+                                                          ADDRESSING,
+                                                          XY) |
+                               FIELD_VALUE(0, DE_STRETCH_FORMAT,
+                                       SOURCE_HEIGHT, 3));
+               break;
+       case 16:
+       default:
+               SMTC_write2Dreg(DE_STRETCH_FORMAT,
+                               FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
+                                         NORMAL) | FIELD_VALUE(0,
+                                                       DE_STRETCH_FORMAT,
+                                                       PATTERN_Y,
+                                                       0) |
+                               FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
+                                   0) | FIELD_SET(0, DE_STRETCH_FORMAT,
+                                                          PIXEL_FORMAT,
+                                                          16) | FIELD_SET(0,
+                                                          DE_STRETCH_FORMAT,
+                                                          ADDRESSING,
+                                                          XY) |
+                               FIELD_VALUE(0, DE_STRETCH_FORMAT,
+                                       SOURCE_HEIGHT, 3));
+               break;
+       }
+
+       SMTC_write2Dreg(DE_MASKS,
+                       FIELD_VALUE(0, DE_MASKS, BYTE_MASK, 0xFFFF) |
+                       FIELD_VALUE(0, DE_MASKS, BIT_MASK, 0xFFFF));
+       SMTC_write2Dreg(DE_COLOR_COMPARE_MASK,
+                       FIELD_VALUE(0, DE_COLOR_COMPARE_MASK, MASKS, \
+                               0xFFFFFF));
+       SMTC_write2Dreg(DE_COLOR_COMPARE,
+                       FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, 0xFFFFFF));
+}
+
+void deVerticalLine(unsigned long dst_base,
+                   unsigned long dst_pitch,
+                   unsigned long nX,
+                   unsigned long nY,
+                   unsigned long dst_height, unsigned long nColor)
+{
+       deWaitForNotBusy();
+
+       SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+                       FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+                                   dst_base));
+
+       SMTC_write2Dreg(DE_PITCH,
+                       FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
+                       FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
+
+       SMTC_write2Dreg(DE_WINDOW_WIDTH,
+                       FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+                           dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
+                                                    SOURCE,
+                                                    dst_pitch));
+
+       SMTC_write2Dreg(DE_FOREGROUND,
+                       FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+       SMTC_write2Dreg(DE_DESTINATION,
+                       FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+                       FIELD_VALUE(0, DE_DESTINATION, X, nX) |
+                       FIELD_VALUE(0, DE_DESTINATION, Y, nY));
+
+       SMTC_write2Dreg(DE_DIMENSION,
+                       FIELD_VALUE(0, DE_DIMENSION, X, 1) |
+                       FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
+
+       SMTC_write2Dreg(DE_CONTROL,
+                       FIELD_SET(0, DE_CONTROL, STATUS, START) |
+                       FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+                       FIELD_SET(0, DE_CONTROL, MAJOR, Y) |
+                       FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) |
+                       FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
+                       FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
+                       FIELD_SET(0, DE_CONTROL, COMMAND, SHORT_STROKE) |
+                       FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+                       FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
+
+       smtc_de_busy = 1;
+}
+
+void deHorizontalLine(unsigned long dst_base,
+                     unsigned long dst_pitch,
+                     unsigned long nX,
+                     unsigned long nY,
+                     unsigned long dst_width, unsigned long nColor)
+{
+       deWaitForNotBusy();
+
+       SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+                       FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+                                   dst_base));
+
+       SMTC_write2Dreg(DE_PITCH,
+                       FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
+                       FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
+
+       SMTC_write2Dreg(DE_WINDOW_WIDTH,
+                       FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+                           dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
+                                                    SOURCE,
+                                                    dst_pitch));
+       SMTC_write2Dreg(DE_FOREGROUND,
+                       FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+       SMTC_write2Dreg(DE_DESTINATION,
+                       FIELD_SET(0, DE_DESTINATION, WRAP,
+                         DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X,
+                                                nX) | FIELD_VALUE(0,
+                                                          DE_DESTINATION,
+                                                          Y,
+                                                          nY));
+       SMTC_write2Dreg(DE_DIMENSION,
+                       FIELD_VALUE(0, DE_DIMENSION, X,
+                           dst_width) | FIELD_VALUE(0, DE_DIMENSION,
+                                                    Y_ET, 1));
+       SMTC_write2Dreg(DE_CONTROL,
+               FIELD_SET(0, DE_CONTROL, STATUS, START) | FIELD_SET(0,
+                                                           DE_CONTROL,
+                                                           DIRECTION,
+                                                           RIGHT_TO_LEFT)
+               | FIELD_SET(0, DE_CONTROL, MAJOR, X) | FIELD_SET(0,
+                                                        DE_CONTROL,
+                                                        STEP_X,
+                                                        POSITIVE)
+               | FIELD_SET(0, DE_CONTROL, STEP_Y,
+                           NEGATIVE) | FIELD_SET(0, DE_CONTROL,
+                                                 LAST_PIXEL,
+                                                 OFF) | FIELD_SET(0,
+                                                          DE_CONTROL,
+                                                          COMMAND,
+                                                          SHORT_STROKE)
+               | FIELD_SET(0, DE_CONTROL, ROP_SELECT,
+                           ROP2) | FIELD_VALUE(0, DE_CONTROL, ROP,
+                                               0x0C));
+
+       smtc_de_busy = 1;
+}
+
+void deLine(unsigned long dst_base,
+           unsigned long dst_pitch,
+           unsigned long nX1,
+           unsigned long nY1,
+           unsigned long nX2, unsigned long nY2, unsigned long nColor)
+{
+       unsigned long nCommand =
+           FIELD_SET(0, DE_CONTROL, STATUS, START) |
+           FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+           FIELD_SET(0, DE_CONTROL, MAJOR, X) |
+           FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) |
+           FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
+           FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
+           FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+           FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C);
+       unsigned long DeltaX;
+       unsigned long DeltaY;
+
+       /* Calculate delta X */
+       if (nX1 <= nX2)
+               DeltaX = nX2 - nX1;
+       else {
+               DeltaX = nX1 - nX2;
+               nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_X, NEGATIVE);
+       }
+
+       /* Calculate delta Y */
+       if (nY1 <= nY2)
+               DeltaY = nY2 - nY1;
+       else {
+               DeltaY = nY1 - nY2;
+               nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_Y, NEGATIVE);
+       }
+
+       /* Determine the major axis */
+       if (DeltaX < DeltaY)
+               nCommand = FIELD_SET(nCommand, DE_CONTROL, MAJOR, Y);
+
+       /* Vertical line? */
+       if (nX1 == nX2)
+               deVerticalLine(dst_base, dst_pitch, nX1, nY1, DeltaY, nColor);
+
+       /* Horizontal line? */
+       else if (nY1 == nY2)
+               deHorizontalLine(dst_base, dst_pitch, nX1, nY1, \
+                               DeltaX, nColor);
+
+       /* Diagonal line? */
+       else if (DeltaX == DeltaY) {
+               deWaitForNotBusy();
+
+               SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+                               FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
+                                           ADDRESS, dst_base));
+
+               SMTC_write2Dreg(DE_PITCH,
+                               FIELD_VALUE(0, DE_PITCH, DESTINATION,
+                                           dst_pitch) | FIELD_VALUE(0,
+                                                            DE_PITCH,
+                                                            SOURCE,
+                                                            dst_pitch));
+
+               SMTC_write2Dreg(DE_WINDOW_WIDTH,
+                               FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+                                           dst_pitch) | FIELD_VALUE(0,
+                                                            DE_WINDOW_WIDTH,
+                                                            SOURCE,
+                                                            dst_pitch));
+
+               SMTC_write2Dreg(DE_FOREGROUND,
+                               FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+               SMTC_write2Dreg(DE_DESTINATION,
+                               FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+                               FIELD_VALUE(0, DE_DESTINATION, X, 1) |
+                               FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
+
+               SMTC_write2Dreg(DE_DIMENSION,
+                               FIELD_VALUE(0, DE_DIMENSION, X, 1) |
+                               FIELD_VALUE(0, DE_DIMENSION, Y_ET, DeltaX));
+
+               SMTC_write2Dreg(DE_CONTROL,
+                               FIELD_SET(nCommand, DE_CONTROL, COMMAND,
+                                         SHORT_STROKE));
+       }
+
+       /* Generic line */
+       else {
+               unsigned int k1, k2, et, w;
+               if (DeltaX < DeltaY) {
+                       k1 = 2 * DeltaX;
+                       et = k1 - DeltaY;
+                       k2 = et - DeltaY;
+                       w = DeltaY + 1;
+               } else {
+                       k1 = 2 * DeltaY;
+                       et = k1 - DeltaX;
+                       k2 = et - DeltaX;
+                       w = DeltaX + 1;
+               }
+
+               deWaitForNotBusy();
+
+               SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+                               FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
+                                           ADDRESS, dst_base));
+
+               SMTC_write2Dreg(DE_PITCH,
+                               FIELD_VALUE(0, DE_PITCH, DESTINATION,
+                                           dst_pitch) | FIELD_VALUE(0,
+                                                            DE_PITCH,
+                                                            SOURCE,
+                                                            dst_pitch));
+
+               SMTC_write2Dreg(DE_WINDOW_WIDTH,
+                               FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+                                           dst_pitch) | FIELD_VALUE(0,
+                                                            DE_WINDOW_WIDTH,
+                                                            SOURCE,
+                                                            dst_pitch));
+
+               SMTC_write2Dreg(DE_FOREGROUND,
+                               FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+               SMTC_write2Dreg(DE_SOURCE,
+                               FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+                               FIELD_VALUE(0, DE_SOURCE, X_K1, k1) |
+                               FIELD_VALUE(0, DE_SOURCE, Y_K2, k2));
+
+               SMTC_write2Dreg(DE_DESTINATION,
+                               FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+                               FIELD_VALUE(0, DE_DESTINATION, X, nX1) |
+                               FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
+
+               SMTC_write2Dreg(DE_DIMENSION,
+                               FIELD_VALUE(0, DE_DIMENSION, X, w) |
+                               FIELD_VALUE(0, DE_DIMENSION, Y_ET, et));
+
+               SMTC_write2Dreg(DE_CONTROL,
+                               FIELD_SET(nCommand, DE_CONTROL, COMMAND,
+                                         LINE_DRAW));
+       }
+
+       smtc_de_busy = 1;
+}
+
+void deFillRect(unsigned long dst_base,
+               unsigned long dst_pitch,
+               unsigned long dst_X,
+               unsigned long dst_Y,
+               unsigned long dst_width,
+               unsigned long dst_height, unsigned long nColor)
+{
+       deWaitForNotBusy();
+
+       SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+                       FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+                                   dst_base));
+
+       if (dst_pitch) {
+               SMTC_write2Dreg(DE_PITCH,
+                               FIELD_VALUE(0, DE_PITCH, DESTINATION,
+                                           dst_pitch) | FIELD_VALUE(0,
+                                                            DE_PITCH,
+                                                            SOURCE,
+                                                            dst_pitch));
+
+               SMTC_write2Dreg(DE_WINDOW_WIDTH,
+                               FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+                                           dst_pitch) | FIELD_VALUE(0,
+                                                            DE_WINDOW_WIDTH,
+                                                            SOURCE,
+                                                            dst_pitch));
+       }
+
+       SMTC_write2Dreg(DE_FOREGROUND,
+                       FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+       SMTC_write2Dreg(DE_DESTINATION,
+                       FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+                       FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
+                       FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
+
+       SMTC_write2Dreg(DE_DIMENSION,
+                       FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
+                       FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
+
+       SMTC_write2Dreg(DE_CONTROL,
+                       FIELD_SET(0, DE_CONTROL, STATUS, START) |
+                       FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+                       FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
+                       FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) |
+                       FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+                       FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
+
+       smtc_de_busy = 1;
+}
+
+/**********************************************************************
+ *
+ * deRotatePattern
+ *
+ * Purpose
+ *    Rotate the given pattern if necessary
+ *
+ * Parameters
+ *    [in]
+ *        pPattern  - Pointer to DE_SURFACE structure containing
+ *                    pattern attributes
+ *        patternX  - X position (0-7) of pattern origin
+ *        patternY  - Y position (0-7) of pattern origin
+ *
+ *    [out]
+ *        pattern_dstaddr - Pointer to pre-allocated buffer containing
+ *        rotated pattern
+ *
+ **********************************************************************/
+void deRotatePattern(unsigned char *pattern_dstaddr,
+                    unsigned long pattern_src_addr,
+                    unsigned long pattern_BPP,
+                    unsigned long pattern_stride, int patternX, int patternY)
+{
+       unsigned int i;
+       unsigned long pattern[PATTERN_WIDTH * PATTERN_HEIGHT];
+       unsigned int x, y;
+       unsigned char *pjPatByte;
+
+       if (pattern_dstaddr != NULL) {
+               deWaitForNotBusy();
+
+               if (patternX || patternY) {
+                       /* Rotate pattern */
+                       pjPatByte = (unsigned char *)pattern;
+
+                       switch (pattern_BPP) {
+                       case 8:
+                               {
+                                       for (y = 0; y < 8; y++) {
+                                               unsigned char *pjBuffer =
+                                                   pattern_dstaddr +
+                                                   ((patternY + y) & 7) * 8;
+                                               for (x = 0; x < 8; x++) {
+                                                       pjBuffer[(patternX +
+                                                                 x) & 7] =
+                                                           pjPatByte[x];
+                                               }
+                                               pjPatByte += pattern_stride;
+                                       }
+                                       break;
+                               }
+
+                       case 16:
+                               {
+                                       for (y = 0; y < 8; y++) {
+                                               unsigned short *pjBuffer =
+                                                   (unsigned short *)
+                                                   pattern_dstaddr +
+                                                   ((patternY + y) & 7) * 8;
+                                               for (x = 0; x < 8; x++) {
+                                                       pjBuffer[(patternX +
+                                                                 x) & 7] =
+                                                           ((unsigned short *)
+                                                            pjPatByte)[x];
+                                               }
+                                               pjPatByte += pattern_stride;
+                                       }
+                                       break;
+                               }
+
+                       case 32:
+                               {
+                                       for (y = 0; y < 8; y++) {
+                                               unsigned long *pjBuffer =
+                                                   (unsigned long *)
+                                                   pattern_dstaddr +
+                                                   ((patternY + y) & 7) * 8;
+                                               for (x = 0; x < 8; x++) {
+                                                       pjBuffer[(patternX +
+                                                                 x) & 7] =
+                                                           ((unsigned long *)
+                                                            pjPatByte)[x];
+                                               }
+                                               pjPatByte += pattern_stride;
+                                       }
+                                       break;
+                               }
+                       }
+               } else {
+                       /*Don't rotate,just copy pattern into pattern_dstaddr*/
+                       for (i = 0; i < (pattern_BPP * 2); i++) {
+                               ((unsigned long *)pattern_dstaddr)[i] =
+                                   pattern[i];
+                       }
+               }
+
+       }
+}
+
+/**********************************************************************
+ *
+ * deCopy
+ *
+ * Purpose
+ *    Copy a rectangular area of the source surface to a destination surface
+ *
+ * Remarks
+ *    Source bitmap must have the same color depth (BPP) as the destination
+ *    bitmap.
+ *
+**********************************************************************/
+void deCopy(unsigned long dst_base,
+           unsigned long dst_pitch,
+           unsigned long dst_BPP,
+           unsigned long dst_X,
+           unsigned long dst_Y,
+           unsigned long dst_width,
+           unsigned long dst_height,
+           unsigned long src_base,
+           unsigned long src_pitch,
+           unsigned long src_X,
+           unsigned long src_Y, pTransparent pTransp, unsigned char nROP2)
+{
+       unsigned long nDirection = 0;
+       unsigned long nTransparent = 0;
+       /* Direction of ROP2 operation:
+        * 1 = Left to Right,
+        * (-1) = Right to Left
+        */
+       unsigned long opSign = 1;
+       /* xWidth is in pixels */
+       unsigned long xWidth = 192 / (dst_BPP / 8);
+       unsigned long de_ctrl = 0;
+
+       deWaitForNotBusy();
+
+       SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+                       FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+                                   dst_base));
+
+       SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE,
+                       FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS,
+                                   src_base));
+
+       if (dst_pitch && src_pitch) {
+               SMTC_write2Dreg(DE_PITCH,
+                       FIELD_VALUE(0, DE_PITCH, DESTINATION,
+                                   dst_pitch) | FIELD_VALUE(0,
+                                                    DE_PITCH,
+                                                    SOURCE,
+                                                    src_pitch));
+
+               SMTC_write2Dreg(DE_WINDOW_WIDTH,
+                       FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+                                   dst_pitch) | FIELD_VALUE(0,
+                                                    DE_WINDOW_WIDTH,
+                                                    SOURCE,
+                                                    src_pitch));
+       }
+
+       /* Set transparent bits if necessary */
+       if (pTransp != NULL) {
+               nTransparent =
+                   pTransp->match | pTransp->select | pTransp->control;
+
+               /* Set color compare register */
+               SMTC_write2Dreg(DE_COLOR_COMPARE,
+                               FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR,
+                                           pTransp->color));
+       }
+
+       /* Determine direction of operation */
+       if (src_Y < dst_Y) {
+               /* +----------+
+                  |S         |
+                  |          +----------+
+                  |          |      |   |
+                  |          |      |   |
+                  +---|------+      |
+                  |               D |
+                  +----------+ */
+
+               nDirection = BOTTOM_TO_TOP;
+       } else if (src_Y > dst_Y) {
+               /* +----------+
+                  |D         |
+                  |          +----------+
+                  |          |      |   |
+                  |          |      |   |
+                  +---|------+      |
+                  |               S |
+                  +----------+ */
+
+               nDirection = TOP_TO_BOTTOM;
+       } else {
+               /* src_Y == dst_Y */
+
+               if (src_X <= dst_X) {
+                       /* +------+---+------+
+                          |S     |   |     D|
+                          |      |   |      |
+                          |      |   |      |
+                          |      |   |      |
+                          +------+---+------+ */
+
+                       nDirection = RIGHT_TO_LEFT;
+               } else {
+                       /* src_X > dst_X */
+
+                       /* +------+---+------+
+                          |D     |   |     S|
+                          |      |   |      |
+                          |      |   |      |
+                          |      |   |      |
+                          +------+---+------+ */
+
+                       nDirection = LEFT_TO_RIGHT;
+               }
+       }
+
+       if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
+               src_X += dst_width - 1;
+               src_Y += dst_height - 1;
+               dst_X += dst_width - 1;
+               dst_Y += dst_height - 1;
+               opSign = (-1);
+       }
+
+       if (dst_BPP >= 24) {
+               src_X *= 3;
+               src_Y *= 3;
+               dst_X *= 3;
+               dst_Y *= 3;
+               dst_width *= 3;
+               if ((nDirection == BOTTOM_TO_TOP)
+                   || (nDirection == RIGHT_TO_LEFT)) {
+                       src_X += 2;
+                       dst_X += 2;
+               }
+       }
+
+       /* Workaround for 192 byte hw bug */
+       if ((nROP2 != 0x0C) && ((dst_width * (dst_BPP / 8)) >= 192)) {
+               /*
+                * Perform the ROP2 operation in chunks of (xWidth *
+                * dst_height)
+                */
+               while (1) {
+                       deWaitForNotBusy();
+
+                       SMTC_write2Dreg(DE_SOURCE,
+                               FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+                               FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
+                               FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
+
+                       SMTC_write2Dreg(DE_DESTINATION,
+                               FIELD_SET(0, DE_DESTINATION, WRAP,
+                                 DISABLE) | FIELD_VALUE(0,
+                                                        DE_DESTINATION,
+                                                        X,
+                                                        dst_X)
+                       | FIELD_VALUE(0, DE_DESTINATION, Y,
+                                                     dst_Y));
+
+                       SMTC_write2Dreg(DE_DIMENSION,
+                               FIELD_VALUE(0, DE_DIMENSION, X,
+                                   xWidth) | FIELD_VALUE(0,
+                                                         DE_DIMENSION,
+                                                         Y_ET,
+                                                         dst_height));
+
+                       de_ctrl =
+                           FIELD_VALUE(0, DE_CONTROL, ROP,
+                               nROP2) | nTransparent | FIELD_SET(0,
+                                                         DE_CONTROL,
+                                                         ROP_SELECT,
+                                                         ROP2)
+                           | FIELD_SET(0, DE_CONTROL, COMMAND,
+                               BITBLT) | ((nDirection ==
+                                           1) ? FIELD_SET(0,
+                                                  DE_CONTROL,
+                                                  DIRECTION,
+                                                  RIGHT_TO_LEFT)
+                                          : FIELD_SET(0, DE_CONTROL,
+                                              DIRECTION,
+                                              LEFT_TO_RIGHT)) |
+                           FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+                       SMTC_write2Dreg(DE_CONTROL, de_ctrl);
+
+                       src_X += (opSign * xWidth);
+                       dst_X += (opSign * xWidth);
+                       dst_width -= xWidth;
+
+                       if (dst_width <= 0) {
+                               /* ROP2 operation is complete */
+                               break;
+                       }
+
+                       if (xWidth > dst_width)
+                               xWidth = dst_width;
+               }
+       } else {
+               deWaitForNotBusy();
+               SMTC_write2Dreg(DE_SOURCE,
+                       FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+                       FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
+                       FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
+
+               SMTC_write2Dreg(DE_DESTINATION,
+                       FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+                       FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
+                       FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
+
+               SMTC_write2Dreg(DE_DIMENSION,
+                       FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
+                       FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
+
+               de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, nROP2) |
+                   nTransparent |
+                   FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+                   FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+                   ((nDirection == 1) ? FIELD_SET(0, DE_CONTROL, DIRECTION,
+                                                  RIGHT_TO_LEFT)
+                    : FIELD_SET(0, DE_CONTROL, DIRECTION,
+                                LEFT_TO_RIGHT)) | FIELD_SET(0, DE_CONTROL,
+                                                            STATUS, START);
+               SMTC_write2Dreg(DE_CONTROL, de_ctrl);
+       }
+
+       smtc_de_busy = 1;
+}
+
+/*
+ * This function sets the pixel format that will apply to the 2D Engine.
+ */
+void deSetPixelFormat(unsigned long bpp)
+{
+       unsigned long de_format;
+
+       de_format = SMTC_read2Dreg(DE_STRETCH_FORMAT);
+
+       switch (bpp) {
+       case 8:
+               de_format =
+                   FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8);
+               break;
+       default:
+       case 16:
+               de_format =
+                   FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16);
+               break;
+       case 32:
+               de_format =
+                   FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32);
+               break;
+       }
+
+       SMTC_write2Dreg(DE_STRETCH_FORMAT, de_format);
+}
+
+/*
+ * System memory to Video memory monochrome expansion.
+ *
+ * Source is monochrome image in system memory.  This function expands the
+ * monochrome data to color image in video memory.
+ */
+
+long deSystemMem2VideoMemMonoBlt(const char *pSrcbuf,
+                                long srcDelta,
+                                unsigned long startBit,
+                                unsigned long dBase,
+                                unsigned long dPitch,
+                                unsigned long bpp,
+                                unsigned long dx, unsigned long dy,
+                                unsigned long width, unsigned long height,
+                                unsigned long fColor,
+                                unsigned long bColor,
+                                unsigned long rop2) {
+       unsigned long bytePerPixel;
+       unsigned long ulBytesPerScan;
+       unsigned long ul4BytesPerScan;
+       unsigned long ulBytesRemain;
+       unsigned long de_ctrl = 0;
+       unsigned char ajRemain[4];
+       long i, j;
+
+       bytePerPixel = bpp / 8;
+
+       /* Just make sure the start bit is within legal range */
+       startBit &= 7;
+
+       ulBytesPerScan = (width + startBit + 7) / 8;
+       ul4BytesPerScan = ulBytesPerScan & ~3;
+       ulBytesRemain = ulBytesPerScan & 3;
+
+       if (smtc_de_busy)
+               deWaitForNotBusy();
+
+       /*
+        * 2D Source Base.  Use 0 for HOST Blt.
+        */
+
+       SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, 0);
+
+       /*
+        * 2D Destination Base.
+        *
+        * It is an address offset (128 bit aligned) from the beginning of
+        * frame buffer.
+        */
+
+       SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, dBase);
+
+       if (dPitch) {
+
+               /*
+                * Program pitch (distance between the 1st points of two
+                * adjacent lines).
+                *
+                * Note that input pitch is BYTE value, but the 2D Pitch
+                * register uses pixel values. Need Byte to pixel convertion.
+                */
+
+               SMTC_write2Dreg(DE_PITCH,
+                       FIELD_VALUE(0, DE_PITCH, DESTINATION,
+                           dPitch /
+                           bytePerPixel) | FIELD_VALUE(0,
+                                                       DE_PITCH,
+                                                       SOURCE,
+                                                       dPitch /
+                                                       bytePerPixel));
+
+               /* Screen Window width in Pixels.
+                *
+                * 2D engine uses this value to calculate the linear address in
+                * frame buffer for a given point.
+                */
+
+               SMTC_write2Dreg(DE_WINDOW_WIDTH,
+                       FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+                           (dPitch /
+                            bytePerPixel)) | FIELD_VALUE(0,
+                                                         DE_WINDOW_WIDTH,
+                                                         SOURCE,
+                                                         (dPitch
+                                                          /
+                                                          bytePerPixel)));
+       }
+       /* Note: For 2D Source in Host Write, only X_K1 field is needed, and
+        * Y_K2 field is not used. For mono bitmap, use startBit for X_K1.
+        */
+
+       SMTC_write2Dreg(DE_SOURCE,
+                       FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+                       FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) |
+                       FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));
+
+       SMTC_write2Dreg(DE_DESTINATION,
+                       FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+                       FIELD_VALUE(0, DE_DESTINATION, X, dx) |
+                       FIELD_VALUE(0, DE_DESTINATION, Y, dy));
+
+       SMTC_write2Dreg(DE_DIMENSION,
+                       FIELD_VALUE(0, DE_DIMENSION, X, width) |
+                       FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+       SMTC_write2Dreg(DE_FOREGROUND, fColor);
+       SMTC_write2Dreg(DE_BACKGROUND, bColor);
+
+       if (bpp)
+               deSetPixelFormat(bpp);
+       /* Set the pixel format of the destination */
+
+       de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+           FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+           FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
+           FIELD_SET(0, DE_CONTROL, HOST, MONO) |
+           FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+       SMTC_write2Dreg(DE_CONTROL, de_ctrl | deGetTransparency());
+
+       /* Write MONO data (line by line) to 2D Engine data port */
+       for (i = 0; i < height; i++) {
+               /* For each line, send the data in chunks of 4 bytes */
+               for (j = 0; j < (ul4BytesPerScan / 4); j++)
+                       SMTC_write2Ddataport(0,
+                                            *(unsigned long *)(pSrcbuf +
+                                                               (j * 4)));
+
+               if (ulBytesRemain) {
+                       memcpy(ajRemain, pSrcbuf + ul4BytesPerScan,
+                              ulBytesRemain);
+                       SMTC_write2Ddataport(0, *(unsigned long *)ajRemain);
+               }
+
+               pSrcbuf += srcDelta;
+       }
+       smtc_de_busy = 1;
+
+       return 0;
+}
+
+/*
+ * This function gets the transparency status from DE_CONTROL register.
+ * It returns a double word with the transparent fields properly set,
+ * while other fields are 0.
+ */
+unsigned long deGetTransparency(void)
+{
+       unsigned long de_ctrl;
+
+       de_ctrl = SMTC_read2Dreg(DE_CONTROL);
+
+       de_ctrl &=
+           FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
+           FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) |
+           FIELD_MASK(DE_CONTROL_TRANSPARENCY);
+
+       return de_ctrl;
+}
diff --git a/drivers/staging/sm7xx/smtc2d.h b/drivers/staging/sm7xx/smtc2d.h
new file mode 100644 (file)
index 0000000..38d0c33
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * Silicon Motion SM712 2D drawing engine functions.
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Author: Ge Wang, gewang@siliconmotion.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzj@lemote.com
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#ifndef NULL
+#define NULL    0
+#endif
+
+/* Internal macros */
+
+#define _F_START(f)            (0 ? f)
+#define _F_END(f)              (1 ? f)
+#define _F_SIZE(f)             (1 + _F_END(f) - _F_START(f))
+#define _F_MASK(f)             (((1ULL << _F_SIZE(f)) - 1) << _F_START(f))
+#define _F_NORMALIZE(v, f)     (((v) & _F_MASK(f)) >> _F_START(f))
+#define _F_DENORMALIZE(v, f)   (((v) << _F_START(f)) & _F_MASK(f))
+
+/* Global macros */
+
+#define FIELD_GET(x, reg, field) \
+( \
+    _F_NORMALIZE((x), reg ## _ ## field) \
+)
+
+#define FIELD_SET(x, reg, field, value) \
+( \
+    (x & ~_F_MASK(reg ## _ ## field)) \
+    | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \
+)
+
+#define FIELD_VALUE(x, reg, field, value) \
+( \
+    (x & ~_F_MASK(reg ## _ ## field)) \
+    | _F_DENORMALIZE(value, reg ## _ ## field) \
+)
+
+#define FIELD_CLEAR(reg, field) \
+( \
+    ~_F_MASK(reg ## _ ## field) \
+)
+
+/* Field Macros                        */
+
+#define FIELD_START(field)     (0 ? field)
+#define FIELD_END(field)       (1 ? field)
+#define FIELD_SIZE(field) \
+       (1 + FIELD_END(field) - FIELD_START(field))
+
+#define FIELD_MASK(field) \
+       (((1 << (FIELD_SIZE(field)-1)) \
+       | ((1 << (FIELD_SIZE(field)-1)) - 1)) \
+       << FIELD_START(field))
+
+#define FIELD_NORMALIZE(reg, field) \
+       (((reg) & FIELD_MASK(field)) >> FIELD_START(field))
+
+#define FIELD_DENORMALIZE(field, value) \
+       (((value) << FIELD_START(field)) & FIELD_MASK(field))
+
+#define FIELD_INIT(reg, field, value) \
+       FIELD_DENORMALIZE(reg ## _ ## field, \
+               reg ## _ ## field ## _ ## value)
+
+#define FIELD_INIT_VAL(reg, field, value) \
+       (FIELD_DENORMALIZE(reg ## _ ## field, value))
+
+#define FIELD_VAL_SET(x, r, f, v) ({ \
+       x = (x & ~FIELD_MASK(r ## _ ## f)) \
+       | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) \
+})
+
+#define RGB(r, g, b)   ((unsigned long)(((r) << 16) | ((g) << 8) | (b)))
+
+/* Transparent info definition */
+typedef struct {
+       unsigned long match;    /* Matching pixel is OPAQUE/TRANSPARENT */
+       unsigned long select;   /* Transparency controlled by SRC/DST */
+       unsigned long control;  /* ENABLE/DISABLE transparency */
+       unsigned long color;    /* Transparent color */
+} Transparent, *pTransparent;
+
+#define PIXEL_DEPTH_1_BP       0       /* 1 bit per pixel */
+#define PIXEL_DEPTH_8_BPP      1       /* 8 bits per pixel */
+#define PIXEL_DEPTH_16_BPP     2       /* 16 bits per pixel */
+#define PIXEL_DEPTH_32_BPP     3       /* 32 bits per pixel */
+#define PIXEL_DEPTH_YUV422     8       /* 16 bits per pixel YUV422 */
+#define PIXEL_DEPTH_YUV420     9       /* 16 bits per pixel YUV420 */
+
+#define PATTERN_WIDTH          8
+#define PATTERN_HEIGHT         8
+
+#define        TOP_TO_BOTTOM           0
+#define        BOTTOM_TO_TOP           1
+#define RIGHT_TO_LEFT          BOTTOM_TO_TOP
+#define LEFT_TO_RIGHT          TOP_TO_BOTTOM
+
+/* Constants used in Transparent structure */
+#define MATCH_OPAQUE           0x00000000
+#define MATCH_TRANSPARENT      0x00000400
+#define SOURCE                 0x00000000
+#define DESTINATION            0x00000200
+
+/* 2D registers. */
+
+#define        DE_SOURCE                       0x000000
+#define        DE_SOURCE_WRAP                  31 : 31
+#define        DE_SOURCE_WRAP_DISABLE          0
+#define        DE_SOURCE_WRAP_ENABLE           1
+#define        DE_SOURCE_X_K1                  29 : 16
+#define        DE_SOURCE_Y_K2                  15 : 0
+
+#define        DE_DESTINATION                  0x000004
+#define        DE_DESTINATION_WRAP             31 : 31
+#define        DE_DESTINATION_WRAP_DISABLE     0
+#define        DE_DESTINATION_WRAP_ENABLE      1
+#define        DE_DESTINATION_X                28 : 16
+#define        DE_DESTINATION_Y                15 : 0
+
+#define        DE_DIMENSION                    0x000008
+#define        DE_DIMENSION_X                  28 : 16
+#define        DE_DIMENSION_Y_ET               15 : 0
+
+#define        DE_CONTROL                      0x00000C
+#define        DE_CONTROL_STATUS               31 : 31
+#define        DE_CONTROL_STATUS_STOP          0
+#define        DE_CONTROL_STATUS_START         1
+#define        DE_CONTROL_PATTERN              30 : 30
+#define        DE_CONTROL_PATTERN_MONO         0
+#define        DE_CONTROL_PATTERN_COLOR        1
+#define        DE_CONTROL_UPDATE_DESTINATION_X         29 : 29
+#define        DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0
+#define        DE_CONTROL_UPDATE_DESTINATION_X_ENABLE  1
+#define        DE_CONTROL_QUICK_START                  28 : 28
+#define        DE_CONTROL_QUICK_START_DISABLE          0
+#define        DE_CONTROL_QUICK_START_ENABLE           1
+#define        DE_CONTROL_DIRECTION                    27 : 27
+#define        DE_CONTROL_DIRECTION_LEFT_TO_RIGHT      0
+#define        DE_CONTROL_DIRECTION_RIGHT_TO_LEFT      1
+#define        DE_CONTROL_MAJOR                        26 : 26
+#define        DE_CONTROL_MAJOR_X                      0
+#define        DE_CONTROL_MAJOR_Y                      1
+#define        DE_CONTROL_STEP_X                       25 : 25
+#define        DE_CONTROL_STEP_X_POSITIVE              1
+#define        DE_CONTROL_STEP_X_NEGATIVE              0
+#define        DE_CONTROL_STEP_Y                       24 : 24
+#define        DE_CONTROL_STEP_Y_POSITIVE              1
+#define        DE_CONTROL_STEP_Y_NEGATIVE              0
+#define        DE_CONTROL_STRETCH                      23 : 23
+#define        DE_CONTROL_STRETCH_DISABLE              0
+#define        DE_CONTROL_STRETCH_ENABLE               1
+#define        DE_CONTROL_HOST                         22 : 22
+#define        DE_CONTROL_HOST_COLOR                   0
+#define        DE_CONTROL_HOST_MONO                    1
+#define        DE_CONTROL_LAST_PIXEL                   21 : 21
+#define        DE_CONTROL_LAST_PIXEL_OFF               0
+#define        DE_CONTROL_LAST_PIXEL_ON                1
+#define        DE_CONTROL_COMMAND                      20 : 16
+#define        DE_CONTROL_COMMAND_BITBLT               0
+#define        DE_CONTROL_COMMAND_RECTANGLE_FILL       1
+#define        DE_CONTROL_COMMAND_DE_TILE              2
+#define        DE_CONTROL_COMMAND_TRAPEZOID_FILL       3
+#define        DE_CONTROL_COMMAND_ALPHA_BLEND          4
+#define        DE_CONTROL_COMMAND_RLE_STRIP            5
+#define        DE_CONTROL_COMMAND_SHORT_STROKE         6
+#define        DE_CONTROL_COMMAND_LINE_DRAW            7
+#define        DE_CONTROL_COMMAND_HOST_WRITE           8
+#define        DE_CONTROL_COMMAND_HOST_READ            9
+#define        DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10
+#define        DE_CONTROL_COMMAND_ROTATE               11
+#define        DE_CONTROL_COMMAND_FONT                 12
+#define        DE_CONTROL_COMMAND_TEXTURE_LOAD         15
+#define        DE_CONTROL_ROP_SELECT                   15 : 15
+#define        DE_CONTROL_ROP_SELECT_ROP3              0
+#define        DE_CONTROL_ROP_SELECT_ROP2              1
+#define        DE_CONTROL_ROP2_SOURCE                  14 : 14
+#define        DE_CONTROL_ROP2_SOURCE_BITMAP           0
+#define        DE_CONTROL_ROP2_SOURCE_PATTERN          1
+#define        DE_CONTROL_MONO_DATA                    13 : 12
+#define        DE_CONTROL_MONO_DATA_NOT_PACKED         0
+#define        DE_CONTROL_MONO_DATA_8_PACKED           1
+#define        DE_CONTROL_MONO_DATA_16_PACKED          2
+#define        DE_CONTROL_MONO_DATA_32_PACKED          3
+#define        DE_CONTROL_REPEAT_ROTATE                11 : 11
+#define        DE_CONTROL_REPEAT_ROTATE_DISABLE        0
+#define        DE_CONTROL_REPEAT_ROTATE_ENABLE         1
+#define        DE_CONTROL_TRANSPARENCY_MATCH           10 : 10
+#define        DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE            0
+#define        DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT       1
+#define        DE_CONTROL_TRANSPARENCY_SELECT                  9 : 9
+#define        DE_CONTROL_TRANSPARENCY_SELECT_SOURCE           0
+#define        DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION      1
+#define        DE_CONTROL_TRANSPARENCY                         8 : 8
+#define        DE_CONTROL_TRANSPARENCY_DISABLE                 0
+#define        DE_CONTROL_TRANSPARENCY_ENABLE                  1
+#define        DE_CONTROL_ROP                                  7 : 0
+
+/* Pseudo fields. */
+
+#define        DE_CONTROL_SHORT_STROKE_DIR                     27 : 24
+#define        DE_CONTROL_SHORT_STROKE_DIR_225                 0
+#define        DE_CONTROL_SHORT_STROKE_DIR_135                 1
+#define        DE_CONTROL_SHORT_STROKE_DIR_315                 2
+#define        DE_CONTROL_SHORT_STROKE_DIR_45                  3
+#define        DE_CONTROL_SHORT_STROKE_DIR_270                 4
+#define        DE_CONTROL_SHORT_STROKE_DIR_90                  5
+#define        DE_CONTROL_SHORT_STROKE_DIR_180                 8
+#define        DE_CONTROL_SHORT_STROKE_DIR_0                   10
+#define        DE_CONTROL_ROTATION                             25 : 24
+#define        DE_CONTROL_ROTATION_0                           0
+#define        DE_CONTROL_ROTATION_270                         1
+#define        DE_CONTROL_ROTATION_90                          2
+#define        DE_CONTROL_ROTATION_180                         3
+
+#define        DE_PITCH                                        0x000010
+#define        DE_PITCH_DESTINATION                            28 : 16
+#define        DE_PITCH_SOURCE                                 12 : 0
+
+#define        DE_FOREGROUND                                   0x000014
+#define        DE_FOREGROUND_COLOR                             31 : 0
+
+#define        DE_BACKGROUND                                   0x000018
+#define        DE_BACKGROUND_COLOR                             31 : 0
+
+#define        DE_STRETCH_FORMAT                               0x00001C
+#define        DE_STRETCH_FORMAT_PATTERN_XY                    30 : 30
+#define        DE_STRETCH_FORMAT_PATTERN_XY_NORMAL             0
+#define        DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE          1
+#define        DE_STRETCH_FORMAT_PATTERN_Y                     29 : 27
+#define        DE_STRETCH_FORMAT_PATTERN_X                     25 : 23
+#define        DE_STRETCH_FORMAT_PIXEL_FORMAT                  21 : 20
+#define        DE_STRETCH_FORMAT_PIXEL_FORMAT_8                0
+#define        DE_STRETCH_FORMAT_PIXEL_FORMAT_16               1
+#define        DE_STRETCH_FORMAT_PIXEL_FORMAT_24               3
+#define        DE_STRETCH_FORMAT_PIXEL_FORMAT_32               2
+#define        DE_STRETCH_FORMAT_ADDRESSING                    19 : 16
+#define        DE_STRETCH_FORMAT_ADDRESSING_XY                 0
+#define        DE_STRETCH_FORMAT_ADDRESSING_LINEAR             15
+#define        DE_STRETCH_FORMAT_SOURCE_HEIGHT                 11 : 0
+
+#define        DE_COLOR_COMPARE                                0x000020
+#define        DE_COLOR_COMPARE_COLOR                          23 : 0
+
+#define        DE_COLOR_COMPARE_MASK                           0x000024
+#define        DE_COLOR_COMPARE_MASK_MASKS                     23 : 0
+
+#define        DE_MASKS                                        0x000028
+#define        DE_MASKS_BYTE_MASK                              31 : 16
+#define        DE_MASKS_BIT_MASK                               15 : 0
+
+#define        DE_CLIP_TL                                      0x00002C
+#define        DE_CLIP_TL_TOP                                  31 : 16
+#define        DE_CLIP_TL_STATUS                               13 : 13
+#define        DE_CLIP_TL_STATUS_DISABLE                       0
+#define        DE_CLIP_TL_STATUS_ENABLE                        1
+#define        DE_CLIP_TL_INHIBIT                              12 : 12
+#define        DE_CLIP_TL_INHIBIT_OUTSIDE                      0
+#define        DE_CLIP_TL_INHIBIT_INSIDE                       1
+#define        DE_CLIP_TL_LEFT                                 11 : 0
+
+#define        DE_CLIP_BR                                      0x000030
+#define        DE_CLIP_BR_BOTTOM                               31 : 16
+#define        DE_CLIP_BR_RIGHT                                12 : 0
+
+#define        DE_MONO_PATTERN_LOW                             0x000034
+#define        DE_MONO_PATTERN_LOW_PATTERN                     31 : 0
+
+#define        DE_MONO_PATTERN_HIGH                            0x000038
+#define        DE_MONO_PATTERN_HIGH_PATTERN                    31 : 0
+
+#define        DE_WINDOW_WIDTH                                 0x00003C
+#define        DE_WINDOW_WIDTH_DESTINATION                     28 : 16
+#define        DE_WINDOW_WIDTH_SOURCE                          12 : 0
+
+#define        DE_WINDOW_SOURCE_BASE                           0x000040
+#define        DE_WINDOW_SOURCE_BASE_EXT                       27 : 27
+#define        DE_WINDOW_SOURCE_BASE_EXT_LOCAL                 0
+#define        DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL              1
+#define        DE_WINDOW_SOURCE_BASE_CS                        26 : 26
+#define        DE_WINDOW_SOURCE_BASE_CS_0                      0
+#define        DE_WINDOW_SOURCE_BASE_CS_1                      1
+#define        DE_WINDOW_SOURCE_BASE_ADDRESS                   25 : 0
+
+#define        DE_WINDOW_DESTINATION_BASE                      0x000044
+#define        DE_WINDOW_DESTINATION_BASE_EXT                  27 : 27
+#define        DE_WINDOW_DESTINATION_BASE_EXT_LOCAL            0
+#define        DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL         1
+#define        DE_WINDOW_DESTINATION_BASE_CS                   26 : 26
+#define        DE_WINDOW_DESTINATION_BASE_CS_0                 0
+#define        DE_WINDOW_DESTINATION_BASE_CS_1                 1
+#define        DE_WINDOW_DESTINATION_BASE_ADDRESS              25 : 0
+
+#define        DE_ALPHA                                        0x000048
+#define        DE_ALPHA_VALUE                                  7 : 0
+
+#define        DE_WRAP                                         0x00004C
+#define        DE_WRAP_X                                       31 : 16
+#define        DE_WRAP_Y                                       15 : 0
+
+#define        DE_STATUS                                       0x000050
+#define        DE_STATUS_CSC                                   1 : 1
+#define        DE_STATUS_CSC_CLEAR                             0
+#define        DE_STATUS_CSC_NOT_ACTIVE                        0
+#define        DE_STATUS_CSC_ACTIVE                            1
+#define        DE_STATUS_2D                                    0 : 0
+#define        DE_STATUS_2D_CLEAR                              0
+#define        DE_STATUS_2D_NOT_ACTIVE                         0
+#define        DE_STATUS_2D_ACTIVE                             1
+
+/* Color Space Conversion registers. */
+
+#define        CSC_Y_SOURCE_BASE                               0x0000C8
+#define        CSC_Y_SOURCE_BASE_EXT                           27 : 27
+#define        CSC_Y_SOURCE_BASE_EXT_LOCAL                     0
+#define        CSC_Y_SOURCE_BASE_EXT_EXTERNAL                  1
+#define        CSC_Y_SOURCE_BASE_CS                            26 : 26
+#define        CSC_Y_SOURCE_BASE_CS_0                          0
+#define        CSC_Y_SOURCE_BASE_CS_1                          1
+#define        CSC_Y_SOURCE_BASE_ADDRESS                       25 : 0
+
+#define        CSC_CONSTANTS                                   0x0000CC
+#define        CSC_CONSTANTS_Y                                 31 : 24
+#define        CSC_CONSTANTS_R                                 23 : 16
+#define        CSC_CONSTANTS_G                                 15 : 8
+#define        CSC_CONSTANTS_B                                 7 : 0
+
+#define        CSC_Y_SOURCE_X                                  0x0000D0
+#define        CSC_Y_SOURCE_X_INTEGER                          26 : 16
+#define        CSC_Y_SOURCE_X_FRACTION                         15 : 3
+
+#define        CSC_Y_SOURCE_Y                                  0x0000D4
+#define        CSC_Y_SOURCE_Y_INTEGER                          27 : 16
+#define        CSC_Y_SOURCE_Y_FRACTION                         15 : 3
+
+#define        CSC_U_SOURCE_BASE                               0x0000D8
+#define        CSC_U_SOURCE_BASE_EXT                           27 : 27
+#define        CSC_U_SOURCE_BASE_EXT_LOCAL                     0
+#define        CSC_U_SOURCE_BASE_EXT_EXTERNAL                  1
+#define        CSC_U_SOURCE_BASE_CS                            26 : 26
+#define        CSC_U_SOURCE_BASE_CS_0                          0
+#define        CSC_U_SOURCE_BASE_CS_1                          1
+#define        CSC_U_SOURCE_BASE_ADDRESS                       25 : 0
+
+#define        CSC_V_SOURCE_BASE                               0x0000DC
+#define        CSC_V_SOURCE_BASE_EXT                           27 : 27
+#define        CSC_V_SOURCE_BASE_EXT_LOCAL                     0
+#define        CSC_V_SOURCE_BASE_EXT_EXTERNAL                  1
+#define        CSC_V_SOURCE_BASE_CS                            26 : 26
+#define        CSC_V_SOURCE_BASE_CS_0                          0
+#define        CSC_V_SOURCE_BASE_CS_1                          1
+#define        CSC_V_SOURCE_BASE_ADDRESS                       25 : 0
+
+#define        CSC_SOURCE_DIMENSION                            0x0000E0
+#define        CSC_SOURCE_DIMENSION_X                          31 : 16
+#define        CSC_SOURCE_DIMENSION_Y                          15 : 0
+
+#define        CSC_SOURCE_PITCH                                0x0000E4
+#define        CSC_SOURCE_PITCH_Y                              31 : 16
+#define        CSC_SOURCE_PITCH_UV                             15 : 0
+
+#define        CSC_DESTINATION                                 0x0000E8
+#define        CSC_DESTINATION_WRAP                            31 : 31
+#define        CSC_DESTINATION_WRAP_DISABLE                    0
+#define        CSC_DESTINATION_WRAP_ENABLE                     1
+#define        CSC_DESTINATION_X                               27 : 16
+#define        CSC_DESTINATION_Y                               11 : 0
+
+#define        CSC_DESTINATION_DIMENSION                       0x0000EC
+#define        CSC_DESTINATION_DIMENSION_X                     31 : 16
+#define        CSC_DESTINATION_DIMENSION_Y                     15 : 0
+
+#define        CSC_DESTINATION_PITCH                           0x0000F0
+#define        CSC_DESTINATION_PITCH_X                         31 : 16
+#define        CSC_DESTINATION_PITCH_Y                         15 : 0
+
+#define        CSC_SCALE_FACTOR                                0x0000F4
+#define        CSC_SCALE_FACTOR_HORIZONTAL                     31 : 16
+#define        CSC_SCALE_FACTOR_VERTICAL                       15 : 0
+
+#define        CSC_DESTINATION_BASE                            0x0000F8
+#define        CSC_DESTINATION_BASE_EXT                        27 : 27
+#define        CSC_DESTINATION_BASE_EXT_LOCAL                  0
+#define        CSC_DESTINATION_BASE_EXT_EXTERNAL               1
+#define        CSC_DESTINATION_BASE_CS                         26 : 26
+#define        CSC_DESTINATION_BASE_CS_0                       0
+#define        CSC_DESTINATION_BASE_CS_1                       1
+#define        CSC_DESTINATION_BASE_ADDRESS                    25 : 0
+
+#define        CSC_CONTROL                                     0x0000FC
+#define        CSC_CONTROL_STATUS                              31 : 31
+#define        CSC_CONTROL_STATUS_STOP                         0
+#define        CSC_CONTROL_STATUS_START                        1
+#define        CSC_CONTROL_SOURCE_FORMAT                       30 : 28
+#define        CSC_CONTROL_SOURCE_FORMAT_YUV422                0
+#define        CSC_CONTROL_SOURCE_FORMAT_YUV420I               1
+#define        CSC_CONTROL_SOURCE_FORMAT_YUV420                2
+#define        CSC_CONTROL_SOURCE_FORMAT_YVU9                  3
+#define        CSC_CONTROL_SOURCE_FORMAT_IYU1                  4
+#define        CSC_CONTROL_SOURCE_FORMAT_IYU2                  5
+#define        CSC_CONTROL_SOURCE_FORMAT_RGB565                6
+#define        CSC_CONTROL_SOURCE_FORMAT_RGB8888               7
+#define        CSC_CONTROL_DESTINATION_FORMAT                  27 : 26
+#define        CSC_CONTROL_DESTINATION_FORMAT_RGB565           0
+#define        CSC_CONTROL_DESTINATION_FORMAT_RGB8888          1
+#define        CSC_CONTROL_HORIZONTAL_FILTER                   25 : 25
+#define        CSC_CONTROL_HORIZONTAL_FILTER_DISABLE           0
+#define        CSC_CONTROL_HORIZONTAL_FILTER_ENABLE            1
+#define        CSC_CONTROL_VERTICAL_FILTER                     24 : 24
+#define        CSC_CONTROL_VERTICAL_FILTER_DISABLE             0
+#define        CSC_CONTROL_VERTICAL_FILTER_ENABLE              1
+#define        CSC_CONTROL_BYTE_ORDER                          23 : 23
+#define        CSC_CONTROL_BYTE_ORDER_YUYV                     0
+#define        CSC_CONTROL_BYTE_ORDER_UYVY                     1
+
+#define        DE_DATA_PORT_501                                0x110000
+#define        DE_DATA_PORT_712                                0x400000
+#define        DE_DATA_PORT_722                                0x6000
+
+/* point to virtual Memory Map IO starting address */
+extern char *smtc_RegBaseAddress;
+/* point to virtual video memory starting address */
+extern char *smtc_VRAMBaseAddress;
+extern unsigned char smtc_de_busy;
+
+extern unsigned long memRead32(unsigned long nOffset);
+extern void memWrite32(unsigned long nOffset, unsigned long nData);
+extern unsigned long SMTC_read2Dreg(unsigned long nOffset);
+
+/* 2D functions */
+extern void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
+                  unsigned int bpp);
+
+extern void deWaitForNotBusy(void);
+
+extern void deVerticalLine(unsigned long dst_base,
+       unsigned long dst_pitch,
+       unsigned long nX,
+       unsigned long nY,
+       unsigned long dst_height,
+       unsigned long nColor);
+
+extern void deHorizontalLine(unsigned long dst_base,
+       unsigned long dst_pitch,
+       unsigned long nX,
+       unsigned long nY,
+       unsigned long dst_width,
+       unsigned long nColor);
+
+extern void deLine(unsigned long dst_base,
+       unsigned long dst_pitch,
+       unsigned long nX1,
+       unsigned long nY1,
+       unsigned long nX2,
+       unsigned long nY2,
+       unsigned long nColor);
+
+extern void deFillRect(unsigned long dst_base,
+       unsigned long dst_pitch,
+       unsigned long dst_X,
+       unsigned long dst_Y,
+       unsigned long dst_width,
+       unsigned long dst_height,
+       unsigned long nColor);
+
+extern void deRotatePattern(unsigned char *pattern_dstaddr,
+       unsigned long pattern_src_addr,
+       unsigned long pattern_BPP,
+       unsigned long pattern_stride,
+       int     patternX,
+       int     patternY);
+
+extern void deCopy(unsigned long dst_base,
+       unsigned long dst_pitch,
+       unsigned long dst_BPP,
+       unsigned long dst_X,
+       unsigned long dst_Y,
+       unsigned long dst_width,
+       unsigned long dst_height,
+       unsigned long src_base,
+       unsigned long src_pitch,
+       unsigned long src_X,
+       unsigned long src_Y,
+       pTransparent    pTransp,
+       unsigned char nROP2);
+
+/*
+ * System memory to Video memory monochrome expansion.
+ *
+ * Source is monochrome image in system memory.  This function expands the
+ * monochrome data to color image in video memory.
+ *
+ * @pSrcbuf: pointer to start of source buffer in system memory
+ * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top
+ *             down and -ive mean button up
+ * @startBit: Mono data can start at any bit in a byte, this value should
+ *             be 0 to 7
+ * @dBase: Address of destination :  offset in frame buffer
+ * @dPitch: Pitch value of destination surface in BYTE
+ * @bpp: Color depth of destination surface
+ * @dx, dy: Starting coordinate of destination surface
+ * @width, height: width and height of rectange in pixel value
+ * @fColor,bColor: Foreground, Background color (corresponding to a 1, 0 in
+ *     the monochrome data)
+ * @rop2: ROP value
+ */
+
+extern long deSystemMem2VideoMemMonoBlt(
+       const char *pSrcbuf,
+       long srcDelta,
+       unsigned long startBit,
+       unsigned long dBase,
+       unsigned long dPitch,
+       unsigned long bpp,
+       unsigned long dx, unsigned long dy,
+       unsigned long width, unsigned long height,
+       unsigned long fColor,
+       unsigned long bColor,
+       unsigned long rop2);
+
+extern unsigned long deGetTransparency(void);
+extern void deSetPixelFormat(unsigned long bpp);
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
new file mode 100644 (file)
index 0000000..161dbc9
--- /dev/null
@@ -0,0 +1,1253 @@
+/*
+ * Silicon Motion SM7XX frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors: Ge Wang, gewang@siliconmotion.com
+ *         Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzj@lemote.com
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ * Version 0.10.26192.21.01
+ *     - Add PowerPC/Big endian support
+ *     - Add 2D support for Lynx
+ *     - Verified on2.6.19.2  Boyod.yang <boyod.yang@siliconmotion.com.cn>
+ *
+ * Version 0.09.2621.00.01
+ *     - Only support Linux Kernel's version 2.6.21.
+ *     Boyod.yang  <boyod.yang@siliconmotion.com.cn>
+ *
+ * Version 0.09
+ *     - Only support Linux Kernel's version 2.6.12.
+ *     Boyod.yang <boyod.yang@siliconmotion.com.cn>
+ */
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+struct screen_info smtc_screen_info;
+
+#include "smtcfb.h"
+#include "smtc2d.h"
+
+#ifdef DEBUG
+#define smdbg(format, arg...)  printk(KERN_DEBUG format , ## arg)
+#else
+#define smdbg(format, arg...)
+#endif
+
+/*
+* Private structure
+*/
+struct smtcfb_info {
+       /*
+        * The following is a pointer to be passed into the
+        * functions below.  The modules outside the main
+        * voyager.c driver have no knowledge as to what
+        * is within this structure.
+        */
+       struct fb_info fb;
+       struct display_switch *dispsw;
+       struct pci_dev *dev;
+       signed int currcon;
+
+       struct {
+               u8 red, green, blue;
+       } palette[NR_RGB];
+
+       u_int palette_size;
+};
+
+struct par_info {
+       /*
+        * Hardware
+        */
+       u16 chipID;
+       unsigned char __iomem *m_pMMIO;
+       char __iomem *m_pLFB;
+       char *m_pDPR;
+       char *m_pVPR;
+       char *m_pCPR;
+
+       u_int width;
+       u_int height;
+       u_int hz;
+       u_long BaseAddressInVRAM;
+       u8 chipRevID;
+};
+
+struct vesa_mode_table {
+       char mode_index[6];
+       u16 lfb_width;
+       u16 lfb_height;
+       u16 lfb_depth;
+};
+
+static struct vesa_mode_table vesa_mode[] = {
+       {"0x301", 640,  480,  8},
+       {"0x303", 800,  600,  8},
+       {"0x305", 1024, 768,    8},
+       {"0x307", 1280, 1024, 8},
+
+       {"0x311", 640,  480,  16},
+       {"0x314", 800,  600,  16},
+       {"0x317", 1024, 768,    16},
+       {"0x31A", 1280, 1024, 16},
+
+       {"0x312", 640,  480,  24},
+       {"0x315", 800,  600,  24},
+       {"0x318", 1024, 768,    24},
+       {"0x31B", 1280, 1024, 24},
+};
+
+char __iomem *smtc_RegBaseAddress;     /* Memory Map IO starting address */
+char __iomem *smtc_VRAMBaseAddress;    /* video memory starting address */
+
+char *smtc_2DBaseAddress;      /* 2D engine starting address */
+char *smtc_2Ddataport;         /* 2D data port offset */
+short smtc_2Dacceleration;
+
+static u32 colreg[17];
+static struct par_info hw;     /* hardware information */
+
+u16 smtc_ChipIDs[] = {
+       0x710,
+       0x712,
+       0x720
+};
+
+#define numSMTCchipIDs (sizeof(smtc_ChipIDs) / sizeof(u16))
+
+void deWaitForNotBusy(void)
+{
+       unsigned long i = 0x1000000;
+       while (i--) {
+               if ((smtc_seqr(0x16) & 0x18) == 0x10)
+                       break;
+       }
+       smtc_de_busy = 0;
+}
+
+static void sm712_set_timing(struct smtcfb_info *sfb,
+                            struct par_info *ppar_info)
+{
+       int i = 0, j = 0;
+       u32 m_nScreenStride;
+
+       smdbg("\nppar_info->width = %d ppar_info->height = %d"
+                       "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n",
+                       ppar_info->width, ppar_info->height,
+                       sfb->fb.var.bits_per_pixel, ppar_info->hz);
+
+       for (j = 0; j < numVGAModes; j++) {
+               if (VGAMode[j].mmSizeX == ppar_info->width &&
+                   VGAMode[j].mmSizeY == ppar_info->height &&
+                   VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
+                   VGAMode[j].hz == ppar_info->hz) {
+
+                       smdbg("\nVGAMode[j].mmSizeX  = %d VGAMode[j].mmSizeY ="
+                                       "%d VGAMode[j].bpp = %d"
+                                       "VGAMode[j].hz=%d\n",
+                                       VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
+                                       VGAMode[j].bpp, VGAMode[j].hz);
+
+                       smdbg("VGAMode index=%d\n", j);
+
+                       smtc_mmiowb(0x0, 0x3c6);
+
+                       smtc_seqw(0, 0x1);
+
+                       smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2);
+
+                       /* init SEQ register SR00 - SR04 */
+                       for (i = 0; i < SIZE_SR00_SR04; i++)
+                               smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]);
+
+                       /* init SEQ register SR10 - SR24 */
+                       for (i = 0; i < SIZE_SR10_SR24; i++)
+                               smtc_seqw(i + 0x10,
+                                         VGAMode[j].Init_SR10_SR24[i]);
+
+                       /* init SEQ register SR30 - SR75 */
+                       for (i = 0; i < SIZE_SR30_SR75; i++)
+                               if (((i + 0x30) != 0x62) \
+                                       && ((i + 0x30) != 0x6a) \
+                                       && ((i + 0x30) != 0x6b))
+                                       smtc_seqw(i + 0x30,
+                                               VGAMode[j].Init_SR30_SR75[i]);
+
+                       /* init SEQ register SR80 - SR93 */
+                       for (i = 0; i < SIZE_SR80_SR93; i++)
+                               smtc_seqw(i + 0x80,
+                                         VGAMode[j].Init_SR80_SR93[i]);
+
+                       /* init SEQ register SRA0 - SRAF */
+                       for (i = 0; i < SIZE_SRA0_SRAF; i++)
+                               smtc_seqw(i + 0xa0,
+                                         VGAMode[j].Init_SRA0_SRAF[i]);
+
+                       /* init Graphic register GR00 - GR08 */
+                       for (i = 0; i < SIZE_GR00_GR08; i++)
+                               smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]);
+
+                       /* init Attribute register AR00 - AR14 */
+                       for (i = 0; i < SIZE_AR00_AR14; i++)
+                               smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]);
+
+                       /* init CRTC register CR00 - CR18 */
+                       for (i = 0; i < SIZE_CR00_CR18; i++)
+                               smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]);
+
+                       /* init CRTC register CR30 - CR4D */
+                       for (i = 0; i < SIZE_CR30_CR4D; i++)
+                               smtc_crtcw(i + 0x30,
+                                          VGAMode[j].Init_CR30_CR4D[i]);
+
+                       /* init CRTC register CR90 - CRA7 */
+                       for (i = 0; i < SIZE_CR90_CRA7; i++)
+                               smtc_crtcw(i + 0x90,
+                                          VGAMode[j].Init_CR90_CRA7[i]);
+               }
+       }
+       smtc_mmiowb(0x67, 0x3c2);
+
+       /* set VPR registers */
+       writel(0x0, ppar_info->m_pVPR + 0x0C);
+       writel(0x0, ppar_info->m_pVPR + 0x40);
+
+       /* set data width */
+       m_nScreenStride =
+               (ppar_info->width * sfb->fb.var.bits_per_pixel) / 64;
+       switch (sfb->fb.var.bits_per_pixel) {
+       case 8:
+               writel(0x0, ppar_info->m_pVPR + 0x0);
+               break;
+       case 16:
+               writel(0x00020000, ppar_info->m_pVPR + 0x0);
+               break;
+       case 24:
+               writel(0x00040000, ppar_info->m_pVPR + 0x0);
+               break;
+       case 32:
+               writel(0x00030000, ppar_info->m_pVPR + 0x0);
+               break;
+       }
+       writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
+              ppar_info->m_pVPR + 0x10);
+
+}
+
+static void sm712_setpalette(int regno, unsigned red, unsigned green,
+                            unsigned blue, struct fb_info *info)
+{
+       struct par_info *cur_par = (struct par_info *)info->par;
+
+       if (cur_par->BaseAddressInVRAM)
+               /*
+                * second display palette for dual head. Enable CRT RAM, 6-bit
+                * RAM
+                */
+               smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x20);
+       else
+               /* primary display palette. Enable LCD RAM only, 6-bit RAM */
+               smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
+       smtc_mmiowb(regno, dac_reg);
+       smtc_mmiowb(red >> 10, dac_val);
+       smtc_mmiowb(green >> 10, dac_val);
+       smtc_mmiowb(blue >> 10, dac_val);
+}
+
+static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info
+               *ppar_info)
+{
+       switch (ppar_info->chipID) {
+       case 0x710:
+       case 0x712:
+       case 0x720:
+               sm712_set_timing(sfb, ppar_info);
+               break;
+       }
+}
+
+static struct fb_var_screeninfo smtcfb_var = {
+       .xres = 1024,
+       .yres = 600,
+       .xres_virtual = 1024,
+       .yres_virtual = 600,
+       .bits_per_pixel = 16,
+       .red = {16, 8, 0},
+       .green = {8, 8, 0},
+       .blue = {0, 8, 0},
+       .activate = FB_ACTIVATE_NOW,
+       .height = -1,
+       .width = -1,
+       .vmode = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo smtcfb_fix = {
+       .id = "sm712fb",
+       .type = FB_TYPE_PACKED_PIXELS,
+       .visual = FB_VISUAL_TRUECOLOR,
+       .line_length = 800 * 3,
+       .accel = FB_ACCEL_SMI_LYNX,
+};
+
+/* chan_to_field
+ *
+ * convert a colour value into a field position
+ *
+ * from pxafb.c
+ */
+
+static inline unsigned int chan_to_field(unsigned int chan,
+                                        struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+static int smtcfb_blank(int blank_mode, struct fb_info *info)
+{
+       /* clear DPMS setting */
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+               /* Screen On: HSync: On, VSync : On */
+               smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+               smtc_seqw(0x6a, 0x16);
+               smtc_seqw(0x6b, 0x02);
+               smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
+               smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+               smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+               smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+               smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
+               break;
+       case FB_BLANK_NORMAL:
+               /* Screen Off: HSync: On, VSync : On   Soft blank */
+               smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+               smtc_seqw(0x6a, 0x16);
+               smtc_seqw(0x6b, 0x02);
+               smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+               smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+               smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               /* Screen On: HSync: On, VSync : Off */
+               smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+               smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+               smtc_seqw(0x6a, 0x0c);
+               smtc_seqw(0x6b, 0x02);
+               smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+               smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
+               smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
+               smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+               smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               /* Screen On: HSync: Off, VSync : On */
+               smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+               smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+               smtc_seqw(0x6a, 0x0c);
+               smtc_seqw(0x6b, 0x02);
+               smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+               smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
+               smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+               smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+               smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+               break;
+       case FB_BLANK_POWERDOWN:
+               /* Screen On: HSync: Off, VSync : Off */
+               smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+               smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+               smtc_seqw(0x6a, 0x0c);
+               smtc_seqw(0x6b, 0x02);
+               smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+               smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
+               smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+               smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+               smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
+                         unsigned blue, unsigned trans, struct fb_info *info)
+{
+       struct smtcfb_info *sfb = (struct smtcfb_info *)info;
+       u32 val;
+
+       if (regno > 255)
+               return 1;
+
+       switch (sfb->fb.fix.visual) {
+       case FB_VISUAL_DIRECTCOLOR:
+       case FB_VISUAL_TRUECOLOR:
+               /*
+                * 16/32 bit true-colour, use pseuo-palette for 16 base color
+                */
+               if (regno < 16) {
+                       if (sfb->fb.var.bits_per_pixel == 16) {
+                               u32 *pal = sfb->fb.pseudo_palette;
+                               val = chan_to_field(red, &sfb->fb.var.red);
+                               val |= chan_to_field(green, \
+                                               &sfb->fb.var.green);
+                               val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+                               pal[regno] =
+                                   ((red & 0xf800) >> 8) |
+                                   ((green & 0xe000) >> 13) |
+                                   ((green & 0x1c00) << 3) |
+                                   ((blue & 0xf800) >> 3);
+#else
+                               pal[regno] = val;
+#endif
+                       } else {
+                               u32 *pal = sfb->fb.pseudo_palette;
+                               val = chan_to_field(red, &sfb->fb.var.red);
+                               val |= chan_to_field(green, \
+                                               &sfb->fb.var.green);
+                               val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+                               val =
+                                   (val & 0xff00ff00 >> 8) |
+                                   (val & 0x00ff00ff << 8);
+#endif
+                               pal[regno] = val;
+                       }
+               }
+               break;
+
+       case FB_VISUAL_PSEUDOCOLOR:
+               /* color depth 8 bit */
+               sm712_setpalette(regno, red, green, blue, info);
+               break;
+
+       default:
+               return 1;       /* unknown type */
+       }
+
+       return 0;
+
+}
+
+#ifdef __BIG_ENDIAN
+static ssize_t smtcfb_read(struct fb_info *info, char __user * buf, size_t
+                               count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+
+       u32 *buffer, *dst;
+       u32 __iomem *src;
+       int c, i, cnt = 0, err = 0;
+       unsigned long total_size;
+
+       if (!info || !info->screen_base)
+               return -ENODEV;
+
+       if (info->state != FBINFO_STATE_RUNNING)
+               return -EPERM;
+
+       total_size = info->screen_size;
+
+       if (total_size == 0)
+               total_size = info->fix.smem_len;
+
+       if (p >= total_size)
+               return 0;
+
+       if (count >= total_size)
+               count = total_size;
+
+       if (count + p > total_size)
+               count = total_size - p;
+
+       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       src = (u32 __iomem *) (info->screen_base + p);
+
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+       while (count) {
+               c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+               dst = buffer;
+               for (i = c >> 2; i--;) {
+                       *dst = fb_readl(src++);
+                       *dst =
+                           (*dst & 0xff00ff00 >> 8) |
+                           (*dst & 0x00ff00ff << 8);
+                       dst++;
+               }
+               if (c & 3) {
+                       u8 *dst8 = (u8 *) dst;
+                       u8 __iomem *src8 = (u8 __iomem *) src;
+
+                       for (i = c & 3; i--;) {
+                               if (i & 1) {
+                                       *dst8++ = fb_readb(++src8);
+                               } else {
+                                       *dst8++ = fb_readb(--src8);
+                                       src8 += 2;
+                               }
+                       }
+                       src = (u32 __iomem *) src8;
+               }
+
+               if (copy_to_user(buf, buffer, c)) {
+                       err = -EFAULT;
+                       break;
+               }
+               *ppos += c;
+               buf += c;
+               cnt += c;
+               count -= c;
+       }
+
+       kfree(buffer);
+
+       return (err) ? err : cnt;
+}
+
+static ssize_t
+smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
+            loff_t *ppos)
+{
+       unsigned long p = *ppos;
+
+       u32 *buffer, *src;
+       u32 __iomem *dst;
+       int c, i, cnt = 0, err = 0;
+       unsigned long total_size;
+
+       if (!info || !info->screen_base)
+               return -ENODEV;
+
+       if (info->state != FBINFO_STATE_RUNNING)
+               return -EPERM;
+
+       total_size = info->screen_size;
+
+       if (total_size == 0)
+               total_size = info->fix.smem_len;
+
+       if (p > total_size)
+               return -EFBIG;
+
+       if (count > total_size) {
+               err = -EFBIG;
+               count = total_size;
+       }
+
+       if (count + p > total_size) {
+               if (!err)
+                       err = -ENOSPC;
+
+               count = total_size - p;
+       }
+
+       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       dst = (u32 __iomem *) (info->screen_base + p);
+
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+       while (count) {
+               c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+               src = buffer;
+
+               if (copy_from_user(src, buf, c)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               for (i = c >> 2; i--;) {
+                       fb_writel((*src & 0xff00ff00 >> 8) |
+                                 (*src & 0x00ff00ff << 8), dst++);
+                       src++;
+               }
+               if (c & 3) {
+                       u8 *src8 = (u8 *) src;
+                       u8 __iomem *dst8 = (u8 __iomem *) dst;
+
+                       for (i = c & 3; i--;) {
+                               if (i & 1) {
+                                       fb_writeb(*src8++, ++dst8);
+                               } else {
+                                       fb_writeb(*src8++, --dst8);
+                                       dst8 += 2;
+                               }
+                       }
+                       dst = (u32 __iomem *) dst8;
+               }
+
+               *ppos += c;
+               buf += c;
+               cnt += c;
+               count -= c;
+       }
+
+       kfree(buffer);
+
+       return (cnt) ? cnt : err;
+}
+#endif /* ! __BIG_ENDIAN */
+
+#include "smtc2d.c"
+
+void smtcfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+       struct par_info *p = (struct par_info *)info->par;
+
+       if (smtc_2Dacceleration) {
+               if (!area->width || !area->height)
+                       return;
+
+               deCopy(p->BaseAddressInVRAM, 0, info->var.bits_per_pixel,
+                      area->dx, area->dy, area->width, area->height,
+                      p->BaseAddressInVRAM, 0, area->sx, area->sy, 0, 0xC);
+
+       } else
+               cfb_copyarea(info, area);
+}
+
+void smtcfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+       struct par_info *p = (struct par_info *)info->par;
+
+       if (smtc_2Dacceleration) {
+               if (!rect->width || !rect->height)
+                       return;
+               if (info->var.bits_per_pixel >= 24)
+                       deFillRect(p->BaseAddressInVRAM, 0, rect->dx * 3,
+                                  rect->dy * 3, rect->width * 3, rect->height,
+                                  rect->color);
+               else
+                       deFillRect(p->BaseAddressInVRAM, 0, rect->dx, rect->dy,
+                                  rect->width, rect->height, rect->color);
+       } else
+               cfb_fillrect(info, rect);
+}
+
+void smtcfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       struct par_info *p = (struct par_info *)info->par;
+       u32 bg_col = 0, fg_col = 0;
+
+       if ((smtc_2Dacceleration) && (image->depth == 1)) {
+               if (smtc_de_busy)
+                       deWaitForNotBusy();
+
+               switch (info->var.bits_per_pixel) {
+               case 8:
+                       bg_col = image->bg_color;
+                       fg_col = image->fg_color;
+                       break;
+               case 16:
+                       bg_col =
+                           ((u32 *) (info->pseudo_palette))[image->bg_color];
+                       fg_col =
+                           ((u32 *) (info->pseudo_palette))[image->fg_color];
+                       break;
+               case 32:
+                       bg_col =
+                           ((u32 *) (info->pseudo_palette))[image->bg_color];
+                       fg_col =
+                           ((u32 *) (info->pseudo_palette))[image->fg_color];
+                       break;
+               }
+
+               deSystemMem2VideoMemMonoBlt(
+                       image->data,
+                       image->width / 8,
+                       0,
+                       p->BaseAddressInVRAM,
+                       0,
+                       0,
+                       image->dx, image->dy,
+                       image->width, image->height,
+                       fg_col, bg_col,
+                       0x0C);
+
+       } else
+               cfb_imageblit(info, image);
+}
+
+static struct fb_ops smtcfb_ops = {
+       .owner = THIS_MODULE,
+       .fb_setcolreg = smtc_setcolreg,
+       .fb_blank = smtcfb_blank,
+       .fb_fillrect = smtcfb_fillrect,
+       .fb_imageblit = smtcfb_imageblit,
+       .fb_copyarea = smtcfb_copyarea,
+#ifdef __BIG_ENDIAN
+       .fb_read = smtcfb_read,
+       .fb_write = smtcfb_write,
+#endif
+
+};
+
+void smtcfb_setmode(struct smtcfb_info *sfb)
+{
+       switch (sfb->fb.var.bits_per_pixel) {
+       case 32:
+               sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+               sfb->fb.fix.line_length = sfb->fb.var.xres * 4;
+               sfb->fb.var.red.length = 8;
+               sfb->fb.var.green.length = 8;
+               sfb->fb.var.blue.length = 8;
+               sfb->fb.var.red.offset = 16;
+               sfb->fb.var.green.offset = 8;
+               sfb->fb.var.blue.offset = 0;
+
+               break;
+       case 8:
+               sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               sfb->fb.fix.line_length = sfb->fb.var.xres;
+               sfb->fb.var.red.offset = 5;
+               sfb->fb.var.red.length = 3;
+               sfb->fb.var.green.offset = 2;
+               sfb->fb.var.green.length = 3;
+               sfb->fb.var.blue.offset = 0;
+               sfb->fb.var.blue.length = 2;
+               break;
+       case 24:
+               sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+               sfb->fb.fix.line_length = sfb->fb.var.xres * 3;
+               sfb->fb.var.red.length = 8;
+               sfb->fb.var.green.length = 8;
+               sfb->fb.var.blue.length = 8;
+
+               sfb->fb.var.red.offset = 16;
+               sfb->fb.var.green.offset = 8;
+               sfb->fb.var.blue.offset = 0;
+
+               break;
+       case 16:
+       default:
+               sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+               sfb->fb.fix.line_length = sfb->fb.var.xres * 2;
+
+               sfb->fb.var.red.length = 5;
+               sfb->fb.var.green.length = 6;
+               sfb->fb.var.blue.length = 5;
+
+               sfb->fb.var.red.offset = 11;
+               sfb->fb.var.green.offset = 5;
+               sfb->fb.var.blue.offset = 0;
+
+               break;
+       }
+
+       hw.width = sfb->fb.var.xres;
+       hw.height = sfb->fb.var.yres;
+       hw.hz = 60;
+       smtc_set_timing(sfb, &hw);
+       if (smtc_2Dacceleration) {
+               printk("2D acceleration enabled!\n");
+               /* Init smtc drawing engine */
+               deInit(sfb->fb.var.xres, sfb->fb.var.yres,
+                               sfb->fb.var.bits_per_pixel);
+       }
+}
+
+/*
+ * Alloc struct smtcfb_info and assign the default value
+ */
+static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
+                                                       char *name)
+{
+       struct smtcfb_info *sfb;
+
+       sfb = kmalloc(sizeof(struct smtcfb_info), GFP_KERNEL);
+
+       if (!sfb)
+               return NULL;
+
+       memset(sfb, 0, sizeof(struct smtcfb_info));
+
+       sfb->currcon = -1;
+       sfb->dev = dev;
+
+       /*** Init sfb->fb with default value ***/
+       sfb->fb.flags = FBINFO_FLAG_DEFAULT;
+       sfb->fb.fbops = &smtcfb_ops;
+       sfb->fb.var = smtcfb_var;
+       sfb->fb.fix = smtcfb_fix;
+
+       strcpy(sfb->fb.fix.id, name);
+
+       sfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+       sfb->fb.fix.type_aux = 0;
+       sfb->fb.fix.xpanstep = 0;
+       sfb->fb.fix.ypanstep = 0;
+       sfb->fb.fix.ywrapstep = 0;
+       sfb->fb.fix.accel = FB_ACCEL_SMI_LYNX;
+
+       sfb->fb.var.nonstd = 0;
+       sfb->fb.var.activate = FB_ACTIVATE_NOW;
+       sfb->fb.var.height = -1;
+       sfb->fb.var.width = -1;
+       /* text mode acceleration */
+       sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
+       sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
+       sfb->fb.par = &hw;
+       sfb->fb.pseudo_palette = colreg;
+
+       return sfb;
+}
+
+/*
+ * Unmap in the memory mapped IO registers
+ */
+
+static void smtc_unmap_mmio(struct smtcfb_info *sfb)
+{
+       if (sfb && smtc_RegBaseAddress)
+               smtc_RegBaseAddress = NULL;
+}
+
+/*
+ * Map in the screen memory
+ */
+
+static int smtc_map_smem(struct smtcfb_info *sfb,
+               struct pci_dev *dev, u_long smem_len)
+{
+       if (sfb->fb.var.bits_per_pixel == 32) {
+#ifdef __BIG_ENDIAN
+               sfb->fb.fix.smem_start = pci_resource_start(dev, 0)
+                       + 0x800000;
+#else
+               sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+#endif
+       } else {
+               sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+       }
+
+       sfb->fb.fix.smem_len = smem_len;
+
+       sfb->fb.screen_base = smtc_VRAMBaseAddress;
+
+       if (!sfb->fb.screen_base) {
+               printk(KERN_INFO "%s: unable to map screen memory\n",
+                               sfb->fb.fix.id);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/*
+ * Unmap in the screen memory
+ *
+ */
+static void smtc_unmap_smem(struct smtcfb_info *sfb)
+{
+       if (sfb && sfb->fb.screen_base) {
+               iounmap(sfb->fb.screen_base);
+               sfb->fb.screen_base = NULL;
+       }
+}
+
+/*
+ * We need to wake up the LynxEM+, and make sure its in linear memory mode.
+ */
+static inline void sm7xx_init_hw(void)
+{
+       outb_p(0x18, 0x3c4);
+       outb_p(0x11, 0x3c5);
+}
+
+static void smtc_free_fb_info(struct smtcfb_info *sfb)
+{
+       if (sfb) {
+               fb_alloc_cmap(&sfb->fb.cmap, 0, 0);
+               kfree(sfb);
+       }
+}
+
+/*
+ *     sm712vga_setup - process command line options, get vga parameter
+ *     @options: string of options
+ *     Returns zero.
+ *
+ */
+static int __init __maybe_unused sm712vga_setup(char *options)
+{
+       int index;
+
+       if (!options || !*options) {
+               smdbg("\n No vga parameter\n");
+               return -EINVAL;
+       }
+
+       smtc_screen_info.lfb_width = 0;
+       smtc_screen_info.lfb_height = 0;
+       smtc_screen_info.lfb_depth = 0;
+
+       smdbg("\nsm712vga_setup = %s\n", options);
+
+       for (index = 0;
+            index < (sizeof(vesa_mode) / sizeof(struct vesa_mode_table));
+            index++) {
+               if (strstr(options, vesa_mode[index].mode_index)) {
+                       smtc_screen_info.lfb_width = vesa_mode[index].lfb_width;
+                       smtc_screen_info.lfb_height =
+                                       vesa_mode[index].lfb_height;
+                       smtc_screen_info.lfb_depth = vesa_mode[index].lfb_depth;
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+__setup("vga=", sm712vga_setup);
+
+/* Jason (08/13/2009)
+ * Original init function changed to probe method to be used by pci_drv
+ * process used to detect chips replaced with kernel process in pci_drv
+ */
+static int __init smtcfb_pci_probe(struct pci_dev *pdev,
+                                  const struct pci_device_id *ent)
+{
+       struct smtcfb_info *sfb;
+       u_long smem_size = 0x00800000;  /* default 8MB */
+       char name[16];
+       int err;
+       unsigned long pFramebufferPhysical;
+
+       printk(KERN_INFO
+               "Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n");
+
+       err = pci_enable_device(pdev);  /* enable SMTC chip */
+
+       if (err)
+               return err;
+       err = -ENOMEM;
+
+       hw.chipID = ent->device;
+       sprintf(name, "sm%Xfb", hw.chipID);
+
+       sfb = smtc_alloc_fb_info(pdev, name);
+
+       if (!sfb)
+               goto failed;
+       /* Jason (08/13/2009)
+        * Store fb_info to be further used when suspending and resuming
+        */
+       pci_set_drvdata(pdev, sfb);
+
+       sm7xx_init_hw();
+
+       /*get mode parameter from smtc_screen_info */
+       if (smtc_screen_info.lfb_width != 0) {
+               sfb->fb.var.xres = smtc_screen_info.lfb_width;
+               sfb->fb.var.yres = smtc_screen_info.lfb_height;
+               sfb->fb.var.bits_per_pixel = smtc_screen_info.lfb_depth;
+       } else {
+               /* default resolution 1024x600 16bit mode */
+               sfb->fb.var.xres = SCREEN_X_RES;
+               sfb->fb.var.yres = SCREEN_Y_RES;
+               sfb->fb.var.bits_per_pixel = SCREEN_BPP;
+       }
+
+#ifdef __BIG_ENDIAN
+       if (sfb->fb.var.bits_per_pixel == 24)
+               sfb->fb.var.bits_per_pixel = (smtc_screen_info.lfb_depth = 32);
+#endif
+       /* Map address and memory detection */
+       pFramebufferPhysical = pci_resource_start(pdev, 0);
+       pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID);
+
+       switch (hw.chipID) {
+       case 0x710:
+       case 0x712:
+               sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
+               sfb->fb.fix.mmio_len = 0x00400000;
+               smem_size = SM712_VIDEOMEMORYSIZE;
+#ifdef __BIG_ENDIAN
+               hw.m_pLFB = (smtc_VRAMBaseAddress =
+                   ioremap(pFramebufferPhysical, 0x00c00000));
+#else
+               hw.m_pLFB = (smtc_VRAMBaseAddress =
+                   ioremap(pFramebufferPhysical, 0x00800000));
+#endif
+               hw.m_pMMIO = (smtc_RegBaseAddress =
+                   smtc_VRAMBaseAddress + 0x00700000);
+               smtc_2DBaseAddress = (hw.m_pDPR =
+                   smtc_VRAMBaseAddress + 0x00408000);
+               smtc_2Ddataport = smtc_VRAMBaseAddress + DE_DATA_PORT_712;
+               hw.m_pVPR = hw.m_pLFB + 0x0040c000;
+#ifdef __BIG_ENDIAN
+               if (sfb->fb.var.bits_per_pixel == 32) {
+                       smtc_VRAMBaseAddress += 0x800000;
+                       hw.m_pLFB += 0x800000;
+                       printk(KERN_INFO
+                               "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n",
+                                       smtc_VRAMBaseAddress, hw.m_pLFB);
+               }
+#endif
+               if (!smtc_RegBaseAddress) {
+                       printk(KERN_INFO
+                               "%s: unable to map memory mapped IO\n",
+                               sfb->fb.fix.id);
+                       return -ENOMEM;
+               }
+
+               /* set MCLK = 14.31818 * (0x16 / 0x2) */
+               smtc_seqw(0x6a, 0x16);
+               smtc_seqw(0x6b, 0x02);
+               smtc_seqw(0x62, 0x3e);
+               /* enable PCI burst */
+               smtc_seqw(0x17, 0x20);
+               /* enable word swap */
+#ifdef __BIG_ENDIAN
+               if (sfb->fb.var.bits_per_pixel == 32)
+                       smtc_seqw(0x17, 0x30);
+#endif
+#ifdef CONFIG_FB_SM7XX_ACCEL
+               smtc_2Dacceleration = 1;
+#endif
+               break;
+       case 0x720:
+               sfb->fb.fix.mmio_start = pFramebufferPhysical;
+               sfb->fb.fix.mmio_len = 0x00200000;
+               smem_size = SM722_VIDEOMEMORYSIZE;
+               smtc_2DBaseAddress = (hw.m_pDPR =
+                   ioremap(pFramebufferPhysical, 0x00a00000));
+               hw.m_pLFB = (smtc_VRAMBaseAddress =
+                   smtc_2DBaseAddress + 0x00200000);
+               hw.m_pMMIO = (smtc_RegBaseAddress =
+                   smtc_2DBaseAddress + 0x000c0000);
+               smtc_2Ddataport = smtc_2DBaseAddress + DE_DATA_PORT_722;
+               hw.m_pVPR = smtc_2DBaseAddress + 0x800;
+
+               smtc_seqw(0x62, 0xff);
+               smtc_seqw(0x6a, 0x0d);
+               smtc_seqw(0x6b, 0x02);
+               smtc_2Dacceleration = 0;
+               break;
+       default:
+               printk(KERN_INFO
+               "No valid Silicon Motion display chip was detected!\n");
+
+               smtc_free_fb_info(sfb);
+               return err;
+       }
+
+       /* can support 32 bpp */
+       if (15 == sfb->fb.var.bits_per_pixel)
+               sfb->fb.var.bits_per_pixel = 16;
+
+       sfb->fb.var.xres_virtual = sfb->fb.var.xres;
+       sfb->fb.var.yres_virtual = sfb->fb.var.yres;
+       err = smtc_map_smem(sfb, pdev, smem_size);
+       if (err)
+               goto failed;
+
+       smtcfb_setmode(sfb);
+       /* Primary display starting from 0 postion */
+       hw.BaseAddressInVRAM = 0;
+       sfb->fb.par = &hw;
+
+       err = register_framebuffer(&sfb->fb);
+       if (err < 0)
+               goto failed;
+
+       printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode"
+                       "%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID,
+                       sfb->fb.var.xres, sfb->fb.var.yres,
+                       sfb->fb.var.bits_per_pixel);
+
+       return 0;
+
+ failed:
+       printk(KERN_INFO "Silicon Motion, Inc.  primary display init fail\n");
+
+       smtc_unmap_smem(sfb);
+       smtc_unmap_mmio(sfb);
+       smtc_free_fb_info(sfb);
+
+       return err;
+}
+
+
+/* Jason (08/11/2009) PCI_DRV wrapper essential structs */
+static struct pci_device_id smtcfb_pci_table[] = {
+       {0x126f, 0x710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x126f, 0x712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x126f, 0x720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0,}
+};
+
+
+/* Jason (08/14/2009)
+ * do some clean up when the driver module is removed
+ */
+static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
+{
+       struct smtcfb_info *sfb;
+
+       sfb = pci_get_drvdata(pdev);
+       pci_set_drvdata(pdev, NULL);
+       smtc_unmap_smem(sfb);
+       smtc_unmap_mmio(sfb);
+       unregister_framebuffer(&sfb->fb);
+       smtc_free_fb_info(sfb);
+}
+
+/* Jason (08/14/2009)
+ * suspend function, called when the suspend event is triggered
+ */
+static int __maybe_unused smtcfb_suspend(struct pci_dev *pdev, pm_message_t msg)
+{
+       struct smtcfb_info *sfb;
+       int retv;
+
+       sfb = pci_get_drvdata(pdev);
+
+       /* set the hw in sleep mode use externel clock and self memory refresh
+        * so that we can turn off internal PLLs later on
+        */
+       smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
+       smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
+
+       switch (msg.event) {
+       case PM_EVENT_FREEZE:
+       case PM_EVENT_PRETHAW:
+               pdev->dev.power.power_state = msg;
+               return 0;
+       }
+
+       /* when doing suspend, call fb apis and pci apis */
+       if (msg.event == PM_EVENT_SUSPEND) {
+               acquire_console_sem();
+               fb_set_suspend(&sfb->fb, 1);
+               release_console_sem();
+               retv = pci_save_state(pdev);
+               pci_disable_device(pdev);
+               retv = pci_choose_state(pdev, msg);
+               retv = pci_set_power_state(pdev, retv);
+       }
+
+       pdev->dev.power.power_state = msg;
+
+       /* additionaly turn off all function blocks including internal PLLs */
+       smtc_seqw(0x21, 0xff);
+
+       return 0;
+}
+
+static int __maybe_unused smtcfb_resume(struct pci_dev *pdev)
+{
+       struct smtcfb_info *sfb;
+       int retv;
+
+       sfb = pci_get_drvdata(pdev);
+
+       /* when resuming, restore pci data and fb cursor */
+       if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
+               retv = pci_set_power_state(pdev, PCI_D0);
+               retv = pci_restore_state(pdev);
+               if (pci_enable_device(pdev))
+                       return -1;
+               pci_set_master(pdev);
+       }
+
+       /* reinit hardware */
+       sm7xx_init_hw();
+       switch (hw.chipID) {
+       case 0x710:
+       case 0x712:
+               /* set MCLK = 14.31818 *  (0x16 / 0x2) */
+               smtc_seqw(0x6a, 0x16);
+               smtc_seqw(0x6b, 0x02);
+               smtc_seqw(0x62, 0x3e);
+               /* enable PCI burst */
+               smtc_seqw(0x17, 0x20);
+#ifdef __BIG_ENDIAN
+               if (sfb->fb.var.bits_per_pixel == 32)
+                       smtc_seqw(0x17, 0x30);
+#endif
+               break;
+       case 0x720:
+               smtc_seqw(0x62, 0xff);
+               smtc_seqw(0x6a, 0x0d);
+               smtc_seqw(0x6b, 0x02);
+               break;
+       }
+
+       smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
+       smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
+
+       smtcfb_setmode(sfb);
+
+       acquire_console_sem();
+       fb_set_suspend(&sfb->fb, 0);
+       release_console_sem();
+
+       return 0;
+}
+
+/* Jason (08/13/2009)
+ * pci_driver struct used to wrap the original driver
+ * so that it can be registered into the kernel and
+ * the proper method would be called when suspending and resuming
+ */
+static struct pci_driver smtcfb_driver = {
+       .name = "smtcfb",
+       .id_table = smtcfb_pci_table,
+       .probe = smtcfb_pci_probe,
+       .remove = __devexit_p(smtcfb_pci_remove),
+#ifdef CONFIG_PM
+       .suspend = smtcfb_suspend,
+       .resume = smtcfb_resume,
+#endif
+};
+
+static int __init smtcfb_init(void)
+{
+       return pci_register_driver(&smtcfb_driver);
+}
+
+static void __exit smtcfb_exit(void)
+{
+       pci_unregister_driver(&smtcfb_driver);
+}
+
+module_init(smtcfb_init);
+module_exit(smtcfb_exit);
+
+MODULE_AUTHOR("Siliconmotion ");
+MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/sm7xx/smtcfb.h b/drivers/staging/sm7xx/smtcfb.h
new file mode 100644 (file)
index 0000000..7f2c341
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ * Silicon Motion SM712 frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors:    Ge Wang, gewang@siliconmotion.com
+ *             Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzj@lemote.com
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#define SMTC_LINUX_FB_VERSION  "version 0.11.2619.21.01 July 27, 2008"
+
+#define NR_PALETTE        256
+#define NR_RGB            2
+
+#define FB_ACCEL_SMI_LYNX 88
+
+#ifdef __BIG_ENDIAN
+#define PC_VGA            0
+#else
+#define PC_VGA            1
+#endif
+
+#define SCREEN_X_RES      1024
+#define SCREEN_Y_RES      600
+#define SCREEN_BPP        16
+
+#ifndef FIELD_OFFSET
+#define FIELD_OFSFET(type, field) \
+       ((unsigned long) (PUCHAR) & (((type *)0)->field))
+#endif
+
+/*Assume SM712 graphics chip has 4MB VRAM */
+#define SM712_VIDEOMEMORYSIZE    0x00400000
+/*Assume SM722 graphics chip has 8MB VRAM */
+#define SM722_VIDEOMEMORYSIZE    0x00800000
+
+#define dac_reg        (0x3c8)
+#define dac_val        (0x3c9)
+
+extern char *smtc_RegBaseAddress;
+#define smtc_mmiowb(dat, reg)  writeb(dat, smtc_RegBaseAddress + reg)
+#define smtc_mmioww(dat, reg)  writew(dat, smtc_RegBaseAddress + reg)
+#define smtc_mmiowl(dat, reg)  writel(dat, smtc_RegBaseAddress + reg)
+
+#define smtc_mmiorb(reg)       readb(smtc_RegBaseAddress + reg)
+#define smtc_mmiorw(reg)       readw(smtc_RegBaseAddress + reg)
+#define smtc_mmiorl(reg)       readl(smtc_RegBaseAddress + reg)
+
+#define SIZE_SR00_SR04      (0x04 - 0x00 + 1)
+#define SIZE_SR10_SR24      (0x24 - 0x10 + 1)
+#define SIZE_SR30_SR75      (0x75 - 0x30 + 1)
+#define SIZE_SR80_SR93      (0x93 - 0x80 + 1)
+#define SIZE_SRA0_SRAF      (0xAF - 0xA0 + 1)
+#define SIZE_GR00_GR08      (0x08 - 0x00 + 1)
+#define SIZE_AR00_AR14      (0x14 - 0x00 + 1)
+#define SIZE_CR00_CR18      (0x18 - 0x00 + 1)
+#define SIZE_CR30_CR4D      (0x4D - 0x30 + 1)
+#define SIZE_CR90_CRA7      (0xA7 - 0x90 + 1)
+#define SIZE_VPR               (0x6C + 1)
+#define SIZE_DPR               (0x44 + 1)
+
+static inline void smtc_crtcw(int reg, int val)
+{
+       smtc_mmiowb(reg, 0x3d4);
+       smtc_mmiowb(val, 0x3d5);
+}
+
+static inline unsigned int smtc_crtcr(int reg)
+{
+       smtc_mmiowb(reg, 0x3d4);
+       return smtc_mmiorb(0x3d5);
+}
+
+static inline void smtc_grphw(int reg, int val)
+{
+       smtc_mmiowb(reg, 0x3ce);
+       smtc_mmiowb(val, 0x3cf);
+}
+
+static inline unsigned int smtc_grphr(int reg)
+{
+       smtc_mmiowb(reg, 0x3ce);
+       return smtc_mmiorb(0x3cf);
+}
+
+static inline void smtc_attrw(int reg, int val)
+{
+       smtc_mmiorb(0x3da);
+       smtc_mmiowb(reg, 0x3c0);
+       smtc_mmiorb(0x3c1);
+       smtc_mmiowb(val, 0x3c0);
+}
+
+static inline void smtc_seqw(int reg, int val)
+{
+       smtc_mmiowb(reg, 0x3c4);
+       smtc_mmiowb(val, 0x3c5);
+}
+
+static inline unsigned int smtc_seqr(int reg)
+{
+       smtc_mmiowb(reg, 0x3c4);
+       return smtc_mmiorb(0x3c5);
+}
+
+/* The next structure holds all information relevant for a specific video mode.
+ */
+
+struct ModeInit {
+       int mmSizeX;
+       int mmSizeY;
+       int bpp;
+       int hz;
+       unsigned char Init_MISC;
+       unsigned char Init_SR00_SR04[SIZE_SR00_SR04];
+       unsigned char Init_SR10_SR24[SIZE_SR10_SR24];
+       unsigned char Init_SR30_SR75[SIZE_SR30_SR75];
+       unsigned char Init_SR80_SR93[SIZE_SR80_SR93];
+       unsigned char Init_SRA0_SRAF[SIZE_SRA0_SRAF];
+       unsigned char Init_GR00_GR08[SIZE_GR00_GR08];
+       unsigned char Init_AR00_AR14[SIZE_AR00_AR14];
+       unsigned char Init_CR00_CR18[SIZE_CR00_CR18];
+       unsigned char Init_CR30_CR4D[SIZE_CR30_CR4D];
+       unsigned char Init_CR90_CRA7[SIZE_CR90_CRA7];
+};
+
+/**********************************************************************
+                        SM712 Mode table.
+ **********************************************************************/
+struct ModeInit VGAMode[] = {
+       {
+        /*  mode#0: 640 x 480  16Bpp  60Hz */
+        640, 480, 16, 60,
+        /*  Init_MISC */
+        0xE3,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x00, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x30, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+         0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+         0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+         0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+         0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+         0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+         0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+         0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+         0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+         0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+         0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+         0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+         0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+         },
+        },
+       {
+        /*  mode#1: 640 x 480  24Bpp  60Hz */
+        640, 480, 24, 60,
+        /*  Init_MISC */
+        0xE3,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x00, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x30, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+         0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+         0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+         0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+         0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+         0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+         0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+         0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+         0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+         0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+         0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+         0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+         0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+         },
+        },
+       {
+        /*  mode#0: 640 x 480  32Bpp  60Hz */
+        640, 480, 32, 60,
+        /*  Init_MISC */
+        0xE3,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x00, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x30, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+         0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+         0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+         0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+         0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+         0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+         0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+         0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+         0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+         0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+         0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+         0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+         0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+         },
+        },
+
+       {                       /*  mode#2: 800 x 600  16Bpp  60Hz */
+        800, 600, 16, 60,
+        /*  Init_MISC */
+        0x2B,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x03, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x30, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+         0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+         0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+         0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+         0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+         0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+         0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+         0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+         0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+         0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+         0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+         0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+         0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+         },
+        },
+       {                       /*  mode#3: 800 x 600  24Bpp  60Hz */
+        800, 600, 24, 60,
+        0x2B,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x03, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x30, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
+         0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
+         0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+         0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
+         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+         0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
+         0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+         0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+         0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+         0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+         0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+         0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+         0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+         },
+        },
+       {                       /*  mode#7: 800 x 600  32Bpp  60Hz */
+        800, 600, 32, 60,
+        /*  Init_MISC */
+        0x2B,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x03, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x30, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+         0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+         0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+         0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+         0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+         0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+         0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+         0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+         0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+         0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+         0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+         0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+         0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+         },
+        },
+       /* We use 1024x768 table to light 1024x600 panel for lemote */
+       {                       /*  mode#4: 1024 x 600  16Bpp  60Hz  */
+        1024, 600, 16, 60,
+        /*  Init_MISC */
+        0xEB,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x00, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
+         0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x30, 0x02, 0x00, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
+         0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
+         0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+         0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
+         0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
+         0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+         0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+         0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+         0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+         0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
+         0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+         0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+         },
+        },
+       {                       /*  mode#5: 1024 x 768  24Bpp  60Hz */
+        1024, 768, 24, 60,
+        /*  Init_MISC */
+        0xEB,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x03, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x30, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+         0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+         0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+         0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+         0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+         0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+         0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+         0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+         0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+         0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+         0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+         },
+        },
+       {                       /*  mode#4: 1024 x 768  32Bpp  60Hz */
+        1024, 768, 32, 60,
+        /*  Init_MISC */
+        0xEB,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x03, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x32, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+         0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+         0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+         0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+         0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+         0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+         0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+         0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+         0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+         0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+         0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+         },
+        },
+       {                       /*  mode#6: 320 x 240  16Bpp  60Hz */
+        320, 240, 16, 60,
+        /*  Init_MISC */
+        0xEB,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x03, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x32, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+         0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+         0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+         0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+         0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+         0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+         0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+         0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+         0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+         0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+         0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+         },
+        },
+
+       {                       /*  mode#8: 320 x 240  32Bpp  60Hz */
+        320, 240, 32, 60,
+        /*  Init_MISC */
+        0xEB,
+        {                      /*  Init_SR0_SR4 */
+         0x03, 0x01, 0x0F, 0x03, 0x0E,
+         },
+        {                      /*  Init_SR10_SR24 */
+         0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+         0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xC4, 0x32, 0x02, 0x01, 0x01,
+         },
+        {                      /*  Init_SR30_SR75 */
+         0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+         0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+         0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+         0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+         0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+         0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+         0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+         },
+        {                      /*  Init_SR80_SR93 */
+         0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+         0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+         0x00, 0x00, 0x00, 0x00,
+         },
+        {                      /*  Init_SRA0_SRAF */
+         0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+         0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+         },
+        {                      /*  Init_GR00_GR08 */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+         0xFF,
+         },
+        {                      /*  Init_AR00_AR14 */
+         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+         0x41, 0x00, 0x0F, 0x00, 0x00,
+         },
+        {                      /*  Init_CR00_CR18 */
+         0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+         0xFF,
+         },
+        {                      /*  Init_CR30_CR4D */
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+         0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+         0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+         0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+         },
+        {                      /*  Init_CR90_CRA7 */
+         0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+         0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+         },
+        },
+};
+
+#define numVGAModes            (sizeof(VGAMode) / sizeof(struct ModeInit))