linux/drivers/staging/sm7xx/smtcfb.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 *  This file is subject to the terms and conditions of the GNU General Public
  12 *  License. See the file COPYING in the main directory of this archive for
  13 *  more details.
  14 *
  15 * Version 0.10.26192.21.01
  16 *      - Add PowerPC/Big endian support
  17 *      - Add 2D support for Lynx
  18 *      - Verified on2.6.19.2  Boyod.yang <boyod.yang@siliconmotion.com.cn>
  19 *
  20 * Version 0.09.2621.00.01
  21 *      - Only support Linux Kernel's version 2.6.21.
  22 *      Boyod.yang  <boyod.yang@siliconmotion.com.cn>
  23 *
  24 * Version 0.09
  25 *      - Only support Linux Kernel's version 2.6.12.
  26 *      Boyod.yang <boyod.yang@siliconmotion.com.cn>
  27 */
  28
  29#ifndef __KERNEL__
  30#define __KERNEL__
  31#endif
  32
  33#include <linux/io.h>
  34#include <linux/fb.h>
  35#include <linux/pci.h>
  36#include <linux/init.h>
  37#include <linux/slab.h>
  38#include <linux/uaccess.h>
  39#include <linux/console.h>
  40#include <linux/screen_info.h>
  41
  42#ifdef CONFIG_PM
  43#include <linux/pm.h>
  44#endif
  45
  46struct screen_info smtc_screen_info;
  47
  48#include "smtcfb.h"
  49
  50#ifdef DEBUG
  51#define smdbg(format, arg...)   printk(KERN_DEBUG format , ## arg)
  52#else
  53#define smdbg(format, arg...)
  54#endif
  55
  56/*
  57* Private structure
  58*/
  59struct smtcfb_info {
  60        /*
  61         * The following is a pointer to be passed into the
  62         * functions below.  The modules outside the main
  63         * voyager.c driver have no knowledge as to what
  64         * is within this structure.
  65         */
  66        struct fb_info fb;
  67        struct display_switch *dispsw;
  68        struct pci_dev *dev;
  69        signed int currcon;
  70
  71        struct {
  72                u8 red, green, blue;
  73        } palette[NR_RGB];
  74
  75        u_int palette_size;
  76};
  77
  78struct par_info {
  79        /*
  80         * Hardware
  81         */
  82        u16 chipID;
  83        unsigned char __iomem *m_pMMIO;
  84        char __iomem *m_pLFB;
  85        char *m_pDPR;
  86        char *m_pVPR;
  87        char *m_pCPR;
  88
  89        u_int width;
  90        u_int height;
  91        u_int hz;
  92        u_long BaseAddressInVRAM;
  93        u8 chipRevID;
  94};
  95
  96struct vesa_mode_table  {
  97        char mode_index[6];
  98        u16 lfb_width;
  99        u16 lfb_height;
 100        u16 lfb_depth;
 101};
 102
 103static struct vesa_mode_table vesa_mode[] = {
 104        {"0x301", 640,  480,  8},
 105        {"0x303", 800,  600,  8},
 106        {"0x305", 1024, 768,    8},
 107        {"0x307", 1280, 1024, 8},
 108
 109        {"0x311", 640,  480,  16},
 110        {"0x314", 800,  600,  16},
 111        {"0x317", 1024, 768,    16},
 112        {"0x31A", 1280, 1024, 16},
 113
 114        {"0x312", 640,  480,  24},
 115        {"0x315", 800,  600,  24},
 116        {"0x318", 1024, 768,    24},
 117        {"0x31B", 1280, 1024, 24},
 118};
 119
 120char __iomem *smtc_RegBaseAddress;      /* Memory Map IO starting address */
 121char __iomem *smtc_VRAMBaseAddress;     /* video memory starting address */
 122
 123static u32 colreg[17];
 124static struct par_info hw;      /* hardware information */
 125
 126u16 smtc_ChipIDs[] = {
 127        0x710,
 128        0x712,
 129        0x720
 130};
 131
 132#define numSMTCchipIDs (sizeof(smtc_ChipIDs) / sizeof(u16))
 133
 134static void sm712_set_timing(struct smtcfb_info *sfb,
 135                             struct par_info *ppar_info)
 136{
 137        int i = 0, j = 0;
 138        u32 m_nScreenStride;
 139
 140        smdbg("\nppar_info->width = %d ppar_info->height = %d"
 141                        "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n",
 142                        ppar_info->width, ppar_info->height,
 143                        sfb->fb.var.bits_per_pixel, ppar_info->hz);
 144
 145        for (j = 0; j < numVGAModes; j++) {
 146                if (VGAMode[j].mmSizeX == ppar_info->width &&
 147                    VGAMode[j].mmSizeY == ppar_info->height &&
 148                    VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
 149                    VGAMode[j].hz == ppar_info->hz) {
 150
 151                        smdbg("\nVGAMode[j].mmSizeX  = %d VGAMode[j].mmSizeY ="
 152                                        "%d VGAMode[j].bpp = %d"
 153                                        "VGAMode[j].hz=%d\n",
 154                                        VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
 155                                        VGAMode[j].bpp, VGAMode[j].hz);
 156
 157                        smdbg("VGAMode index=%d\n", j);
 158
 159                        smtc_mmiowb(0x0, 0x3c6);
 160
 161                        smtc_seqw(0, 0x1);
 162
 163                        smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2);
 164
 165                        /* init SEQ register SR00 - SR04 */
 166                        for (i = 0; i < SIZE_SR00_SR04; i++)
 167                                smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]);
 168
 169                        /* init SEQ register SR10 - SR24 */
 170                        for (i = 0; i < SIZE_SR10_SR24; i++)
 171                                smtc_seqw(i + 0x10,
 172                                          VGAMode[j].Init_SR10_SR24[i]);
 173
 174                        /* init SEQ register SR30 - SR75 */
 175                        for (i = 0; i < SIZE_SR30_SR75; i++)
 176                                if (((i + 0x30) != 0x62) \
 177                                        && ((i + 0x30) != 0x6a) \
 178                                        && ((i + 0x30) != 0x6b))
 179                                        smtc_seqw(i + 0x30,
 180                                                VGAMode[j].Init_SR30_SR75[i]);
 181
 182                        /* init SEQ register SR80 - SR93 */
 183                        for (i = 0; i < SIZE_SR80_SR93; i++)
 184                                smtc_seqw(i + 0x80,
 185                                          VGAMode[j].Init_SR80_SR93[i]);
 186
 187                        /* init SEQ register SRA0 - SRAF */
 188                        for (i = 0; i < SIZE_SRA0_SRAF; i++)
 189                                smtc_seqw(i + 0xa0,
 190                                          VGAMode[j].Init_SRA0_SRAF[i]);
 191
 192                        /* init Graphic register GR00 - GR08 */
 193                        for (i = 0; i < SIZE_GR00_GR08; i++)
 194                                smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]);
 195
 196                        /* init Attribute register AR00 - AR14 */
 197                        for (i = 0; i < SIZE_AR00_AR14; i++)
 198                                smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]);
 199
 200                        /* init CRTC register CR00 - CR18 */
 201                        for (i = 0; i < SIZE_CR00_CR18; i++)
 202                                smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]);
 203
 204                        /* init CRTC register CR30 - CR4D */
 205                        for (i = 0; i < SIZE_CR30_CR4D; i++)
 206                                smtc_crtcw(i + 0x30,
 207                                           VGAMode[j].Init_CR30_CR4D[i]);
 208
 209                        /* init CRTC register CR90 - CRA7 */
 210                        for (i = 0; i < SIZE_CR90_CRA7; i++)
 211                                smtc_crtcw(i + 0x90,
 212                                           VGAMode[j].Init_CR90_CRA7[i]);
 213                }
 214        }
 215        smtc_mmiowb(0x67, 0x3c2);
 216
 217        /* set VPR registers */
 218        writel(0x0, ppar_info->m_pVPR + 0x0C);
 219        writel(0x0, ppar_info->m_pVPR + 0x40);
 220
 221        /* set data width */
 222        m_nScreenStride =
 223                (ppar_info->width * sfb->fb.var.bits_per_pixel) / 64;
 224        switch (sfb->fb.var.bits_per_pixel) {
 225        case 8:
 226                writel(0x0, ppar_info->m_pVPR + 0x0);
 227                break;
 228        case 16:
 229                writel(0x00020000, ppar_info->m_pVPR + 0x0);
 230                break;
 231        case 24:
 232                writel(0x00040000, ppar_info->m_pVPR + 0x0);
 233                break;
 234        case 32:
 235                writel(0x00030000, ppar_info->m_pVPR + 0x0);
 236                break;
 237        }
 238        writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
 239               ppar_info->m_pVPR + 0x10);
 240
 241}
 242
 243static void sm712_setpalette(int regno, unsigned red, unsigned green,
 244                             unsigned blue, struct fb_info *info)
 245{
 246        struct par_info *cur_par = (struct par_info *)info->par;
 247
 248        if (cur_par->BaseAddressInVRAM)
 249                /*
 250                 * second display palette for dual head. Enable CRT RAM, 6-bit
 251                 * RAM
 252                 */
 253                smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x20);
 254        else
 255                /* primary display palette. Enable LCD RAM only, 6-bit RAM */
 256                smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
 257        smtc_mmiowb(regno, dac_reg);
 258        smtc_mmiowb(red >> 10, dac_val);
 259        smtc_mmiowb(green >> 10, dac_val);
 260        smtc_mmiowb(blue >> 10, dac_val);
 261}
 262
 263static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info
 264                *ppar_info)
 265{
 266        switch (ppar_info->chipID) {
 267        case 0x710:
 268        case 0x712:
 269        case 0x720:
 270                sm712_set_timing(sfb, ppar_info);
 271                break;
 272        }
 273}
 274
 275static struct fb_var_screeninfo smtcfb_var = {
 276        .xres = 1024,
 277        .yres = 600,
 278        .xres_virtual = 1024,
 279        .yres_virtual = 600,
 280        .bits_per_pixel = 16,
 281        .red = {16, 8, 0},
 282        .green = {8, 8, 0},
 283        .blue = {0, 8, 0},
 284        .activate = FB_ACTIVATE_NOW,
 285        .height = -1,
 286        .width = -1,
 287        .vmode = FB_VMODE_NONINTERLACED,
 288};
 289
 290static struct fb_fix_screeninfo smtcfb_fix = {
 291        .id = "sm712fb",
 292        .type = FB_TYPE_PACKED_PIXELS,
 293        .visual = FB_VISUAL_TRUECOLOR,
 294        .line_length = 800 * 3,
 295        .accel = FB_ACCEL_SMI_LYNX,
 296};
 297
 298/* chan_to_field
 299 *
 300 * convert a colour value into a field position
 301 *
 302 * from pxafb.c
 303 */
 304
 305static inline unsigned int chan_to_field(unsigned int chan,
 306                                         struct fb_bitfield *bf)
 307{
 308        chan &= 0xffff;
 309        chan >>= 16 - bf->length;
 310        return chan << bf->offset;
 311}
 312
 313static int cfb_blank(int blank_mode, struct fb_info *info)
 314{
 315        /* clear DPMS setting */
 316        switch (blank_mode) {
 317        case FB_BLANK_UNBLANK:
 318                /* Screen On: HSync: On, VSync : On */
 319                smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
 320                smtc_seqw(0x6a, 0x16);
 321                smtc_seqw(0x6b, 0x02);
 322                smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
 323                smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
 324                smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
 325                smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
 326                smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
 327                break;
 328        case FB_BLANK_NORMAL:
 329                /* Screen Off: HSync: On, VSync : On   Soft blank */
 330                smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
 331                smtc_seqw(0x6a, 0x16);
 332                smtc_seqw(0x6b, 0x02);
 333                smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
 334                smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
 335                smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
 336                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 337                break;
 338        case FB_BLANK_VSYNC_SUSPEND:
 339                /* Screen On: HSync: On, VSync : Off */
 340                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
 341                smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
 342                smtc_seqw(0x6a, 0x0c);
 343                smtc_seqw(0x6b, 0x02);
 344                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
 345                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
 346                smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
 347                smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
 348                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 349                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
 350                break;
 351        case FB_BLANK_HSYNC_SUSPEND:
 352                /* Screen On: HSync: Off, VSync : On */
 353                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
 354                smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
 355                smtc_seqw(0x6a, 0x0c);
 356                smtc_seqw(0x6b, 0x02);
 357                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
 358                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
 359                smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
 360                smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
 361                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 362                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
 363                break;
 364        case FB_BLANK_POWERDOWN:
 365                /* Screen On: HSync: Off, VSync : Off */
 366                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
 367                smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
 368                smtc_seqw(0x6a, 0x0c);
 369                smtc_seqw(0x6b, 0x02);
 370                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
 371                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
 372                smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
 373                smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
 374                smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
 375                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
 376                break;
 377        default:
 378                return -EINVAL;
 379        }
 380
 381        return 0;
 382}
 383
 384static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
 385                          unsigned blue, unsigned trans, struct fb_info *info)
 386{
 387        struct smtcfb_info *sfb = (struct smtcfb_info *)info;
 388        u32 val;
 389
 390        if (regno > 255)
 391                return 1;
 392
 393        switch (sfb->fb.fix.visual) {
 394        case FB_VISUAL_DIRECTCOLOR:
 395        case FB_VISUAL_TRUECOLOR:
 396                /*
 397                 * 16/32 bit true-colour, use pseuo-palette for 16 base color
 398                 */
 399                if (regno < 16) {
 400                        if (sfb->fb.var.bits_per_pixel == 16) {
 401                                u32 *pal = sfb->fb.pseudo_palette;
 402                                val = chan_to_field(red, &sfb->fb.var.red);
 403                                val |= chan_to_field(green, \
 404                                                &sfb->fb.var.green);
 405                                val |= chan_to_field(blue, &sfb->fb.var.blue);
 406#ifdef __BIG_ENDIAN
 407                                pal[regno] =
 408                                    ((red & 0xf800) >> 8) |
 409                                    ((green & 0xe000) >> 13) |
 410                                    ((green & 0x1c00) << 3) |
 411                                    ((blue & 0xf800) >> 3);
 412#else
 413                                pal[regno] = val;
 414#endif
 415                        } else {
 416                                u32 *pal = sfb->fb.pseudo_palette;
 417                                val = chan_to_field(red, &sfb->fb.var.red);
 418                                val |= chan_to_field(green, \
 419                                                &sfb->fb.var.green);
 420                                val |= chan_to_field(blue, &sfb->fb.var.blue);
 421#ifdef __BIG_ENDIAN
 422                                val =
 423                                    (val & 0xff00ff00 >> 8) |
 424                                    (val & 0x00ff00ff << 8);
 425#endif
 426                                pal[regno] = val;
 427                        }
 428                }
 429                break;
 430
 431        case FB_VISUAL_PSEUDOCOLOR:
 432                /* color depth 8 bit */
 433                sm712_setpalette(regno, red, green, blue, info);
 434                break;
 435
 436        default:
 437                return 1;       /* unknown type */
 438        }
 439
 440        return 0;
 441
 442}
 443
 444#ifdef __BIG_ENDIAN
 445static ssize_t smtcfb_read(struct fb_info *info, char __user * buf, size_t
 446                                count, loff_t *ppos)
 447{
 448        unsigned long p = *ppos;
 449
 450        u32 *buffer, *dst;
 451        u32 __iomem *src;
 452        int c, i, cnt = 0, err = 0;
 453        unsigned long total_size;
 454
 455        if (!info || !info->screen_base)
 456                return -ENODEV;
 457
 458        if (info->state != FBINFO_STATE_RUNNING)
 459                return -EPERM;
 460
 461        total_size = info->screen_size;
 462
 463        if (total_size == 0)
 464                total_size = info->fix.smem_len;
 465
 466        if (p >= total_size)
 467                return 0;
 468
 469        if (count >= total_size)
 470                count = total_size;
 471
 472        if (count + p > total_size)
 473                count = total_size - p;
 474
 475        buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
 476        if (!buffer)
 477                return -ENOMEM;
 478
 479        src = (u32 __iomem *) (info->screen_base + p);
 480
 481        if (info->fbops->fb_sync)
 482                info->fbops->fb_sync(info);
 483
 484        while (count) {
 485                c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
 486                dst = buffer;
 487                for (i = c >> 2; i--;) {
 488                        *dst = fb_readl(src++);
 489                        *dst =
 490                            (*dst & 0xff00ff00 >> 8) |
 491                            (*dst & 0x00ff00ff << 8);
 492                        dst++;
 493                }
 494                if (c & 3) {
 495                        u8 *dst8 = (u8 *) dst;
 496                        u8 __iomem *src8 = (u8 __iomem *) src;
 497
 498                        for (i = c & 3; i--;) {
 499                                if (i & 1) {
 500                                        *dst8++ = fb_readb(++src8);
 501                                } else {
 502                                        *dst8++ = fb_readb(--src8);
 503                                        src8 += 2;
 504                                }
 505                        }
 506                        src = (u32 __iomem *) src8;
 507                }
 508
 509                if (copy_to_user(buf, buffer, c)) {
 510                        err = -EFAULT;
 511                        break;
 512                }
 513                *ppos += c;
 514                buf += c;
 515                cnt += c;
 516                count -= c;
 517        }
 518
 519        kfree(buffer);
 520
 521        return (err) ? err : cnt;
 522}
 523
 524static ssize_t
 525smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
 526             loff_t *ppos)
 527{
 528        unsigned long p = *ppos;
 529
 530        u32 *buffer, *src;
 531        u32 __iomem *dst;
 532        int c, i, cnt = 0, err = 0;
 533        unsigned long total_size;
 534
 535        if (!info || !info->screen_base)
 536                return -ENODEV;
 537
 538        if (info->state != FBINFO_STATE_RUNNING)
 539                return -EPERM;
 540
 541        total_size = info->screen_size;
 542
 543        if (total_size == 0)
 544                total_size = info->fix.smem_len;
 545
 546        if (p > total_size)
 547                return -EFBIG;
 548
 549        if (count > total_size) {
 550                err = -EFBIG;
 551                count = total_size;
 552        }
 553
 554        if (count + p > total_size) {
 555                if (!err)
 556                        err = -ENOSPC;
 557
 558                count = total_size - p;
 559        }
 560
 561        buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
 562        if (!buffer)
 563                return -ENOMEM;
 564
 565        dst = (u32 __iomem *) (info->screen_base + p);
 566
 567        if (info->fbops->fb_sync)
 568                info->fbops->fb_sync(info);
 569
 570        while (count) {
 571                c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
 572                src = buffer;
 573
 574                if (copy_from_user(src, buf, c)) {
 575                        err = -EFAULT;
 576                        break;
 577                }
 578
 579                for (i = c >> 2; i--;) {
 580                        fb_writel((*src & 0xff00ff00 >> 8) |
 581                                  (*src & 0x00ff00ff << 8), dst++);
 582                        src++;
 583                }
 584                if (c & 3) {
 585                        u8 *src8 = (u8 *) src;
 586                        u8 __iomem *dst8 = (u8 __iomem *) dst;
 587
 588                        for (i = c & 3; i--;) {
 589                                if (i & 1) {
 590                                        fb_writeb(*src8++, ++dst8);
 591                                } else {
 592                                        fb_writeb(*src8++, --dst8);
 593                                        dst8 += 2;
 594                                }
 595                        }
 596                        dst = (u32 __iomem *) dst8;
 597                }
 598
 599                *ppos += c;
 600                buf += c;
 601                cnt += c;
 602                count -= c;
 603        }
 604
 605        kfree(buffer);
 606
 607        return (cnt) ? cnt : err;
 608}
 609#endif  /* ! __BIG_ENDIAN */
 610
 611static struct fb_ops smtcfb_ops = {
 612        .owner = THIS_MODULE,
 613        .fb_setcolreg = smtc_setcolreg,
 614        .fb_blank = cfb_blank,
 615        .fb_fillrect = cfb_fillrect,
 616        .fb_imageblit = cfb_imageblit,
 617        .fb_copyarea = cfb_copyarea,
 618#ifdef __BIG_ENDIAN
 619        .fb_read = smtcfb_read,
 620        .fb_write = smtcfb_write,
 621#endif
 622
 623};
 624
 625void smtcfb_setmode(struct smtcfb_info *sfb)
 626{
 627        switch (sfb->fb.var.bits_per_pixel) {
 628        case 32:
 629                sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
 630                sfb->fb.fix.line_length = sfb->fb.var.xres * 4;
 631                sfb->fb.var.red.length = 8;
 632                sfb->fb.var.green.length = 8;
 633                sfb->fb.var.blue.length = 8;
 634                sfb->fb.var.red.offset = 16;
 635                sfb->fb.var.green.offset = 8;
 636                sfb->fb.var.blue.offset = 0;
 637
 638                break;
 639        case 8:
 640                sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
 641                sfb->fb.fix.line_length = sfb->fb.var.xres;
 642                sfb->fb.var.red.offset = 5;
 643                sfb->fb.var.red.length = 3;
 644                sfb->fb.var.green.offset = 2;
 645                sfb->fb.var.green.length = 3;
 646                sfb->fb.var.blue.offset = 0;
 647                sfb->fb.var.blue.length = 2;
 648                break;
 649        case 24:
 650                sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
 651                sfb->fb.fix.line_length = sfb->fb.var.xres * 3;
 652                sfb->fb.var.red.length = 8;
 653                sfb->fb.var.green.length = 8;
 654                sfb->fb.var.blue.length = 8;
 655
 656                sfb->fb.var.red.offset = 16;
 657                sfb->fb.var.green.offset = 8;
 658                sfb->fb.var.blue.offset = 0;
 659
 660                break;
 661        case 16:
 662        default:
 663                sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
 664                sfb->fb.fix.line_length = sfb->fb.var.xres * 2;
 665
 666                sfb->fb.var.red.length = 5;
 667                sfb->fb.var.green.length = 6;
 668                sfb->fb.var.blue.length = 5;
 669
 670                sfb->fb.var.red.offset = 11;
 671                sfb->fb.var.green.offset = 5;
 672                sfb->fb.var.blue.offset = 0;
 673
 674                break;
 675        }
 676
 677        hw.width = sfb->fb.var.xres;
 678        hw.height = sfb->fb.var.yres;
 679        hw.hz = 60;
 680        smtc_set_timing(sfb, &hw);
 681}
 682
 683/*
 684 * Alloc struct smtcfb_info and assign the default value
 685 */
 686static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
 687                                                        char *name)
 688{
 689        struct smtcfb_info *sfb;
 690
 691        sfb = kzalloc(sizeof(struct smtcfb_info), GFP_KERNEL);
 692
 693        if (!sfb)
 694                return NULL;
 695
 696        sfb->currcon = -1;
 697        sfb->dev = dev;
 698
 699        /*** Init sfb->fb with default value ***/
 700        sfb->fb.flags = FBINFO_FLAG_DEFAULT;
 701        sfb->fb.fbops = &smtcfb_ops;
 702        sfb->fb.var = smtcfb_var;
 703        sfb->fb.fix = smtcfb_fix;
 704
 705        strcpy(sfb->fb.fix.id, name);
 706
 707        sfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
 708        sfb->fb.fix.type_aux = 0;
 709        sfb->fb.fix.xpanstep = 0;
 710        sfb->fb.fix.ypanstep = 0;
 711        sfb->fb.fix.ywrapstep = 0;
 712        sfb->fb.fix.accel = FB_ACCEL_SMI_LYNX;
 713
 714        sfb->fb.var.nonstd = 0;
 715        sfb->fb.var.activate = FB_ACTIVATE_NOW;
 716        sfb->fb.var.height = -1;
 717        sfb->fb.var.width = -1;
 718        /* text mode acceleration */
 719        sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
 720        sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
 721        sfb->fb.par = &hw;
 722        sfb->fb.pseudo_palette = colreg;
 723
 724        return sfb;
 725}
 726
 727/*
 728 * Unmap in the memory mapped IO registers
 729 */
 730
 731static void smtc_unmap_mmio(struct smtcfb_info *sfb)
 732{
 733        if (sfb && smtc_RegBaseAddress)
 734                smtc_RegBaseAddress = NULL;
 735}
 736
 737/*
 738 * Map in the screen memory
 739 */
 740
 741static int smtc_map_smem(struct smtcfb_info *sfb,
 742                struct pci_dev *dev, u_long smem_len)
 743{
 744        if (sfb->fb.var.bits_per_pixel == 32) {
 745#ifdef __BIG_ENDIAN
 746                sfb->fb.fix.smem_start = pci_resource_start(dev, 0)
 747                        + 0x800000;
 748#else
 749                sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
 750#endif
 751        } else {
 752                sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
 753        }
 754
 755        sfb->fb.fix.smem_len = smem_len;
 756
 757        sfb->fb.screen_base = smtc_VRAMBaseAddress;
 758
 759        if (!sfb->fb.screen_base) {
 760                printk(KERN_INFO "%s: unable to map screen memory\n",
 761                                sfb->fb.fix.id);
 762                return -ENOMEM;
 763        }
 764
 765        return 0;
 766}
 767
 768/*
 769 * Unmap in the screen memory
 770 *
 771 */
 772static void smtc_unmap_smem(struct smtcfb_info *sfb)
 773{
 774        if (sfb && sfb->fb.screen_base) {
 775                iounmap(sfb->fb.screen_base);
 776                sfb->fb.screen_base = NULL;
 777        }
 778}
 779
 780/*
 781 * We need to wake up the LynxEM+, and make sure its in linear memory mode.
 782 */
 783static inline void sm7xx_init_hw(void)
 784{
 785        outb_p(0x18, 0x3c4);
 786        outb_p(0x11, 0x3c5);
 787}
 788
 789static void smtc_free_fb_info(struct smtcfb_info *sfb)
 790{
 791        if (sfb) {
 792                fb_alloc_cmap(&sfb->fb.cmap, 0, 0);
 793                kfree(sfb);
 794        }
 795}
 796
 797/*
 798 *      sm712vga_setup - process command line options, get vga parameter
 799 *      @options: string of options
 800 *      Returns zero.
 801 *
 802 */
 803static int __init __maybe_unused sm712vga_setup(char *options)
 804{
 805        int index;
 806
 807        if (!options || !*options) {
 808                smdbg("\n No vga parameter\n");
 809                return -EINVAL;
 810        }
 811
 812        smtc_screen_info.lfb_width = 0;
 813        smtc_screen_info.lfb_height = 0;
 814        smtc_screen_info.lfb_depth = 0;
 815
 816        smdbg("\nsm712vga_setup = %s\n", options);
 817
 818        for (index = 0;
 819             index < (sizeof(vesa_mode) / sizeof(struct vesa_mode_table));
 820             index++) {
 821                if (strstr(options, vesa_mode[index].mode_index)) {
 822                        smtc_screen_info.lfb_width = vesa_mode[index].lfb_width;
 823                        smtc_screen_info.lfb_height =
 824                                        vesa_mode[index].lfb_height;
 825                        smtc_screen_info.lfb_depth = vesa_mode[index].lfb_depth;
 826                        return 0;
 827                }
 828        }
 829
 830        return -1;
 831}
 832__setup("vga=", sm712vga_setup);
 833
 834/* Jason (08/13/2009)
 835 * Original init function changed to probe method to be used by pci_drv
 836 * process used to detect chips replaced with kernel process in pci_drv
 837 */
 838static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
 839                                   const struct pci_device_id *ent)
 840{
 841        struct smtcfb_info *sfb;
 842        u_long smem_size = 0x00800000;  /* default 8MB */
 843        char name[16];
 844        int err;
 845        unsigned long pFramebufferPhysical;
 846
 847        printk(KERN_INFO
 848                "Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n");
 849
 850        err = pci_enable_device(pdev);  /* enable SMTC chip */
 851        if (err)
 852                return err;
 853        err = -ENOMEM;
 854
 855        hw.chipID = ent->device;
 856        sprintf(name, "sm%Xfb", hw.chipID);
 857
 858        sfb = smtc_alloc_fb_info(pdev, name);
 859
 860        if (!sfb)
 861                goto failed_free;
 862        /* Jason (08/13/2009)
 863         * Store fb_info to be further used when suspending and resuming
 864         */
 865        pci_set_drvdata(pdev, sfb);
 866
 867        sm7xx_init_hw();
 868
 869        /*get mode parameter from smtc_screen_info */
 870        if (smtc_screen_info.lfb_width != 0) {
 871                sfb->fb.var.xres = smtc_screen_info.lfb_width;
 872                sfb->fb.var.yres = smtc_screen_info.lfb_height;
 873                sfb->fb.var.bits_per_pixel = smtc_screen_info.lfb_depth;
 874        } else {
 875                /* default resolution 1024x600 16bit mode */
 876                sfb->fb.var.xres = SCREEN_X_RES;
 877                sfb->fb.var.yres = SCREEN_Y_RES;
 878                sfb->fb.var.bits_per_pixel = SCREEN_BPP;
 879        }
 880
 881#ifdef __BIG_ENDIAN
 882        if (sfb->fb.var.bits_per_pixel == 24)
 883                sfb->fb.var.bits_per_pixel = (smtc_screen_info.lfb_depth = 32);
 884#endif
 885        /* Map address and memory detection */
 886        pFramebufferPhysical = pci_resource_start(pdev, 0);
 887        pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID);
 888
 889        switch (hw.chipID) {
 890        case 0x710:
 891        case 0x712:
 892                sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
 893                sfb->fb.fix.mmio_len = 0x00400000;
 894                smem_size = SM712_VIDEOMEMORYSIZE;
 895#ifdef __BIG_ENDIAN
 896                hw.m_pLFB = (smtc_VRAMBaseAddress =
 897                    ioremap(pFramebufferPhysical, 0x00c00000));
 898#else
 899                hw.m_pLFB = (smtc_VRAMBaseAddress =
 900                    ioremap(pFramebufferPhysical, 0x00800000));
 901#endif
 902                hw.m_pMMIO = (smtc_RegBaseAddress =
 903                    smtc_VRAMBaseAddress + 0x00700000);
 904                hw.m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
 905                hw.m_pVPR = hw.m_pLFB + 0x0040c000;
 906#ifdef __BIG_ENDIAN
 907                if (sfb->fb.var.bits_per_pixel == 32) {
 908                        smtc_VRAMBaseAddress += 0x800000;
 909                        hw.m_pLFB += 0x800000;
 910                        printk(KERN_INFO
 911                                "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n",
 912                                        smtc_VRAMBaseAddress, hw.m_pLFB);
 913                }
 914#endif
 915                if (!smtc_RegBaseAddress) {
 916                        printk(KERN_INFO
 917                                "%s: unable to map memory mapped IO\n",
 918                                sfb->fb.fix.id);
 919                        err = -ENOMEM;
 920                        goto failed_fb;
 921                }
 922
 923                /* set MCLK = 14.31818 * (0x16 / 0x2) */
 924                smtc_seqw(0x6a, 0x16);
 925                smtc_seqw(0x6b, 0x02);
 926                smtc_seqw(0x62, 0x3e);
 927                /* enable PCI burst */
 928                smtc_seqw(0x17, 0x20);
 929                /* enable word swap */
 930#ifdef __BIG_ENDIAN
 931                if (sfb->fb.var.bits_per_pixel == 32)
 932                        smtc_seqw(0x17, 0x30);
 933#endif
 934                break;
 935        case 0x720:
 936                sfb->fb.fix.mmio_start = pFramebufferPhysical;
 937                sfb->fb.fix.mmio_len = 0x00200000;
 938                smem_size = SM722_VIDEOMEMORYSIZE;
 939                hw.m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
 940                hw.m_pLFB = (smtc_VRAMBaseAddress =
 941                    hw.m_pDPR + 0x00200000);
 942                hw.m_pMMIO = (smtc_RegBaseAddress =
 943                    hw.m_pDPR + 0x000c0000);
 944                hw.m_pVPR = hw.m_pDPR + 0x800;
 945
 946                smtc_seqw(0x62, 0xff);
 947                smtc_seqw(0x6a, 0x0d);
 948                smtc_seqw(0x6b, 0x02);
 949                break;
 950        default:
 951                printk(KERN_INFO
 952                "No valid Silicon Motion display chip was detected!\n");
 953
 954                goto failed_fb;
 955        }
 956
 957        /* can support 32 bpp */
 958        if (15 == sfb->fb.var.bits_per_pixel)
 959                sfb->fb.var.bits_per_pixel = 16;
 960
 961        sfb->fb.var.xres_virtual = sfb->fb.var.xres;
 962        sfb->fb.var.yres_virtual = sfb->fb.var.yres;
 963        err = smtc_map_smem(sfb, pdev, smem_size);
 964        if (err)
 965                goto failed;
 966
 967        smtcfb_setmode(sfb);
 968        /* Primary display starting from 0 postion */
 969        hw.BaseAddressInVRAM = 0;
 970        sfb->fb.par = &hw;
 971
 972        err = register_framebuffer(&sfb->fb);
 973        if (err < 0)
 974                goto failed;
 975
 976        printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode"
 977                        "%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID,
 978                        sfb->fb.var.xres, sfb->fb.var.yres,
 979                        sfb->fb.var.bits_per_pixel);
 980
 981        return 0;
 982
 983 failed:
 984        printk(KERN_INFO "Silicon Motion, Inc.  primary display init fail\n");
 985
 986        smtc_unmap_smem(sfb);
 987        smtc_unmap_mmio(sfb);
 988failed_fb:
 989        smtc_free_fb_info(sfb);
 990
 991failed_free:
 992        pci_disable_device(pdev);
 993
 994        return err;
 995}
 996
 997
 998/* Jason (08/11/2009) PCI_DRV wrapper essential structs */
 999static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
1000        {0x126f, 0x710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1001        {0x126f, 0x712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1002        {0x126f, 0x720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1003        {0,}
1004};
1005
1006
1007/* Jason (08/14/2009)
1008 * do some clean up when the driver module is removed
1009 */
1010static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
1011{
1012        struct smtcfb_info *sfb;
1013
1014        sfb = pci_get_drvdata(pdev);
1015        pci_set_drvdata(pdev, NULL);
1016        smtc_unmap_smem(sfb);
1017        smtc_unmap_mmio(sfb);
1018        unregister_framebuffer(&sfb->fb);
1019        smtc_free_fb_info(sfb);
1020}
1021
1022/* Jason (08/14/2009)
1023 * suspend function, called when the suspend event is triggered
1024 */
1025static int __maybe_unused smtcfb_suspend(struct pci_dev *pdev, pm_message_t msg)
1026{
1027        struct smtcfb_info *sfb;
1028        int retv;
1029
1030        sfb = pci_get_drvdata(pdev);
1031
1032        /* set the hw in sleep mode use externel clock and self memory refresh
1033         * so that we can turn off internal PLLs later on
1034         */
1035        smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1036        smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1037
1038        switch (msg.event) {
1039        case PM_EVENT_FREEZE:
1040        case PM_EVENT_PRETHAW:
1041                pdev->dev.power.power_state = msg;
1042                return 0;
1043        }
1044
1045        /* when doing suspend, call fb apis and pci apis */
1046        if (msg.event == PM_EVENT_SUSPEND) {
1047                console_lock();
1048                fb_set_suspend(&sfb->fb, 1);
1049                console_unlock();
1050                retv = pci_save_state(pdev);
1051                pci_disable_device(pdev);
1052                retv = pci_choose_state(pdev, msg);
1053                retv = pci_set_power_state(pdev, retv);
1054        }
1055
1056        pdev->dev.power.power_state = msg;
1057
1058        /* additionaly turn off all function blocks including internal PLLs */
1059        smtc_seqw(0x21, 0xff);
1060
1061        return 0;
1062}
1063
1064static int __maybe_unused smtcfb_resume(struct pci_dev *pdev)
1065{
1066        struct smtcfb_info *sfb;
1067        int retv;
1068
1069        sfb = pci_get_drvdata(pdev);
1070
1071        /* when resuming, restore pci data and fb cursor */
1072        if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
1073                retv = pci_set_power_state(pdev, PCI_D0);
1074                pci_restore_state(pdev);
1075                if (pci_enable_device(pdev))
1076                        return -1;
1077                pci_set_master(pdev);
1078        }
1079
1080        /* reinit hardware */
1081        sm7xx_init_hw();
1082        switch (hw.chipID) {
1083        case 0x710:
1084        case 0x712:
1085                /* set MCLK = 14.31818 *  (0x16 / 0x2) */
1086                smtc_seqw(0x6a, 0x16);
1087                smtc_seqw(0x6b, 0x02);
1088                smtc_seqw(0x62, 0x3e);
1089                /* enable PCI burst */
1090                smtc_seqw(0x17, 0x20);
1091#ifdef __BIG_ENDIAN
1092                if (sfb->fb.var.bits_per_pixel == 32)
1093                        smtc_seqw(0x17, 0x30);
1094#endif
1095                break;
1096        case 0x720:
1097                smtc_seqw(0x62, 0xff);
1098                smtc_seqw(0x6a, 0x0d);
1099                smtc_seqw(0x6b, 0x02);
1100                break;
1101        }
1102
1103        smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1104        smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1105
1106        smtcfb_setmode(sfb);
1107
1108        console_lock();
1109        fb_set_suspend(&sfb->fb, 0);
1110        console_unlock();
1111
1112        return 0;
1113}
1114
1115/* Jason (08/13/2009)
1116 * pci_driver struct used to wrap the original driver
1117 * so that it can be registered into the kernel and
1118 * the proper method would be called when suspending and resuming
1119 */
1120static struct pci_driver smtcfb_driver = {
1121        .name = "smtcfb",
1122        .id_table = smtcfb_pci_table,
1123        .probe = smtcfb_pci_probe,
1124        .remove = __devexit_p(smtcfb_pci_remove),
1125#ifdef CONFIG_PM
1126        .suspend = smtcfb_suspend,
1127        .resume = smtcfb_resume,
1128#endif
1129};
1130
1131static int __init smtcfb_init(void)
1132{
1133        return pci_register_driver(&smtcfb_driver);
1134}
1135
1136static void __exit smtcfb_exit(void)
1137{
1138        pci_unregister_driver(&smtcfb_driver);
1139}
1140
1141module_init(smtcfb_init);
1142module_exit(smtcfb_exit);
1143
1144MODULE_AUTHOR("Siliconmotion ");
1145MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1146MODULE_LICENSE("GPL");
1147