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        {       /*  mode#5: 1024 x 768  24Bpp  60Hz */
 534                1024, 768, 24, 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                        0x00, 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#4: 1024 x 768  32Bpp  60Hz */
 593                1024, 768, 32, 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, 0x32, 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#6: 320 x 240  16Bpp  60Hz */
 652                320, 240, 16, 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, 0x08, 0x43, 0x08, 0x43,
 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, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
 701                        0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
 702                        0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
 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
 711        {       /*  mode#8: 320 x 240  32Bpp  60Hz */
 712                320, 240, 32, 60,
 713                /*  Init_MISC */
 714                0xEB,
 715                {       /*  Init_SR0_SR4 */
 716                        0x03, 0x01, 0x0F, 0x03, 0x0E,
 717                },
 718                {       /*  Init_SR10_SR24 */
 719                        0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
 720                        0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
 721                        0xC4, 0x32, 0x02, 0x01, 0x01,
 722                },
 723                {       /*  Init_SR30_SR75 */
 724                        0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
 725                        0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
 726                        0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
 727                        0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
 728                        0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
 729                        0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
 730                        0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
 731                        0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
 732                        0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
 733                },
 734                {       /*  Init_SR80_SR93 */
 735                        0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
 736                        0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
 737                        0x00, 0x00, 0x00, 0x00,
 738                },
 739                {       /*  Init_SRA0_SRAF */
 740                        0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
 741                        0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
 742                },
 743                {       /*  Init_GR00_GR08 */
 744                        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
 745                        0xFF,
 746                },
 747                {       /*  Init_AR00_AR14 */
 748                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 749                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 750                        0x41, 0x00, 0x0F, 0x00, 0x00,
 751                },
 752                {       /*  Init_CR00_CR18 */
 753                        0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
 754                        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 755                        0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
 756                        0xFF,
 757                },
 758                {       /*  Init_CR30_CR4D */
 759                        0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
 760                        0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
 761                        0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
 762                        0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
 763                },
 764                {       /*  Init_CR90_CRA7 */
 765                        0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
 766                        0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
 767                        0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
 768                },
 769        },
 770};
 771
 772static struct screen_info smtc_scr_info;
 773
 774static char *mode_option;
 775
 776/* process command line options, get vga parameter */
 777static void __init sm7xx_vga_setup(char *options)
 778{
 779        int i;
 780
 781        if (!options || !*options)
 782                return;
 783
 784        smtc_scr_info.lfb_width = 0;
 785        smtc_scr_info.lfb_height = 0;
 786        smtc_scr_info.lfb_depth = 0;
 787
 788        pr_debug("sm7xx_vga_setup = %s\n", options);
 789
 790        for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
 791                if (strstr(options, vesa_mode_table[i].index)) {
 792                        smtc_scr_info.lfb_width  = vesa_mode_table[i].lfb_width;
 793                        smtc_scr_info.lfb_height =
 794                                                vesa_mode_table[i].lfb_height;
 795                        smtc_scr_info.lfb_depth  = vesa_mode_table[i].lfb_depth;
 796                        return;
 797                }
 798        }
 799}
 800
 801static void sm712_setpalette(int regno, unsigned red, unsigned green,
 802                             unsigned blue, struct fb_info *info)
 803{
 804        /* set bit 5:4 = 01 (write LCD RAM only) */
 805        smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
 806
 807        smtc_mmiowb(regno, dac_reg);
 808        smtc_mmiowb(red >> 10, dac_val);
 809        smtc_mmiowb(green >> 10, dac_val);
 810        smtc_mmiowb(blue >> 10, dac_val);
 811}
 812
 813/* chan_to_field
 814 *
 815 * convert a colour value into a field position
 816 *
 817 * from pxafb.c
 818 */
 819
 820static inline unsigned int chan_to_field(unsigned int chan,
 821                                         struct fb_bitfield *bf)
 822{
 823        chan &= 0xffff;
 824        chan >>= 16 - bf->length;
 825        return chan << bf->offset;
 826}
 827
 828static int smtc_blank(int blank_mode, struct fb_info *info)
 829{
 830        /* clear DPMS setting */
 831        switch (blank_mode) {
 832        case FB_BLANK_UNBLANK:
 833                /* Screen On: HSync: On, VSync : On */
 834                smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
 835                smtc_seqw(0x6a, 0x16);
 836                smtc_seqw(0x6b, 0x02);
 837                smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
 838                smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
 839                smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
 840                smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
 841                smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
 842                break;
 843        case FB_BLANK_NORMAL:
 844                /* Screen Off: HSync: On, VSync : On   Soft blank */
 845                smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
 846                smtc_seqw(0x6a, 0x16);
 847                smtc_seqw(0x6b, 0x02);
 848                smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
 849                smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
 850                smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
 851                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 852                break;
 853        case FB_BLANK_VSYNC_SUSPEND:
 854                /* Screen On: HSync: On, VSync : Off */
 855                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
 856                smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
 857                smtc_seqw(0x6a, 0x0c);
 858                smtc_seqw(0x6b, 0x02);
 859                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
 860                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
 861                smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
 862                smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
 863                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 864                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
 865                break;
 866        case FB_BLANK_HSYNC_SUSPEND:
 867                /* Screen On: HSync: Off, VSync : On */
 868                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
 869                smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
 870                smtc_seqw(0x6a, 0x0c);
 871                smtc_seqw(0x6b, 0x02);
 872                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
 873                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
 874                smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
 875                smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
 876                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 877                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
 878                break;
 879        case FB_BLANK_POWERDOWN:
 880                /* Screen On: HSync: Off, VSync : Off */
 881                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
 882                smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
 883                smtc_seqw(0x6a, 0x0c);
 884                smtc_seqw(0x6b, 0x02);
 885                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
 886                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
 887                smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
 888                smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
 889                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 890                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
 891                break;
 892        default:
 893                return -EINVAL;
 894        }
 895
 896        return 0;
 897}
 898
 899static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
 900                          unsigned blue, unsigned trans, struct fb_info *info)
 901{
 902        struct smtcfb_info *sfb;
 903        u32 val;
 904
 905        sfb = info->par;
 906
 907        if (regno > 255)
 908                return 1;
 909
 910        switch (sfb->fb->fix.visual) {
 911        case FB_VISUAL_DIRECTCOLOR:
 912        case FB_VISUAL_TRUECOLOR:
 913                /*
 914                 * 16/32 bit true-colour, use pseudo-palette for 16 base color
 915                 */
 916                if (regno >= 16)
 917                        break;
 918                if (sfb->fb->var.bits_per_pixel == 16) {
 919                        u32 *pal = sfb->fb->pseudo_palette;
 920
 921                        val = chan_to_field(red, &sfb->fb->var.red);
 922                        val |= chan_to_field(green, &sfb->fb->var.green);
 923                        val |= chan_to_field(blue, &sfb->fb->var.blue);
 924                        pal[regno] = pal_rgb(red, green, blue, val);
 925                } else {
 926                        u32 *pal = sfb->fb->pseudo_palette;
 927
 928                        val = chan_to_field(red, &sfb->fb->var.red);
 929                        val |= chan_to_field(green, &sfb->fb->var.green);
 930                        val |= chan_to_field(blue, &sfb->fb->var.blue);
 931                        pal[regno] = big_swap(val);
 932                }
 933                break;
 934
 935        case FB_VISUAL_PSEUDOCOLOR:
 936                /* color depth 8 bit */
 937                sm712_setpalette(regno, red, green, blue, info);
 938                break;
 939
 940        default:
 941                return 1;       /* unknown type */
 942        }
 943
 944        return 0;
 945}
 946
 947static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
 948                           size_t count, loff_t *ppos)
 949{
 950        unsigned long p = *ppos;
 951
 952        u32 *buffer, *dst;
 953        u32 __iomem *src;
 954        int c, i, cnt = 0, err = 0;
 955        unsigned long total_size;
 956
 957        if (!info || !info->screen_base)
 958                return -ENODEV;
 959
 960        if (info->state != FBINFO_STATE_RUNNING)
 961                return -EPERM;
 962
 963        total_size = info->screen_size;
 964
 965        if (total_size == 0)
 966                total_size = info->fix.smem_len;
 967
 968        if (p >= total_size)
 969                return 0;
 970
 971        if (count >= total_size)
 972                count = total_size;
 973
 974        if (count + p > total_size)
 975                count = total_size - p;
 976
 977        buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
 978        if (!buffer)
 979                return -ENOMEM;
 980
 981        src = (u32 __iomem *)(info->screen_base + p);
 982
 983        if (info->fbops->fb_sync)
 984                info->fbops->fb_sync(info);
 985
 986        while (count) {
 987                c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
 988                dst = buffer;
 989                for (i = c >> 2; i--;) {
 990                        *dst = fb_readl(src++);
 991                        *dst = big_swap(*dst);
 992                        dst++;
 993                }
 994                if (c & 3) {
 995                        u8 *dst8 = (u8 *)dst;
 996                        u8 __iomem *src8 = (u8 __iomem *)src;
 997
 998                        for (i = c & 3; i--;) {
 999                                if (i & 1) {
1000                                        *dst8++ = fb_readb(++src8);
1001                                } else {
1002                                        *dst8++ = fb_readb(--src8);
1003                                        src8 += 2;
1004                                }
1005                        }
1006                        src = (u32 __iomem *)src8;
1007                }
1008
1009                if (copy_to_user(buf, buffer, c)) {
1010                        err = -EFAULT;
1011                        break;
1012                }
1013                *ppos += c;
1014                buf += c;
1015                cnt += c;
1016                count -= c;
1017        }
1018
1019        kfree(buffer);
1020
1021        return (err) ? err : cnt;
1022}
1023
1024static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1025                            size_t count, loff_t *ppos)
1026{
1027        unsigned long p = *ppos;
1028
1029        u32 *buffer, *src;
1030        u32 __iomem *dst;
1031        int c, i, cnt = 0, err = 0;
1032        unsigned long total_size;
1033
1034        if (!info || !info->screen_base)
1035                return -ENODEV;
1036
1037        if (info->state != FBINFO_STATE_RUNNING)
1038                return -EPERM;
1039
1040        total_size = info->screen_size;
1041
1042        if (total_size == 0)
1043                total_size = info->fix.smem_len;
1044
1045        if (p > total_size)
1046                return -EFBIG;
1047
1048        if (count > total_size) {
1049                err = -EFBIG;
1050                count = total_size;
1051        }
1052
1053        if (count + p > total_size) {
1054                if (!err)
1055                        err = -ENOSPC;
1056
1057                count = total_size - p;
1058        }
1059
1060        buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
1061        if (!buffer)
1062                return -ENOMEM;
1063
1064        dst = (u32 __iomem *)(info->screen_base + p);
1065
1066        if (info->fbops->fb_sync)
1067                info->fbops->fb_sync(info);
1068
1069        while (count) {
1070                c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1071                src = buffer;
1072
1073                if (copy_from_user(src, buf, c)) {
1074                        err = -EFAULT;
1075                        break;
1076                }
1077
1078                for (i = c >> 2; i--;) {
1079                        fb_writel(big_swap(*src), dst++);
1080                        src++;
1081                }
1082                if (c & 3) {
1083                        u8 *src8 = (u8 *)src;
1084                        u8 __iomem *dst8 = (u8 __iomem *)dst;
1085
1086                        for (i = c & 3; i--;) {
1087                                if (i & 1) {
1088                                        fb_writeb(*src8++, ++dst8);
1089                                } else {
1090                                        fb_writeb(*src8++, --dst8);
1091                                        dst8 += 2;
1092                                }
1093                        }
1094                        dst = (u32 __iomem *)dst8;
1095                }
1096
1097                *ppos += c;
1098                buf += c;
1099                cnt += c;
1100                count -= c;
1101        }
1102
1103        kfree(buffer);
1104
1105        return (cnt) ? cnt : err;
1106}
1107
1108static void sm7xx_set_timing(struct smtcfb_info *sfb)
1109{
1110        int i = 0, j = 0;
1111        u32 m_nscreenstride;
1112
1113        dev_dbg(&sfb->pdev->dev,
1114                "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1115                sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1116
1117        for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1118                if (vgamode[j].mmsizex != sfb->width ||
1119                    vgamode[j].mmsizey != sfb->height ||
1120                    vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1121                    vgamode[j].hz != sfb->hz)
1122                        continue;
1123
1124                dev_dbg(&sfb->pdev->dev,
1125                        "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1126                        vgamode[j].mmsizex, vgamode[j].mmsizey,
1127                        vgamode[j].bpp, vgamode[j].hz);
1128
1129                dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1130
1131                smtc_mmiowb(0x0, 0x3c6);
1132
1133                smtc_seqw(0, 0x1);
1134
1135                smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1136
1137                /* init SEQ register SR00 - SR04 */
1138                for (i = 0; i < SIZE_SR00_SR04; i++)
1139                        smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1140
1141                /* init SEQ register SR10 - SR24 */
1142                for (i = 0; i < SIZE_SR10_SR24; i++)
1143                        smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1144
1145                /* init SEQ register SR30 - SR75 */
1146                for (i = 0; i < SIZE_SR30_SR75; i++)
1147                        if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a &&
1148                            (i + 0x30) != 0x6b)
1149                                smtc_seqw(i + 0x30,
1150                                          vgamode[j].init_sr30_sr75[i]);
1151
1152                /* init SEQ register SR80 - SR93 */
1153                for (i = 0; i < SIZE_SR80_SR93; i++)
1154                        smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1155
1156                /* init SEQ register SRA0 - SRAF */
1157                for (i = 0; i < SIZE_SRA0_SRAF; i++)
1158                        smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1159
1160                /* init Graphic register GR00 - GR08 */
1161                for (i = 0; i < SIZE_GR00_GR08; i++)
1162                        smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1163
1164                /* init Attribute register AR00 - AR14 */
1165                for (i = 0; i < SIZE_AR00_AR14; i++)
1166                        smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1167
1168                /* init CRTC register CR00 - CR18 */
1169                for (i = 0; i < SIZE_CR00_CR18; i++)
1170                        smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1171
1172                /* init CRTC register CR30 - CR4D */
1173                for (i = 0; i < SIZE_CR30_CR4D; i++)
1174                        smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1175
1176                /* init CRTC register CR90 - CRA7 */
1177                for (i = 0; i < SIZE_CR90_CRA7; i++)
1178                        smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1179        }
1180        smtc_mmiowb(0x67, 0x3c2);
1181
1182        /* set VPR registers */
1183        writel(0x0, sfb->vp_regs + 0x0C);
1184        writel(0x0, sfb->vp_regs + 0x40);
1185
1186        /* set data width */
1187        m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1188        switch (sfb->fb->var.bits_per_pixel) {
1189        case 8:
1190                writel(0x0, sfb->vp_regs + 0x0);
1191                break;
1192        case 16:
1193                writel(0x00020000, sfb->vp_regs + 0x0);
1194                break;
1195        case 24:
1196                writel(0x00040000, sfb->vp_regs + 0x0);
1197                break;
1198        case 32:
1199                writel(0x00030000, sfb->vp_regs + 0x0);
1200                break;
1201        }
1202        writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1203               sfb->vp_regs + 0x10);
1204}
1205
1206static void smtc_set_timing(struct smtcfb_info *sfb)
1207{
1208        switch (sfb->chip_id) {
1209        case 0x710:
1210        case 0x712:
1211        case 0x720:
1212                sm7xx_set_timing(sfb);
1213                break;
1214        }
1215}
1216
1217static void smtcfb_setmode(struct smtcfb_info *sfb)
1218{
1219        switch (sfb->fb->var.bits_per_pixel) {
1220        case 32:
1221                sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1222                sfb->fb->fix.line_length  = sfb->fb->var.xres * 4;
1223                sfb->fb->var.red.length   = 8;
1224                sfb->fb->var.green.length = 8;
1225                sfb->fb->var.blue.length  = 8;
1226                sfb->fb->var.red.offset   = 16;
1227                sfb->fb->var.green.offset = 8;
1228                sfb->fb->var.blue.offset  = 0;
1229                break;
1230        case 24:
1231                sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1232                sfb->fb->fix.line_length  = sfb->fb->var.xres * 3;
1233                sfb->fb->var.red.length   = 8;
1234                sfb->fb->var.green.length = 8;
1235                sfb->fb->var.blue.length  = 8;
1236                sfb->fb->var.red.offset   = 16;
1237                sfb->fb->var.green.offset = 8;
1238                sfb->fb->var.blue.offset  = 0;
1239                break;
1240        case 8:
1241                sfb->fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
1242                sfb->fb->fix.line_length  = sfb->fb->var.xres;
1243                sfb->fb->var.red.length   = 3;
1244                sfb->fb->var.green.length = 3;
1245                sfb->fb->var.blue.length  = 2;
1246                sfb->fb->var.red.offset   = 5;
1247                sfb->fb->var.green.offset = 2;
1248                sfb->fb->var.blue.offset  = 0;
1249                break;
1250        case 16:
1251        default:
1252                sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1253                sfb->fb->fix.line_length  = sfb->fb->var.xres * 2;
1254                sfb->fb->var.red.length   = 5;
1255                sfb->fb->var.green.length = 6;
1256                sfb->fb->var.blue.length  = 5;
1257                sfb->fb->var.red.offset   = 11;
1258                sfb->fb->var.green.offset = 5;
1259                sfb->fb->var.blue.offset  = 0;
1260                break;
1261        }
1262
1263        sfb->width  = sfb->fb->var.xres;
1264        sfb->height = sfb->fb->var.yres;
1265        sfb->hz = 60;
1266        smtc_set_timing(sfb);
1267}
1268
1269static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1270{
1271        /* sanity checks */
1272        if (var->xres_virtual < var->xres)
1273                var->xres_virtual = var->xres;
1274
1275        if (var->yres_virtual < var->yres)
1276                var->yres_virtual = var->yres;
1277
1278        /* set valid default bpp */
1279        if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
1280            (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1281                var->bits_per_pixel = 16;
1282
1283        return 0;
1284}
1285
1286static int smtc_set_par(struct fb_info *info)
1287{
1288        smtcfb_setmode(info->par);
1289
1290        return 0;
1291}
1292
1293static struct fb_ops smtcfb_ops = {
1294        .owner        = THIS_MODULE,
1295        .fb_check_var = smtc_check_var,
1296        .fb_set_par   = smtc_set_par,
1297        .fb_setcolreg = smtc_setcolreg,
1298        .fb_blank     = smtc_blank,
1299        .fb_fillrect  = cfb_fillrect,
1300        .fb_imageblit = cfb_imageblit,
1301        .fb_copyarea  = cfb_copyarea,
1302        .fb_read      = smtcfb_read,
1303        .fb_write     = smtcfb_write,
1304};
1305
1306/*
1307 * Unmap in the memory mapped IO registers
1308 */
1309
1310static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1311{
1312        if (sfb && smtc_regbaseaddress)
1313                smtc_regbaseaddress = NULL;
1314}
1315
1316/*
1317 * Map in the screen memory
1318 */
1319
1320static int smtc_map_smem(struct smtcfb_info *sfb,
1321                         struct pci_dev *pdev, u_long smem_len)
1322{
1323        sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1324
1325        if (sfb->fb->var.bits_per_pixel == 32)
1326                sfb->fb->fix.smem_start += big_addr;
1327
1328        sfb->fb->fix.smem_len = smem_len;
1329
1330        sfb->fb->screen_base = sfb->lfb;
1331
1332        if (!sfb->fb->screen_base) {
1333                dev_err(&pdev->dev,
1334                        "%s: unable to map screen memory\n", sfb->fb->fix.id);
1335                return -ENOMEM;
1336        }
1337
1338        return 0;
1339}
1340
1341/*
1342 * Unmap in the screen memory
1343 *
1344 */
1345static void smtc_unmap_smem(struct smtcfb_info *sfb)
1346{
1347        if (sfb && sfb->fb->screen_base) {
1348                iounmap(sfb->fb->screen_base);
1349                sfb->fb->screen_base = NULL;
1350        }
1351}
1352
1353/*
1354 * We need to wake up the device and make sure its in linear memory mode.
1355 */
1356static inline void sm7xx_init_hw(void)
1357{
1358        outb_p(0x18, 0x3c4);
1359        outb_p(0x11, 0x3c5);
1360}
1361
1362static int smtcfb_pci_probe(struct pci_dev *pdev,
1363                            const struct pci_device_id *ent)
1364{
1365        struct smtcfb_info *sfb;
1366        struct fb_info *info;
1367        u_long smem_size = 0x00800000;  /* default 8MB */
1368        int err;
1369        unsigned long mmio_base;
1370
1371        dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1372
1373        err = pci_enable_device(pdev);  /* enable SMTC chip */
1374        if (err)
1375                return err;
1376
1377        err = pci_request_region(pdev, 0, "sm7xxfb");
1378        if (err < 0) {
1379                dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1380                goto failed_regions;
1381        }
1382
1383        sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1384
1385        info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1386        if (!info) {
1387                dev_err(&pdev->dev, "framebuffer_alloc failed\n");
1388                err = -ENOMEM;
1389                goto failed_free;
1390        }
1391
1392        sfb = info->par;
1393        sfb->fb = info;
1394        sfb->chip_id = ent->device;
1395        sfb->pdev = pdev;
1396        info->flags = FBINFO_FLAG_DEFAULT;
1397        info->fbops = &smtcfb_ops;
1398        info->fix = smtcfb_fix;
1399        info->var = smtcfb_var;
1400        info->pseudo_palette = sfb->colreg;
1401        info->par = sfb;
1402
1403        pci_set_drvdata(pdev, sfb);
1404
1405        sm7xx_init_hw();
1406
1407        /* get mode parameter from smtc_scr_info */
1408        if (smtc_scr_info.lfb_width != 0) {
1409                sfb->fb->var.xres = smtc_scr_info.lfb_width;
1410                sfb->fb->var.yres = smtc_scr_info.lfb_height;
1411                sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1412        } else {
1413                /* default resolution 1024x600 16bit mode */
1414                sfb->fb->var.xres = SCREEN_X_RES;
1415                sfb->fb->var.yres = SCREEN_Y_RES;
1416                sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1417        }
1418
1419        big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1420        /* Map address and memory detection */
1421        mmio_base = pci_resource_start(pdev, 0);
1422        pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1423
1424        switch (sfb->chip_id) {
1425        case 0x710:
1426        case 0x712:
1427                sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1428                sfb->fb->fix.mmio_len = 0x00400000;
1429                smem_size = SM712_VIDEOMEMORYSIZE;
1430                sfb->lfb = ioremap(mmio_base, mmio_addr);
1431                if (!sfb->lfb) {
1432                        dev_err(&pdev->dev,
1433                                "%s: unable to map memory mapped IO!\n",
1434                                sfb->fb->fix.id);
1435                        err = -ENOMEM;
1436                        goto failed_fb;
1437                }
1438
1439                sfb->mmio = (smtc_regbaseaddress =
1440                    sfb->lfb + 0x00700000);
1441                sfb->dp_regs = sfb->lfb + 0x00408000;
1442                sfb->vp_regs = sfb->lfb + 0x0040c000;
1443                if (sfb->fb->var.bits_per_pixel == 32) {
1444                        sfb->lfb += big_addr;
1445                        dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1446                }
1447
1448                /* set MCLK = 14.31818 * (0x16 / 0x2) */
1449                smtc_seqw(0x6a, 0x16);
1450                smtc_seqw(0x6b, 0x02);
1451                smtc_seqw(0x62, 0x3e);
1452                /* enable PCI burst */
1453                smtc_seqw(0x17, 0x20);
1454                /* enable word swap */
1455                if (sfb->fb->var.bits_per_pixel == 32)
1456                        seqw17();
1457                break;
1458        case 0x720:
1459                sfb->fb->fix.mmio_start = mmio_base;
1460                sfb->fb->fix.mmio_len = 0x00200000;
1461                smem_size = SM722_VIDEOMEMORYSIZE;
1462                sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
1463                sfb->lfb = sfb->dp_regs + 0x00200000;
1464                sfb->mmio = (smtc_regbaseaddress =
1465                    sfb->dp_regs + 0x000c0000);
1466                sfb->vp_regs = sfb->dp_regs + 0x800;
1467
1468                smtc_seqw(0x62, 0xff);
1469                smtc_seqw(0x6a, 0x0d);
1470                smtc_seqw(0x6b, 0x02);
1471                break;
1472        default:
1473                dev_err(&pdev->dev,
1474                        "No valid Silicon Motion display chip was detected!\n");
1475
1476                goto failed_fb;
1477        }
1478
1479        /* can support 32 bpp */
1480        if (15 == sfb->fb->var.bits_per_pixel)
1481                sfb->fb->var.bits_per_pixel = 16;
1482
1483        sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1484        sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1485        err = smtc_map_smem(sfb, pdev, smem_size);
1486        if (err)
1487                goto failed;
1488
1489        smtcfb_setmode(sfb);
1490
1491        err = register_framebuffer(info);
1492        if (err < 0)
1493                goto failed;
1494
1495        dev_info(&pdev->dev,
1496                 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1497                 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1498                 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1499
1500        return 0;
1501
1502failed:
1503        dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1504
1505        smtc_unmap_smem(sfb);
1506        smtc_unmap_mmio(sfb);
1507failed_fb:
1508        framebuffer_release(info);
1509
1510failed_free:
1511        pci_release_region(pdev, 0);
1512
1513failed_regions:
1514        pci_disable_device(pdev);
1515
1516        return err;
1517}
1518
1519/*
1520 * 0x710 (LynxEM)
1521 * 0x712 (LynxEM+)
1522 * 0x720 (Lynx3DM, Lynx3DM+)
1523 */
1524static const struct pci_device_id smtcfb_pci_table[] = {
1525        { PCI_DEVICE(0x126f, 0x710), },
1526        { PCI_DEVICE(0x126f, 0x712), },
1527        { PCI_DEVICE(0x126f, 0x720), },
1528        {0,}
1529};
1530
1531MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1532
1533static void smtcfb_pci_remove(struct pci_dev *pdev)
1534{
1535        struct smtcfb_info *sfb;
1536
1537        sfb = pci_get_drvdata(pdev);
1538        smtc_unmap_smem(sfb);
1539        smtc_unmap_mmio(sfb);
1540        unregister_framebuffer(sfb->fb);
1541        framebuffer_release(sfb->fb);
1542        pci_release_region(pdev, 0);
1543        pci_disable_device(pdev);
1544}
1545
1546static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1547{
1548        struct pci_dev *pdev = to_pci_dev(device);
1549        struct smtcfb_info *sfb;
1550
1551        sfb = pci_get_drvdata(pdev);
1552
1553        /* set the hw in sleep mode use external clock and self memory refresh
1554         * so that we can turn off internal PLLs later on
1555         */
1556        smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1557        smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1558
1559        console_lock();
1560        fb_set_suspend(sfb->fb, 1);
1561        console_unlock();
1562
1563        /* additionally turn off all function blocks including internal PLLs */
1564        smtc_seqw(0x21, 0xff);
1565
1566        return 0;
1567}
1568
1569static int __maybe_unused smtcfb_pci_resume(struct device *device)
1570{
1571        struct pci_dev *pdev = to_pci_dev(device);
1572        struct smtcfb_info *sfb;
1573
1574        sfb = pci_get_drvdata(pdev);
1575
1576        /* reinit hardware */
1577        sm7xx_init_hw();
1578        switch (sfb->chip_id) {
1579        case 0x710:
1580        case 0x712:
1581                /* set MCLK = 14.31818 *  (0x16 / 0x2) */
1582                smtc_seqw(0x6a, 0x16);
1583                smtc_seqw(0x6b, 0x02);
1584                smtc_seqw(0x62, 0x3e);
1585                /* enable PCI burst */
1586                smtc_seqw(0x17, 0x20);
1587                if (sfb->fb->var.bits_per_pixel == 32)
1588                        seqw17();
1589                break;
1590        case 0x720:
1591                smtc_seqw(0x62, 0xff);
1592                smtc_seqw(0x6a, 0x0d);
1593                smtc_seqw(0x6b, 0x02);
1594                break;
1595        }
1596
1597        smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1598        smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1599
1600        smtcfb_setmode(sfb);
1601
1602        console_lock();
1603        fb_set_suspend(sfb->fb, 0);
1604        console_unlock();
1605
1606        return 0;
1607}
1608
1609static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1610
1611static struct pci_driver smtcfb_driver = {
1612        .name = "smtcfb",
1613        .id_table = smtcfb_pci_table,
1614        .probe = smtcfb_pci_probe,
1615        .remove = smtcfb_pci_remove,
1616        .driver.pm  = &sm7xx_pm_ops,
1617};
1618
1619static int __init sm712fb_init(void)
1620{
1621        char *option = NULL;
1622
1623        if (fb_get_options("sm712fb", &option))
1624                return -ENODEV;
1625        if (option && *option)
1626                mode_option = option;
1627        sm7xx_vga_setup(mode_option);
1628
1629        return pci_register_driver(&smtcfb_driver);
1630}
1631
1632module_init(sm712fb_init);
1633
1634static void __exit sm712fb_exit(void)
1635{
1636        pci_unregister_driver(&smtcfb_driver);
1637}
1638
1639module_exit(sm712fb_exit);
1640
1641MODULE_AUTHOR("Siliconmotion ");
1642MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1643MODULE_LICENSE("GPL");
1644