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 * 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 * Version 0.10.26192.21.01
  19 *      - Add PowerPC/Big endian support
  20 *      - Verified on 2.6.19.2
  21 *      Boyod.yang <boyod.yang@siliconmotion.com.cn>
  22 *
  23 * Version 0.09.2621.00.01
  24 *      - Only support Linux Kernel's version 2.6.21
  25 *      Boyod.yang <boyod.yang@siliconmotion.com.cn>
  26 *
  27 * Version 0.09
  28 *      - Only support Linux Kernel's version 2.6.12
  29 *      Boyod.yang <boyod.yang@siliconmotion.com.cn>
  30 */
  31
  32#include <linux/io.h>
  33#include <linux/fb.h>
  34#include <linux/pci.h>
  35#include <linux/init.h>
  36#include <linux/slab.h>
  37#include <linux/uaccess.h>
  38#include <linux/module.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
  46#include "smtcfb.h"
  47
  48#ifdef DEBUG
  49#define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg)
  50#else
  51#define smdbg(format, arg...)
  52#endif
  53
  54struct screen_info smtc_screen_info;
  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 ARRAY_SIZE(smtc_ChipIDs)
 133
 134static struct fb_var_screeninfo smtcfb_var = {
 135        .xres           = 1024,
 136        .yres           = 600,
 137        .xres_virtual   = 1024,
 138        .yres_virtual   = 600,
 139        .bits_per_pixel = 16,
 140        .red            = {16, 8, 0},
 141        .green          = {8, 8, 0},
 142        .blue           = {0, 8, 0},
 143        .activate       = FB_ACTIVATE_NOW,
 144        .height         = -1,
 145        .width          = -1,
 146        .vmode          = FB_VMODE_NONINTERLACED,
 147};
 148
 149static struct fb_fix_screeninfo smtcfb_fix = {
 150        .id             = "sm712fb",
 151        .type           = FB_TYPE_PACKED_PIXELS,
 152        .visual         = FB_VISUAL_TRUECOLOR,
 153        .line_length    = 800 * 3,
 154        .accel          = FB_ACCEL_SMI_LYNX,
 155};
 156
 157static void sm712_set_timing(struct smtcfb_info *sfb,
 158                             struct par_info *ppar_info)
 159{
 160        int i = 0, j = 0;
 161        u32 m_nScreenStride;
 162
 163        smdbg("\nppar_info->width = %d ppar_info->height = %d"
 164                        "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n",
 165                        ppar_info->width, ppar_info->height,
 166                        sfb->fb.var.bits_per_pixel, ppar_info->hz);
 167
 168        for (j = 0; j < numVGAModes; j++) {
 169                if (VGAMode[j].mmSizeX == ppar_info->width &&
 170                    VGAMode[j].mmSizeY == ppar_info->height &&
 171                    VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
 172                    VGAMode[j].hz == ppar_info->hz) {
 173
 174                        smdbg("\nVGAMode[j].mmSizeX  = %d VGAMode[j].mmSizeY ="
 175                                        "%d VGAMode[j].bpp = %d"
 176                                        "VGAMode[j].hz=%d\n",
 177                                        VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
 178                                        VGAMode[j].bpp, VGAMode[j].hz);
 179
 180                        smdbg("VGAMode index=%d\n", j);
 181
 182                        smtc_mmiowb(0x0, 0x3c6);
 183
 184                        smtc_seqw(0, 0x1);
 185
 186                        smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2);
 187
 188                        /* init SEQ register SR00 - SR04 */
 189                        for (i = 0; i < SIZE_SR00_SR04; i++)
 190                                smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]);
 191
 192                        /* init SEQ register SR10 - SR24 */
 193                        for (i = 0; i < SIZE_SR10_SR24; i++)
 194                                smtc_seqw(i + 0x10,
 195                                          VGAMode[j].Init_SR10_SR24[i]);
 196
 197                        /* init SEQ register SR30 - SR75 */
 198                        for (i = 0; i < SIZE_SR30_SR75; i++)
 199                                if (((i + 0x30) != 0x62) \
 200                                        && ((i + 0x30) != 0x6a) \
 201                                        && ((i + 0x30) != 0x6b))
 202                                        smtc_seqw(i + 0x30,
 203                                                VGAMode[j].Init_SR30_SR75[i]);
 204
 205                        /* init SEQ register SR80 - SR93 */
 206                        for (i = 0; i < SIZE_SR80_SR93; i++)
 207                                smtc_seqw(i + 0x80,
 208                                          VGAMode[j].Init_SR80_SR93[i]);
 209
 210                        /* init SEQ register SRA0 - SRAF */
 211                        for (i = 0; i < SIZE_SRA0_SRAF; i++)
 212                                smtc_seqw(i + 0xa0,
 213                                          VGAMode[j].Init_SRA0_SRAF[i]);
 214
 215                        /* init Graphic register GR00 - GR08 */
 216                        for (i = 0; i < SIZE_GR00_GR08; i++)
 217                                smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]);
 218
 219                        /* init Attribute register AR00 - AR14 */
 220                        for (i = 0; i < SIZE_AR00_AR14; i++)
 221                                smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]);
 222
 223                        /* init CRTC register CR00 - CR18 */
 224                        for (i = 0; i < SIZE_CR00_CR18; i++)
 225                                smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]);
 226
 227                        /* init CRTC register CR30 - CR4D */
 228                        for (i = 0; i < SIZE_CR30_CR4D; i++)
 229                                smtc_crtcw(i + 0x30,
 230                                           VGAMode[j].Init_CR30_CR4D[i]);
 231
 232                        /* init CRTC register CR90 - CRA7 */
 233                        for (i = 0; i < SIZE_CR90_CRA7; i++)
 234                                smtc_crtcw(i + 0x90,
 235                                           VGAMode[j].Init_CR90_CRA7[i]);
 236                }
 237        }
 238        smtc_mmiowb(0x67, 0x3c2);
 239
 240        /* set VPR registers */
 241        writel(0x0, ppar_info->m_pVPR + 0x0C);
 242        writel(0x0, ppar_info->m_pVPR + 0x40);
 243
 244        /* set data width */
 245        m_nScreenStride =
 246                (ppar_info->width * sfb->fb.var.bits_per_pixel) / 64;
 247        switch (sfb->fb.var.bits_per_pixel) {
 248        case 8:
 249                writel(0x0, ppar_info->m_pVPR + 0x0);
 250                break;
 251        case 16:
 252                writel(0x00020000, ppar_info->m_pVPR + 0x0);
 253                break;
 254        case 24:
 255                writel(0x00040000, ppar_info->m_pVPR + 0x0);
 256                break;
 257        case 32:
 258                writel(0x00030000, ppar_info->m_pVPR + 0x0);
 259                break;
 260        }
 261        writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
 262               ppar_info->m_pVPR + 0x10);
 263
 264}
 265
 266static void sm712_setpalette(int regno, unsigned red, unsigned green,
 267                             unsigned blue, struct fb_info *info)
 268{
 269        struct par_info *cur_par = (struct par_info *)info->par;
 270
 271        if (cur_par->BaseAddressInVRAM)
 272                /*
 273                 * second display palette for dual head. Enable CRT RAM, 6-bit
 274                 * RAM
 275                 */
 276                smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x20);
 277        else
 278                /* primary display palette. Enable LCD RAM only, 6-bit RAM */
 279                smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
 280        smtc_mmiowb(regno, dac_reg);
 281        smtc_mmiowb(red >> 10, dac_val);
 282        smtc_mmiowb(green >> 10, dac_val);
 283        smtc_mmiowb(blue >> 10, dac_val);
 284}
 285
 286static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info
 287                *ppar_info)
 288{
 289        switch (ppar_info->chipID) {
 290        case 0x710:
 291        case 0x712:
 292        case 0x720:
 293                sm712_set_timing(sfb, ppar_info);
 294                break;
 295        }
 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
 611void smtcfb_setmode(struct smtcfb_info *sfb)
 612{
 613        switch (sfb->fb.var.bits_per_pixel) {
 614        case 32:
 615                sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
 616                sfb->fb.fix.line_length = sfb->fb.var.xres * 4;
 617                sfb->fb.var.red.length = 8;
 618                sfb->fb.var.green.length = 8;
 619                sfb->fb.var.blue.length = 8;
 620                sfb->fb.var.red.offset = 16;
 621                sfb->fb.var.green.offset = 8;
 622                sfb->fb.var.blue.offset = 0;
 623
 624                break;
 625        case 8:
 626                sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
 627                sfb->fb.fix.line_length = sfb->fb.var.xres;
 628                sfb->fb.var.red.offset = 5;
 629                sfb->fb.var.red.length = 3;
 630                sfb->fb.var.green.offset = 2;
 631                sfb->fb.var.green.length = 3;
 632                sfb->fb.var.blue.offset = 0;
 633                sfb->fb.var.blue.length = 2;
 634                break;
 635        case 24:
 636                sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
 637                sfb->fb.fix.line_length = sfb->fb.var.xres * 3;
 638                sfb->fb.var.red.length = 8;
 639                sfb->fb.var.green.length = 8;
 640                sfb->fb.var.blue.length = 8;
 641
 642                sfb->fb.var.red.offset = 16;
 643                sfb->fb.var.green.offset = 8;
 644                sfb->fb.var.blue.offset = 0;
 645
 646                break;
 647        case 16:
 648        default:
 649                sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
 650                sfb->fb.fix.line_length = sfb->fb.var.xres * 2;
 651
 652                sfb->fb.var.red.length = 5;
 653                sfb->fb.var.green.length = 6;
 654                sfb->fb.var.blue.length = 5;
 655
 656                sfb->fb.var.red.offset = 11;
 657                sfb->fb.var.green.offset = 5;
 658                sfb->fb.var.blue.offset = 0;
 659
 660                break;
 661        }
 662
 663        hw.width = sfb->fb.var.xres;
 664        hw.height = sfb->fb.var.yres;
 665        hw.hz = 60;
 666        smtc_set_timing(sfb, &hw);
 667}
 668
 669static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 670{
 671        /* sanity checks */
 672        if (var->xres_virtual < var->xres)
 673                var->xres_virtual = var->xres;
 674
 675        if (var->yres_virtual < var->yres)
 676                var->yres_virtual = var->yres;
 677
 678        /* set valid default bpp */
 679        if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
 680            (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
 681                var->bits_per_pixel = 16;
 682
 683        return 0;
 684}
 685
 686static int smtc_set_par(struct fb_info *info)
 687{
 688        struct smtcfb_info *sfb = (struct smtcfb_info *)info;
 689
 690        smtcfb_setmode(sfb);
 691
 692        return 0;
 693}
 694
 695static struct fb_ops smtcfb_ops = {
 696        .owner        = THIS_MODULE,
 697        .fb_check_var = smtc_check_var,
 698        .fb_set_par   = smtc_set_par,
 699        .fb_setcolreg = smtc_setcolreg,
 700        .fb_blank     = cfb_blank,
 701        .fb_fillrect  = cfb_fillrect,
 702        .fb_imageblit = cfb_imageblit,
 703        .fb_copyarea  = cfb_copyarea,
 704#ifdef __BIG_ENDIAN
 705        .fb_read      = smtcfb_read,
 706        .fb_write     = smtcfb_write,
 707#endif
 708};
 709
 710/*
 711 * Alloc struct smtcfb_info and assign the default value
 712 */
 713static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
 714                                                        char *name)
 715{
 716        struct smtcfb_info *sfb;
 717
 718        sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
 719
 720        if (!sfb)
 721                return NULL;
 722
 723        sfb->currcon = -1;
 724        sfb->dev = dev;
 725
 726        /*** Init sfb->fb with default value ***/
 727        sfb->fb.flags = FBINFO_FLAG_DEFAULT;
 728        sfb->fb.fbops = &smtcfb_ops;
 729        sfb->fb.var = smtcfb_var;
 730        sfb->fb.fix = smtcfb_fix;
 731
 732        strcpy(sfb->fb.fix.id, name);
 733
 734        sfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
 735        sfb->fb.fix.type_aux = 0;
 736        sfb->fb.fix.xpanstep = 0;
 737        sfb->fb.fix.ypanstep = 0;
 738        sfb->fb.fix.ywrapstep = 0;
 739        sfb->fb.fix.accel = FB_ACCEL_SMI_LYNX;
 740
 741        sfb->fb.var.nonstd = 0;
 742        sfb->fb.var.activate = FB_ACTIVATE_NOW;
 743        sfb->fb.var.height = -1;
 744        sfb->fb.var.width = -1;
 745        /* text mode acceleration */
 746        sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
 747        sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
 748        sfb->fb.par = &hw;
 749        sfb->fb.pseudo_palette = colreg;
 750
 751        return sfb;
 752}
 753
 754/*
 755 * Unmap in the memory mapped IO registers
 756 */
 757
 758static void smtc_unmap_mmio(struct smtcfb_info *sfb)
 759{
 760        if (sfb && smtc_RegBaseAddress)
 761                smtc_RegBaseAddress = NULL;
 762}
 763
 764/*
 765 * Map in the screen memory
 766 */
 767
 768static int smtc_map_smem(struct smtcfb_info *sfb,
 769                struct pci_dev *dev, u_long smem_len)
 770{
 771        if (sfb->fb.var.bits_per_pixel == 32) {
 772#ifdef __BIG_ENDIAN
 773                sfb->fb.fix.smem_start = pci_resource_start(dev, 0)
 774                        + 0x800000;
 775#else
 776                sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
 777#endif
 778        } else {
 779                sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
 780        }
 781
 782        sfb->fb.fix.smem_len = smem_len;
 783
 784        sfb->fb.screen_base = smtc_VRAMBaseAddress;
 785
 786        if (!sfb->fb.screen_base) {
 787                printk(KERN_ERR "%s: unable to map screen memory\n",
 788                                sfb->fb.fix.id);
 789                return -ENOMEM;
 790        }
 791
 792        return 0;
 793}
 794
 795/*
 796 * Unmap in the screen memory
 797 *
 798 */
 799static void smtc_unmap_smem(struct smtcfb_info *sfb)
 800{
 801        if (sfb && sfb->fb.screen_base) {
 802                iounmap(sfb->fb.screen_base);
 803                sfb->fb.screen_base = NULL;
 804        }
 805}
 806
 807/*
 808 * We need to wake up the LynxEM+, and make sure its in linear memory mode.
 809 */
 810static inline void sm7xx_init_hw(void)
 811{
 812        outb_p(0x18, 0x3c4);
 813        outb_p(0x11, 0x3c5);
 814}
 815
 816static void smtc_free_fb_info(struct smtcfb_info *sfb)
 817{
 818        if (sfb) {
 819                fb_alloc_cmap(&sfb->fb.cmap, 0, 0);
 820                kfree(sfb);
 821        }
 822}
 823
 824/*
 825 *      sm712vga_setup - process command line options, get vga parameter
 826 *      @options: string of options
 827 *      Returns zero.
 828 *
 829 */
 830static int __init sm712vga_setup(char *options)
 831{
 832        int index;
 833
 834        if (!options || !*options) {
 835                smdbg("\n No vga parameter\n");
 836                return -EINVAL;
 837        }
 838
 839        smtc_screen_info.lfb_width = 0;
 840        smtc_screen_info.lfb_height = 0;
 841        smtc_screen_info.lfb_depth = 0;
 842
 843        smdbg("\nsm712vga_setup = %s\n", options);
 844
 845        for (index = 0;
 846             index < ARRAY_SIZE(vesa_mode);
 847             index++) {
 848                if (strstr(options, vesa_mode[index].mode_index)) {
 849                        smtc_screen_info.lfb_width = vesa_mode[index].lfb_width;
 850                        smtc_screen_info.lfb_height =
 851                                        vesa_mode[index].lfb_height;
 852                        smtc_screen_info.lfb_depth = vesa_mode[index].lfb_depth;
 853                        return 0;
 854                }
 855        }
 856
 857        return -1;
 858}
 859__setup("vga=", sm712vga_setup);
 860
 861/* Jason (08/13/2009)
 862 * Original init function changed to probe method to be used by pci_drv
 863 * process used to detect chips replaced with kernel process in pci_drv
 864 */
 865static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
 866                                   const struct pci_device_id *ent)
 867{
 868        struct smtcfb_info *sfb;
 869        u_long smem_size = 0x00800000;  /* default 8MB */
 870        char name[16];
 871        int err;
 872        unsigned long pFramebufferPhysical;
 873
 874        printk(KERN_INFO
 875                "Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n");
 876
 877        err = pci_enable_device(pdev);  /* enable SMTC chip */
 878        if (err)
 879                return err;
 880
 881        hw.chipID = ent->device;
 882        sprintf(name, "sm%Xfb", hw.chipID);
 883
 884        sfb = smtc_alloc_fb_info(pdev, name);
 885
 886        if (!sfb)
 887                goto failed_free;
 888        /* Jason (08/13/2009)
 889         * Store fb_info to be further used when suspending and resuming
 890         */
 891        pci_set_drvdata(pdev, sfb);
 892
 893        sm7xx_init_hw();
 894
 895        /*get mode parameter from smtc_screen_info */
 896        if (smtc_screen_info.lfb_width != 0) {
 897                sfb->fb.var.xres = smtc_screen_info.lfb_width;
 898                sfb->fb.var.yres = smtc_screen_info.lfb_height;
 899                sfb->fb.var.bits_per_pixel = smtc_screen_info.lfb_depth;
 900        } else {
 901                /* default resolution 1024x600 16bit mode */
 902                sfb->fb.var.xres = SCREEN_X_RES;
 903                sfb->fb.var.yres = SCREEN_Y_RES;
 904                sfb->fb.var.bits_per_pixel = SCREEN_BPP;
 905        }
 906
 907#ifdef __BIG_ENDIAN
 908        if (sfb->fb.var.bits_per_pixel == 24)
 909                sfb->fb.var.bits_per_pixel = (smtc_screen_info.lfb_depth = 32);
 910#endif
 911        /* Map address and memory detection */
 912        pFramebufferPhysical = pci_resource_start(pdev, 0);
 913        pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID);
 914
 915        switch (hw.chipID) {
 916        case 0x710:
 917        case 0x712:
 918                sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
 919                sfb->fb.fix.mmio_len = 0x00400000;
 920                smem_size = SM712_VIDEOMEMORYSIZE;
 921#ifdef __BIG_ENDIAN
 922                hw.m_pLFB = (smtc_VRAMBaseAddress =
 923                    ioremap(pFramebufferPhysical, 0x00c00000));
 924#else
 925                hw.m_pLFB = (smtc_VRAMBaseAddress =
 926                    ioremap(pFramebufferPhysical, 0x00800000));
 927#endif
 928                hw.m_pMMIO = (smtc_RegBaseAddress =
 929                    smtc_VRAMBaseAddress + 0x00700000);
 930                hw.m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
 931                hw.m_pVPR = hw.m_pLFB + 0x0040c000;
 932#ifdef __BIG_ENDIAN
 933                if (sfb->fb.var.bits_per_pixel == 32) {
 934                        smtc_VRAMBaseAddress += 0x800000;
 935                        hw.m_pLFB += 0x800000;
 936                        printk(KERN_INFO
 937                                "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n",
 938                                        smtc_VRAMBaseAddress, hw.m_pLFB);
 939                }
 940#endif
 941                if (!smtc_RegBaseAddress) {
 942                        printk(KERN_ERR
 943                                "%s: unable to map memory mapped IO\n",
 944                                sfb->fb.fix.id);
 945                        err = -ENOMEM;
 946                        goto failed_fb;
 947                }
 948
 949                /* set MCLK = 14.31818 * (0x16 / 0x2) */
 950                smtc_seqw(0x6a, 0x16);
 951                smtc_seqw(0x6b, 0x02);
 952                smtc_seqw(0x62, 0x3e);
 953                /* enable PCI burst */
 954                smtc_seqw(0x17, 0x20);
 955                /* enable word swap */
 956#ifdef __BIG_ENDIAN
 957                if (sfb->fb.var.bits_per_pixel == 32)
 958                        smtc_seqw(0x17, 0x30);
 959#endif
 960                break;
 961        case 0x720:
 962                sfb->fb.fix.mmio_start = pFramebufferPhysical;
 963                sfb->fb.fix.mmio_len = 0x00200000;
 964                smem_size = SM722_VIDEOMEMORYSIZE;
 965                hw.m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
 966                hw.m_pLFB = (smtc_VRAMBaseAddress =
 967                    hw.m_pDPR + 0x00200000);
 968                hw.m_pMMIO = (smtc_RegBaseAddress =
 969                    hw.m_pDPR + 0x000c0000);
 970                hw.m_pVPR = hw.m_pDPR + 0x800;
 971
 972                smtc_seqw(0x62, 0xff);
 973                smtc_seqw(0x6a, 0x0d);
 974                smtc_seqw(0x6b, 0x02);
 975                break;
 976        default:
 977                printk(KERN_ERR
 978                "No valid Silicon Motion display chip was detected!\n");
 979
 980                goto failed_fb;
 981        }
 982
 983        /* can support 32 bpp */
 984        if (15 == sfb->fb.var.bits_per_pixel)
 985                sfb->fb.var.bits_per_pixel = 16;
 986
 987        sfb->fb.var.xres_virtual = sfb->fb.var.xres;
 988        sfb->fb.var.yres_virtual = sfb->fb.var.yres;
 989        err = smtc_map_smem(sfb, pdev, smem_size);
 990        if (err)
 991                goto failed;
 992
 993        smtcfb_setmode(sfb);
 994        /* Primary display starting from 0 position */
 995        hw.BaseAddressInVRAM = 0;
 996        sfb->fb.par = &hw;
 997
 998        err = register_framebuffer(&sfb->fb);
 999        if (err < 0)
1000                goto failed;
1001
1002        printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode"
1003                        "%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID,
1004                        sfb->fb.var.xres, sfb->fb.var.yres,
1005                        sfb->fb.var.bits_per_pixel);
1006
1007        return 0;
1008
1009failed:
1010        printk(KERN_ERR "Silicon Motion, Inc.  primary display init fail\n");
1011
1012        smtc_unmap_smem(sfb);
1013        smtc_unmap_mmio(sfb);
1014failed_fb:
1015        smtc_free_fb_info(sfb);
1016
1017failed_free:
1018        pci_disable_device(pdev);
1019
1020        return err;
1021}
1022
1023
1024/* Jason (08/11/2009) PCI_DRV wrapper essential structs */
1025static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
1026        { PCI_DEVICE(0x126f, 0x710), },
1027        { PCI_DEVICE(0x126f, 0x712), },
1028        { PCI_DEVICE(0x126f, 0x720), },
1029        {0,}
1030};
1031
1032
1033/* Jason (08/14/2009)
1034 * do some clean up when the driver module is removed
1035 */
1036static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
1037{
1038        struct smtcfb_info *sfb;
1039
1040        sfb = pci_get_drvdata(pdev);
1041        pci_set_drvdata(pdev, NULL);
1042        smtc_unmap_smem(sfb);
1043        smtc_unmap_mmio(sfb);
1044        unregister_framebuffer(&sfb->fb);
1045        smtc_free_fb_info(sfb);
1046}
1047
1048#ifdef CONFIG_PM
1049static int smtcfb_pci_suspend(struct device *device)
1050{
1051        struct pci_dev *pdev = to_pci_dev(device);
1052        struct smtcfb_info *sfb;
1053
1054        sfb = pci_get_drvdata(pdev);
1055
1056        /* set the hw in sleep mode use externel clock and self memory refresh
1057         * so that we can turn off internal PLLs later on
1058         */
1059        smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1060        smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1061
1062        console_lock();
1063        fb_set_suspend(&sfb->fb, 1);
1064        console_unlock();
1065
1066        /* additionally turn off all function blocks including internal PLLs */
1067        smtc_seqw(0x21, 0xff);
1068
1069        return 0;
1070}
1071
1072static int smtcfb_pci_resume(struct device *device)
1073{
1074        struct pci_dev *pdev = to_pci_dev(device);
1075        struct smtcfb_info *sfb;
1076
1077        sfb = pci_get_drvdata(pdev);
1078
1079        /* reinit hardware */
1080        sm7xx_init_hw();
1081        switch (hw.chipID) {
1082        case 0x710:
1083        case 0x712:
1084                /* set MCLK = 14.31818 *  (0x16 / 0x2) */
1085                smtc_seqw(0x6a, 0x16);
1086                smtc_seqw(0x6b, 0x02);
1087                smtc_seqw(0x62, 0x3e);
1088                /* enable PCI burst */
1089                smtc_seqw(0x17, 0x20);
1090#ifdef __BIG_ENDIAN
1091                if (sfb->fb.var.bits_per_pixel == 32)
1092                        smtc_seqw(0x17, 0x30);
1093#endif
1094                break;
1095        case 0x720:
1096                smtc_seqw(0x62, 0xff);
1097                smtc_seqw(0x6a, 0x0d);
1098                smtc_seqw(0x6b, 0x02);
1099                break;
1100        }
1101
1102        smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1103        smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1104
1105        smtcfb_setmode(sfb);
1106
1107        console_lock();
1108        fb_set_suspend(&sfb->fb, 0);
1109        console_unlock();
1110
1111        return 0;
1112}
1113
1114static const struct dev_pm_ops sm7xx_pm_ops = {
1115        .suspend = smtcfb_pci_suspend,
1116        .resume = smtcfb_pci_resume,
1117        .freeze = smtcfb_pci_suspend,
1118        .thaw = smtcfb_pci_resume,
1119        .poweroff = smtcfb_pci_suspend,
1120        .restore = smtcfb_pci_resume,
1121};
1122
1123#define SM7XX_PM_OPS (&sm7xx_pm_ops)
1124
1125#else  /* !CONFIG_PM */
1126
1127#define SM7XX_PM_OPS NULL
1128
1129#endif /* !CONFIG_PM */
1130
1131static struct pci_driver smtcfb_driver = {
1132        .name = "smtcfb",
1133        .id_table = smtcfb_pci_table,
1134        .probe = smtcfb_pci_probe,
1135        .remove = __devexit_p(smtcfb_pci_remove),
1136        .driver.pm  = SM7XX_PM_OPS,
1137};
1138
1139static int __init smtcfb_init(void)
1140{
1141        return pci_register_driver(&smtcfb_driver);
1142}
1143
1144static void __exit smtcfb_exit(void)
1145{
1146        pci_unregister_driver(&smtcfb_driver);
1147}
1148
1149module_init(smtcfb_init);
1150module_exit(smtcfb_exit);
1151
1152MODULE_AUTHOR("Siliconmotion ");
1153MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1154MODULE_LICENSE("GPL");
1155