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