linux/drivers/video/fbdev/sm712fb.c
<<
>>
Prefs
   1/*
   2 * Silicon Motion SM7XX frame buffer device
   3 *
   4 * Copyright (C) 2006 Silicon Motion Technology Corp.
   5 * Authors:  Ge Wang, gewang@siliconmotion.com
   6 *           Boyod boyod.yang@siliconmotion.com.cn
   7 *
   8 * Copyright (C) 2009 Lemote, Inc.
   9 * Author:   Wu Zhangjin, wuzhangjin@gmail.com
  10 *
  11 * Copyright (C) 2011 Igalia, S.L.
  12 * Author:   Javier M. Mellid <jmunhoz@igalia.com>
  13 *
  14 * This file is subject to the terms and conditions of the GNU General Public
  15 * License. See the file COPYING in the main directory of this archive for
  16 * more details.
  17 *
  18 * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips
  19 */
  20
  21#include <linux/io.h>
  22#include <linux/fb.h>
  23#include <linux/pci.h>
  24#include <linux/init.h>
  25#include <linux/slab.h>
  26#include <linux/uaccess.h>
  27#include <linux/module.h>
  28#include <linux/console.h>
  29#include <linux/screen_info.h>
  30
  31#include <linux/pm.h>
  32
  33#include "sm712.h"
  34
  35/*
  36 * Private structure
  37 */
  38struct smtcfb_info {
  39        struct pci_dev *pdev;
  40        struct fb_info *fb;
  41        u16 chip_id;
  42        u8  chip_rev_id;
  43
  44        void __iomem *lfb;      /* linear frame buffer */
  45        void __iomem *dp_regs;  /* drawing processor control regs */
  46        void __iomem *vp_regs;  /* video processor control regs */
  47        void __iomem *cp_regs;  /* capture processor control regs */
  48        void __iomem *mmio;     /* memory map IO port */
  49
  50        u_int width;
  51        u_int height;
  52        u_int hz;
  53
  54        u32 colreg[17];
  55};
  56
  57void __iomem *smtc_regbaseaddress;      /* Memory Map IO starting address */
  58
  59static const struct fb_var_screeninfo smtcfb_var = {
  60        .xres           = 1024,
  61        .yres           = 600,
  62        .xres_virtual   = 1024,
  63        .yres_virtual   = 600,
  64        .bits_per_pixel = 16,
  65        .red            = {16, 8, 0},
  66        .green          = {8, 8, 0},
  67        .blue           = {0, 8, 0},
  68        .activate       = FB_ACTIVATE_NOW,
  69        .height         = -1,
  70        .width          = -1,
  71        .vmode          = FB_VMODE_NONINTERLACED,
  72        .nonstd         = 0,
  73        .accel_flags    = FB_ACCELF_TEXT,
  74};
  75
  76static struct fb_fix_screeninfo smtcfb_fix = {
  77        .id             = "smXXXfb",
  78        .type           = FB_TYPE_PACKED_PIXELS,
  79        .visual         = FB_VISUAL_TRUECOLOR,
  80        .line_length    = 800 * 3,
  81        .accel          = FB_ACCEL_SMI_LYNX,
  82        .type_aux       = 0,
  83        .xpanstep       = 0,
  84        .ypanstep       = 0,
  85        .ywrapstep      = 0,
  86};
  87
  88struct vesa_mode {
  89        char index[6];
  90        u16  lfb_width;
  91        u16  lfb_height;
  92        u16  lfb_depth;
  93};
  94
  95static const struct vesa_mode vesa_mode_table[] = {
  96        {"0x301", 640,  480,  8},
  97        {"0x303", 800,  600,  8},
  98        {"0x305", 1024, 768,  8},
  99        {"0x307", 1280, 1024, 8},
 100
 101        {"0x311", 640,  480,  16},
 102        {"0x314", 800,  600,  16},
 103        {"0x317", 1024, 768,  16},
 104        {"0x31A", 1280, 1024, 16},
 105
 106        {"0x312", 640,  480,  24},
 107        {"0x315", 800,  600,  24},
 108        {"0x318", 1024, 768,  24},
 109        {"0x31B", 1280, 1024, 24},
 110};
 111
 112/**********************************************************************
 113                         SM712 Mode table.
 114 **********************************************************************/
 115static const struct modeinit vgamode[] = {
 116        {
 117                /*  mode#0: 640 x 480  16Bpp  60Hz */
 118                640, 480, 16, 60,
 119                /*  Init_MISC */
 120                0xE3,
 121                {       /*  Init_SR0_SR4 */
 122                        0x03, 0x01, 0x0F, 0x00, 0x0E,
 123                },
 124                {       /*  Init_SR10_SR24 */
 125                        0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
 126                        0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 127                        0xC4, 0x30, 0x02, 0x01, 0x01,
 128                },
 129                {       /*  Init_SR30_SR75 */
 130                        0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
 131                        0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
 132                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 133                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
 134                        0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
 135                        0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
 136                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 137                        0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
 138                        0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
 139                },
 140                {       /*  Init_SR80_SR93 */
 141                        0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
 142                        0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
 143                        0x00, 0x00, 0x00, 0x00,
 144                },
 145                {       /*  Init_SRA0_SRAF */
 146                        0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
 147                        0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
 148                },
 149                {       /*  Init_GR00_GR08 */
 150                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 151                        0xFF,
 152                },
 153                {       /*  Init_AR00_AR14 */
 154                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 155                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 156                        0x41, 0x00, 0x0F, 0x00, 0x00,
 157                },
 158                {       /*  Init_CR00_CR18 */
 159                        0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
 160                        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 161                        0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
 162                        0xFF,
 163                },
 164                {       /*  Init_CR30_CR4D */
 165                        0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
 166                        0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
 167                        0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
 168                        0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
 169                },
 170                {       /*  Init_CR90_CRA7 */
 171                        0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
 172                        0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
 173                        0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
 174                },
 175        },
 176        {
 177                /*  mode#1: 640 x 480  24Bpp  60Hz */
 178                640, 480, 24, 60,
 179                /*  Init_MISC */
 180                0xE3,
 181                {       /*  Init_SR0_SR4 */
 182                        0x03, 0x01, 0x0F, 0x00, 0x0E,
 183                },
 184                {       /*  Init_SR10_SR24 */
 185                        0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
 186                        0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 187                        0xC4, 0x30, 0x02, 0x01, 0x01,
 188                },
 189                {       /*  Init_SR30_SR75 */
 190                        0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
 191                        0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
 192                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 193                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
 194                        0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
 195                        0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
 196                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 197                        0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
 198                        0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
 199                },
 200                {       /*  Init_SR80_SR93 */
 201                        0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
 202                        0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
 203                        0x00, 0x00, 0x00, 0x00,
 204                },
 205                {       /*  Init_SRA0_SRAF */
 206                        0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
 207                        0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
 208                },
 209                {       /*  Init_GR00_GR08 */
 210                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 211                        0xFF,
 212                },
 213                {       /*  Init_AR00_AR14 */
 214                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 215                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 216                        0x41, 0x00, 0x0F, 0x00, 0x00,
 217                },
 218                {       /*  Init_CR00_CR18 */
 219                        0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
 220                        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 221                        0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
 222                        0xFF,
 223                },
 224                {       /*  Init_CR30_CR4D */
 225                        0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
 226                        0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
 227                        0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
 228                        0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
 229                },
 230                {       /*  Init_CR90_CRA7 */
 231                        0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
 232                        0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
 233                        0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
 234                },
 235        },
 236        {
 237                /*  mode#0: 640 x 480  32Bpp  60Hz */
 238                640, 480, 32, 60,
 239                /*  Init_MISC */
 240                0xE3,
 241                {       /*  Init_SR0_SR4 */
 242                        0x03, 0x01, 0x0F, 0x00, 0x0E,
 243                },
 244                {       /*  Init_SR10_SR24 */
 245                        0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
 246                        0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 247                        0xC4, 0x30, 0x02, 0x01, 0x01,
 248                },
 249                {       /*  Init_SR30_SR75 */
 250                        0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
 251                        0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
 252                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 253                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
 254                        0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
 255                        0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
 256                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 257                        0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
 258                        0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
 259                },
 260                {       /*  Init_SR80_SR93 */
 261                        0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
 262                        0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
 263                        0x00, 0x00, 0x00, 0x00,
 264                },
 265                {       /*  Init_SRA0_SRAF */
 266                        0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
 267                        0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
 268                },
 269                {       /*  Init_GR00_GR08 */
 270                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 271                        0xFF,
 272                },
 273                {       /*  Init_AR00_AR14 */
 274                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 275                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 276                        0x41, 0x00, 0x0F, 0x00, 0x00,
 277                },
 278                {       /*  Init_CR00_CR18 */
 279                        0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
 280                        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 281                        0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
 282                        0xFF,
 283                },
 284                {       /*  Init_CR30_CR4D */
 285                        0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
 286                        0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
 287                        0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
 288                        0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
 289                },
 290                {       /*  Init_CR90_CRA7 */
 291                        0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
 292                        0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
 293                        0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
 294                },
 295        },
 296
 297        {       /*  mode#2: 800 x 600  16Bpp  60Hz */
 298                800, 600, 16, 60,
 299                /*  Init_MISC */
 300                0x2B,
 301                {       /*  Init_SR0_SR4 */
 302                        0x03, 0x01, 0x0F, 0x03, 0x0E,
 303                },
 304                {       /*  Init_SR10_SR24 */
 305                        0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
 306                        0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
 307                        0xC4, 0x30, 0x02, 0x01, 0x01,
 308                },
 309                {       /*  Init_SR30_SR75 */
 310                        0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
 311                        0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
 312                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
 313                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
 314                        0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
 315                        0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
 316                        0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 317                        0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
 318                        0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
 319                },
 320                {       /*  Init_SR80_SR93 */
 321                        0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
 322                        0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
 323                        0x00, 0x00, 0x00, 0x00,
 324                },
 325                {       /*  Init_SRA0_SRAF */
 326                        0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
 327                        0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
 328                },
 329                {       /*  Init_GR00_GR08 */
 330                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 331                        0xFF,
 332                },
 333                {       /*  Init_AR00_AR14 */
 334                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 335                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 336                        0x41, 0x00, 0x0F, 0x00, 0x00,
 337                },
 338                {       /*  Init_CR00_CR18 */
 339                        0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
 340                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 341                        0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
 342                        0xFF,
 343                },
 344                {       /*  Init_CR30_CR4D */
 345                        0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
 346                        0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
 347                        0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
 348                        0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
 349                },
 350                {       /*  Init_CR90_CRA7 */
 351                        0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
 352                        0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
 353                        0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
 354                },
 355        },
 356        {       /*  mode#3: 800 x 600  24Bpp  60Hz */
 357                800, 600, 24, 60,
 358                0x2B,
 359                {       /*  Init_SR0_SR4 */
 360                        0x03, 0x01, 0x0F, 0x03, 0x0E,
 361                },
 362                {       /*  Init_SR10_SR24 */
 363                        0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
 364                        0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 365                        0xC4, 0x30, 0x02, 0x01, 0x01,
 366                },
 367                {       /*  Init_SR30_SR75 */
 368                        0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
 369                        0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
 370                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 371                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
 372                        0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
 373                        0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
 374                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 375                        0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
 376                        0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
 377                },
 378                {       /*  Init_SR80_SR93 */
 379                        0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
 380                        0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
 381                        0x00, 0x00, 0x00, 0x00,
 382                },
 383                {       /*  Init_SRA0_SRAF */
 384                        0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
 385                        0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
 386                },
 387                {       /*  Init_GR00_GR08 */
 388                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 389                        0xFF,
 390                },
 391                {       /*  Init_AR00_AR14 */
 392                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 393                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 394                        0x41, 0x00, 0x0F, 0x00, 0x00,
 395                },
 396                {       /*  Init_CR00_CR18 */
 397                        0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
 398                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 399                        0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
 400                        0xFF,
 401                },
 402                {       /*  Init_CR30_CR4D */
 403                        0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
 404                        0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
 405                        0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
 406                        0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
 407                },
 408                {       /*  Init_CR90_CRA7 */
 409                        0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
 410                        0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
 411                        0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
 412                },
 413        },
 414        {       /*  mode#7: 800 x 600  32Bpp  60Hz */
 415                800, 600, 32, 60,
 416                /*  Init_MISC */
 417                0x2B,
 418                {       /*  Init_SR0_SR4 */
 419                        0x03, 0x01, 0x0F, 0x03, 0x0E,
 420                },
 421                {       /*  Init_SR10_SR24 */
 422                        0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
 423                        0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
 424                        0xC4, 0x30, 0x02, 0x01, 0x01,
 425                },
 426                {       /*  Init_SR30_SR75 */
 427                        0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
 428                        0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
 429                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
 430                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
 431                        0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
 432                        0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
 433                        0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 434                        0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
 435                        0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
 436                },
 437                {       /*  Init_SR80_SR93 */
 438                        0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
 439                        0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
 440                        0x00, 0x00, 0x00, 0x00,
 441                },
 442                {       /*  Init_SRA0_SRAF */
 443                        0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
 444                        0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
 445                },
 446                {       /*  Init_GR00_GR08 */
 447                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 448                        0xFF,
 449                },
 450                {       /*  Init_AR00_AR14 */
 451                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 452                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 453                        0x41, 0x00, 0x0F, 0x00, 0x00,
 454                },
 455                {       /*  Init_CR00_CR18 */
 456                        0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
 457                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 458                        0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
 459                        0xFF,
 460                },
 461                {       /*  Init_CR30_CR4D */
 462                        0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
 463                        0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
 464                        0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
 465                        0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
 466                },
 467                {       /*  Init_CR90_CRA7 */
 468                        0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
 469                        0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
 470                        0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
 471                },
 472        },
 473        /* We use 1024x768 table to light 1024x600 panel for lemote */
 474        {       /*  mode#4: 1024 x 600  16Bpp  60Hz  */
 475                1024, 600, 16, 60,
 476                /*  Init_MISC */
 477                0xEB,
 478                {       /*  Init_SR0_SR4 */
 479                        0x03, 0x01, 0x0F, 0x00, 0x0E,
 480                },
 481                {       /*  Init_SR10_SR24 */
 482                        0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
 483                        0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
 484                        0xC4, 0x30, 0x02, 0x00, 0x01,
 485                },
 486                {       /*  Init_SR30_SR75 */
 487                        0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
 488                        0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
 489                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 490                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
 491                        0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
 492                        0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
 493                        0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 494                        0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
 495                        0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
 496                },
 497                {       /*  Init_SR80_SR93 */
 498                        0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
 499                        0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
 500                        0x00, 0x00, 0x00, 0x00,
 501                },
 502                {       /*  Init_SRA0_SRAF */
 503                        0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
 504                        0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
 505                },
 506                {       /*  Init_GR00_GR08 */
 507                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 508                        0xFF,
 509                },
 510                {       /*  Init_AR00_AR14 */
 511                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 512                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 513                        0x41, 0x00, 0x0F, 0x00, 0x00,
 514                },
 515                {       /*  Init_CR00_CR18 */
 516                        0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
 517                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 518                        0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
 519                        0xFF,
 520                },
 521                {       /*  Init_CR30_CR4D */
 522                        0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
 523                        0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
 524                        0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
 525                        0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
 526                },
 527                {       /*  Init_CR90_CRA7 */
 528                        0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
 529                        0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
 530                        0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
 531                },
 532        },
 533        {       /*  1024 x 768  16Bpp  60Hz */
 534                1024, 768, 16, 60,
 535                /*  Init_MISC */
 536                0xEB,
 537                {       /*  Init_SR0_SR4 */
 538                        0x03, 0x01, 0x0F, 0x03, 0x0E,
 539                },
 540                {       /*  Init_SR10_SR24 */
 541                        0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
 542                        0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
 543                        0xC4, 0x30, 0x02, 0x01, 0x01,
 544                },
 545                {       /*  Init_SR30_SR75 */
 546                        0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
 547                        0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
 548                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 549                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
 550                        0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
 551                        0x0F, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
 552                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 553                        0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
 554                        0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
 555                },
 556                {       /*  Init_SR80_SR93 */
 557                        0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
 558                        0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
 559                        0x00, 0x00, 0x00, 0x00,
 560                },
 561                {       /*  Init_SRA0_SRAF */
 562                        0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
 563                        0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
 564                },
 565                {       /*  Init_GR00_GR08 */
 566                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 567                        0xFF,
 568                },
 569                {       /*  Init_AR00_AR14 */
 570                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 571                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 572                        0x41, 0x00, 0x0F, 0x00, 0x00,
 573                },
 574                {       /*  Init_CR00_CR18 */
 575                        0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
 576                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 577                        0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
 578                        0xFF,
 579                },
 580                {       /*  Init_CR30_CR4D */
 581                        0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
 582                        0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
 583                        0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
 584                        0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
 585                },
 586                {       /*  Init_CR90_CRA7 */
 587                        0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
 588                        0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
 589                        0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
 590                },
 591        },
 592        {       /*  mode#5: 1024 x 768  24Bpp  60Hz */
 593                1024, 768, 24, 60,
 594                /*  Init_MISC */
 595                0xEB,
 596                {       /*  Init_SR0_SR4 */
 597                        0x03, 0x01, 0x0F, 0x03, 0x0E,
 598                },
 599                {       /*  Init_SR10_SR24 */
 600                        0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
 601                        0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
 602                        0xC4, 0x30, 0x02, 0x01, 0x01,
 603                },
 604                {       /*  Init_SR30_SR75 */
 605                        0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
 606                        0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
 607                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 608                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
 609                        0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
 610                        0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
 611                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 612                        0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
 613                        0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
 614                },
 615                {       /*  Init_SR80_SR93 */
 616                        0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
 617                        0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
 618                        0x00, 0x00, 0x00, 0x00,
 619                },
 620                {       /*  Init_SRA0_SRAF */
 621                        0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
 622                        0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
 623                },
 624                {       /*  Init_GR00_GR08 */
 625                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 626                        0xFF,
 627                },
 628                {       /*  Init_AR00_AR14 */
 629                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 630                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 631                        0x41, 0x00, 0x0F, 0x00, 0x00,
 632                },
 633                {       /*  Init_CR00_CR18 */
 634                        0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
 635                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 636                        0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
 637                        0xFF,
 638                },
 639                {       /*  Init_CR30_CR4D */
 640                        0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
 641                        0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
 642                        0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
 643                        0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
 644                },
 645                {       /*  Init_CR90_CRA7 */
 646                        0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
 647                        0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
 648                        0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
 649                },
 650        },
 651        {       /*  mode#4: 1024 x 768  32Bpp  60Hz */
 652                1024, 768, 32, 60,
 653                /*  Init_MISC */
 654                0xEB,
 655                {       /*  Init_SR0_SR4 */
 656                        0x03, 0x01, 0x0F, 0x03, 0x0E,
 657                },
 658                {       /*  Init_SR10_SR24 */
 659                        0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
 660                        0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
 661                        0xC4, 0x32, 0x02, 0x01, 0x01,
 662                },
 663                {       /*  Init_SR30_SR75 */
 664                        0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
 665                        0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
 666                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 667                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
 668                        0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
 669                        0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
 670                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 671                        0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
 672                        0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
 673                },
 674                {       /*  Init_SR80_SR93 */
 675                        0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
 676                        0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
 677                        0x00, 0x00, 0x00, 0x00,
 678                },
 679                {       /*  Init_SRA0_SRAF */
 680                        0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
 681                        0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
 682                },
 683                {       /*  Init_GR00_GR08 */
 684                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 685                        0xFF,
 686                },
 687                {       /*  Init_AR00_AR14 */
 688                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 689                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 690                        0x41, 0x00, 0x0F, 0x00, 0x00,
 691                },
 692                {       /*  Init_CR00_CR18 */
 693                        0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
 694                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 695                        0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
 696                        0xFF,
 697                },
 698                {       /*  Init_CR30_CR4D */
 699                        0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
 700                        0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
 701                        0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
 702                        0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
 703                },
 704                {       /*  Init_CR90_CRA7 */
 705                        0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
 706                        0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
 707                        0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
 708                },
 709        },
 710        {       /*  mode#6: 320 x 240  16Bpp  60Hz */
 711                320, 240, 16, 60,
 712                /*  Init_MISC */
 713                0xEB,
 714                {       /*  Init_SR0_SR4 */
 715                        0x03, 0x01, 0x0F, 0x03, 0x0E,
 716                },
 717                {       /*  Init_SR10_SR24 */
 718                        0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
 719                        0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
 720                        0xC4, 0x32, 0x02, 0x01, 0x01,
 721                },
 722                {       /*  Init_SR30_SR75 */
 723                        0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
 724                        0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
 725                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 726                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
 727                        0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
 728                        0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
 729                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 730                        0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
 731                        0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
 732                },
 733                {       /*  Init_SR80_SR93 */
 734                        0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
 735                        0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
 736                        0x00, 0x00, 0x00, 0x00,
 737                },
 738                {       /*  Init_SRA0_SRAF */
 739                        0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
 740                        0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
 741                },
 742                {       /*  Init_GR00_GR08 */
 743                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 744                        0xFF,
 745                },
 746                {       /*  Init_AR00_AR14 */
 747                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 748                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 749                        0x41, 0x00, 0x0F, 0x00, 0x00,
 750                },
 751                {       /*  Init_CR00_CR18 */
 752                        0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
 753                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 754                        0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
 755                        0xFF,
 756                },
 757                {       /*  Init_CR30_CR4D */
 758                        0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
 759                        0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
 760                        0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
 761                        0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
 762                },
 763                {       /*  Init_CR90_CRA7 */
 764                        0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
 765                        0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
 766                        0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
 767                },
 768        },
 769
 770        {       /*  mode#8: 320 x 240  32Bpp  60Hz */
 771                320, 240, 32, 60,
 772                /*  Init_MISC */
 773                0xEB,
 774                {       /*  Init_SR0_SR4 */
 775                        0x03, 0x01, 0x0F, 0x03, 0x0E,
 776                },
 777                {       /*  Init_SR10_SR24 */
 778                        0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
 779                        0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
 780                        0xC4, 0x32, 0x02, 0x01, 0x01,
 781                },
 782                {       /*  Init_SR30_SR75 */
 783                        0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
 784                        0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
 785                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 786                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
 787                        0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
 788                        0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
 789                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 790                        0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
 791                        0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
 792                },
 793                {       /*  Init_SR80_SR93 */
 794                        0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
 795                        0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
 796                        0x00, 0x00, 0x00, 0x00,
 797                },
 798                {       /*  Init_SRA0_SRAF */
 799                        0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
 800                        0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
 801                },
 802                {       /*  Init_GR00_GR08 */
 803                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 804                        0xFF,
 805                },
 806                {       /*  Init_AR00_AR14 */
 807                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 808                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 809                        0x41, 0x00, 0x0F, 0x00, 0x00,
 810                },
 811                {       /*  Init_CR00_CR18 */
 812                        0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
 813                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 814                        0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
 815                        0xFF,
 816                },
 817                {       /*  Init_CR30_CR4D */
 818                        0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
 819                        0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
 820                        0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
 821                        0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
 822                },
 823                {       /*  Init_CR90_CRA7 */
 824                        0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
 825                        0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
 826                        0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
 827                },
 828        },
 829};
 830
 831static struct screen_info smtc_scr_info;
 832
 833static char *mode_option;
 834
 835/* process command line options, get vga parameter */
 836static void __init sm7xx_vga_setup(char *options)
 837{
 838        int i;
 839
 840        if (!options || !*options)
 841                return;
 842
 843        smtc_scr_info.lfb_width = 0;
 844        smtc_scr_info.lfb_height = 0;
 845        smtc_scr_info.lfb_depth = 0;
 846
 847        pr_debug("%s = %s\n", __func__, options);
 848
 849        for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
 850                if (strstr(options, vesa_mode_table[i].index)) {
 851                        smtc_scr_info.lfb_width  = vesa_mode_table[i].lfb_width;
 852                        smtc_scr_info.lfb_height =
 853                                                vesa_mode_table[i].lfb_height;
 854                        smtc_scr_info.lfb_depth  = vesa_mode_table[i].lfb_depth;
 855                        return;
 856                }
 857        }
 858}
 859
 860static void sm712_setpalette(int regno, unsigned int red, unsigned int green,
 861                             unsigned int blue, struct fb_info *info)
 862{
 863        /* set bit 5:4 = 01 (write LCD RAM only) */
 864        smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
 865
 866        smtc_mmiowb(regno, dac_reg);
 867        smtc_mmiowb(red >> 10, dac_val);
 868        smtc_mmiowb(green >> 10, dac_val);
 869        smtc_mmiowb(blue >> 10, dac_val);
 870}
 871
 872/* chan_to_field
 873 *
 874 * convert a colour value into a field position
 875 *
 876 * from pxafb.c
 877 */
 878
 879static inline unsigned int chan_to_field(unsigned int chan,
 880                                         struct fb_bitfield *bf)
 881{
 882        chan &= 0xffff;
 883        chan >>= 16 - bf->length;
 884        return chan << bf->offset;
 885}
 886
 887static int smtc_blank(int blank_mode, struct fb_info *info)
 888{
 889        struct smtcfb_info *sfb = info->par;
 890
 891        /* clear DPMS setting */
 892        switch (blank_mode) {
 893        case FB_BLANK_UNBLANK:
 894                /* Screen On: HSync: On, VSync : On */
 895
 896                switch (sfb->chip_id) {
 897                case 0x710:
 898                case 0x712:
 899                        smtc_seqw(0x6a, 0x16);
 900                        smtc_seqw(0x6b, 0x02);
 901                        break;
 902                case 0x720:
 903                        smtc_seqw(0x6a, 0x0d);
 904                        smtc_seqw(0x6b, 0x02);
 905                        break;
 906                }
 907
 908                smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
 909                smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
 910                smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
 911                smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
 912                smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
 913                smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
 914                break;
 915        case FB_BLANK_NORMAL:
 916                /* Screen Off: HSync: On, VSync : On   Soft blank */
 917                smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
 918                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 919                smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
 920                smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
 921                smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
 922                smtc_seqw(0x6a, 0x16);
 923                smtc_seqw(0x6b, 0x02);
 924                break;
 925        case FB_BLANK_VSYNC_SUSPEND:
 926                /* Screen On: HSync: On, VSync : Off */
 927                smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
 928                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 929                smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
 930                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
 931                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
 932                smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
 933                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
 934                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
 935                smtc_seqw(0x6a, 0x0c);
 936                smtc_seqw(0x6b, 0x02);
 937                break;
 938        case FB_BLANK_HSYNC_SUSPEND:
 939                /* Screen On: HSync: Off, VSync : On */
 940                smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
 941                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 942                smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
 943                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
 944                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
 945                smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
 946                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
 947                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
 948                smtc_seqw(0x6a, 0x0c);
 949                smtc_seqw(0x6b, 0x02);
 950                break;
 951        case FB_BLANK_POWERDOWN:
 952                /* Screen On: HSync: Off, VSync : Off */
 953                smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
 954                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 955                smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
 956                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
 957                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
 958                smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
 959                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
 960                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
 961                smtc_seqw(0x6a, 0x0c);
 962                smtc_seqw(0x6b, 0x02);
 963                break;
 964        default:
 965                return -EINVAL;
 966        }
 967
 968        return 0;
 969}
 970
 971static int smtc_setcolreg(unsigned int regno, unsigned int red,
 972                          unsigned int green, unsigned int blue,
 973                          unsigned int trans, struct fb_info *info)
 974{
 975        struct smtcfb_info *sfb;
 976        u32 val;
 977
 978        sfb = info->par;
 979
 980        if (regno > 255)
 981                return 1;
 982
 983        switch (sfb->fb->fix.visual) {
 984        case FB_VISUAL_DIRECTCOLOR:
 985        case FB_VISUAL_TRUECOLOR:
 986                /*
 987                 * 16/32 bit true-colour, use pseudo-palette for 16 base color
 988                 */
 989                if (regno >= 16)
 990                        break;
 991                if (sfb->fb->var.bits_per_pixel == 16) {
 992                        u32 *pal = sfb->fb->pseudo_palette;
 993
 994                        val = chan_to_field(red, &sfb->fb->var.red);
 995                        val |= chan_to_field(green, &sfb->fb->var.green);
 996                        val |= chan_to_field(blue, &sfb->fb->var.blue);
 997                        pal[regno] = pal_rgb(red, green, blue, val);
 998                } else {
 999                        u32 *pal = sfb->fb->pseudo_palette;
1000
1001                        val = chan_to_field(red, &sfb->fb->var.red);
1002                        val |= chan_to_field(green, &sfb->fb->var.green);
1003                        val |= chan_to_field(blue, &sfb->fb->var.blue);
1004                        pal[regno] = big_swap(val);
1005                }
1006                break;
1007
1008        case FB_VISUAL_PSEUDOCOLOR:
1009                /* color depth 8 bit */
1010                sm712_setpalette(regno, red, green, blue, info);
1011                break;
1012
1013        default:
1014                return 1;       /* unknown type */
1015        }
1016
1017        return 0;
1018}
1019
1020static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
1021                           size_t count, loff_t *ppos)
1022{
1023        unsigned long p = *ppos;
1024
1025        u32 *buffer, *dst;
1026        u32 __iomem *src;
1027        int c, i, cnt = 0, err = 0;
1028        unsigned long total_size;
1029
1030        if (!info || !info->screen_base)
1031                return -ENODEV;
1032
1033        if (info->state != FBINFO_STATE_RUNNING)
1034                return -EPERM;
1035
1036        total_size = info->screen_size;
1037
1038        if (total_size == 0)
1039                total_size = info->fix.smem_len;
1040
1041        if (p >= total_size)
1042                return 0;
1043
1044        if (count >= total_size)
1045                count = total_size;
1046
1047        if (count + p > total_size)
1048                count = total_size - p;
1049
1050        buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
1051        if (!buffer)
1052                return -ENOMEM;
1053
1054        src = (u32 __iomem *)(info->screen_base + p);
1055
1056        if (info->fbops->fb_sync)
1057                info->fbops->fb_sync(info);
1058
1059        while (count) {
1060                c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1061                dst = buffer;
1062                for (i = c >> 2; i--;) {
1063                        *dst = fb_readl(src++);
1064                        *dst = big_swap(*dst);
1065                        dst++;
1066                }
1067                if (c & 3) {
1068                        u8 *dst8 = (u8 *)dst;
1069                        u8 __iomem *src8 = (u8 __iomem *)src;
1070
1071                        for (i = c & 3; i--;) {
1072                                if (i & 1) {
1073                                        *dst8++ = fb_readb(++src8);
1074                                } else {
1075                                        *dst8++ = fb_readb(--src8);
1076                                        src8 += 2;
1077                                }
1078                        }
1079                        src = (u32 __iomem *)src8;
1080                }
1081
1082                if (copy_to_user(buf, buffer, c)) {
1083                        err = -EFAULT;
1084                        break;
1085                }
1086                *ppos += c;
1087                buf += c;
1088                cnt += c;
1089                count -= c;
1090        }
1091
1092        kfree(buffer);
1093
1094        return (err) ? err : cnt;
1095}
1096
1097static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1098                            size_t count, loff_t *ppos)
1099{
1100        unsigned long p = *ppos;
1101
1102        u32 *buffer, *src;
1103        u32 __iomem *dst;
1104        int c, i, cnt = 0, err = 0;
1105        unsigned long total_size;
1106
1107        if (!info || !info->screen_base)
1108                return -ENODEV;
1109
1110        if (info->state != FBINFO_STATE_RUNNING)
1111                return -EPERM;
1112
1113        total_size = info->screen_size;
1114
1115        if (total_size == 0)
1116                total_size = info->fix.smem_len;
1117
1118        if (p > total_size)
1119                return -EFBIG;
1120
1121        if (count > total_size) {
1122                err = -EFBIG;
1123                count = total_size;
1124        }
1125
1126        if (count + p > total_size) {
1127                if (!err)
1128                        err = -ENOSPC;
1129
1130                count = total_size - p;
1131        }
1132
1133        buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
1134        if (!buffer)
1135                return -ENOMEM;
1136
1137        dst = (u32 __iomem *)(info->screen_base + p);
1138
1139        if (info->fbops->fb_sync)
1140                info->fbops->fb_sync(info);
1141
1142        while (count) {
1143                c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1144                src = buffer;
1145
1146                if (copy_from_user(src, buf, c)) {
1147                        err = -EFAULT;
1148                        break;
1149                }
1150
1151                for (i = c >> 2; i--;) {
1152                        fb_writel(big_swap(*src), dst++);
1153                        src++;
1154                }
1155                if (c & 3) {
1156                        u8 *src8 = (u8 *)src;
1157                        u8 __iomem *dst8 = (u8 __iomem *)dst;
1158
1159                        for (i = c & 3; i--;) {
1160                                if (i & 1) {
1161                                        fb_writeb(*src8++, ++dst8);
1162                                } else {
1163                                        fb_writeb(*src8++, --dst8);
1164                                        dst8 += 2;
1165                                }
1166                        }
1167                        dst = (u32 __iomem *)dst8;
1168                }
1169
1170                *ppos += c;
1171                buf += c;
1172                cnt += c;
1173                count -= c;
1174        }
1175
1176        kfree(buffer);
1177
1178        return (cnt) ? cnt : err;
1179}
1180
1181static void sm7xx_set_timing(struct smtcfb_info *sfb)
1182{
1183        int i = 0, j = 0;
1184        u32 m_nscreenstride;
1185
1186        dev_dbg(&sfb->pdev->dev,
1187                "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1188                sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1189
1190        for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1191                if (vgamode[j].mmsizex != sfb->width ||
1192                    vgamode[j].mmsizey != sfb->height ||
1193                    vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1194                    vgamode[j].hz != sfb->hz)
1195                        continue;
1196
1197                dev_dbg(&sfb->pdev->dev,
1198                        "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1199                        vgamode[j].mmsizex, vgamode[j].mmsizey,
1200                        vgamode[j].bpp, vgamode[j].hz);
1201
1202                dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1203
1204                smtc_mmiowb(0x0, 0x3c6);
1205
1206                smtc_seqw(0, 0x1);
1207
1208                smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1209
1210                /* init SEQ register SR00 - SR04 */
1211                for (i = 0; i < SIZE_SR00_SR04; i++)
1212                        smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1213
1214                /* init SEQ register SR10 - SR24 */
1215                for (i = 0; i < SIZE_SR10_SR24; i++)
1216                        smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1217
1218                /* init SEQ register SR30 - SR75 */
1219                for (i = 0; i < SIZE_SR30_SR75; i++)
1220                        if ((i + 0x30) != 0x30 && (i + 0x30) != 0x62 &&
1221                            (i + 0x30) != 0x6a && (i + 0x30) != 0x6b &&
1222                            (i + 0x30) != 0x70 && (i + 0x30) != 0x71 &&
1223                            (i + 0x30) != 0x74 && (i + 0x30) != 0x75)
1224                                smtc_seqw(i + 0x30,
1225                                          vgamode[j].init_sr30_sr75[i]);
1226
1227                /* init SEQ register SR80 - SR93 */
1228                for (i = 0; i < SIZE_SR80_SR93; i++)
1229                        smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1230
1231                /* init SEQ register SRA0 - SRAF */
1232                for (i = 0; i < SIZE_SRA0_SRAF; i++)
1233                        smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1234
1235                /* init Graphic register GR00 - GR08 */
1236                for (i = 0; i < SIZE_GR00_GR08; i++)
1237                        smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1238
1239                /* init Attribute register AR00 - AR14 */
1240                for (i = 0; i < SIZE_AR00_AR14; i++)
1241                        smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1242
1243                /* init CRTC register CR00 - CR18 */
1244                for (i = 0; i < SIZE_CR00_CR18; i++)
1245                        smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1246
1247                /* init CRTC register CR30 - CR4D */
1248                for (i = 0; i < SIZE_CR30_CR4D; i++) {
1249                        if ((i + 0x30) >= 0x3B && (i + 0x30) <= 0x3F)
1250                                /* side-effect, don't write to CR3B-CR3F */
1251                                continue;
1252                        smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1253                }
1254
1255                /* init CRTC register CR90 - CRA7 */
1256                for (i = 0; i < SIZE_CR90_CRA7; i++)
1257                        smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1258        }
1259        smtc_mmiowb(0x67, 0x3c2);
1260
1261        /* set VPR registers */
1262        writel(0x0, sfb->vp_regs + 0x0C);
1263        writel(0x0, sfb->vp_regs + 0x40);
1264
1265        /* set data width */
1266        m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1267        switch (sfb->fb->var.bits_per_pixel) {
1268        case 8:
1269                writel(0x0, sfb->vp_regs + 0x0);
1270                break;
1271        case 16:
1272                writel(0x00020000, sfb->vp_regs + 0x0);
1273                break;
1274        case 24:
1275                writel(0x00040000, sfb->vp_regs + 0x0);
1276                break;
1277        case 32:
1278                writel(0x00030000, sfb->vp_regs + 0x0);
1279                break;
1280        }
1281        writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1282               sfb->vp_regs + 0x10);
1283}
1284
1285static void smtc_set_timing(struct smtcfb_info *sfb)
1286{
1287        switch (sfb->chip_id) {
1288        case 0x710:
1289        case 0x712:
1290        case 0x720:
1291                sm7xx_set_timing(sfb);
1292                break;
1293        }
1294}
1295
1296static void smtcfb_setmode(struct smtcfb_info *sfb)
1297{
1298        switch (sfb->fb->var.bits_per_pixel) {
1299        case 32:
1300                sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1301                sfb->fb->fix.line_length  = sfb->fb->var.xres * 4;
1302                sfb->fb->var.red.length   = 8;
1303                sfb->fb->var.green.length = 8;
1304                sfb->fb->var.blue.length  = 8;
1305                sfb->fb->var.red.offset   = 16;
1306                sfb->fb->var.green.offset = 8;
1307                sfb->fb->var.blue.offset  = 0;
1308                break;
1309        case 24:
1310                sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1311                sfb->fb->fix.line_length  = sfb->fb->var.xres * 3;
1312                sfb->fb->var.red.length   = 8;
1313                sfb->fb->var.green.length = 8;
1314                sfb->fb->var.blue.length  = 8;
1315                sfb->fb->var.red.offset   = 16;
1316                sfb->fb->var.green.offset = 8;
1317                sfb->fb->var.blue.offset  = 0;
1318                break;
1319        case 8:
1320                sfb->fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
1321                sfb->fb->fix.line_length  = sfb->fb->var.xres;
1322                sfb->fb->var.red.length   = 3;
1323                sfb->fb->var.green.length = 3;
1324                sfb->fb->var.blue.length  = 2;
1325                sfb->fb->var.red.offset   = 5;
1326                sfb->fb->var.green.offset = 2;
1327                sfb->fb->var.blue.offset  = 0;
1328                break;
1329        case 16:
1330        default:
1331                sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1332                sfb->fb->fix.line_length  = sfb->fb->var.xres * 2;
1333                sfb->fb->var.red.length   = 5;
1334                sfb->fb->var.green.length = 6;
1335                sfb->fb->var.blue.length  = 5;
1336                sfb->fb->var.red.offset   = 11;
1337                sfb->fb->var.green.offset = 5;
1338                sfb->fb->var.blue.offset  = 0;
1339                break;
1340        }
1341
1342        sfb->width  = sfb->fb->var.xres;
1343        sfb->height = sfb->fb->var.yres;
1344        sfb->hz = 60;
1345        smtc_set_timing(sfb);
1346}
1347
1348static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1349{
1350        /* sanity checks */
1351        if (var->xres_virtual < var->xres)
1352                var->xres_virtual = var->xres;
1353
1354        if (var->yres_virtual < var->yres)
1355                var->yres_virtual = var->yres;
1356
1357        /* set valid default bpp */
1358        if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
1359            (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1360                var->bits_per_pixel = 16;
1361
1362        return 0;
1363}
1364
1365static int smtc_set_par(struct fb_info *info)
1366{
1367        smtcfb_setmode(info->par);
1368
1369        return 0;
1370}
1371
1372static struct fb_ops smtcfb_ops = {
1373        .owner        = THIS_MODULE,
1374        .fb_check_var = smtc_check_var,
1375        .fb_set_par   = smtc_set_par,
1376        .fb_setcolreg = smtc_setcolreg,
1377        .fb_blank     = smtc_blank,
1378        .fb_fillrect  = cfb_fillrect,
1379        .fb_imageblit = cfb_imageblit,
1380        .fb_copyarea  = cfb_copyarea,
1381        .fb_read      = smtcfb_read,
1382        .fb_write     = smtcfb_write,
1383};
1384
1385/*
1386 * Unmap in the memory mapped IO registers
1387 */
1388
1389static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1390{
1391        if (sfb && smtc_regbaseaddress)
1392                smtc_regbaseaddress = NULL;
1393}
1394
1395/*
1396 * Map in the screen memory
1397 */
1398
1399static int smtc_map_smem(struct smtcfb_info *sfb,
1400                         struct pci_dev *pdev, u_long smem_len)
1401{
1402        sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1403
1404        if (sfb->chip_id == 0x720)
1405                /* on SM720, the framebuffer starts at the 1 MB offset */
1406                sfb->fb->fix.smem_start += 0x00200000;
1407
1408        /* XXX: is it safe for SM720 on Big-Endian? */
1409        if (sfb->fb->var.bits_per_pixel == 32)
1410                sfb->fb->fix.smem_start += big_addr;
1411
1412        sfb->fb->fix.smem_len = smem_len;
1413
1414        sfb->fb->screen_base = sfb->lfb;
1415
1416        if (!sfb->fb->screen_base) {
1417                dev_err(&pdev->dev,
1418                        "%s: unable to map screen memory\n", sfb->fb->fix.id);
1419                return -ENOMEM;
1420        }
1421
1422        return 0;
1423}
1424
1425/*
1426 * Unmap in the screen memory
1427 *
1428 */
1429static void smtc_unmap_smem(struct smtcfb_info *sfb)
1430{
1431        if (sfb && sfb->fb->screen_base) {
1432                iounmap(sfb->fb->screen_base);
1433                sfb->fb->screen_base = NULL;
1434        }
1435}
1436
1437/*
1438 * We need to wake up the device and make sure its in linear memory mode.
1439 */
1440static inline void sm7xx_init_hw(void)
1441{
1442        outb_p(0x18, 0x3c4);
1443        outb_p(0x11, 0x3c5);
1444}
1445
1446static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
1447{
1448        u8 vram;
1449
1450        switch (sfb->chip_id) {
1451        case 0x710:
1452        case 0x712:
1453                /*
1454                 * Assume SM712 graphics chip has 4MB VRAM.
1455                 *
1456                 * FIXME: SM712 can have 2MB VRAM, which is used on earlier
1457                 * laptops, such as IBM Thinkpad 240X. This driver would
1458                 * probably crash on those machines. If anyone gets one of
1459                 * those and is willing to help, run "git blame" and send me
1460                 * an E-mail.
1461                 */
1462                return 0x00400000;
1463        case 0x720:
1464                outb_p(0x76, 0x3c4);
1465                vram = inb_p(0x3c5) >> 6;
1466
1467                if (vram == 0x00)
1468                        return 0x00800000;  /* 8 MB */
1469                else if (vram == 0x01)
1470                        return 0x01000000;  /* 16 MB */
1471                else if (vram == 0x02)
1472                        return 0x00400000;  /* illegal, fallback to 4 MB */
1473                else if (vram == 0x03)
1474                        return 0x00400000;  /* 4 MB */
1475        }
1476        return 0;  /* unknown hardware */
1477}
1478
1479static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
1480{
1481        /* get mode parameter from smtc_scr_info */
1482        if (smtc_scr_info.lfb_width != 0) {
1483                sfb->fb->var.xres = smtc_scr_info.lfb_width;
1484                sfb->fb->var.yres = smtc_scr_info.lfb_height;
1485                sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1486                goto final;
1487        }
1488
1489        /*
1490         * No parameter, default resolution is 1024x768-16.
1491         *
1492         * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
1493         * panel, also see the comments about Thinkpad 240X above.
1494         */
1495        sfb->fb->var.xres = SCREEN_X_RES;
1496        sfb->fb->var.yres = SCREEN_Y_RES_PC;
1497        sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1498
1499#ifdef CONFIG_MIPS
1500        /*
1501         * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
1502         * target platform of this driver, but nearly all old x86 laptops have
1503         * 1024x768. Lighting 768 panels using 600's timings would partially
1504         * garble the display, so we don't want that. But it's not possible to
1505         * distinguish them reliably.
1506         *
1507         * So we change the default to 768, but keep 600 as-is on MIPS.
1508         */
1509        sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
1510#endif
1511
1512final:
1513        big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1514}
1515
1516static int smtcfb_pci_probe(struct pci_dev *pdev,
1517                            const struct pci_device_id *ent)
1518{
1519        struct smtcfb_info *sfb;
1520        struct fb_info *info;
1521        u_long smem_size;
1522        int err;
1523        unsigned long mmio_base;
1524
1525        dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1526
1527        err = pci_enable_device(pdev);  /* enable SMTC chip */
1528        if (err)
1529                return err;
1530
1531        err = pci_request_region(pdev, 0, "sm7xxfb");
1532        if (err < 0) {
1533                dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1534                goto failed_regions;
1535        }
1536
1537        sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1538
1539        info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1540        if (!info) {
1541                err = -ENOMEM;
1542                goto failed_free;
1543        }
1544
1545        sfb = info->par;
1546        sfb->fb = info;
1547        sfb->chip_id = ent->device;
1548        sfb->pdev = pdev;
1549        info->flags = FBINFO_FLAG_DEFAULT;
1550        info->fbops = &smtcfb_ops;
1551        info->fix = smtcfb_fix;
1552        info->var = smtcfb_var;
1553        info->pseudo_palette = sfb->colreg;
1554        info->par = sfb;
1555
1556        pci_set_drvdata(pdev, sfb);
1557
1558        sm7xx_init_hw();
1559
1560        /* Map address and memory detection */
1561        mmio_base = pci_resource_start(pdev, 0);
1562        pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1563
1564        smem_size = sm7xx_vram_probe(sfb);
1565        dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
1566                                        smem_size / 1048576);
1567
1568        switch (sfb->chip_id) {
1569        case 0x710:
1570        case 0x712:
1571                sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1572                sfb->fb->fix.mmio_len = 0x00400000;
1573                sfb->lfb = ioremap(mmio_base, mmio_addr);
1574                if (!sfb->lfb) {
1575                        dev_err(&pdev->dev,
1576                                "%s: unable to map memory mapped IO!\n",
1577                                sfb->fb->fix.id);
1578                        err = -ENOMEM;
1579                        goto failed_fb;
1580                }
1581
1582                sfb->mmio = (smtc_regbaseaddress =
1583                    sfb->lfb + 0x00700000);
1584                sfb->dp_regs = sfb->lfb + 0x00408000;
1585                sfb->vp_regs = sfb->lfb + 0x0040c000;
1586                if (sfb->fb->var.bits_per_pixel == 32) {
1587                        sfb->lfb += big_addr;
1588                        dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1589                }
1590
1591                /* set MCLK = 14.31818 * (0x16 / 0x2) */
1592                smtc_seqw(0x6a, 0x16);
1593                smtc_seqw(0x6b, 0x02);
1594                smtc_seqw(0x62, 0x3e);
1595                /* enable PCI burst */
1596                smtc_seqw(0x17, 0x20);
1597                /* enable word swap */
1598                if (sfb->fb->var.bits_per_pixel == 32)
1599                        seqw17();
1600                break;
1601        case 0x720:
1602                sfb->fb->fix.mmio_start = mmio_base;
1603                sfb->fb->fix.mmio_len = 0x00200000;
1604                sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
1605                sfb->lfb = sfb->dp_regs + 0x00200000;
1606                sfb->mmio = (smtc_regbaseaddress =
1607                    sfb->dp_regs + 0x000c0000);
1608                sfb->vp_regs = sfb->dp_regs + 0x800;
1609
1610                smtc_seqw(0x62, 0xff);
1611                smtc_seqw(0x6a, 0x0d);
1612                smtc_seqw(0x6b, 0x02);
1613                break;
1614        default:
1615                dev_err(&pdev->dev,
1616                        "No valid Silicon Motion display chip was detected!\n");
1617
1618                goto failed_fb;
1619        }
1620
1621        /* probe and decide resolution */
1622        sm7xx_resolution_probe(sfb);
1623
1624        /* can support 32 bpp */
1625        if (sfb->fb->var.bits_per_pixel == 15)
1626                sfb->fb->var.bits_per_pixel = 16;
1627
1628        sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1629        sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1630        err = smtc_map_smem(sfb, pdev, smem_size);
1631        if (err)
1632                goto failed;
1633
1634        /*
1635         * The screen would be temporarily garbled when sm712fb takes over
1636         * vesafb or VGA text mode. Zero the framebuffer.
1637         */
1638        memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
1639
1640        err = register_framebuffer(info);
1641        if (err < 0)
1642                goto failed;
1643
1644        dev_info(&pdev->dev,
1645                 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1646                 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1647                 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1648
1649        return 0;
1650
1651failed:
1652        dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1653
1654        smtc_unmap_smem(sfb);
1655        smtc_unmap_mmio(sfb);
1656failed_fb:
1657        framebuffer_release(info);
1658
1659failed_free:
1660        pci_release_region(pdev, 0);
1661
1662failed_regions:
1663        pci_disable_device(pdev);
1664
1665        return err;
1666}
1667
1668/*
1669 * 0x710 (LynxEM)
1670 * 0x712 (LynxEM+)
1671 * 0x720 (Lynx3DM, Lynx3DM+)
1672 */
1673static const struct pci_device_id smtcfb_pci_table[] = {
1674        { PCI_DEVICE(0x126f, 0x710), },
1675        { PCI_DEVICE(0x126f, 0x712), },
1676        { PCI_DEVICE(0x126f, 0x720), },
1677        {0,}
1678};
1679
1680MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1681
1682static void smtcfb_pci_remove(struct pci_dev *pdev)
1683{
1684        struct smtcfb_info *sfb;
1685
1686        sfb = pci_get_drvdata(pdev);
1687        smtc_unmap_smem(sfb);
1688        smtc_unmap_mmio(sfb);
1689        unregister_framebuffer(sfb->fb);
1690        framebuffer_release(sfb->fb);
1691        pci_release_region(pdev, 0);
1692        pci_disable_device(pdev);
1693}
1694
1695static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1696{
1697        struct smtcfb_info *sfb = dev_get_drvdata(device);
1698
1699
1700        /* set the hw in sleep mode use external clock and self memory refresh
1701         * so that we can turn off internal PLLs later on
1702         */
1703        smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1704        smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1705
1706        console_lock();
1707        fb_set_suspend(sfb->fb, 1);
1708        console_unlock();
1709
1710        /* additionally turn off all function blocks including internal PLLs */
1711        smtc_seqw(0x21, 0xff);
1712
1713        return 0;
1714}
1715
1716static int __maybe_unused smtcfb_pci_resume(struct device *device)
1717{
1718        struct smtcfb_info *sfb = dev_get_drvdata(device);
1719
1720
1721        /* reinit hardware */
1722        sm7xx_init_hw();
1723        switch (sfb->chip_id) {
1724        case 0x710:
1725        case 0x712:
1726                /* set MCLK = 14.31818 *  (0x16 / 0x2) */
1727                smtc_seqw(0x6a, 0x16);
1728                smtc_seqw(0x6b, 0x02);
1729                smtc_seqw(0x62, 0x3e);
1730                /* enable PCI burst */
1731                smtc_seqw(0x17, 0x20);
1732                if (sfb->fb->var.bits_per_pixel == 32)
1733                        seqw17();
1734                break;
1735        case 0x720:
1736                smtc_seqw(0x62, 0xff);
1737                smtc_seqw(0x6a, 0x0d);
1738                smtc_seqw(0x6b, 0x02);
1739                break;
1740        }
1741
1742        smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1743        smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1744
1745        smtcfb_setmode(sfb);
1746
1747        console_lock();
1748        fb_set_suspend(sfb->fb, 0);
1749        console_unlock();
1750
1751        return 0;
1752}
1753
1754static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1755
1756static struct pci_driver smtcfb_driver = {
1757        .name = "smtcfb",
1758        .id_table = smtcfb_pci_table,
1759        .probe = smtcfb_pci_probe,
1760        .remove = smtcfb_pci_remove,
1761        .driver.pm  = &sm7xx_pm_ops,
1762};
1763
1764static int __init sm712fb_init(void)
1765{
1766        char *option = NULL;
1767
1768        if (fb_get_options("sm712fb", &option))
1769                return -ENODEV;
1770        if (option && *option)
1771                mode_option = option;
1772        sm7xx_vga_setup(mode_option);
1773
1774        return pci_register_driver(&smtcfb_driver);
1775}
1776
1777module_init(sm712fb_init);
1778
1779static void __exit sm712fb_exit(void)
1780{
1781        pci_unregister_driver(&smtcfb_driver);
1782}
1783
1784module_exit(sm712fb_exit);
1785
1786MODULE_AUTHOR("Siliconmotion ");
1787MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1788MODULE_LICENSE("GPL");
1789