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 const 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                if (sfb->chip_id == 0x720)
1433                        sfb->fb->screen_base -= 0x00200000;
1434                iounmap(sfb->fb->screen_base);
1435                sfb->fb->screen_base = NULL;
1436        }
1437}
1438
1439/*
1440 * We need to wake up the device and make sure its in linear memory mode.
1441 */
1442static inline void sm7xx_init_hw(void)
1443{
1444        outb_p(0x18, 0x3c4);
1445        outb_p(0x11, 0x3c5);
1446}
1447
1448static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
1449{
1450        u8 vram;
1451
1452        switch (sfb->chip_id) {
1453        case 0x710:
1454        case 0x712:
1455                /*
1456                 * Assume SM712 graphics chip has 4MB VRAM.
1457                 *
1458                 * FIXME: SM712 can have 2MB VRAM, which is used on earlier
1459                 * laptops, such as IBM Thinkpad 240X. This driver would
1460                 * probably crash on those machines. If anyone gets one of
1461                 * those and is willing to help, run "git blame" and send me
1462                 * an E-mail.
1463                 */
1464                return 0x00400000;
1465        case 0x720:
1466                outb_p(0x76, 0x3c4);
1467                vram = inb_p(0x3c5) >> 6;
1468
1469                if (vram == 0x00)
1470                        return 0x00800000;  /* 8 MB */
1471                else if (vram == 0x01)
1472                        return 0x01000000;  /* 16 MB */
1473                else if (vram == 0x02)
1474                        return 0x00400000;  /* illegal, fallback to 4 MB */
1475                else if (vram == 0x03)
1476                        return 0x00400000;  /* 4 MB */
1477        }
1478        return 0;  /* unknown hardware */
1479}
1480
1481static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
1482{
1483        /* get mode parameter from smtc_scr_info */
1484        if (smtc_scr_info.lfb_width != 0) {
1485                sfb->fb->var.xres = smtc_scr_info.lfb_width;
1486                sfb->fb->var.yres = smtc_scr_info.lfb_height;
1487                sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1488                goto final;
1489        }
1490
1491        /*
1492         * No parameter, default resolution is 1024x768-16.
1493         *
1494         * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
1495         * panel, also see the comments about Thinkpad 240X above.
1496         */
1497        sfb->fb->var.xres = SCREEN_X_RES;
1498        sfb->fb->var.yres = SCREEN_Y_RES_PC;
1499        sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1500
1501#ifdef CONFIG_MIPS
1502        /*
1503         * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
1504         * target platform of this driver, but nearly all old x86 laptops have
1505         * 1024x768. Lighting 768 panels using 600's timings would partially
1506         * garble the display, so we don't want that. But it's not possible to
1507         * distinguish them reliably.
1508         *
1509         * So we change the default to 768, but keep 600 as-is on MIPS.
1510         */
1511        sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
1512#endif
1513
1514final:
1515        big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1516}
1517
1518static int smtcfb_pci_probe(struct pci_dev *pdev,
1519                            const struct pci_device_id *ent)
1520{
1521        struct smtcfb_info *sfb;
1522        struct fb_info *info;
1523        u_long smem_size;
1524        int err;
1525        unsigned long mmio_base;
1526
1527        dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1528
1529        err = pci_enable_device(pdev);  /* enable SMTC chip */
1530        if (err)
1531                return err;
1532
1533        err = pci_request_region(pdev, 0, "sm7xxfb");
1534        if (err < 0) {
1535                dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1536                goto failed_regions;
1537        }
1538
1539        sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1540
1541        info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1542        if (!info) {
1543                err = -ENOMEM;
1544                goto failed_free;
1545        }
1546
1547        sfb = info->par;
1548        sfb->fb = info;
1549        sfb->chip_id = ent->device;
1550        sfb->pdev = pdev;
1551        info->flags = FBINFO_FLAG_DEFAULT;
1552        info->fbops = &smtcfb_ops;
1553        info->fix = smtcfb_fix;
1554        info->var = smtcfb_var;
1555        info->pseudo_palette = sfb->colreg;
1556        info->par = sfb;
1557
1558        pci_set_drvdata(pdev, sfb);
1559
1560        sm7xx_init_hw();
1561
1562        /* Map address and memory detection */
1563        mmio_base = pci_resource_start(pdev, 0);
1564        pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1565
1566        smem_size = sm7xx_vram_probe(sfb);
1567        dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
1568                                        smem_size / 1048576);
1569
1570        switch (sfb->chip_id) {
1571        case 0x710:
1572        case 0x712:
1573                sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1574                sfb->fb->fix.mmio_len = 0x00400000;
1575                sfb->lfb = ioremap(mmio_base, mmio_addr);
1576                if (!sfb->lfb) {
1577                        dev_err(&pdev->dev,
1578                                "%s: unable to map memory mapped IO!\n",
1579                                sfb->fb->fix.id);
1580                        err = -ENOMEM;
1581                        goto failed_fb;
1582                }
1583
1584                sfb->mmio = (smtc_regbaseaddress =
1585                    sfb->lfb + 0x00700000);
1586                sfb->dp_regs = sfb->lfb + 0x00408000;
1587                sfb->vp_regs = sfb->lfb + 0x0040c000;
1588                if (sfb->fb->var.bits_per_pixel == 32) {
1589                        sfb->lfb += big_addr;
1590                        dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1591                }
1592
1593                /* set MCLK = 14.31818 * (0x16 / 0x2) */
1594                smtc_seqw(0x6a, 0x16);
1595                smtc_seqw(0x6b, 0x02);
1596                smtc_seqw(0x62, 0x3e);
1597                /* enable PCI burst */
1598                smtc_seqw(0x17, 0x20);
1599                /* enable word swap */
1600                if (sfb->fb->var.bits_per_pixel == 32)
1601                        seqw17();
1602                break;
1603        case 0x720:
1604                sfb->fb->fix.mmio_start = mmio_base;
1605                sfb->fb->fix.mmio_len = 0x00200000;
1606                sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
1607                if (!sfb->dp_regs) {
1608                        dev_err(&pdev->dev,
1609                                "%s: unable to map memory mapped IO!\n",
1610                                sfb->fb->fix.id);
1611                        err = -ENOMEM;
1612                        goto failed_fb;
1613                }
1614
1615                sfb->lfb = sfb->dp_regs + 0x00200000;
1616                sfb->mmio = (smtc_regbaseaddress =
1617                    sfb->dp_regs + 0x000c0000);
1618                sfb->vp_regs = sfb->dp_regs + 0x800;
1619
1620                smtc_seqw(0x62, 0xff);
1621                smtc_seqw(0x6a, 0x0d);
1622                smtc_seqw(0x6b, 0x02);
1623                break;
1624        default:
1625                dev_err(&pdev->dev,
1626                        "No valid Silicon Motion display chip was detected!\n");
1627                err = -ENODEV;
1628                goto failed_fb;
1629        }
1630
1631        /* probe and decide resolution */
1632        sm7xx_resolution_probe(sfb);
1633
1634        /* can support 32 bpp */
1635        if (sfb->fb->var.bits_per_pixel == 15)
1636                sfb->fb->var.bits_per_pixel = 16;
1637
1638        sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1639        sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1640        err = smtc_map_smem(sfb, pdev, smem_size);
1641        if (err)
1642                goto failed;
1643
1644        /*
1645         * The screen would be temporarily garbled when sm712fb takes over
1646         * vesafb or VGA text mode. Zero the framebuffer.
1647         */
1648        memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
1649
1650        err = register_framebuffer(info);
1651        if (err < 0)
1652                goto failed;
1653
1654        dev_info(&pdev->dev,
1655                 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1656                 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1657                 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1658
1659        return 0;
1660
1661failed:
1662        dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1663
1664        smtc_unmap_smem(sfb);
1665        smtc_unmap_mmio(sfb);
1666failed_fb:
1667        framebuffer_release(info);
1668
1669failed_free:
1670        pci_release_region(pdev, 0);
1671
1672failed_regions:
1673        pci_disable_device(pdev);
1674
1675        return err;
1676}
1677
1678/*
1679 * 0x710 (LynxEM)
1680 * 0x712 (LynxEM+)
1681 * 0x720 (Lynx3DM, Lynx3DM+)
1682 */
1683static const struct pci_device_id smtcfb_pci_table[] = {
1684        { PCI_DEVICE(0x126f, 0x710), },
1685        { PCI_DEVICE(0x126f, 0x712), },
1686        { PCI_DEVICE(0x126f, 0x720), },
1687        {0,}
1688};
1689
1690MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1691
1692static void smtcfb_pci_remove(struct pci_dev *pdev)
1693{
1694        struct smtcfb_info *sfb;
1695
1696        sfb = pci_get_drvdata(pdev);
1697        smtc_unmap_smem(sfb);
1698        smtc_unmap_mmio(sfb);
1699        unregister_framebuffer(sfb->fb);
1700        framebuffer_release(sfb->fb);
1701        pci_release_region(pdev, 0);
1702        pci_disable_device(pdev);
1703}
1704
1705static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1706{
1707        struct smtcfb_info *sfb = dev_get_drvdata(device);
1708
1709
1710        /* set the hw in sleep mode use external clock and self memory refresh
1711         * so that we can turn off internal PLLs later on
1712         */
1713        smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1714        smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1715
1716        console_lock();
1717        fb_set_suspend(sfb->fb, 1);
1718        console_unlock();
1719
1720        /* additionally turn off all function blocks including internal PLLs */
1721        smtc_seqw(0x21, 0xff);
1722
1723        return 0;
1724}
1725
1726static int __maybe_unused smtcfb_pci_resume(struct device *device)
1727{
1728        struct smtcfb_info *sfb = dev_get_drvdata(device);
1729
1730
1731        /* reinit hardware */
1732        sm7xx_init_hw();
1733        switch (sfb->chip_id) {
1734        case 0x710:
1735        case 0x712:
1736                /* set MCLK = 14.31818 *  (0x16 / 0x2) */
1737                smtc_seqw(0x6a, 0x16);
1738                smtc_seqw(0x6b, 0x02);
1739                smtc_seqw(0x62, 0x3e);
1740                /* enable PCI burst */
1741                smtc_seqw(0x17, 0x20);
1742                if (sfb->fb->var.bits_per_pixel == 32)
1743                        seqw17();
1744                break;
1745        case 0x720:
1746                smtc_seqw(0x62, 0xff);
1747                smtc_seqw(0x6a, 0x0d);
1748                smtc_seqw(0x6b, 0x02);
1749                break;
1750        }
1751
1752        smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1753        smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1754
1755        smtcfb_setmode(sfb);
1756
1757        console_lock();
1758        fb_set_suspend(sfb->fb, 0);
1759        console_unlock();
1760
1761        return 0;
1762}
1763
1764static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1765
1766static struct pci_driver smtcfb_driver = {
1767        .name = "smtcfb",
1768        .id_table = smtcfb_pci_table,
1769        .probe = smtcfb_pci_probe,
1770        .remove = smtcfb_pci_remove,
1771        .driver.pm  = &sm7xx_pm_ops,
1772};
1773
1774static int __init sm712fb_init(void)
1775{
1776        char *option = NULL;
1777
1778        if (fb_get_options("sm712fb", &option))
1779                return -ENODEV;
1780        if (option && *option)
1781                mode_option = option;
1782        sm7xx_vga_setup(mode_option);
1783
1784        return pci_register_driver(&smtcfb_driver);
1785}
1786
1787module_init(sm712fb_init);
1788
1789static void __exit sm712fb_exit(void)
1790{
1791        pci_unregister_driver(&smtcfb_driver);
1792}
1793
1794module_exit(sm712fb_exit);
1795
1796MODULE_AUTHOR("Siliconmotion ");
1797MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1798MODULE_LICENSE("GPL");
1799